F:/KPlato/koffice/libs/koproperty/editor.cpp

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
00003    Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
00004    Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "editor.h"
00023 #include "editoritem.h"
00024 #include "set.h"
00025 #include "factory.h"
00026 #include "property.h"
00027 #include "widget.h"
00028 
00029 #include <QPushButton>
00030 #include <QLayout>
00031 #include <QMap>
00032 #include <QPointer>
00033 #include <q3header.h>
00034 #include <q3asciidict.h>
00035 #include <QToolTip>
00036 #include <QApplication>
00037 #include <QEventLoop>
00038 #include <QTimer>
00039 #include <QLabel>
00040 #include <QByteArray>
00041 #include <QEvent>
00042 #include <QKeyEvent>
00043 #include <QResizeEvent>
00044 #include <QMouseEvent>
00045 
00046 #include <kdebug.h>
00047 #include <kiconloader.h>
00048 #include <klocale.h>
00049 #include <kdeversion.h>
00050 #include <kapplication.h>
00051 
00052 namespace KoProperty {
00053 
00055 static bool kofficeAppDirAdded = false;
00056 
00059 inline bool hasParent(QObject* par, QObject* o)
00060 {
00061         if (!o || !par)
00062                 return false;
00063         while (o && o != par)
00064                 o = o->parent();
00065         return o == par;
00066 }
00067 
00068 class EditorPrivate
00069 {
00070         public:
00071                 EditorPrivate(Editor *editor)
00072                 : itemDict(101, false), justClickedItem(false)
00073                 {
00074                         currentItem = 0;
00075                         undoButton = 0;
00076                         topItem = 0;
00077                         itemToSelectLater = 0;
00078                         if (!kofficeAppDirAdded) {
00079                                 kofficeAppDirAdded = true;
00080                                 KGlobal::iconLoader()->addAppDir("koffice");
00081                         }
00082                         previouslyCollapsedGroupItem = 0;
00083                         childFormPreviouslyCollapsedGroupItem = 0;
00084                         slotPropertyChanged_enabled = true;
00085                         QObject::connect(&changeSetLaterTimer, SIGNAL(timeout()),
00086                                 editor, SLOT(changeSetLater()));
00087                 }
00088                 ~EditorPrivate()
00089                 {
00090                 }
00091 
00092                 QPointer<Set> set;
00094                 QMap<Property*, Widget* >  widgetCache;
00095                 QPointer<Widget> currentWidget;
00096                 EditorItem *currentItem;
00097                 EditorItem *topItem; 
00098                 QPushButton *undoButton; 
00099                 EditorItem::Dict itemDict;
00100 
00101                 int baseRowHeight;
00102                 bool sync : 1;
00103                 bool insideSlotValueChanged : 1;
00104 
00106                 QTimer changeSetLaterTimer;
00107                 bool setListLater_set : 1;
00108                 bool preservePrevSelection_preservePrevSelection : 1;
00109                 QByteArray preservePrevSelection_propertyToSelect;
00110                 //bool doNotSetFocusOnSelection : 1;
00112                 bool justClickedItem : 1;
00114                 bool slotPropertyChanged_enabled : 1;
00116                 Set* setListLater_list;
00118                 EditorItem *itemToSelectLater;
00119 
00120                 Q3ListViewItem *previouslyCollapsedGroupItem;
00121                 Q3ListViewItem *childFormPreviouslyCollapsedGroupItem;
00122 };
00123 }
00124 
00125 using namespace KoProperty;
00126 
00127 Editor::Editor(QWidget *parent, bool autoSync, const char *name)
00128  : K3ListView(parent)
00129 {
00130         setObjectName(name);
00131         d = new EditorPrivate(this);
00132         d->itemDict.setAutoDelete(false);
00133 
00134         d->set = 0;
00135         d->topItem = 0;
00136         d->currentItem = 0;
00137         d->sync = autoSync;
00138         d->insideSlotValueChanged = false;
00139         d->setListLater_set = false;
00140         d->preservePrevSelection_preservePrevSelection = false;
00141         d->setListLater_list = 0;
00142 
00143         d->undoButton = new QPushButton(viewport());
00144         d->undoButton->setFocusPolicy(Qt::NoFocus);
00145         setFocusPolicy(Qt::ClickFocus);
00146         d->undoButton->setMinimumSize(QSize(5,5)); // allow to resize undoButton even below pixmap size
00147         d->undoButton->setIcon(SmallIcon("undo"));
00148         d->undoButton->setToolTip( i18n("Undo changes"));
00149         d->undoButton->hide();
00150         connect(d->undoButton, SIGNAL(clicked()), this, SLOT(undo()));
00151 
00152         installEventFilter(this);
00153         viewport()->installEventFilter(this);
00154 
00155         addColumn(i18n("Name"));
00156         addColumn(i18n("Value"));
00157         setAllColumnsShowFocus(true);
00158         setColumnWidthMode(0, Q3ListView::Maximum);
00159         setFullWidth(true);
00160         setShowSortIndicator(false);
00161         setShadeSortColumn(false);
00162         setTooltipColumn(0);
00163         setSorting(0);
00164         setItemMargin(KPROPEDITOR_ITEM_MARGIN);
00165         header()->setMovingEnabled( false );
00166         setTreeStepSize(16 + 2/*left*/ + 1/*right*/);
00167 
00168         updateFont();
00169 //      d->baseRowHeight = QFontMetrics(font()).height() + itemMargin()*2;
00170 
00171         connect(this, SIGNAL(selectionChanged(Q3ListViewItem *)), this, SLOT(slotClicked(Q3ListViewItem *)));
00172         connect(this, SIGNAL(currentChanged(Q3ListViewItem *)), this, SLOT(slotCurrentChanged(Q3ListViewItem *)));
00173         connect(this, SIGNAL(expanded(Q3ListViewItem *)), this, SLOT(slotExpanded(Q3ListViewItem *)));
00174         connect(this, SIGNAL(collapsed(Q3ListViewItem *)), this, SLOT(slotCollapsed(Q3ListViewItem *)));
00175         connect(header(), SIGNAL(sizeChange(int, int, int)), this, SLOT(slotColumnSizeChanged(int, int, int)));
00176 //      connect(header(), SIGNAL(clicked(int)), this, SLOT(updateEditorGeometry()));
00177 //      connect(header(), SIGNAL(clicked(int)), this, SLOT(updateEditorGeometryAndGroupLabels()));
00178         connect(header(), SIGNAL(sectionHandleDoubleClicked (int)), this, SLOT(slotColumnSizeChanged(int)));
00179 }
00180 
00181 Editor::~Editor()
00182 {
00183         clearWidgetCache();
00184         delete d;
00185         d = 0;
00186 }
00187 
00188 void
00189 Editor::fill()
00190 {
00191         setUpdatesEnabled(false);
00192         d->itemToSelectLater = 0;
00193         qApp->processEvents(QEventLoop::AllEvents);
00194         hideEditor();
00195         K3ListView::clear();
00196         d->itemDict.clear();
00197         clearWidgetCache();
00198         if(!d->set) {
00199                 d->topItem = 0;
00200                 setUpdatesEnabled(true);
00201                 triggerUpdate();
00202                 return;
00203         }
00204 
00205         d->topItem = new EditorDummyItem(this);
00206 
00207         const QList<QByteArray> groupNames = d->set->groupNames();
00208 //      kopropertydbg << "Editor::fill(): group names = " << groupNames.count() << endl;
00209         if(groupNames.count() == 1) { // one group (default one), so don't show groups
00210                 //add flat set of properties
00211                 const QList<QByteArray>& propertyNames = d->set->propertyNamesForGroup( groupNames.first() );
00212                 for (QList<QByteArray>::ConstIterator it = propertyNames.constBegin();
00213                         it != propertyNames.constEnd(); ++it)
00214                 {
00215                         addItem(*it, d->topItem);
00216                 }
00217         }
00218         else { // create a groupItem for each group
00219                 EditorGroupItem *prevGroupItem = 0;
00220                 int sortOrder = 0;
00221                 for (QList<QByteArray>::ConstIterator it = groupNames.constBegin(); it!=groupNames.constEnd(); 
00222                         ++it, sortOrder++) 
00223                 {
00224                         const QList<QByteArray>& propertyNames = d->set->propertyNamesForGroup(*it);
00225                         EditorGroupItem *groupItem;
00226                         if (prevGroupItem)
00227                                 groupItem = new EditorGroupItem(d->topItem, prevGroupItem, 
00228                                         d->set->groupDescription(*it), d->set->groupIcon(*it), sortOrder );
00229                         else
00230                                 groupItem = new EditorGroupItem(d->topItem, 
00231                                         d->set->groupDescription(*it), d->set->groupIcon(*it), sortOrder );
00232 
00233                         QList<QByteArray>::ConstIterator it2 = propertyNames.constBegin();
00234                         for( ; it2 != propertyNames.constEnd(); ++it2)
00235                                 addItem(*it2, groupItem);
00236 
00237                         prevGroupItem = groupItem;
00238                 }
00239         }
00240 
00241 //      repaint();
00242 
00243         if (firstChild())
00244         {
00245                 setCurrentItem(firstChild());
00246                 setSelected(firstChild(), true);
00247                 slotClicked(firstChild());
00248                 updateGroupLabelsPosition();
00249         }
00250         setUpdatesEnabled(true);
00251         // aaah, call this instead of update() as explained here http://lists.trolltech.com/qt-interest/2000-06/thread00337-0.html
00252         triggerUpdate();
00253 }
00254 
00255 void
00256 Editor::addItem(const QByteArray &name, EditorItem *parent)
00257 {
00258         if(!d->set || !d->set->contains(name))
00259                 return;
00260 
00261         Property *property = &(d->set->property(name));
00262         if(!property || !property->isVisible()) {
00263 //              kopropertydbg << "Property is not visible: " << name << endl;
00264                 return;
00265         }
00266         Q3ListViewItem *last = parent ? parent->firstChild() : d->topItem->firstChild();
00267         while(last && last->nextSibling())
00268                 last = last->nextSibling();
00269 
00270         EditorItem *item=0;
00271         if(parent)
00272                 item = new EditorItem(this, parent, property, last);
00273         else
00274                 item = new EditorItem(this, d->topItem, property, last);
00275         d->itemDict.insert(name, item);
00276 
00277         // Create child items
00278         item->setOpen(true);
00279         if(!property->children())
00280                 return;
00281 
00282         last = 0;
00283         QList<Property*>::ConstIterator endIt = property->children()->constEnd();
00284         for(QList<Property*>::ConstIterator it = property->children()->constBegin(); it != endIt; ++it) {
00286                 if( *it && (*it)->isVisible() )
00287                         last = new EditorItem(this, item, *it, last);
00288         }
00289 }
00290 
00291 void
00292 Editor::changeSet(Set *set, bool preservePrevSelection)
00293 {
00294         changeSetInternal(set, preservePrevSelection, "");
00295 }
00296 
00297 void
00298 Editor::changeSet(Set *set, const QByteArray& propertyToSelect)
00299 {
00300         changeSetInternal(set, !propertyToSelect.isEmpty(), propertyToSelect);
00301 }
00302 
00303 void
00304 Editor::changeSetInternal(Set *set, bool preservePrevSelection, const QByteArray& propertyToSelect)
00305 {
00306         if (d->insideSlotValueChanged) {
00307                 //changeSet() called from inside of slotValueChanged()
00308                 //this is dangerous, because there can be pending events,
00309                 //especially for the GUI stuff, so let's do delayed work
00310                 d->setListLater_list = set;
00311                 d->preservePrevSelection_preservePrevSelection = preservePrevSelection;
00312                 d->preservePrevSelection_propertyToSelect = propertyToSelect;
00313                 qApp->processEvents(QEventLoop::AllEvents);
00314                 if (d->set) {
00315                         //store prev. selection for this prop set
00316                         if (d->currentItem)
00317                                 d->set->setPrevSelection( d->currentItem->property()->name() );
00318                         kDebug() << d->set->prevSelection() << endl;
00319                 }
00320                 if (!d->setListLater_set) {
00321                         d->setListLater_set = true;
00322                         d->changeSetLaterTimer.setSingleShot(true);
00323                         d->changeSetLaterTimer.start(10);
00324                 }
00325                 return;
00326         }
00327 
00328         if (d->set) {
00329                 slotWidgetAcceptInput(d->currentWidget);
00330                 //store prev. selection for this prop set
00331                 if (d->currentItem)
00332                         d->set->setPrevSelection( d->currentItem->property()->name() );
00333                 else
00334                         d->set->setPrevSelection( "" );
00335                 d->set->disconnect(this);
00336         }
00337 
00338         QByteArray selectedPropertyName1 = propertyToSelect, selectedPropertyName2 = propertyToSelect;
00339         if (preservePrevSelection) {
00340                 //try to find prev. selection:
00341                 //1. in new list's prev. selection
00342                 if(set)
00343                         selectedPropertyName1 = set->prevSelection();
00344                 //2. in prev. list's current selection
00345                 if(d->set)
00346                         selectedPropertyName2 = d->set->prevSelection();
00347         }
00348 
00349         d->set = set;
00350         if (d->set) {
00351                 //receive property changes
00352                 connect(d->set, SIGNAL(propertyChangedInternal(KoProperty::Set&, KoProperty::Property&)),
00353                         this, SLOT(slotPropertyChanged(KoProperty::Set&, KoProperty::Property&)));
00354                 connect(d->set, SIGNAL(propertyReset(KoProperty::Set&, KoProperty::Property&)),
00355                         this, SLOT(slotPropertyReset(KoProperty::Set&, KoProperty::Property&)));
00356                 connect(d->set,SIGNAL(aboutToBeCleared()), this, SLOT(slotSetWillBeCleared()));
00357                 connect(d->set,SIGNAL(aboutToBeDeleted()), this, SLOT(slotSetWillBeDeleted()));
00358         }
00359 
00360         fill();
00361 
00362         emit propertySetChanged(d->set);
00363 
00364         if (d->set) {
00365                 //select prev. selected item
00366                 EditorItem * item = 0;
00367                 if (!selectedPropertyName2.isEmpty()) //try other one for old prop set
00368                         item = d->itemDict[selectedPropertyName2];
00369                 if (!item && !selectedPropertyName1.isEmpty()) //try old one for current prop set
00370                         item = d->itemDict[selectedPropertyName1];
00371 
00372                 if (item) {
00373                         d->itemToSelectLater = item;
00374                         QTimer::singleShot(10, this, SLOT(selectItemLater()));
00375                         //d->doNotSetFocusOnSelection = !hasParent(this, focusWidget());
00376                         //setSelected(item, true);
00377                         //d->doNotSetFocusOnSelection = false;
00378 //                      ensureItemVisible(item);
00379                 }
00380         }
00381 }
00382 
00384 void Editor::selectItemLater()
00385 {
00386         if (!d->itemToSelectLater)
00387                 return;
00388         EditorItem *item = d->itemToSelectLater;
00389         d->itemToSelectLater = 0;
00390         setSelected(item, true);
00391         ensureItemVisible(item);
00392 }
00393 
00395 void
00396 Editor::changeSetLater()
00397 {
00398         qApp->processEvents(QEventLoop::AllEvents);
00399         if (kapp->hasPendingEvents()) {
00400                 d->changeSetLaterTimer.setSingleShot(true);
00401                 d->changeSetLaterTimer.start(10); //try again...
00402                 return;
00403         }
00404         d->setListLater_set = false;
00405         if (!d->setListLater_list)
00406                 return;
00407 
00408         bool b = d->insideSlotValueChanged;
00409         d->insideSlotValueChanged = false;
00410         changeSet(d->setListLater_list, d->preservePrevSelection_preservePrevSelection);
00411         changeSetInternal(d->setListLater_list, d->preservePrevSelection_preservePrevSelection, 
00412                 d->preservePrevSelection_propertyToSelect);
00413         d->insideSlotValueChanged = b;
00414 }
00415 
00416 void
00417 Editor::clear(bool editorOnly)
00418 {
00419         d->itemToSelectLater = 0;
00420         hideEditor();
00421 
00422         if(!editorOnly) {
00423                 qApp->processEvents(QEventLoop::AllEvents);
00424                 if(d->set)
00425                         d->set->disconnect(this);
00426                 clearWidgetCache();
00427                 K3ListView::clear();
00428                 d->itemDict.clear();
00429                 d->topItem = 0;
00430         }
00431 }
00432 
00433 void
00434 Editor::undo()
00435 {
00436         if(!d->currentWidget || !d->currentItem || (d->set && d->set->isReadOnly()) || (d->currentWidget && d->currentWidget->isReadOnly()))
00437                 return;
00438 
00439         int propertySync = d->currentWidget->property()->autoSync();
00440         bool sync = (propertySync != 0 && propertySync != 1) ?
00441                                  d->sync : (propertySync!=0);
00442 
00443         if(sync)
00444                 d->currentItem->property()->resetValue();
00445         if (d->currentWidget && d->currentItem) {//(check because current widget could be removed by resetValue())
00446                 d->currentWidget->setValue( d->currentItem->property()->value());
00447                 repaintItem(d->currentItem);
00448         }
00449 }
00450 
00451 void
00452 Editor::slotPropertyChanged(Set& set, Property& property)
00453 {
00454         if (!d->slotPropertyChanged_enabled)
00455                 return;
00456         if(&set != d->set)
00457                 return;
00458 
00459         if (d->currentItem && d->currentItem->property() == &property) {
00460                 d->currentWidget->setValue(property.value(), false);
00461                 for(Q3ListViewItem *item = d->currentItem->firstChild(); item; item = item->nextSibling())
00462                         repaintItem(item);
00463         }
00464         else  {
00465                 // prop not in the dict, might be a child property:
00466                 EditorItem *item = d->itemDict[property.name()];
00467                 if(!item && property.parent())
00468                         item = d->itemDict[property.parent()->name()];
00469                 if (item) {
00470                         repaintItem(item);
00471                         for(Q3ListViewItem *it = item->firstChild(); it; it = it->nextSibling())
00472                                 repaintItem(it);
00473                 }
00474         }
00475 
00477 #if 0
00478         if (property.parent() && property.parent()->type()==Rect) {
00479                 const int delta = property.value().toInt()-previousValue.toInt();
00480                 if (property.type()==Rect_X) { //|| property.type()==Rect_Y)
00481                         property.parent()->child("width")->setValue(delta, false);
00482                 }
00483 
00484 /*      if (widget->property() && (QWidget*)d->currentWidget==widget && d->currentItem->parent()) {
00485                 EditorItem *parentItem = static_cast<EditorItem*>(d->currentItem->parent());
00486                 const int thisType = ;
00487                         && parentItem->property()->type()==Rect) {
00488                         //changing x or y components of Rect type shouldn't change width or height, respectively
00489                         if (thisType==Rect_X) {
00490                                 EditorItem *rectWidthItem = static_cast<EditorItem*>(d->currentItem->nextSibling()->nextSibling());
00491                                 if (delta!=0) {
00492                                         rectWidthItem->property()->setValue(rectWidthItem->property()->value().toInt()+delta, false);
00493                                 }
00494                         }
00495                 }*/
00496         }
00497 #endif
00498         showUndoButton( property.isModified() );
00499 }
00500 
00501 void
00502 Editor::slotPropertyReset(Set& set, Property& property)
00503 {
00504         if(&set != d->set)
00505                 return;
00506 
00507         if (d->currentItem && d->currentItem->property() == &property) {
00508                 d->currentWidget->setValue(property.value(), false);
00509                 for(Q3ListViewItem *item = d->currentItem->firstChild(); item; item = item->nextSibling())
00510                         repaintItem(item);
00511         }
00512         else  {
00513                 EditorItem *item = d->itemDict[property.name()];
00514                 // prop not in the dict, might be a child prop.
00515                 if(!item && property.parent())
00516                         item = d->itemDict[property.parent()->name()];
00517                 if (item) {
00518                         repaintItem(item);
00519                         for(Q3ListViewItem *it = item->firstChild(); it; it = it->nextSibling())
00520                                 repaintItem(it);
00521                 }
00522         }
00523 
00524         showUndoButton( false );
00525 }
00526 
00527 void
00528 Editor::slotWidgetValueChanged(Widget *widget)
00529 {
00530         if(!widget || !d->set || (d->set && d->set->isReadOnly()) || (widget && widget->isReadOnly()) || !widget->property())
00531                 return;
00532 
00533         d->insideSlotValueChanged = true;
00534 
00535         QVariant value = widget->value();
00536         int propertySync = widget->property()->autoSync();
00537         bool sync = (propertySync != 0 && propertySync != 1) ?
00538                                  d->sync : (propertySync!=0);
00539 
00540         if(sync) {
00541                 d->slotPropertyChanged_enabled = false;
00542                 QPointer<Widget> pWidget = widget; //safe, widget can be destroyed in the meantime
00543                 widget->property()->setValue(value);
00544                 if (pWidget)
00545                   showUndoButton( pWidget->property()->isModified() );
00546                 d->slotPropertyChanged_enabled = true;
00547         }
00548 
00549         d->insideSlotValueChanged = false;
00550 }
00551 
00552 void
00553 Editor::acceptInput()
00554 {
00555         slotWidgetAcceptInput(d->currentWidget);
00556 }
00557 
00558 void
00559 Editor::slotWidgetAcceptInput(Widget *widget)
00560 {
00561         if(!widget || !d->set || !widget->property() || (d->set && d->set->isReadOnly()) || (widget && widget->isReadOnly()))
00562                 return;
00563 
00564         widget->property()->setValue(widget->value());
00565 }
00566 
00567 void
00568 Editor::slotWidgetRejectInput(Widget *widget)
00569 {
00570         if(!widget || !d->set)
00571                 return;
00572 
00573         undo();
00574 }
00575 
00576 void
00577 Editor::slotClicked(Q3ListViewItem *it)
00578 {
00579         d->previouslyCollapsedGroupItem = 0;
00580         d->childFormPreviouslyCollapsedGroupItem = 0;
00581 
00582         acceptInput();
00583 
00584         hideEditor();
00585         if(!it)
00586                 return;
00587 
00588         EditorItem *item = static_cast<EditorItem*>(it);
00589         Property *p = item->property();
00590         if(!p)
00591                 return;
00592 
00593         d->currentItem = item;
00594         d->currentWidget = createWidgetForProperty(p);
00595 
00596         //moved up updateEditorGeometry();
00597         showUndoButton( p->isModified() );
00598         if (d->currentWidget) {
00599                 if (d->currentWidget->visibleFlag()) {
00600                         d->currentWidget->show();
00601                         if (hasParent( this, kapp->focusWidget() ))
00602                                 d->currentWidget->setFocus();
00603                 }
00604         }
00605 
00606         d->justClickedItem = true;
00607 }
00608 
00609 void
00610 Editor::slotCurrentChanged(Q3ListViewItem *item)
00611 {
00612         if (item == firstChild()) {
00613                 Q3ListViewItem *oldItem = item;
00614                 while (item && (!item->isSelectable() || !item->isVisible()))
00615                         item = item->itemBelow();
00616                 if (item && item != oldItem) {
00617                         setSelected(item,true);
00618                         return;
00619                 }
00620         }
00621 }
00622 
00623 void
00624 Editor::slotSetWillBeCleared()
00625 {
00626         d->itemToSelectLater = 0;
00627         if (d->currentWidget) {
00628                 acceptInput();
00629                 d->currentWidget->setProperty(0);
00630         }
00631         clear();
00632 }
00633 
00634 void
00635 Editor::slotSetWillBeDeleted()
00636 {
00637         clear();
00638         d->set = 0;
00639 }
00640 
00641 Widget*
00642 Editor::createWidgetForProperty(Property *property, bool changeWidgetProperty)
00643 {
00644 //      int type = property->type();
00645         QPointer<Widget> widget = d->widgetCache[property];
00646 
00647         if(!widget) {
00648                 widget = FactoryManager::self()->createWidgetForProperty(property);
00649                 if (!widget)
00650                         return 0;
00651                 widget->setReadOnly( (d->set && d->set->isReadOnly()) || property->isReadOnly() );
00652                 d->widgetCache[property] = widget;
00653                 widget->setProperty(0); // to force reloading property later
00654                 widget->hide();
00655                 connect(widget, SIGNAL(valueChanged(Widget*)),
00656                         this, SLOT(slotWidgetValueChanged(Widget*)) );
00657                 connect(widget, SIGNAL(acceptInput(Widget*)),
00658                         this, SLOT(slotWidgetAcceptInput(Widget*)) );
00659                 connect(widget, SIGNAL(rejectInput(Widget*)),
00660                         this, SLOT(slotWidgetRejectInput(Widget*)) );
00661         }
00662 
00663         //update geometry earlier, because Widget::setValue() can depend on widget's geometry
00664         updateEditorGeometry(d->currentItem, widget);
00665 
00666         if(widget && (!widget->property() || changeWidgetProperty))
00667                 widget->setProperty(property);
00668 
00669 //      if (!d->doNotSetFocusOnSelection) {
00670 //              widget->setFocus();
00671 //      }
00672 
00673         return widget;
00674 }
00675 
00676 
00677 void
00678 Editor::clearWidgetCache()
00679 {
00680         for(QMap<Property*, Widget*>::iterator it = d->widgetCache.begin(); it != d->widgetCache.end(); ++it)
00681                 it.value()->deleteLater();
00682 //              delete it.data();
00683         d->widgetCache.clear();
00684 }
00685 
00686 void
00687 Editor::updateEditorGeometry(bool forceUndoButtonSettings, bool undoButtonVisible)
00688 {
00689         updateEditorGeometry(d->currentItem, d->currentWidget,
00690                 forceUndoButtonSettings, undoButtonVisible);
00691 }
00692 
00693 void
00694 Editor::updateEditorGeometry(EditorItem *item, Widget* widget,
00695   bool forceUndoButtonSettings, bool undoButtonVisible)
00696 {
00697         if(!item || !widget)
00698                 return;
00699 
00700         int placeForUndoButton;
00701         if (forceUndoButtonSettings ? undoButtonVisible : d->undoButton->isVisible())
00702                 placeForUndoButton = d->undoButton->width();
00703         else
00704                 placeForUndoButton = widget->leavesTheSpaceForRevertButton() ? d->undoButton->width() : 0;
00705 
00706         QRect r;
00707         int y = itemPos(item);
00708         r.setX(header()->sectionPos(1)-(widget->hasBorders()?1:0)); //-1, to align to horizontal line
00709         r.setY(y-(widget->hasBorders()?1:0));
00710         r.setWidth(header()->sectionSize(1)+(widget->hasBorders()?1:0) //+1 because we subtracted 1 from X
00711                 - placeForUndoButton);
00712         r.setHeight(item->height()+(widget->hasBorders()?1:-1));
00713 
00714         // check if the column is fully visible
00715         if (visibleWidth() < r.right())
00716                 r.setRight(visibleWidth());
00717 
00718         moveChild(widget, r.x(), r.y());
00719         widget->resize(r.size());
00720         qApp->processEvents(QEventLoop::AllEvents);
00721 }
00722 
00723 void
00724 Editor::updateGroupLabelsPosition()
00725 {
00726         if(!d->topItem || d->itemDict.isEmpty())
00727                 return;
00728 
00729         EditorGroupItem *group = dynamic_cast<EditorGroupItem*>(d->topItem->firstChild());
00730         while(group) {
00731                 QRect r = itemRect((Q3ListViewItem*) group);
00732                 if(group->label()) {
00733                         group->label()->setGeometry(r);
00734                         group->label()->repaint();
00735                 }
00736                 group = dynamic_cast<EditorGroupItem*>(group->nextSibling());
00737         }
00738 }
00739 
00740 void
00741 Editor::hideEditor()
00742 {
00743         d->currentItem = 0;
00744         QWidget *cw = d->currentWidget;
00745         if(cw) {
00746                 d->currentWidget = 0;
00747                 cw->hide();
00748         }
00749         d->undoButton->hide();
00750 }
00751 
00752 void
00753 Editor::showUndoButton( bool show )
00754 {
00755         if (!d->currentItem || !d->currentWidget || (d->currentWidget && d->currentWidget->isReadOnly()))
00756                 return;
00757 
00758         int y = viewportToContents(QPoint(0, itemRect(d->currentItem).y())).y();
00759         QRect geometry(columnWidth(0), y, columnWidth(1) + 1, d->currentItem->height());
00760         d->undoButton->resize(d->baseRowHeight, d->currentItem->height());
00761 
00762         updateEditorGeometry(true, show);
00763 
00764         if (!show) {
00765 /*        if (d->currentWidget) {
00766                         if (d->currentWidget->leavesTheSpaceForRevertButton()) {
00767                                 geometry.setWidth(geometry.width()-d->undoButton->width());
00768                         }
00769                         d->currentWidget->resize(geometry.width(), geometry.height());
00770                 }*/
00771                 d->undoButton->hide();
00772                 return;
00773         }
00774 
00775         QPoint p = contentsToViewport(QPoint(0, geometry.y()));
00776         d->undoButton->move(geometry.x() + geometry.width()
00777                 -((d->currentWidget && d->currentWidget->hasBorders())?1:0)/*editor is moved by 1 to left*/
00778                 - d->undoButton->width(), p.y());
00779 //  if (d->currentWidget) {
00780 //        d->currentWidget->move(d->currentWidget->x(), p.y());
00781 //        d->currentWidget->resize(geometry.width()-d->undoButton->width(), geometry.height());
00782 //  }
00783         d->undoButton->show();
00784 }
00785 
00786 void
00787 Editor::slotExpanded(Q3ListViewItem *item)
00788 {
00789         if (!item)
00790                 return;
00791 
00792         //select child item again if a group item has been expanded
00793         if (!selectedItem() && dynamic_cast<EditorGroupItem*>(item) && d->previouslyCollapsedGroupItem == item
00794                 && d->childFormPreviouslyCollapsedGroupItem) {
00795                         setSelected(d->childFormPreviouslyCollapsedGroupItem, true);
00796                         setCurrentItem(selectedItem());
00797                         slotClicked(selectedItem());
00798         }
00799         updateEditorGeometry();
00800         updateGroupLabelsPosition();
00801         repaintContents();
00802         repaint();
00803 }
00804 
00805 void
00806 Editor::slotCollapsed(Q3ListViewItem *item)
00807 {
00808         if (!item)
00809                 return;
00810         //unselect child item and hide editor if a group item has been collapsed
00811         if (dynamic_cast<EditorGroupItem*>(item)) {
00812                 for (Q3ListViewItem *i = selectedItem(); i; i = i->parent()) {
00813                         if (i->parent()==item) {
00814                                 d->previouslyCollapsedGroupItem = item;
00815                                 d->childFormPreviouslyCollapsedGroupItem = selectedItem();
00816                                 hideEditor();
00817                                 setSelected(selectedItem(), false);
00818                                 setSelected(item->nextSibling(), true);
00819                                 break;
00820                         }
00821                 }
00822         }
00823         updateEditorGeometry();
00824         updateGroupLabelsPosition();
00825         repaintContents();
00826         repaint();
00827 }
00828 
00829 void
00830 Editor::slotColumnSizeChanged(int section, int oldSize, int newSize)
00831 {
00832         Q_UNUSED(section);
00833         Q_UNUSED(oldSize);
00834         Q_UNUSED(newSize);
00835         /*for (Q3ListViewItemIterator it(this); it.current(); ++it) {
00836 //              if (section == 0 && dynamic_cast<EditorGroupItem*>(it.current())) {
00837 //                      it.current()->repaint();
00838 //      }
00839         }*/
00840 /*
00841         if(d->currentWidget) {
00842                 if(section == 0)
00843                         d->currentWidget->move(newS, d->currentWidget->y());
00844                 else  {
00845                         if(d->undoButton->isVisible())
00846                                 d->currentWidget->resize(newS - d->undoButton->width(), d->currentWidget->height());
00847                         else
00848                                 d->currentWidget->resize(
00849                                         newS-(d->currentWidget->leavesTheSpaceForRevertButton() ? d->undoButton->width() : 0),
00850                                         d->currentWidget->height());
00851                 }
00852         }*/
00853 //      repaintContents();
00854 //      repaint();
00855         updateEditorGeometry();
00856         update();
00857 }
00858 
00859 void
00860 Editor::slotColumnSizeChanged(int section)
00861 {
00862         setColumnWidth(1, viewport()->width() - columnWidth(0));
00863         slotColumnSizeChanged(section, 0, header()->sectionSize(section));
00864 
00865 /*  if(d->currentWidget) {
00866                 if(d->undoButton->isVisible())
00867                         d->currentWidget->resize(columnWidth(1) - d->undoButton->width(), d->currentWidget->height());
00868                 else
00869                         d->currentWidget->resize(
00870                                 columnWidth(1)-(d->currentWidget->leavesTheSpaceForRevertButton() ? d->undoButton->width() : 0),
00871                                 d->currentWidget->height());
00872         }*/
00873         if(d->undoButton->isVisible())
00874                 showUndoButton(true);
00875         else
00876                 updateEditorGeometry();
00877 }
00878 
00879 QSize
00880 Editor::sizeHint() const
00881 {
00882         return QSize( QFontMetrics(font()).width(columnText(0)+columnText(1)+"   "),
00883                 K3ListView::sizeHint().height());
00884 }
00885 
00886 void
00887 Editor::setFocus()
00888 {
00889         EditorItem *item = static_cast<EditorItem *>(selectedItem());
00890         if (item) {
00891                 if (!d->justClickedItem)
00892                         ensureItemVisible(item);
00893                 d->justClickedItem = false;
00894         }
00895         else {
00896                 //select an item before focusing
00897                 item = static_cast<EditorItem *>(itemAt(QPoint(10,1)));
00898                 if (item) {
00899                         ensureItemVisible(item);
00900                         setSelected(item, true);
00901                 }
00902         }
00903         if (d->currentWidget) {
00904 //              kopropertydbg << "d->currentWidget->setFocus()" << endl;
00905                 d->currentWidget->setFocus();
00906         }
00907         else {
00908 //              kopropertydbg << "K3ListView::setFocus()" << endl;
00909                 K3ListView::setFocus();
00910         }
00911 }
00912 
00913 void
00914 Editor::resizeEvent(QResizeEvent *ev)
00915 {
00916         K3ListView::resizeEvent(ev);
00917         if(d->undoButton->isVisible())
00918                 showUndoButton(true);
00919         update();
00920         updateGroupLabelsPosition();
00921 }
00922 
00923 bool
00924 Editor::eventFilter( QObject * watched, QEvent * e )
00925 {
00926         if ((watched==this || watched==viewport()) && e->type()==QEvent::KeyPress) {
00927                 if (handleKeyPress(static_cast<QKeyEvent*>(e)))
00928                         return true;
00929         }
00930         return K3ListView::eventFilter(watched, e);
00931 }
00932 
00933 bool
00934 Editor::handleKeyPress(QKeyEvent* ev)
00935 {
00936         const int k = ev->key();
00937         const Qt::KeyboardModifiers s = ev->modifiers();
00938 
00939         //selection moving
00940         Q3ListViewItem *item = 0;
00941 
00942         if ( ((s == Qt::NoModifier) && (k == Qt::Key_Up)) || (k==Qt::Key_Backtab) ) {
00943                 //find prev visible
00944                 item = selectedItem() ? selectedItem()->itemAbove() : 0;
00945                 while (item && (!item->isSelectable() || !item->isVisible()))
00946                         item = item->itemAbove();
00947                 if (!item)
00948                         return true;
00949         }
00950         else if( (s == Qt::NoModifier) && ((k == Qt::Key_Down) || (k == Qt::Key_Tab)) ) {
00951                 //find next visible
00952                 item = selectedItem() ? selectedItem()->itemBelow() : 0;
00953                 while (item && (!item->isSelectable() || !item->isVisible()))
00954                         item = item->itemBelow();
00955                 if (!item)
00956                         return true;
00957         }
00958         else if( (s == Qt::NoModifier) && (k==Qt::Key_Home) ) {
00959                 if (d->currentWidget && d->currentWidget->hasFocus())
00960                         return false;
00961                 //find 1st visible
00962                 item = firstChild();
00963                 while (item && (!item->isSelectable() || !item->isVisible()))
00964                         item = item->itemBelow();
00965         }
00966         else if( (s == Qt::NoModifier) && (k==Qt::Key_End) ) {
00967                 if (d->currentWidget && d->currentWidget->hasFocus())
00968                         return false;
00969                 //find last visible
00970                 item = selectedItem();
00971                 Q3ListViewItem *lastVisible = item;
00972                 while (item) { // && (!item->isSelectable() || !item->isVisible()))
00973                         item = item->itemBelow();
00974                         if (item && item->isSelectable() && item->isVisible())
00975                                 lastVisible = item;
00976                 }
00977                 item = lastVisible;
00978         }
00979 
00980         if(item) {
00981                 ev->accept();
00982                 ensureItemVisible(item);
00983                 setSelected(item, true);
00984                 return true;
00985         }
00986         return false;
00987 }
00988 
00989 void
00990 Editor::updateFont()
00991 {
00992         setFont(parentWidget()->font());
00993         d->baseRowHeight = QFontMetrics(parentWidget()->font()).height() + itemMargin() * 2;
00994         if (!d->currentItem)
00995                 d->undoButton->resize(d->baseRowHeight, d->baseRowHeight);
00996         else {
00997                 showUndoButton(d->undoButton->isVisible());
00998                 updateEditorGeometry();
00999         }
01000         updateGroupLabelsPosition();
01001 }
01002 
01003 bool
01004 Editor::event( QEvent * e )
01005 {
01006         if (e->type()==QEvent::FontChange) {
01007                 updateFont();
01008         }
01009         return K3ListView::event(e);
01010 }
01011 
01012 void
01013 Editor::contentsMousePressEvent( QMouseEvent * e )
01014 {
01015         Q3ListViewItem *item = itemAt(e->pos());
01016         if (dynamic_cast<EditorGroupItem*>(item)) {
01017                 setOpen( item, !isOpen(item) );
01018                 return;
01019         }
01020         K3ListView::contentsMousePressEvent(e);
01021 }
01022 
01023 void
01024 Editor::setSorting( int column, bool ascending )
01025 {
01026         if (d->set && d->set->groupNames().count()>1) //do not sort when groups are present (maybe reenable this later?)
01027                 return;
01028         K3ListView::setSorting( column, ascending );
01029         updateEditorGeometry();
01030         updateGroupLabelsPosition();
01031         repaintContents();
01032         repaint();
01033 }
01034 
01035 #include "editor.moc"

Généré le Wed Nov 22 23:41:06 2006 pour KPlato par  doxygen 1.5.1-p1