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.
1028 lines
28 KiB
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;
|
|
TDEGlobal::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"
|