You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/koproperty/editor.cpp

1028 lines
28 KiB

/* This file is part of the KDE project
Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "editor.h"
#include "editoritem.h"
#include "set.h"
#include "factory.h"
#include "property.h"
#include "widget.h"
#include <tqpushbutton.h>
#include <tqlayout.h>
#include <tqmap.h>
#include <tqguardedptr.h>
#include <tqheader.h>
#include <tqasciidict.h>
#include <tqtooltip.h>
#include <tqapplication.h>
#include <tqeventloop.h>
#include <tqtimer.h>
#include <tqlabel.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klocale.h>
#include <tdeversion.h>
#include <kapplication.h>
namespace KoProperty {
//! @internal
static bool kofficeAppDirAdded = false;
//! \return true if \a o has parent \a par.
//! @internal
inline bool hasParent(TQObject* par, TQObject* o)
{
if (!o || !par)
return false;
while (o && o != par)
o = o->parent();
return o == par;
}
class EditorPrivate
{
public:
EditorPrivate(Editor *editor)
: itemDict(101, false), justClickedItem(false)
{
currentItem = 0;
undoButton = 0;
topItem = 0;
itemToSelectLater = 0;
if (!kofficeAppDirAdded) {
kofficeAppDirAdded = true;
KGlobal::iconLoader()->addAppDir("koffice");
}
previouslyCollapsedGroupItem = 0;
childFormPreviouslyCollapsedGroupItem = 0;
slotPropertyChanged_enabled = true;
TQObject::connect(&changeSetLaterTimer, TQT_SIGNAL(timeout()),
editor, TQT_SLOT(changeSetLater()));
}
~EditorPrivate()
{
}
TQGuardedPtr<Set> set;
//! widget cache for property types, widget will be deleted
TQMap<Property*, Widget* > widgetCache;
TQGuardedPtr<Widget> currentWidget;
EditorItem *currentItem;
EditorItem *topItem; //! The top item is used to control the drawing of every branches.
TQPushButton *undoButton; //! "Revert to defaults" button
EditorItem::Dict itemDict;
int baseRowHeight;
bool sync : 1;
bool insideSlotValueChanged : 1;
//! Helpers for changeSetLater()
TQTimer changeSetLaterTimer;
bool setListLater_set : 1;
bool preservePrevSelection_preservePrevSelection : 1;
TQCString preservePrevSelection_propertyToSelect;
//bool doNotSetFocusOnSelection : 1;
//! Used in setFocus() to prevent scrolling to previously selected item on mouse click
bool justClickedItem : 1;
//! Helper for slotWidgetValueChanged()
bool slotPropertyChanged_enabled : 1;
//! Helper for changeSet()
Set* setListLater_list;
//! used by selectItemLater()
EditorItem *itemToSelectLater;
TQListViewItem *previouslyCollapsedGroupItem;
TQListViewItem *childFormPreviouslyCollapsedGroupItem;
};
}
using namespace KoProperty;
Editor::Editor(TQWidget *parent, bool autoSync, const char *name)
: KListView(parent, name)
{
d = new EditorPrivate(this);
d->itemDict.setAutoDelete(false);
d->set = 0;
d->topItem = 0;
d->currentItem = 0;
d->sync = autoSync;
d->insideSlotValueChanged = false;
d->setListLater_set = false;
d->preservePrevSelection_preservePrevSelection = false;
d->setListLater_list = 0;
d->undoButton = new TQPushButton(viewport());
d->undoButton->setFocusPolicy(TQ_NoFocus);
setFocusPolicy(TQ_ClickFocus);
d->undoButton->setMinimumSize(TQSize(5,5)); // allow to resize undoButton even below pixmap size
d->undoButton->setPixmap(SmallIcon("undo"));
TQToolTip::add(d->undoButton, i18n("Undo changes"));
d->undoButton->hide();
connect(d->undoButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(undo()));
installEventFilter(this);
viewport()->installEventFilter(this);
addColumn(i18n("Name"));
addColumn(i18n("Value"));
setAllColumnsShowFocus(true);
setColumnWidthMode(0, TQListView::Maximum);
setFullWidth(true);
setShowSortIndicator(false);
#if KDE_IS_VERSION(3,3,9)
setShadeSortColumn(false);
#endif
setTooltipColumn(0);
setSorting(0);
setItemMargin(KPROPEDITOR_ITEM_MARGIN);
header()->setMovingEnabled( false );
setTreeStepSize(16 + 2/*left*/ + 1/*right*/);
updateFont();
// d->baseRowHeight = TQFontMetrics(font()).height() + itemMargin()*2;
connect(this, TQT_SIGNAL(selectionChanged(TQListViewItem *)), this, TQT_SLOT(slotClicked(TQListViewItem *)));
connect(this, TQT_SIGNAL(currentChanged(TQListViewItem *)), this, TQT_SLOT(slotCurrentChanged(TQListViewItem *)));
connect(this, TQT_SIGNAL(expanded(TQListViewItem *)), this, TQT_SLOT(slotExpanded(TQListViewItem *)));
connect(this, TQT_SIGNAL(collapsed(TQListViewItem *)), this, TQT_SLOT(slotCollapsed(TQListViewItem *)));
connect(header(), TQT_SIGNAL(sizeChange(int, int, int)), this, TQT_SLOT(slotColumnSizeChanged(int, int, int)));
// connect(header(), TQT_SIGNAL(clicked(int)), this, TQT_SLOT(updateEditorGeometry()));
// connect(header(), TQT_SIGNAL(clicked(int)), this, TQT_SLOT(updateEditorGeometryAndGroupLabels()));
connect(header(), TQT_SIGNAL(sectionHandleDoubleClicked (int)), this, TQT_SLOT(slotColumnSizeChanged(int)));
updateGroupLabelsPosition();
}
Editor::~Editor()
{
clearWidgetCache();
delete d;
d = 0;
}
void
Editor::fill()
{
setUpdatesEnabled(false);
d->itemToSelectLater = 0;
tqApp->eventLoop()->processEvents(TQEventLoop::AllEvents);
hideEditor();
KListView::clear();
d->itemDict.clear();
clearWidgetCache();
if(!d->set) {
d->topItem = 0;
setUpdatesEnabled(true);
triggerUpdate();
return;
}
d->topItem = new EditorDummyItem(this);
const TQValueList<TQCString> groupNames = d->set->groupNames();
// kopropertydbg << "Editor::fill(): group names = " << groupNames.count() << endl;
if(groupNames.count() == 1) { // one group (default one), so don't show groups
//add flat set of properties
const TQValueList<TQCString>& propertyNames = d->set->propertyNamesForGroup( groupNames.first() );
TQValueListConstIterator<TQCString> it = propertyNames.constBegin();
for( ; it != propertyNames.constEnd(); ++it)
addItem(*it, d->topItem);
}
else { // create a groupItem for each group
EditorGroupItem *prevGroupItem = 0;
int sortOrder = 0;
for (TQValueListConstIterator<TQCString> it = groupNames.constBegin(); it!=groupNames.constEnd();
++it, sortOrder++)
{
const TQValueList<TQCString>& propertyNames = d->set->propertyNamesForGroup(*it);
EditorGroupItem *groupItem;
if (prevGroupItem)
groupItem = new EditorGroupItem(d->topItem, prevGroupItem,
d->set->groupDescription(*it), d->set->groupIcon(*it), sortOrder );
else
groupItem = new EditorGroupItem(d->topItem,
d->set->groupDescription(*it), d->set->groupIcon(*it), sortOrder );
TQValueList<TQCString>::ConstIterator it2 = propertyNames.constBegin();
for( ; it2 != propertyNames.constEnd(); ++it2)
addItem(*it2, groupItem);
prevGroupItem = groupItem;
}
}
// repaint();
if (firstChild())
{
setCurrentItem(firstChild());
setSelected(firstChild(), true);
slotClicked(firstChild());
updateGroupLabelsPosition();
}
setUpdatesEnabled(true);
// aaah, call this instead of update() as explained here http://lists.trolltech.com/qt-interest/2000-06/thread00337-0.html
triggerUpdate();
}
void
Editor::addItem(const TQCString &name, EditorItem *parent)
{
if(!d->set || !d->set->contains(name))
return;
Property *property = &(d->set->property(name));
if(!property || !property->isVisible()) {
// kopropertydbg << "Property is not visible: " << name << endl;
return;
}
TQListViewItem *last = parent ? parent->firstChild() : d->topItem->firstChild();
while(last && last->nextSibling())
last = last->nextSibling();
EditorItem *item=0;
if(parent)
item = new EditorItem(this, parent, property, last);
else
item = new EditorItem(this, d->topItem, property, last);
d->itemDict.insert(name, item);
// Create child items
item->setOpen(true);
if(!property->children())
return;
last = 0;
TQValueList<Property*>::ConstIterator endIt = property->children()->constEnd();
for(TQValueList<Property*>::ConstIterator it = property->children()->constBegin(); it != endIt; ++it) {
//! \todo allow to have child prop with child items too
if( *it && (*it)->isVisible() )
last = new EditorItem(this, item, *it, last);
}
}
void
Editor::changeSet(Set *set, bool preservePrevSelection)
{
changeSetInternal(set, preservePrevSelection, "");
}
void
Editor::changeSet(Set *set, const TQCString& propertyToSelect)
{
changeSetInternal(set, !propertyToSelect.isEmpty(), propertyToSelect);
}
void
Editor::changeSetInternal(Set *set, bool preservePrevSelection, const TQCString& propertyToSelect)
{
if (d->insideSlotValueChanged) {
//changeSet() called from inside of slotValueChanged()
//this is dangerous, because there can be pending events,
//especially for the GUI stuff, so let's do delayed work
d->setListLater_list = set;
d->preservePrevSelection_preservePrevSelection = preservePrevSelection;
d->preservePrevSelection_propertyToSelect = propertyToSelect;
tqApp->eventLoop()->processEvents(TQEventLoop::AllEvents);
if (d->set) {
//store prev. selection for this prop set
if (d->currentItem)
d->set->setPrevSelection( d->currentItem->property()->name() );
kdDebug() << d->set->prevSelection() << endl;
}
if (!d->setListLater_set) {
d->setListLater_set = true;
d->changeSetLaterTimer.start(10, true);
}
return;
}
if (d->set) {
slotWidgetAcceptInput(d->currentWidget);
//store prev. selection for this prop set
if (d->currentItem)
d->set->setPrevSelection( d->currentItem->property()->name() );
else
d->set->setPrevSelection( "" );
d->set->disconnect(this);
}
TQCString selectedPropertyName1 = propertyToSelect, selectedPropertyName2 = propertyToSelect;
if (preservePrevSelection) {
//try to find prev. selection:
//1. in new list's prev. selection
if(set)
selectedPropertyName1 = set->prevSelection();
//2. in prev. list's current selection
if(d->set)
selectedPropertyName2 = d->set->prevSelection();
}
d->set = set;
if (d->set) {
//receive property changes
connect(d->set, TQT_SIGNAL(propertyChangedInternal(KoProperty::Set&, KoProperty::Property&)),
this, TQT_SLOT(slotPropertyChanged(KoProperty::Set&, KoProperty::Property&)));
connect(d->set, TQT_SIGNAL(propertyReset(KoProperty::Set&, KoProperty::Property&)),
this, TQT_SLOT(slotPropertyReset(KoProperty::Set&, KoProperty::Property&)));
connect(d->set,TQT_SIGNAL(aboutToBeCleared()), this, TQT_SLOT(slotSetWillBeCleared()));
connect(d->set,TQT_SIGNAL(aboutToBeDeleted()), this, TQT_SLOT(slotSetWillBeDeleted()));
}
fill();
emit propertySetChanged(d->set);
if (d->set) {
//select prev. selected item
EditorItem * item = 0;
if (!selectedPropertyName2.isEmpty()) //try other one for old prop set
item = d->itemDict[selectedPropertyName2];
if (!item && !selectedPropertyName1.isEmpty()) //try old one for current prop set
item = d->itemDict[selectedPropertyName1];
if (item) {
d->itemToSelectLater = item;
TQTimer::singleShot(10, this, TQT_SLOT(selectItemLater()));
//d->doNotSetFocusOnSelection = !hasParent(this, focusWidget());
//setSelected(item, true);
//d->doNotSetFocusOnSelection = false;
// ensureItemVisible(item);
}
}
}
//! @internal
void Editor::selectItemLater()
{
if (!d->itemToSelectLater)
return;
EditorItem *item = d->itemToSelectLater;
d->itemToSelectLater = 0;
setSelected(item, true);
ensureItemVisible(item);
}
//! @internal
void
Editor::changeSetLater()
{
tqApp->eventLoop()->processEvents(TQEventLoop::AllEvents);
if (kapp->hasPendingEvents()) {
d->changeSetLaterTimer.start(10, true); //try again...
return;
}
d->setListLater_set = false;
if (!d->setListLater_list)
return;
bool b = d->insideSlotValueChanged;
d->insideSlotValueChanged = false;
changeSetInternal(d->setListLater_list, d->preservePrevSelection_preservePrevSelection,
d->preservePrevSelection_propertyToSelect);
d->insideSlotValueChanged = b;
}
void
Editor::clear(bool editorOnly)
{
d->itemToSelectLater = 0;
hideEditor();
if(!editorOnly) {
tqApp->eventLoop()->processEvents(TQEventLoop::AllEvents);
if(d->set)
d->set->disconnect(this);
clearWidgetCache();
KListView::clear();
d->itemDict.clear();
d->topItem = 0;
}
}
void
Editor::undo()
{
if(!d->currentWidget || !d->currentItem || (d->set && d->set->isReadOnly()) || (d->currentWidget && d->currentWidget->isReadOnly()))
return;
int propertySync = d->currentWidget->property()->autoSync();
bool sync = (propertySync != 0 && propertySync != 1) ?
d->sync : (propertySync!=0);
if(sync)
d->currentItem->property()->resetValue();
if (d->currentWidget && d->currentItem) {//(check because current widget could be removed by resetValue())
d->currentWidget->setValue( d->currentItem->property()->value());
repaintItem(d->currentItem);
}
}
void
Editor::slotPropertyChanged(Set& set, Property& property)
{
if (!d->slotPropertyChanged_enabled)
return;
if(&set != d->set)
return;
if (d->currentItem && d->currentItem->property() == &property) {
d->currentWidget->setValue(property.value(), false);
for(TQListViewItem *item = d->currentItem->firstChild(); item; item = item->nextSibling())
repaintItem(item);
}
else {
// prop not in the dict, might be a child property:
EditorItem *item = d->itemDict[property.name()];
if(!item && property.parent())
item = d->itemDict[property.parent()->name()];
if (item) {
repaintItem(item);
for(TQListViewItem *it = item->firstChild(); it; it = it->nextSibling())
repaintItem(it);
}
}
//! @todo should we move this somewhere?
#if 0
if (property.parent() && property.parent()->type()==Rect) {
const int delta = property.value().toInt()-previousValue.toInt();
if (property.type()==Rect_X) { //|| property.type()==Rect_Y)
property.parent()->child("width")->setValue(delta, false);
}
/* if (widget->property() && (TQWidget*)d->currentWidget==widget && d->currentItem->parent()) {
EditorItem *parentItem = static_cast<EditorItem*>(d->currentItem->parent());
const int thisType = ;
&& parentItem->property()->type()==Rect) {
//changing x or y components of Rect type shouldn't change width or height, respectively
if (thisType==Rect_X) {
EditorItem *rectWidthItem = static_cast<EditorItem*>(d->currentItem->nextSibling()->nextSibling());
if (delta!=0) {
rectWidthItem->property()->setValue(rectWidthItem->property()->value().toInt()+delta, false);
}
}
}*/
}
#endif
showUndoButton( property.isModified() );
}
void
Editor::slotPropertyReset(Set& set, Property& property)
{
if(&set != d->set)
return;
if (d->currentItem && d->currentItem->property() == &property) {
d->currentWidget->setValue(property.value(), false);
for(TQListViewItem *item = d->currentItem->firstChild(); item; item = item->nextSibling())
repaintItem(item);
}
else {
EditorItem *item = d->itemDict[property.name()];
// prop not in the dict, might be a child prop.
if(!item && property.parent())
item = d->itemDict[property.parent()->name()];
if (item) {
repaintItem(item);
for(TQListViewItem *it = item->firstChild(); it; it = it->nextSibling())
repaintItem(it);
}
}
showUndoButton( false );
}
void
Editor::slotWidgetValueChanged(Widget *widget)
{
if(!widget || !d->set || (d->set && d->set->isReadOnly()) || (widget && widget->isReadOnly()) || !widget->property())
return;
d->insideSlotValueChanged = true;
TQVariant value = widget->value();
int propertySync = widget->property()->autoSync();
bool sync = (propertySync != 0 && propertySync != 1) ?
d->sync : (propertySync!=0);
if(sync) {
d->slotPropertyChanged_enabled = false;
TQGuardedPtr<Widget> pWidget = widget; //safe, widget can be destroyed in the meantime
widget->property()->setValue(value);
if (pWidget)
showUndoButton( pWidget->property()->isModified() );
d->slotPropertyChanged_enabled = true;
}
d->insideSlotValueChanged = false;
}
void
Editor::acceptInput()
{
slotWidgetAcceptInput(d->currentWidget);
}
void
Editor::slotWidgetAcceptInput(Widget *widget)
{
if(!widget || !d->set || !widget->property() || (d->set && d->set->isReadOnly()) || (widget && widget->isReadOnly()))
return;
widget->property()->setValue(widget->value());
}
void
Editor::slotWidgetRejectInput(Widget *widget)
{
if(!widget || !d->set)
return;
undo();
}
void
Editor::slotClicked(TQListViewItem *it)
{
d->previouslyCollapsedGroupItem = 0;
d->childFormPreviouslyCollapsedGroupItem = 0;
acceptInput();
hideEditor();
if(!it)
return;
EditorItem *item = static_cast<EditorItem*>(it);
Property *p = item ? item->property() : 0;
if(!p)
return;
d->currentItem = item;
d->currentWidget = createWidgetForProperty(p);
//moved up updateEditorGeometry();
showUndoButton( p->isModified() );
if (d->currentWidget) {
if (d->currentWidget->visibleFlag()) {
d->currentWidget->show();
if (hasParent( TQT_TQOBJECT(this), TQT_TQOBJECT(kapp->focusWidget()) ))
d->currentWidget->setFocus();
}
}
d->justClickedItem = true;
}
void
Editor::slotCurrentChanged(TQListViewItem *item)
{
if (item == firstChild()) {
TQListViewItem *oldItem = item;
while (item && (!item->isSelectable() || !item->isVisible()))
item = item->itemBelow();
if (item && item != oldItem) {
setSelected(item,true);
return;
}
}
}
void
Editor::slotSetWillBeCleared()
{
d->itemToSelectLater = 0;
if (d->currentWidget) {
acceptInput();
d->currentWidget->setProperty(0);
}
clear();
}
void
Editor::slotSetWillBeDeleted()
{
clear();
d->set = 0;
}
Widget*
Editor::createWidgetForProperty(Property *property, bool changeWidgetProperty)
{
// int type = property->type();
TQGuardedPtr<Widget> widget = d->widgetCache[property];
if(!widget) {
widget = FactoryManager::self()->createWidgetForProperty(property);
if (!widget)
return 0;
widget->setReadOnly( (d->set && d->set->isReadOnly()) || property->isReadOnly() );
d->widgetCache[property] = widget;
widget->setProperty(0); // to force reloading property later
widget->hide();
connect(widget, TQT_SIGNAL(valueChanged(Widget*)),
this, TQT_SLOT(slotWidgetValueChanged(Widget*)) );
connect(widget, TQT_SIGNAL(acceptInput(Widget*)),
this, TQT_SLOT(slotWidgetAcceptInput(Widget*)) );
connect(widget, TQT_SIGNAL(rejectInput(Widget*)),
this, TQT_SLOT(slotWidgetRejectInput(Widget*)) );
}
//update geometry earlier, because Widget::setValue() can depend on widget's geometry
updateEditorGeometry(d->currentItem, widget);
if(widget && (!widget->property() || changeWidgetProperty))
widget->setProperty(property);
// if (!d->doNotSetFocusOnSelection) {
// widget->setFocus();
// }
return widget;
}
void
Editor::clearWidgetCache()
{
for(TQMap<Property*, Widget*>::iterator it = d->widgetCache.begin(); it != d->widgetCache.end(); ++it)
it.data()->deleteLater();
// delete it.data();
d->widgetCache.clear();
}
void
Editor::updateEditorGeometry(bool forceUndoButtonSettings, bool undoButtonVisible)
{
updateEditorGeometry(d->currentItem, d->currentWidget,
forceUndoButtonSettings, undoButtonVisible);
}
void
Editor::updateEditorGeometry(EditorItem *item, Widget* widget,
bool forceUndoButtonSettings, bool undoButtonVisible)
{
if(!item || !widget)
return;
int placeForUndoButton;
if (forceUndoButtonSettings ? undoButtonVisible : d->undoButton->isVisible())
placeForUndoButton = d->undoButton->width();
else
placeForUndoButton = widget->leavesTheSpaceForRevertButton() ? d->undoButton->width() : 0;
TQRect r;
int y = itemPos(item);
r.setX(header()->sectionPos(1)-(widget->hasBorders()?1:0)); //-1, to align to horizontal line
r.setY(y-(widget->hasBorders()?1:0));
r.setWidth(header()->sectionSize(1)+(widget->hasBorders()?1:0) //+1 because we subtracted 1 from X
- placeForUndoButton);
r.setHeight(item->height()+(widget->hasBorders()?1:-1));
// check if the column is fully visible
if (visibleWidth() < r.right())
r.setRight(visibleWidth());
moveChild(widget, r.x(), r.y());
widget->resize(r.size());
tqApp->eventLoop()->processEvents(TQEventLoop::AllEvents);
}
void
Editor::updateGroupLabelsPosition()
{
if(!d->topItem || d->itemDict.isEmpty())
return;
EditorGroupItem *group = dynamic_cast<EditorGroupItem*>(d->topItem->firstChild());
while(group) {
TQRect r = itemRect((TQListViewItem*) group);
if(group->label()) {
group->label()->setGeometry(r);
group->label()->repaint();
}
group = dynamic_cast<EditorGroupItem*>(group->nextSibling());
}
}
void
Editor::hideEditor()
{
d->currentItem = 0;
TQWidget *cw = d->currentWidget;
if(cw) {
d->currentWidget = 0;
cw->hide();
}
d->undoButton->hide();
}
void
Editor::showUndoButton( bool show )
{
if (!d->currentItem || !d->currentWidget || (d->currentWidget && d->currentWidget->isReadOnly()))
return;
int y = viewportToContents(TQPoint(0, itemRect(d->currentItem).y())).y();
TQRect geometry(columnWidth(0), y, columnWidth(1) + 1, d->currentItem->height());
d->undoButton->resize(d->baseRowHeight, d->currentItem->height());
updateEditorGeometry(true, show);
if (!show) {
/* if (d->currentWidget) {
if (d->currentWidget->leavesTheSpaceForRevertButton()) {
geometry.setWidth(geometry.width()-d->undoButton->width());
}
d->currentWidget->resize(geometry.width(), geometry.height());
}*/
d->undoButton->hide();
return;
}
TQPoint p = contentsToViewport(TQPoint(0, geometry.y()));
d->undoButton->move(geometry.x() + geometry.width()
-((d->currentWidget && d->currentWidget->hasBorders())?1:0)/*editor is moved by 1 to left*/
- d->undoButton->width(), p.y());
// if (d->currentWidget) {
// d->currentWidget->move(d->currentWidget->x(), p.y());
// d->currentWidget->resize(geometry.width()-d->undoButton->width(), geometry.height());
// }
d->undoButton->show();
}
void
Editor::slotExpanded(TQListViewItem *item)
{
if (!item)
return;
//select child item again if a group item has been expanded
if (!selectedItem() && dynamic_cast<EditorGroupItem*>(item) && d->previouslyCollapsedGroupItem == item
&& d->childFormPreviouslyCollapsedGroupItem) {
setSelected(d->childFormPreviouslyCollapsedGroupItem, true);
setCurrentItem(selectedItem());
slotClicked(selectedItem());
}
updateEditorGeometry();
updateGroupLabelsPosition();
repaintContents();
repaint();
}
void
Editor::slotCollapsed(TQListViewItem *item)
{
if (!item)
return;
//unselect child item and hide editor if a group item has been collapsed
if (dynamic_cast<EditorGroupItem*>(item)) {
for (TQListViewItem *i = selectedItem(); i; i = i->parent()) {
if (i->parent()==item) {
d->previouslyCollapsedGroupItem = item;
d->childFormPreviouslyCollapsedGroupItem = selectedItem();
hideEditor();
setSelected(selectedItem(), false);
setSelected(item->nextSibling(), true);
break;
}
}
}
updateEditorGeometry();
updateGroupLabelsPosition();
repaintContents();
repaint();
}
void
Editor::slotColumnSizeChanged(int section, int oldSize, int newSize)
{
Q_UNUSED(section);
Q_UNUSED(oldSize);
Q_UNUSED(newSize);
/*for (TQListViewItemIterator it(this); it.current(); ++it) {
if (section == 0 && dynamic_cast<EditorGroupItem*>(it.current())) {
it.current()->repaint();
}
}*/
/*
if(d->currentWidget) {
if(section == 0)
d->currentWidget->move(newS, d->currentWidget->y());
else {
if(d->undoButton->isVisible())
d->currentWidget->resize(newS - d->undoButton->width(), d->currentWidget->height());
else
d->currentWidget->resize(
newS-(d->currentWidget->leavesTheSpaceForRevertButton() ? d->undoButton->width() : 0),
d->currentWidget->height());
}
}*/
// repaintContents();
// repaint();
updateEditorGeometry();
update();
}
void
Editor::slotColumnSizeChanged(int section)
{
setColumnWidth(1, viewport()->width() - columnWidth(0));
slotColumnSizeChanged(section, 0, header()->sectionSize(section));
/* if(d->currentWidget) {
if(d->undoButton->isVisible())
d->currentWidget->resize(columnWidth(1) - d->undoButton->width(), d->currentWidget->height());
else
d->currentWidget->resize(
columnWidth(1)-(d->currentWidget->leavesTheSpaceForRevertButton() ? d->undoButton->width() : 0),
d->currentWidget->height());
}*/
if(d->undoButton->isVisible())
showUndoButton(true);
else
updateEditorGeometry();
}
TQSize
Editor::sizeHint() const
{
return TQSize( TQFontMetrics(font()).width(columnText(0)+columnText(1)+" "),
KListView::sizeHint().height());
}
void
Editor::setFocus()
{
EditorItem *item = static_cast<EditorItem *>(selectedItem());
if (item) {
if (!d->justClickedItem)
ensureItemVisible(item);
d->justClickedItem = false;
}
else {
//select an item before focusing
item = static_cast<EditorItem *>(itemAt(TQPoint(10,1)));
if (item) {
ensureItemVisible(item);
setSelected(item, true);
}
}
if (d->currentWidget) {
// kopropertydbg << "d->currentWidget->setFocus()" << endl;
d->currentWidget->setFocus();
}
else {
// kopropertydbg << "KListView::setFocus()" << endl;
KListView::setFocus();
}
}
void
Editor::resizeEvent(TQResizeEvent *ev)
{
KListView::resizeEvent(ev);
if(d->undoButton->isVisible())
showUndoButton(true);
update();
updateGroupLabelsPosition();
}
bool
Editor::eventFilter( TQObject * watched, TQEvent * e )
{
if ((TQT_BASE_OBJECT(watched)==TQT_BASE_OBJECT(this) || TQT_BASE_OBJECT(watched)==TQT_BASE_OBJECT(viewport())) && e->type()==TQEvent::KeyPress) {
if (handleKeyPress(TQT_TQKEYEVENT(e)))
return true;
}
return KListView::eventFilter(watched, e);
}
bool
Editor::handleKeyPress(TQKeyEvent* ev)
{
const int k = ev->key();
const TQt::ButtonState s = ev->state();
//selection moving
TQListViewItem *item = 0;
if ( ((s == Qt::NoButton) && (k == Key_Up)) || (k==Key_BackTab) ) {
//find prev visible
item = selectedItem() ? selectedItem()->itemAbove() : 0;
while (item && (!item->isSelectable() || !item->isVisible()))
item = item->itemAbove();
if (!item)
return true;
}
else if( (s == Qt::NoButton) && ((k == Key_Down) || (k == Key_Tab)) ) {
//find next visible
item = selectedItem() ? selectedItem()->itemBelow() : 0;
while (item && (!item->isSelectable() || !item->isVisible()))
item = item->itemBelow();
if (!item)
return true;
}
else if( (s==Qt::NoButton) && (k==Key_Home) ) {
if (d->currentWidget && d->currentWidget->hasFocus())
return false;
//find 1st visible
item = firstChild();
while (item && (!item->isSelectable() || !item->isVisible()))
item = item->itemBelow();
}
else if( (s==Qt::NoButton) && (k==Key_End) ) {
if (d->currentWidget && d->currentWidget->hasFocus())
return false;
//find last visible
item = selectedItem();
TQListViewItem *lastVisible = item;
while (item) { // && (!item->isSelectable() || !item->isVisible()))
item = item->itemBelow();
if (item && item->isSelectable() && item->isVisible())
lastVisible = item;
}
item = lastVisible;
}
if(item) {
ev->accept();
ensureItemVisible(item);
setSelected(item, true);
return true;
}
return false;
}
void
Editor::updateFont()
{
setFont(parentWidget()->font());
d->baseRowHeight = TQFontMetrics(parentWidget()->font()).height() + itemMargin() * 2;
if (!d->currentItem)
d->undoButton->resize(d->baseRowHeight, d->baseRowHeight);
else {
showUndoButton(d->undoButton->isVisible());
updateEditorGeometry();
}
updateGroupLabelsPosition();
}
bool
Editor::event( TQEvent * e )
{
if (e->type()==TQEvent::ParentFontChange) {
updateFont();
}
return KListView::event(e);
}
void
Editor::contentsMousePressEvent( TQMouseEvent * e )
{
TQListViewItem *item = itemAt(e->pos());
if (dynamic_cast<EditorGroupItem*>(item)) {
setOpen( item, !isOpen(item) );
return;
}
KListView::contentsMousePressEvent(e);
}
void
Editor::setSorting( int column, bool ascending )
{
if (d->set && d->set->groupNames().count()>1) //do not sort when groups are present (maybe reenable this later?)
return;
KListView::setSorting( column, ascending );
updateEditorGeometry();
updateGroupLabelsPosition();
repaintContents();
repaint();
}
#include "editor.moc"