kexi

form.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
00003    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
00004    Copyright (C) 2004-2007 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 <qwidget.h>
00023 #include <qlabel.h>
00024 #include <qobjectlist.h>
00025 #include <qptrdict.h>
00026 
00027 #include <kdebug.h>
00028 #include <klocale.h>
00029 #include <kcommand.h>
00030 #include <kaction.h>
00031 #include <kmessagebox.h>
00032 
00033 #include "container.h"
00034 #include "objecttree.h"
00035 #include "widgetpropertyset.h"
00036 #include "formIO.h"
00037 #include "formmanager.h"
00038 #include "widgetlibrary.h"
00039 #include "spring.h"
00040 #include "pixmapcollection.h"
00041 #include "events.h"
00042 #include "utils.h"
00043 #include "form.h"
00044 #include <koproperty/property.h>
00045 #include <kexiutils/utils.h>
00046 
00047 using namespace KFormDesigner;
00048 
00049 FormPrivate::FormPrivate()
00050 {
00051     toplevel = 0;
00052     topTree = 0;
00053     widget = 0;
00054     resizeHandles.setAutoDelete(true);
00055     dirty = false;
00056     interactive = true;
00057     design = true;
00058     autoTabstops = false;
00059     tabstops.setAutoDelete(false);
00060     connBuffer = new ConnectionBuffer();
00061     formatVersion = KFormDesigner::version();
00062     originalFormatVersion = KFormDesigner::version();
00063 }
00064 
00065 FormPrivate::~FormPrivate()
00066 {
00067     delete history;
00068     delete topTree;
00069     delete connBuffer;
00070     connBuffer = 0;
00071     resizeHandles.setAutoDelete(false);
00072     // otherwise, it tries to delete widgets which doesn't exist anymore
00073 }
00074 
00075 //--------------------------------------
00076 
00077 FormWidget::FormWidget()
00078  : m_form(0)
00079 {
00080 }
00081 
00082 FormWidget::~FormWidget()
00083 {
00084     if (m_form) {
00085         m_form->setFormWidget(0);
00086     }
00087 }
00088 
00089 //--------------------------------------
00090 
00091 Form::Form(WidgetLibrary* library, const char *name, bool designMode)
00092   : QObject(library, name)
00093   , m_lib(library)
00094 {
00095     d = new FormPrivate();
00096 //  d->manager = manager;
00097     d->design = designMode;
00098 
00099     // Init actions
00100     d->collection = new KActionCollection(0, this);
00101     d->history = new KCommandHistory(d->collection, true);
00102     connect(d->history, SIGNAL(commandExecuted()), this, SLOT(slotCommandExecuted()));
00103     connect(d->history, SIGNAL(documentRestored()), this, SLOT(slotFormRestored()));
00104 }
00105 
00106 Form::~Form()
00107 {
00108     emit destroying();
00109     delete d;
00110     d = 0;
00111 }
00112 
00113 QWidget*
00114 Form::widget() const
00115 {
00116     if(d->topTree)
00117         return d->topTree->widget();
00118     else if(d->toplevel)
00119         return d->toplevel->widget();
00120     else // preview form
00121         return d->widget;
00122 }
00123 
00125 
00126 void
00127 Form::createToplevel(QWidget *container, FormWidget *formWidget, const QCString &)
00128 {
00129     kdDebug() << "Form::createToplevel() container= "<< (container ? container->name() : "<NULL>")
00130         << " formWidget=" << formWidget << "className=" << name() << endl;
00131 
00132     setFormWidget( formWidget );
00133     d->toplevel = new Container(0, container, this, name());
00134     d->topTree = new ObjectTree(i18n("Form"), container->name(), container, d->toplevel);
00135     d->toplevel->setObjectTree(d->topTree);
00136     d->toplevel->setForm(this);
00137     d->pixcollection = new PixmapCollection(container->name(), this);
00138 
00139     d->topTree->setWidget(container);
00141 //  d->topTree->addModifiedProperty("caption", name());
00142     //m_topTree->addModifiedProperty("icon");
00143 
00144     connect(container, SIGNAL(destroyed()), this, SLOT(formDeleted()));
00145 
00146     kdDebug() << "Form::createToplevel(): d->toplevel=" << d->toplevel << endl;
00147 }
00148 
00149 
00150 Container*
00151 Form::activeContainer()
00152 {
00153     ObjectTreeItem *it;
00154     if(d->selected.count() == 0)
00155         return d->toplevel;
00156 
00157     if(d->selected.count() == 1)
00158         it = d->topTree->lookup(d->selected.last()->name());
00159     else
00160         it = commonParentContainer( &(d->selected) );
00161 
00162     if (!it)
00163         return 0;
00164     if(it->container())
00165         return it->container();
00166     else
00167         return it->parent()->container();
00168 }
00169 
00170 ObjectTreeItem*
00171 Form::commonParentContainer(WidgetList *wlist)
00172 {
00173     ObjectTreeItem *item = 0;
00174     WidgetList *list = new WidgetList();
00175 
00176     // Creates a list of all widget parents
00177     for(QWidget *w = wlist->first(); w; w = wlist->next())
00178     {
00179         if(list->findRef(w->parentWidget()) == -1)
00180             list->append(w->parentWidget());
00181     }
00182 
00183     removeChildrenFromList(*list);
00184 
00185     // one widget remains == the container we are looking for
00186     if(list->count() == 1)
00187         item = d->topTree->lookup(list->first()->name());
00188     else // we need to go one level up
00189         item =  commonParentContainer(list);
00190 
00191     delete list;
00192     return item;
00193 }
00194 
00195 Container*
00196 Form::parentContainer(QWidget *w)
00197 {
00198     ObjectTreeItem *it;
00199     if(!w)
00200         return 0;
00201     //  it = d->topTree->lookup(d->selected.last()->name());
00202     //else
00203     it = d->topTree->lookup(w->name());
00204 
00205     if(it->parent()->container())
00206         return it->parent()->container();
00207     else
00208         return it->parent()->parent()->container();
00209 }
00210 
00211 
00212 
00213 void
00214 Form::setDesignMode(bool design)
00215 {
00216     d->design = design;
00217     if(!design)
00218     {
00219         ObjectTreeDict *dict = new ObjectTreeDict( *(d->topTree->dict()) );
00220         ObjectTreeDictIterator it(*dict);
00221         for(; it.current(); ++it)
00222             m_lib->previewWidget(it.current()->widget()->className(), it.current()->widget(), d->toplevel);
00223         delete dict;
00224 
00225         d->widget = d->topTree->widget();
00226         delete (d->topTree);
00227         d->topTree = 0;
00228         delete (d->toplevel);
00229         d->toplevel = 0;
00230     }
00231 }
00232 
00233 
00235 
00236 void
00237 Form::setSelectedWidget(QWidget *w, bool add, bool dontRaise, bool moreWillBeSelected)
00238 {
00239     if((d->selected.isEmpty()) || (w == widget()) || (d->selected.first() == widget()))
00240         add = false;
00241 
00242     if(!w)
00243     {
00244         setSelectedWidget(widget());
00245         return;
00246     }
00247 
00248     //raise selected widget and all possible parents
00249     QWidget *wtmp = w;
00250     while(!dontRaise && wtmp && wtmp->parentWidget() && (wtmp != widget()))
00251     {
00252         wtmp->raise();
00253         if(d->resizeHandles[ wtmp->name() ])
00254             d->resizeHandles[ wtmp->name() ]->raise();
00255         wtmp = wtmp->parentWidget();
00256     }
00257 
00258     if (wtmp)
00259         wtmp->setFocus();
00260 
00261     if(!add)
00262     {
00263         d->selected.clear();
00264         d->resizeHandles.clear();
00265     }
00266     d->selected.append(w);
00267     emit selectionChanged(w, add, moreWillBeSelected);
00268     emitActionSignals(false);
00269 
00270     // WidgetStack and TabWidget pages widgets shouldn't have resize handles, but their parent
00271     if(!FormManager::self()->isTopLevel(w) && w->parentWidget() && w->parentWidget()->isA("QWidgetStack"))
00272     {
00273         w = w->parentWidget();
00274         if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget"))
00275             w = w->parentWidget();
00276     }
00277 
00278     if(w && w != widget())
00279         d->resizeHandles.insert(w->name(), new ResizeHandleSet(w, this));
00280 }
00281 
00282 ResizeHandleSet*
00283 Form::resizeHandlesForWidget(QWidget* w)
00284 {
00285     return d->resizeHandles[w->name()];
00286 }
00287 
00288 void
00289 Form::unSelectWidget(QWidget *w)
00290 {
00291     d->selected.remove(w);
00292     d->resizeHandles.remove(w->name());
00293 }
00294 
00295 void
00296 Form::selectFormWidget()
00297 {
00298     setSelectedWidget(widget(), false);
00299 }
00300 
00301 void
00302 Form::clearSelection()
00303 {
00304     d->selected.clear();
00305     d->resizeHandles.clear();
00306     emit selectionChanged(0, false);
00307     emitActionSignals(false);
00308 }
00309 
00310 void
00311 Form::emitActionSignals(bool withUndoAction)
00312 {
00313     // Update menu and toolbar items
00314     if(d->selected.count() > 1)
00315         FormManager::self()->emitWidgetSelected(this, true);
00316     else if(d->selected.first() != widget())
00317         FormManager::self()->emitWidgetSelected(this, false);
00318     else
00319         FormManager::self()->emitFormWidgetSelected(this);
00320 
00321     if(!withUndoAction)
00322         return;
00323 
00324     KAction *undoAction = d->collection->action("edit_undo");
00325     if(undoAction)
00326         FormManager::self()->emitUndoEnabled(undoAction->isEnabled(), undoAction->text());
00327 
00328     KAction *redoAction = d->collection->action("edit_redo");
00329     if(redoAction)
00330         FormManager::self()->emitRedoEnabled(redoAction->isEnabled(), redoAction->text());
00331 }
00332 
00333 void
00334 Form::emitSelectionSignals()
00335 {
00336     emit selectionChanged(selectedWidgets()->first(), false);
00337 //  for(QWidget *w = selectedWidgets()->next(); w; w = selectedWidgets()->next())
00338 //      emit selectionChanged(selectedWidgets()->first(), true);
00339     for (WidgetListIterator it(*selectedWidgets()); it.current(); ++it)
00340         emit selectionChanged(it.current(), true);
00341 }
00342 
00344 void
00345 Form::formDeleted()
00346 {
00347 //  clearSelection();
00348     d->selected.clear();
00349     d->resizeHandles.setAutoDelete(false);
00350     d->resizeHandles.clear();
00351     d->resizeHandles.setAutoDelete(true);
00352 //  emit selectionChanged(0, false);
00353 //  emitActionSignals(false);
00354 
00355     FormManager::self()->deleteForm(this);
00356     //delete this;
00357     deleteLater();
00358 }
00359 
00360 void
00361 Form::changeName(const QCString &oldname, const QCString &newname)
00362 {
00363     if(oldname == newname)
00364         return;
00365     if(!d->topTree->rename(oldname, newname)) // rename failed
00366     {
00367         KMessageBox::sorry(widget()->topLevelWidget(),
00368             i18n("Renaming widget \"%1\" to \"%2\" failed.").arg(oldname).arg(newname));
00369 //moved to WidgetPropertySet::slotChangeProperty()
00370 //      KMessageBox::sorry(widget()->topLevelWidget(),
00371 //      i18n("A widget with this name already exists. "
00372 //          "Please choose another name or rename existing widget."));
00373         kdDebug() << "Form::changeName() : ERROR : A widget named " << newname << " already exists" << endl;
00374         FormManager::self()->propertySet()->property("name") = QVariant(oldname);
00375     }
00376     else
00377     {
00378         d->connBuffer->fixName(oldname, newname);
00379         ResizeHandleSet *temp = d->resizeHandles.take(oldname);
00380         d->resizeHandles.insert(newname, temp);
00381     }
00382 }
00383 
00384 void
00385 Form::emitChildAdded(ObjectTreeItem *item)
00386 {
00387     addWidgetToTabStops(item);
00388     emit childAdded(item);
00389 }
00390 
00391 void
00392 Form::emitChildRemoved(ObjectTreeItem *item)
00393 {
00394     d->tabstops.remove(item);
00395     if(d->connBuffer)
00396         d->connBuffer->removeAllConnectionsForWidget(item->name());
00397     emit childRemoved(item);
00398 }
00399 
00400 void
00401 Form::addCommand(KCommand *command, bool execute)
00402 {
00403     emit FormManager::self()->dirty(this, true);
00404     d->dirty = true;
00405     d->history->addCommand(command, execute);
00406     if(!execute) // simulate command to activate 'undo' menu
00407         slotCommandExecuted();
00408 }
00409 
00410 void
00411 Form::clearCommandHistory()
00412 {
00413     d->history->clear();
00414     FormManager::self()->emitUndoEnabled(false, QString::null); 
00415     FormManager::self()->emitRedoEnabled(false, QString::null); 
00416 }
00417 
00418 void
00419 Form::slotCommandExecuted()
00420 {
00421     emit FormManager::self()->dirty(this, true);
00422     d->dirty = true;
00423     // because actions text is changed after the commandExecuted() signal is emitted
00424     QTimer::singleShot(10, this, SLOT(emitUndoEnabled()));
00425     QTimer::singleShot(10, this, SLOT(emitRedoEnabled()));
00426 }
00427 
00428 void
00429 Form::emitUndoEnabled()
00430 {
00431     KAction *undoAction = d->collection->action("edit_undo");
00432     if(undoAction)
00433         FormManager::self()->emitUndoEnabled(undoAction->isEnabled(), undoAction->text());
00434 }
00435 
00436 void
00437 Form::emitRedoEnabled()
00438 {
00439     KAction *redoAction = d->collection->action("edit_redo");
00440     if(redoAction)
00441         FormManager::self()->emitRedoEnabled(redoAction->isEnabled(), redoAction->text());
00442 }
00443 
00444 void
00445 Form::slotFormRestored()
00446 {
00447     emit FormManager::self()->dirty(this, false);
00448     d->dirty = false;
00449 }
00450 
00451 
00453 
00454 void
00455 Form::addWidgetToTabStops(ObjectTreeItem *it)
00456 {
00457     QWidget *w = it->widget();
00458     if(!w)
00459         return;
00460     if(!(w->focusPolicy() & QWidget::TabFocus))
00461     {
00462         if (!w->children())
00463             return;
00464         // For composed widgets, we check if one of the child can have focus
00465         for(QObjectListIterator chIt(*w->children()); chIt.current(); ++chIt) {
00466             if(chIt.current()->isWidgetType()) {//QWidget::TabFocus flag will be checked later!
00467                 if(d->tabstops.findRef(it) == -1) {
00468                     d->tabstops.append(it);
00469                     return;
00470                 }
00471             }
00472         }
00473     }
00474     else if(d->tabstops.findRef(it) == -1) // not yet in the list
00475         d->tabstops.append(it);
00476 }
00477 
00478 void
00479 Form::updateTabStopsOrder()
00480 {
00481     for (ObjectTreeListIterator it(d->tabstops);it.current();) {
00482         if(!(it.current()->widget()->focusPolicy() & QWidget::TabFocus)) {
00483             kexidbg << "Form::updateTabStopsOrder(): widget removed because has no TabFocus: " << it.current()->widget()->name() << endl;
00484             d->tabstops.remove( it.current() );
00485         }
00486         else
00487             ++it;
00488     }
00489 }
00490 
00492 void collectContainers(ObjectTreeItem* item, QPtrDict<char>& containers)
00493 {
00494     if (!item->container())
00495         return;
00496     if (!containers[ item->container() ]) {
00497         kdDebug() << "collectContainers() " << item->container()->objectTree()->className() 
00498             << " " << item->container()->objectTree()->name() << endl;
00499         containers.insert( item->container(), (const char *)1 );
00500     }
00501     for (ObjectTreeListIterator it(*item->children()); it.current(); ++it)
00502         collectContainers(it.current(), containers);
00503 }
00504 
00505 void
00506 Form::autoAssignTabStops()
00507 {
00508     VerWidgetList list(toplevelContainer()->widget());
00509     HorWidgetList hlist(toplevelContainer()->widget());
00510 
00511     // 1. Collect all the containers, as we'll be sorting widgets groupped by containers
00512     QPtrDict<char> containers;
00513 
00514     collectContainers( toplevelContainer()->objectTree(), containers );
00515 
00516     foreach_list(ObjectTreeListIterator, it, d->tabstops) {
00517         if(it.current()->widget()) {
00518             kdDebug() << "Form::autoAssignTabStops() widget to sort: " << it.current()->widget() << endl;
00519             list.append(it.current()->widget());
00520         }
00521     }
00522 
00523     list.sort();
00524     foreach_list(QPtrListIterator<QWidget>, iter, list)
00525         kdDebug() << iter.current()->className() << " " << iter.current()->name() << endl;
00526 
00527     d->tabstops.clear();
00528 
00531     foreach_list(WidgetListIterator, it, list) {
00532         QWidget *w = it.current();
00533         hlist.append(w);
00534 
00535         ++it;
00536         QWidget *nextw = it.current();
00537         QObject *page_w = 0;
00538         KFormDesigner::TabWidget *tab_w = KFormDesigner::findParent<KFormDesigner::TabWidget>(w, "KFormDesigner::TabWidget", page_w);
00539         while (nextw) {
00540             if (KexiUtils::hasParent(w, nextw)) // do not group (sort) widgets where on is a child of another
00541                 break;
00542             if (nextw->y() >= (w->y() + 20))
00543                 break;
00544             if (tab_w) {
00545                 QObject *page_nextw = 0;
00546                 KFormDesigner::TabWidget *tab_nextw = KFormDesigner::findParent<KFormDesigner::TabWidget>(nextw, "KFormDesigner::TabWidget", page_nextw);
00547                 if (tab_w == tab_nextw) {
00548                     if (page_w != page_nextw) // 'nextw' widget within different tab page
00549                         break;
00550                 }
00551             }
00552             hlist.append(nextw);
00553             ++it;
00554             nextw = it.current();
00555         }
00556         hlist.sort();
00557 
00558         for(WidgetListIterator it2(hlist); it2.current() != 0; ++it2) {
00559             ObjectTreeItem *tree = d->topTree->lookup(it2.current()->name());
00560             if(tree) {
00561                 kdDebug() << "Form::autoAssignTabStops() adding " << tree->name() << endl;
00562                 d->tabstops.append(tree);
00563             }
00564         }
00565 
00566         --it;
00567         hlist.clear();
00568     }
00569 }
00570 
00571 uint Form::formatVersion() const
00572 {
00573     return d->formatVersion;
00574 }
00575 
00576 void Form::setFormatVersion(uint ver)
00577 {
00578     d->formatVersion = ver;
00579 }
00580 uint Form::originalFormatVersion() const
00581 {
00582     return d->originalFormatVersion;
00583 }
00584 
00585 void Form::setOriginalFormatVersion(uint ver)
00586 {
00587     d->originalFormatVersion = ver;
00588 }
00589 
00590 void Form::setFormWidget(FormWidget* w)
00591 {
00592     if (!d)
00593         return;
00594     d->formWidget = w;
00595     if (!d->formWidget)
00596         return;
00597     d->formWidget->m_form = this;
00598 }
00599 
00600 #include "form.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys