/* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2005 Jaroslaw Staniek 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 #include #include #include #include #include #include #include #include #include #include #include "formIO.h" #include "container.h" #include "objecttree.h" #include "formmanager.h" #include "form.h" #include "widgetlibrary.h" #include "events.h" #include "utils.h" #include "widgetpropertyset.h" #include "widgetwithsubpropertiesinterface.h" #include #include "commands.h" using namespace KFormDesigner; // Command Command::Command() : KCommand() { } Command::~Command() { } // PropertyCommand PropertyCommand::PropertyCommand(WidgetPropertySet *set, const TQCString &wname, const TQVariant &oldValue, const TQVariant &value, const TQCString &property) : Command(), m_propSet(set), m_value(value), m_property(property) { m_oldvalues.insert(wname, oldValue); } PropertyCommand::PropertyCommand(WidgetPropertySet *set, const TQMap &oldvalues, const TQVariant &value, const TQCString &property) : Command(), m_propSet(set), m_value(value), m_oldvalues(oldvalues), m_property(property) { } /* MultiCommand::MultiCommand() { } MultiCommandGroup::addSubCommand(PropertyCommand* subCommand) : Command(), m_propSet(set), m_value(value), m_oldvalues(oldvalues), m_property(property) { } */ void PropertyCommand::setValue(const TQVariant &value) { m_value = value; emit FormManager::self()->dirty(FormManager::self()->activeForm()); } void PropertyCommand::execute() { FormManager::self()->activeForm()->selectFormWidget(); m_propSet->setUndoing(true); TQMap::ConstIterator endIt = m_oldvalues.constEnd(); for(TQMap::ConstIterator it = m_oldvalues.constBegin(); it != endIt; ++it) { ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(it.key()); if (item) {//we're checking for item!=0 because the name could be of a form widget FormManager::self()->activeForm()->setSelectedWidget(item->widget(), true); } } (*m_propSet)[m_property] = m_value; m_propSet->setUndoing(false); } void PropertyCommand::unexecute() { FormManager::self()->activeForm()->selectFormWidget(); m_propSet->setUndoing(true); TQMap::ConstIterator endIt = m_oldvalues.constEnd(); for(TQMap::ConstIterator it = m_oldvalues.constBegin(); it != endIt; ++it) { ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(it.key()); if (!item) continue; //better this than a crash TQWidget *widg = item->widget(); FormManager::self()->activeForm()->setSelectedWidget(widg, true); //m_propSet->setSelectedWidget(widg, true); WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(widg); TQWidget *subWidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : widg; if (-1!=subWidget->metaObject()->findProperty( m_property, true )) subWidget->setProperty(m_property, it.data()); } (*m_propSet)[m_property] = m_oldvalues.begin().data(); m_propSet->setUndoing(false); } TQString PropertyCommand::name() const { if(m_oldvalues.count() >= 2) return i18n("Change \"%1\" property for multiple widgets" ).arg(TQString(m_property)); else return i18n("Change \"%1\" property for widget \"%2\"" ).arg(TQString(m_property)).arg(TQString(m_oldvalues.begin().key())); } void PropertyCommand::debug() { kdDebug() << "PropertyCommand: name=\"" << name() << "\" widgets=" << m_oldvalues.keys() << " value=" << m_value << " oldValues=" << m_oldvalues.values() << endl; } // GeometryPropertyCommand (for multiples widgets) GeometryPropertyCommand::GeometryPropertyCommand(WidgetPropertySet *set, const TQStringList &names, const TQPoint& oldPos) : Command(), m_propSet(set), m_names(names), m_oldPos(oldPos) { } void GeometryPropertyCommand::execute() { m_propSet->setUndoing(true); int dx = m_pos.x() - m_oldPos.x(); int dy = m_pos.y() - m_oldPos.y(); TQStringList::ConstIterator endIt = m_names.constEnd(); // We move every widget in our list by (dx, dy) for(TQStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it) { ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(*it); if (!item) continue; //better this than a crash TQWidget *w = item->widget(); w->move(w->x() + dx, w->y() + dy); } m_propSet->setUndoing(false); } void GeometryPropertyCommand::unexecute() { m_propSet->setUndoing(true); int dx = m_pos.x() - m_oldPos.x(); int dy = m_pos.y() - m_oldPos.y(); TQStringList::ConstIterator endIt = m_names.constEnd(); // We move every widget in our list by (-dx, -dy) to undo the move for(TQStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it) { ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(*it); if (!item) continue; //better this than a crash TQWidget *w = item->widget(); w->move(w->x() - dx, w->y() - dy); } m_propSet->setUndoing(false); } void GeometryPropertyCommand::setPos(const TQPoint& pos) { m_pos = pos; emit FormManager::self()->dirty(FormManager::self()->activeForm()); } TQString GeometryPropertyCommand::name() const { return i18n("Move multiple widgets"); } void GeometryPropertyCommand::debug() { kdDebug() << "GeometryPropertyCommand: pos=" << m_pos << " oldPos=" << m_oldPos << " widgets=" << m_names << endl; } ///////////////// AlignWidgetsCommand //////// AlignWidgetsCommand::AlignWidgetsCommand(int type, WidgetList &list, Form *form) : Command(), m_form(form), m_type(type) { for(TQWidget *w = list.first(); w; w = list.next()) m_pos.insert(w->name(), w->pos()); } void AlignWidgetsCommand::execute() { // To avoid creation of GeometryPropertyCommand m_form->selectFormWidget(); int gridX = m_form->gridSize(); int gridY = m_form->gridSize(); TQWidget *parentWidget = m_form->selectedWidgets()->first()->parentWidget(); int tmpx, tmpy; WidgetList list; TQMap::ConstIterator endIt = m_pos.constEnd(); for(TQMap::ConstIterator it = m_pos.constBegin(); it != endIt; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.key()); if(item && item->widget()) list.append(item->widget()); } switch(m_type) { case AlignToGrid: { for(TQWidget *w = list.first(); w; w = list.next()) { tmpx = int( (float)w->x() / ((float)gridX) + 0.5 ) * gridX; tmpy = int( (float)w->y() / ((float)gridY) + 0.5 ) * gridY; if((tmpx != w->x()) || (tmpy != w->y())) w->move(tmpx, tmpy); } break; } case AlignToLeft: { tmpx = parentWidget->width(); for(TQWidget *w = list.first(); w; w = list.next()) { if(w->x() < tmpx) tmpx = w->x(); } for(TQWidget *w = list.first(); w; w = list.next()) w->move(tmpx, w->y()); break; } case AlignToRight: { tmpx = 0; for(TQWidget *w = list.first(); w; w = list.next()) { if(w->x() + w->width() > tmpx) tmpx = w->x() + w->width(); } for(TQWidget *w = list.first(); w; w = list.next()) w->move(tmpx - w->width(), w->y()); break; } case AlignToTop: { tmpy = parentWidget->height(); for(TQWidget *w = list.first(); w; w = list.next()) { if(w->y() < tmpy) tmpy = w->y(); } for(TQWidget *w = list.first(); w; w = list.next()) w->move(w->x(), tmpy); break; } case AlignToBottom: { tmpy = 0; for(TQWidget *w = list.first(); w; w = list.next()) { if(w->y() + w->height() > tmpy) tmpy = w->y() + w->height(); } for(TQWidget *w = list.first(); w; w = list.next()) w->move(w->x(), tmpy - w->height()); break; } default: return; } // We restore selection for(TQWidget *w = list.first(); w; w = list.next()) m_form->setSelectedWidget(w, true); } void AlignWidgetsCommand::unexecute() { // To avoid creation of GeometryPropertyCommand m_form->selectFormWidget(); // We move widgets to their original pos TQMap::ConstIterator endIt = m_pos.constEnd(); for(TQMap::ConstIterator it = m_pos.constBegin(); it != endIt; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.key()); if(item && item->widget()) item->widget()->move( m_pos[item->widget()->name()] ); m_form->setSelectedWidget(item->widget(), true); // We restore selection } } TQString AlignWidgetsCommand::name() const { switch(m_type) { case AlignToGrid: return i18n("Align Widgets to Grid"); case AlignToLeft: return i18n("Align Widgets to Left"); case AlignToRight: return i18n("Align Widgets to Right"); case AlignToTop: return i18n("Align Widgets to Top"); case AlignToBottom: return i18n("Align Widgets to Bottom"); default: return TQString(); } } void AlignWidgetsCommand::debug() { kdDebug() << "AlignWidgetsCommand: name=\"" << name() << "\" form=" << m_form->widget()->name() << " widgets=" << m_pos.keys() << endl; } ///// AdjustSizeCommand /////////// AdjustSizeCommand::AdjustSizeCommand(int type, WidgetList &list, Form *form) : Command(), m_form(form), m_type(type) { for(TQWidget *w = list.first(); w; w = list.next()) { if(w->parentWidget() && w->parentWidget()->isA("TQWidgetStack")) { w = w->parentWidget(); // widget is WidgetStack page if(w->parentWidget() && w->parentWidget()->inherits("TQTabWidget")) // widget is tabwidget page w = w->parentWidget(); } m_sizes.insert(w->name(), w->size()); if(m_type == SizeToGrid) // SizeToGrid also move widgets m_pos.insert(w->name(), w->pos()); } } void AdjustSizeCommand::execute() { // To avoid creation of GeometryPropertyCommand m_form->selectFormWidget(); int gridX = m_form->gridSize(); int gridY = m_form->gridSize(); int tmpw=0, tmph=0; WidgetList list; TQMap::ConstIterator endIt = m_sizes.constEnd(); for(TQMap::ConstIterator it = m_sizes.constBegin(); it != endIt; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.key()); if(item && item->widget()) list.append(item->widget()); } switch(m_type) { case SizeToGrid: { int tmpx=0, tmpy=0; // same as in 'Align to Grid' + for the size for(TQWidget *w = list.first(); w; w = list.next()) { tmpx = int( (float)w->x() / ((float)gridX) + 0.5 ) * gridX; tmpy = int( (float)w->y() / ((float)gridY) + 0.5 ) * gridY; tmpw = int( (float)w->width() / ((float)gridX) + 0.5 ) * gridX; tmph = int( (float)w->height() / ((float)gridY) + 0.5 ) * gridY; if((tmpx != w->x()) || (tmpy != w->y())) w->move(tmpx, tmpy); if((tmpw != w->width()) || (tmph != w->height())) w->resize(tmpw, tmph); } break; } case SizeToFit: { for(TQWidget *w = list.first(); w; w = list.next()) { ObjectTreeItem *item = m_form->objectTree()->lookup(w->name()); if(item && !item->children()->isEmpty()) { // container TQSize s; if(item->container() && item->container()->layout()) s = w->sizeHint(); else s = getSizeFromChildren(item); // minimum size for containers if(s.width() < 30) s.setWidth(30); if(s.height() < 30) s.setHeight(30); // small hack for flow layouts int type = item->container() ? item->container()->layoutType() : Container::NoLayout; if(type == Container::HFlow) s.setWidth(s.width() + 5); else if(type == Container::VFlow) s.setHeight(s.height() + 5); w->resize(s); } else if(item && item->container()) // empty container w->resize(item->container()->form()->gridSize() * 5, item->container()->form()->gridSize() * 5); // basic size else { TQSize sizeHint(w->sizeHint()); if (sizeHint.isValid()) w->resize(sizeHint); } } break; } case SizeToSmallWidth: { for(TQWidget *w = list.first(); w; w = list.next()) { if((tmpw == 0) || (w->width() < tmpw)) tmpw = w->width(); } for(TQWidget *w = list.first(); w; w = list.next()) { if(tmpw != w->width()) w->resize(tmpw, w->height()); } break; } case SizeToBigWidth: { for(TQWidget *w = list.first(); w; w = list.next()) { if(w->width() > tmpw) tmpw = w->width(); } for(TQWidget *w = list.first(); w; w = list.next()) { if(tmpw != w->width()) w->resize(tmpw, w->height()); } break; } case SizeToSmallHeight: { for(TQWidget *w = list.first(); w; w = list.next()) { if((tmph == 0) || (w->height() < tmph)) tmph = w->height(); } for(TQWidget *w = list.first(); w; w = list.next()) { if(tmph != w->height()) w->resize(w->width(), tmph); } break; } case SizeToBigHeight: { for(TQWidget *w = list.first(); w; w = list.next()) { if(w->height() > tmph) tmph = w->height(); } for(TQWidget *w = list.first(); w; w = list.next()) { if(tmph != w->height()) w->resize(w->width(), tmph); } break; } default: break; } // We restore selection for(TQWidget *w = list.first(); w; w = list.next()) m_form->setSelectedWidget(w, true); } TQSize AdjustSizeCommand::getSizeFromChildren(ObjectTreeItem *item) { if(!item->container()) // multi pages containers (eg tabwidget) { TQSize s; // get size for each container, and keep the biggest one for(ObjectTreeItem *tree = item->children()->first(); tree; tree = item->children()->next()) s = s.expandedTo(getSizeFromChildren(tree)); return s; } int tmpw = 0, tmph = 0; for(ObjectTreeItem *tree = item->children()->first(); tree; tree = item->children()->next()) { if(!tree->widget()) continue; tmpw = TQMAX(tmpw, tree->widget()->geometry().right()); tmph = TQMAX(tmph, tree->widget()->geometry().bottom()); } return TQSize(tmpw, tmph) + TQSize(10, 10); } void AdjustSizeCommand::unexecute() { // To avoid creation of GeometryPropertyCommand m_form->selectFormWidget(); // We resize widgets to their original size TQMap::ConstIterator endIt = m_sizes.constEnd(); for(TQMap::ConstIterator it = m_sizes.constBegin(); it != endIt; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.key()); if(item && item->widget()) { item->widget()->resize( m_sizes[item->widget()->name()] ); if(m_type == SizeToGrid) item->widget()->move( m_pos[item->widget()->name()] ); m_form->setSelectedWidget(item->widget(), true); // We restore selection } } } TQString AdjustSizeCommand::name() const { switch(m_type) { case SizeToGrid: return i18n("Resize Widgets to Grid"); case SizeToFit: return i18n("Resize Widgets to Fit Contents"); case SizeToSmallWidth: return i18n("Resize Widgets to Narrowest"); case SizeToBigWidth: return i18n("Resize Widgets to Widest"); case SizeToSmallHeight: return i18n("Resize Widgets to Shortest"); case SizeToBigHeight: return i18n("Resize Widgets to Tallest"); default: return TQString(); } } void AdjustSizeCommand::debug() { kdDebug() << "AdjustSizeCommand: name=\"" << name() << "\" form=" << m_form->widget()->name() << " widgets=" << m_sizes.keys() << endl; } // LayoutPropertyCommand LayoutPropertyCommand::LayoutPropertyCommand(WidgetPropertySet *buf, const TQCString &wname, const TQVariant &oldValue, const TQVariant &value) : PropertyCommand(buf, wname, oldValue, value, "layout") { m_form = FormManager::self()->activeForm(); ObjectTreeItem* titem = m_form->objectTree()->lookup(wname); if (!titem) return; //better this than a crash Container *m_container = titem->container(); // We save the geometry of each wigdet for(ObjectTreeItem *it = m_container->objectTree()->children()->first(); it; it = m_container->objectTree()->children()->next()) m_geometries.insert(it->name().latin1(), it->widget()->geometry()); } void LayoutPropertyCommand::execute() { PropertyCommand::execute(); } void LayoutPropertyCommand::unexecute() { ObjectTreeItem* titem = m_form->objectTree()->lookup(m_oldvalues.begin().key()); if (!titem) return; //better this than a crash Container *m_container = titem->container(); m_container->setLayout(Container::NoLayout); // We put every widget back in its old location TQMap::ConstIterator endIt = m_geometries.constEnd(); for(TQMap::ConstIterator it = m_geometries.constBegin(); it != endIt; ++it) { ObjectTreeItem *tree = m_container->form()->objectTree()->lookup(it.key()); if(tree) tree->widget()->setGeometry(it.data()); } PropertyCommand::unexecute(); } TQString LayoutPropertyCommand::name() const { return i18n("Change layout of widget \"%1\"").arg(TQString(m_oldvalues.begin().key())); } void LayoutPropertyCommand::debug() { kdDebug() << "LayoutPropertyCommand: name=\"" << name() << "\" oldValue=" << m_oldvalues.keys() << " value=" << m_value << endl; } // InsertWidgetCommand InsertWidgetCommand::InsertWidgetCommand(Container *container) : Command() { m_containername = container->widget()->name(); m_form = container->form(); m_class = FormManager::self()->selectedClass(); m_insertRect = container->m_insertRect; m_point = container->m_insertBegin; m_name = container->form()->objectTree()->generateUniqueName( container->form()->library()->namePrefix(m_class).latin1(), /*!numberSuffixRequired*/false); } InsertWidgetCommand::InsertWidgetCommand(Container *container, const TQCString& className, const TQPoint& pos, const TQCString& namePrefix) : Command() { m_containername = container->widget()->name(); m_form = container->form(); m_class = className; //m_insertRect is null (default) m_point = pos; if (namePrefix.isEmpty()) { m_name = container->form()->objectTree()->generateUniqueName( container->form()->library()->namePrefix(m_class).latin1() ); } else { m_name = container->form()->objectTree()->generateUniqueName( namePrefix, false /*!numberSuffixRequired*/ ); } } void InsertWidgetCommand::execute() { if (!m_form->objectTree()) return; ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername); if (!titem) return; //better this than a crash Container *m_container = titem->container(); int options = WidgetFactory::DesignViewMode | WidgetFactory::AnyOrientation; if (m_container->form()->library()->internalProperty(m_class, "orientationSelectionPopup")=="1") { if(m_insertRect.isValid()) { if (m_insertRect.width() < m_insertRect.height()) { options |= WidgetFactory::VerticalOrientation; options ^= WidgetFactory::AnyOrientation; } else if (m_insertRect.width() > m_insertRect.height()) { options |= WidgetFactory::HorizontalOrientation; options ^= WidgetFactory::AnyOrientation; } } if (options & WidgetFactory::AnyOrientation) { options ^= WidgetFactory::AnyOrientation; options |= m_container->form()->library()->showOrientationSelectionPopup( m_class, m_container->m_container, m_container->form()->widget()->mapToGlobal(m_point)); if (options & WidgetFactory::AnyOrientation) return; //cancelled } } else options |= WidgetFactory::AnyOrientation; TQWidget *w = m_container->form()->library()->createWidget(m_class, m_container->m_container, m_name, m_container, options); if(!w) { FormManager::self()->stopInsert(); WidgetInfo *winfo = m_container->form()->library()->widgetInfoForClassName(m_class); KMessageBox::sorry(FormManager::self()->activeForm() ? FormManager::self()->activeForm()->widget() : 0, i18n("Could not insert widget of type \"%1\". A problem with widget's creation encountered.") .arg(winfo ? winfo->name() : TQString())); kdWarning() << "InsertWidgetCommand::execute() ERROR: widget creation failed" << endl; return; } #if TDE_VERSION >= TDE_MAKE_VERSION(3,4,0) //! @todo allow setting this for data view mode as well if (m_form->designMode()) { //don't generate accelerators for widgets in design mode TDEAcceleratorManager::setNoAccel(w); } #endif // if the insertRect is invalid (ie only one point), we use widget' size hint if(( (m_insertRect.width() < 21) && (m_insertRect.height() < 21))) { TQSize s = w->sizeHint(); if(s.isEmpty()) s = TQSize(20, 20); // Minimum size to avoid creating a (0,0) widget int x, y; if(m_insertRect.isValid()) { x = m_insertRect.x(); y = m_insertRect.y(); } else { x = m_point.x(); y = m_point.y(); } m_insertRect = TQRect(x, y, s.width() + 16/* add some space so more text can be entered*/, s.height()); } w->move(m_insertRect.x(), m_insertRect.y()); w->resize(m_insertRect.width()-1, m_insertRect.height()-1); // -1 is not to hide dots w->setStyle(&(m_container->widget()->style())); w->setBackgroundOrigin(TQWidget::ParentOrigin); w->show(); FormManager::self()->stopInsert(); // ObjectTreeItem object already exists for widgets which corresponds to a Container // it's already created in Container's constructor ObjectTreeItem *item = m_container->form()->objectTree()->lookup(m_name); if (!item) { //not yet created... m_container->form()->objectTree()->addItem(m_container->m_tree, item = new ObjectTreeItem(m_container->form()->library()->displayName(m_class), m_name, w, m_container) ); } //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface //(e.g. KexiDBAutoField) if (m_form->designMode() && dynamic_cast(w)) { dynamic_cast(w)->assignItem(item); } // We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later TQValueList list(m_container->form()->library()->autoSaveProperties(w->className())); TQValueList::ConstIterator endIt = list.constEnd(); for(TQValueList::ConstIterator it = list.constBegin(); it != endIt; ++it) item->addModifiedProperty(*it, w->property(*it)); m_container->reloadLayout(); // reload the layout to take the new wigdet into account m_container->setSelectedWidget(w, false); if (m_container->form()->library()->internalProperty(w->className(), "dontStartEditingOnInserting").isEmpty()) { m_container->form()->library()->startEditing( w->className(), w, item->container() ? item->container() : m_container); // we edit the widget on creation } //! @todo update widget's width for entered text's metrics kdDebug() << "Container::eventFilter(): widget added " << this << endl; } void InsertWidgetCommand::unexecute() { ObjectTreeItem* titem = m_form->objectTree()->lookup(m_name); if (!titem) return; //better this than a crash TQWidget *m_widget = titem->widget(); Container *m_container = m_form->objectTree()->lookup(m_containername)->container(); m_container->deleteWidget(m_widget); } TQString InsertWidgetCommand::name() const { if(!m_name.isEmpty()) return i18n("Insert widget \"%1\"").arg(TQString(m_name)); else return i18n("Insert widget"); } void InsertWidgetCommand::debug() { kdDebug() << "InsertWidgetCommand: name=\"" << name() << "\" generatedName=" << m_name << " container=" << m_containername << " form=" << m_form->widget()->name() << " class=" << m_class << " rect=" << m_insertRect << " pos=" << m_point << endl; } /// CreateLayoutCommand /////////////// CreateLayoutCommand::CreateLayoutCommand(int layoutType, WidgetList &list, Form *form) : m_form(form), m_type(layoutType) { WidgetList *m_list=0; switch(layoutType) { case Container::HBox: case Container::Grid: case Container::HSplitter: case Container::HFlow: m_list = new HorWidgetList(form->toplevelContainer()->widget()); break; case Container::VBox: case Container::VSplitter: case Container::VFlow: m_list = new VerWidgetList(form->toplevelContainer()->widget()); break; } for(TQWidget *w = list.first(); w; w = list.next()) m_list->append(w); m_list->sort(); // we sort them now, before creating the layout for(TQWidget *w = m_list->first(); w; w = m_list->next()) m_pos.insert(w->name(), w->geometry()); ObjectTreeItem *item = form->objectTree()->lookup(m_list->first()->name()); if(item && item->parent()->container()) m_containername = item->parent()->name(); delete m_list; } void CreateLayoutCommand::execute() { WidgetLibrary *lib = m_form->library(); if(!lib) return; ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername); Container *container = titem ? titem->container() : 0; if(!container) container = m_form->toplevelContainer(); // use toplevelContainer by default TQCString classname; switch(m_type) { case Container::HSplitter: case Container::VSplitter: classname = "TQSplitter"; break; default: classname = Container::layoutTypeToString(m_type).latin1(); } if(m_name.isEmpty())// the name must be generated only once m_name = m_form->objectTree()->generateUniqueName(classname); TQWidget *w = lib->createWidget(classname, container->widget(), m_name.latin1(), container); #if TDE_VERSION >= TDE_MAKE_VERSION(3,4,0) //! @todo allow setting this for data view mode as well if (w) { if (m_form->designMode()) { //don't generate accelerators for widgets in design mode TDEAcceleratorManager::setNoAccel(w); } } #endif ObjectTreeItem *tree = w ? m_form->objectTree()->lookup(w->name()) : 0; if(!tree) return; container->setSelectedWidget(0, false); w->move(m_pos.begin().data().topLeft()); // we move the layout at the position of the topleft widget // sizeHint of these widgets depends on geometry, so give them appropriate geometry if(m_type == Container::HFlow) w->resize( TQSize(700, 20) ); else if(m_type == Container::VFlow) w->resize( TQSize(20, 700)); w->show(); // We reparent every widget to the Layout and insert them into it TQMap::ConstIterator endIt = m_pos.constEnd(); for(TQMap::ConstIterator it = m_pos.constBegin(); it != endIt; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.key()); if(item && item->widget()) { item->widget()->reparent(w, item->widget()->pos(), true); item->eventEater()->setContainer(tree->container()); m_form->objectTree()->reparent(item->name(), m_name); } } if(m_type == Container::HSplitter) ((TQSplitter*)w)->setOrientation(TQt::Horizontal); else if(m_type == Container::VSplitter) ((TQSplitter*)w)->setOrientation(TQt::Vertical); else if(tree->container()) { tree->container()->setLayout((Container::LayoutType)m_type); w->resize(tree->container()->layout()->sizeHint()); // the layout doesn't have its own size } container->setSelectedWidget(w, false); FormManager::self()->windowChanged(m_form->widget()); // to reload the ObjectTreeView } void CreateLayoutCommand::unexecute() { ObjectTreeItem *parent = m_form->objectTree()->lookup(m_containername); if(!parent) parent = m_form->objectTree(); // We reparent every widget to the Container and take them out of the layout TQMap::ConstIterator endIt = m_pos.constEnd(); for(TQMap::ConstIterator it = m_pos.constBegin(); it != endIt; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.key()); if(item && item->widget()) { item->widget()->reparent(parent->widget(), TQPoint(0,0), true); item->eventEater()->setContainer(parent->container()); if(m_pos[it.key()].isValid()) item->widget()->setGeometry(m_pos[it.key()]); m_form->objectTree()->reparent(item->name(), m_containername); } } if(!parent->container()) return; ObjectTreeItem* titem = m_form->objectTree()->lookup(m_name); if (!titem) return; //better this than a crash TQWidget *w = titem->widget(); parent->container()->deleteWidget(w); // delete the layout widget FormManager::self()->windowChanged(m_form->widget()); // to reload ObjectTreeView } TQString CreateLayoutCommand::name() const { switch(m_type) { case Container::HBox: return i18n("Group Widgets Horizontally"); case Container::VBox: return i18n("Group Widgets Vertically"); case Container::Grid: return i18n("Group Widgets in a Grid"); case Container::HSplitter: return i18n("Group Widgets Horizontally in a Splitter"); case Container::VSplitter: return i18n("Group Widgets Vertically in a Splitter"); case Container::HFlow: return i18n("Group Widgets By Rows"); case Container::VFlow: return i18n("Group Widgets Vertically By Columns"); default: return i18n("Group widgets"); } } void CreateLayoutCommand::debug() { kdDebug() << "CreateLayoutCommand: name=\"" << name() << "\" generatedName=" << m_name << " widgets=" << m_pos.keys() << " container=" << m_containername << " form=" << m_form->widget()->name() << endl; } /// BreakLayoutCommand /////////////// BreakLayoutCommand::BreakLayoutCommand(Container *container) : CreateLayoutCommand() { m_containername = container->toplevel()->widget()->name(); m_name = container->widget()->name(); m_form = container->form(); m_type = container->layoutType(); for(ObjectTreeItem *tree = container->objectTree()->children()->first(); tree; tree = container->objectTree()->children()->next()) { TQRect r(container->widget()->mapTo(container->widget()->parentWidget(), tree->widget()->pos()), tree->widget()->size()); m_pos.insert(tree->widget()->name(), r); } } void BreakLayoutCommand::execute() { CreateLayoutCommand::unexecute(); } void BreakLayoutCommand::unexecute() { CreateLayoutCommand::execute(); } TQString BreakLayoutCommand::name() const { return i18n("Break Layout: \"%1\"").arg(m_name); } void BreakLayoutCommand::debug() { kdDebug() << "BreakLayoutCommand: name=\"" << name() << " widgets=" << m_pos.keys() << " container=" << m_containername << " form=" << m_form->widget()->name() << endl; } // PasteWidgetCommand PasteWidgetCommand::PasteWidgetCommand(TQDomDocument &domDoc, Container *container, const TQPoint& p) : m_point(p) { m_data = domDoc.toCString(); m_containername = container->widget()->name(); m_form = container->form(); if(domDoc.namedItem("UI").firstChild().nextSibling().toElement().tagName() != "widget") return; TQRect boundingRect; for(TQDomNode n = domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling()) // more than one widget { if(n.toElement().tagName() != "widget") continue; TQDomElement el = n.toElement(); TQDomElement rect; for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry")) rect = n.firstChild().toElement(); } TQDomElement x = rect.namedItem("x").toElement(); TQDomElement y = rect.namedItem("y").toElement(); TQDomElement wi = rect.namedItem("width").toElement(); TQDomElement h = rect.namedItem("height").toElement(); int rx = x.text().toInt(); int ry = y.text().toInt(); int rw = wi.text().toInt(); int rh = h.text().toInt(); TQRect r(rx, ry, rw, rh); boundingRect = boundingRect.unite(r); } m_point = m_point - boundingRect.topLeft(); } void PasteWidgetCommand::execute() { ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername); if (!titem) return; //better this than a crash Container *container = titem->container(); TQString errMsg; int errLine; int errCol; TQDomDocument domDoc("UI"); bool parsed = domDoc.setContent(m_data, false, &errMsg, &errLine, &errCol); if(!parsed) { kdDebug() << "WidgetWatcher::load(): " << errMsg << endl; kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl; return; } //FormIO::setCurrentForm(m_container->form()); kdDebug() << domDoc.toString() << endl; if(!domDoc.namedItem("UI").hasChildNodes()) // nothing in the doc return; if(domDoc.namedItem("UI").firstChild().nextSibling().toElement().tagName() != "widget") // only one widget, so we can paste it at cursor pos { TQDomElement el = domDoc.namedItem("UI").firstChild().toElement(); fixNames(el); if(m_point.isNull()) fixPos(el, container); else changePos(el, m_point); m_form->setInteractiveMode(false); FormIO::loadWidget(container, el); m_form->setInteractiveMode(true); } else for(TQDomNode n = domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling()) // more than one widget { if(n.toElement().tagName() != "widget") continue; TQDomElement el = n.toElement(); fixNames(el); if(!m_point.isNull()) moveWidgetBy(el, container, m_point); else { fixPos(el, container); kdDebug() << "jdkjfldfksmfkdfjmqdsklfjdkkfmsqfksdfsm" << endl; } m_form->setInteractiveMode(false); FormIO::loadWidget(container, el); m_form->setInteractiveMode(true); } //FormIO::setCurrentForm(0); m_names.clear(); // We store the names of all the created widgets, to delete them later for(TQDomNode n = domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling()) { if(n.toElement().tagName() != "widget") continue; for(TQDomNode m = n.firstChild(); !m.isNull(); n = m.nextSibling()) { if((m.toElement().tagName() == "property") && (m.toElement().attribute("name") == "name")) { m_names.append(m.toElement().text()); break; } } } container->form()->selectFormWidget(); TQStringList::ConstIterator endIt = m_names.constEnd(); for(TQStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it) // We select all the pasted widgets { ObjectTreeItem *item = m_form->objectTree()->lookup(*it); if(item) container->setSelectedWidget(item->widget(), true); } } void PasteWidgetCommand::unexecute() { ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername); if (!titem) return; //better this than a crash Container *container = titem->container(); // We just delete all the widgets we have created TQStringList::ConstIterator endIt = m_names.constEnd(); for(TQStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it) { ObjectTreeItem* titem = container->form()->objectTree()->lookup(*it); if (!titem) continue; //better this than a crash TQWidget *w = titem->widget(); container->deleteWidget(w); } } TQString PasteWidgetCommand::name() const { return i18n("Paste"); } void //TQDomElement PasteWidgetCommand::changePos(TQDomElement &el, const TQPoint &newpos) { //TQDomElement el = widg.cloneNode(true).toElement(); TQDomElement rect; // Find the widget geometry if there is one for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry")) rect = n.firstChild().toElement(); } TQDomElement x = rect.namedItem("x").toElement(); x.removeChild(x.firstChild()); TQDomText valueX = el.ownerDocument().createTextNode(TQString::number(newpos.x())); x.appendChild(valueX); TQDomElement y = rect.namedItem("y").toElement(); y.removeChild(y.firstChild()); TQDomText valueY = el.ownerDocument().createTextNode(TQString::number(newpos.y())); y.appendChild(valueY); //return el; } void PasteWidgetCommand::fixPos(TQDomElement &el, Container *container) { /* TQDomElement rect; for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry")) rect = n.firstChild().toElement(); } TQDomElement x = rect.namedItem("x").toElement(); TQDomElement y = rect.namedItem("y").toElement(); TQDomElement wi = rect.namedItem("width").toElement(); TQDomElement h = rect.namedItem("height").toElement(); int rx = x.text().toInt(); int ry = y.text().toInt(); int rw = wi.text().toInt(); int rh = h.text().toInt(); TQRect r(rx, ry, rw, rh); TQWidget *w = m_form->widget()->childAt(r.x() + 6, r.y() + 6, false); if(!w) return; while((w->geometry() == r) && (w != 0))// there is already a widget there, with the same size { w = m_form->widget()->childAt(w->x() + 16, w->y() + 16, false); r.moveBy(10,10); } // the pasted wigdet should stay inside container's boundaries if(r.x() < 0) r.moveLeft(0); else if(r.right() > container->widget()->width()) r.moveLeft(container->widget()->width() - r.width()); if(r.y() < 0) r.moveTop(0); else if(r.bottom() > container->widget()->height()) r.moveTop(container->widget()->height() - r.height()); if(r != TQRect(rx, ry, rw, rh)) //return el; //else changePos(el, TQPoint(r.x(), r.y())); */ moveWidgetBy(el, container, TQPoint(0, 0)); } void PasteWidgetCommand::moveWidgetBy(TQDomElement &el, Container *container, const TQPoint &p) { TQDomElement rect; for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry")) rect = n.firstChild().toElement(); } TQDomElement x = rect.namedItem("x").toElement(); TQDomElement y = rect.namedItem("y").toElement(); TQDomElement wi = rect.namedItem("width").toElement(); TQDomElement h = rect.namedItem("height").toElement(); int rx = x.text().toInt(); int ry = y.text().toInt(); int rw = wi.text().toInt(); int rh = h.text().toInt(); TQRect r(rx + p.x(), ry + p.y(), rw, rh); kdDebug() << "Moving widget by " << p << " from " << rx << " " << ry << " to " << r.topLeft() << endl; TQWidget *w = m_form->widget()->childAt(r.x() + 6, r.y() + 6, false); while(w && (w->geometry() == r))// there is already a widget there, with the same size { w = m_form->widget()->childAt(w->x() + 16, w->y() + 16, false); r.moveBy(10,10); } // the pasted wigdet should stay inside container's boundaries if(r.x() < 0) r.moveLeft(0); else if(r.right() > container->widget()->width()) r.moveLeft(container->widget()->width() - r.width()); if(r.y() < 0) r.moveTop(0); else if(r.bottom() > container->widget()->height()) r.moveTop(container->widget()->height() - r.height()); if(r != TQRect(rx, ry, rw, rh)) //return el; //else changePos(el, TQPoint(r.x(), r.y())); } void PasteWidgetCommand::fixNames(TQDomElement &el) { TQString wname; for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name")) { wname = n.toElement().text(); while(m_form->objectTree()->lookup(wname)) // name already exists { bool ok; int num = wname.right(1).toInt(&ok, 10); if(ok) wname = wname.left(wname.length()-1) + TQString::number(num+1); else wname += "2"; } if(wname != n.toElement().text()) // we change the name, so we recreate the element { n.removeChild(n.firstChild()); TQDomElement type = el.ownerDocument().createElement("string"); TQDomText valueE = el.ownerDocument().createTextNode(wname); type.appendChild(valueE); n.toElement().appendChild(type); } } if(n.toElement().tagName() == "widget") // fix child widgets names { TQDomElement child = n.toElement(); fixNames(child); } } } void PasteWidgetCommand::debug() { kdDebug() << "PasteWidgetCommand: pos=" << m_point << " widgets=" << m_names << " container=" << m_containername << " form=" << m_form->widget()->name() << " data=\"" << m_data.left(80) << "...\"" << endl; } // DeleteWidgetCommand DeleteWidgetCommand::DeleteWidgetCommand(WidgetList &list, Form *form) : Command(), m_form(form) { m_domDoc = TQDomDocument("UI"); m_domDoc.appendChild(m_domDoc.createElement("UI")); TQDomElement parent = m_domDoc.namedItem("UI").toElement(); //for(TQWidget *w = list.first(); w; w = list.next()) /*for(WidgetListIterator it(list); it.current() != 0; ++it) { TQWidget *w = it.current(); // Don't delete tabwidget or widgetstack pages if(w->parentWidget()->inherits("TQWidgetStack")) { list.remove(w); continue; } }*/ removeChildrenFromList(list); for(WidgetListIterator it(list); it.current() != 0; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.current()->name()); if (!item) return; // We need to store both parentContainer and parentWidget as they may be different (eg for TabWidget page) m_containers.insert(item->name().latin1(), m_form->parentContainer(item->widget())->widget()->name()); m_parents.insert(item->name().latin1(), item->parent()->name().latin1()); FormIO::saveWidget(item, parent, m_domDoc); form->connectionBuffer()->saveAllConnectionsForWidget(item->widget()->name(), m_domDoc); } FormIO::cleanClipboard(parent); } void DeleteWidgetCommand::execute() { Container *containerToSelect = 0; TQMap::ConstIterator endIt = m_containers.constEnd(); for(TQMap::ConstIterator it = m_containers.constBegin(); it != endIt; ++it) { ObjectTreeItem *item = m_form->objectTree()->lookup(it.key()); if (!item || !item->widget()) continue; Container *cont = m_form->parentContainer(item->widget()); if (!containerToSelect) containerToSelect = cont; cont->deleteWidget(item->widget()); } //now we've nothing selecte: select parent container if (containerToSelect) m_form->setSelectedWidget( containerToSelect->widget() ); } void DeleteWidgetCommand::unexecute() { TQCString wname; m_form->setInteractiveMode(false); for(TQDomNode n = m_domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling()) { if(n.toElement().tagName() == "connections") // restore the widget connections m_form->connectionBuffer()->load(n); if(n.toElement().tagName() != "widget") continue; // We need first to know the name of the widget for(TQDomNode m = n.firstChild(); !m.isNull(); n = m.nextSibling()) { if((m.toElement().tagName() == "property") && (m.toElement().attribute("name") == "name")) { wname = m.toElement().text().latin1(); break; } } ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containers[wname]); if (!titem) return; //better this than a crash Container *cont = titem->container(); ObjectTreeItem *parent = m_form->objectTree()->lookup(m_parents[wname]); TQDomElement widg = n.toElement(); if(parent) FormIO::loadWidget(cont, widg, parent->widget()); else FormIO::loadWidget(cont, widg); } m_form->setInteractiveMode(true); } TQString DeleteWidgetCommand::name() const { return i18n("Delete widget"); } void DeleteWidgetCommand::debug() { kdDebug() << "DeleteWidgetCommand: containers=" << m_containers.keys() << " parents=" << m_parents.keys() << " form=" << m_form->widget()->name() << endl; } // CutWidgetCommand CutWidgetCommand::CutWidgetCommand(WidgetList &list, Form *form) : DeleteWidgetCommand(list, form) {} void CutWidgetCommand::execute() { DeleteWidgetCommand::execute(); m_data = FormManager::self()->m_domDoc.toCString(); FormManager::self()->m_domDoc.setContent(m_domDoc.toCString()); } void CutWidgetCommand::unexecute() { DeleteWidgetCommand::unexecute(); FormManager::self()->m_domDoc.setContent(m_data); } TQString CutWidgetCommand::name() const { return i18n("Cut"); } void CutWidgetCommand::debug() { kdDebug() << "CutWidgetCommand: containers=" << m_containers.keys() << " parents=" << m_parents.keys() << " form=" << m_form->widget()->name() << " data=\"" << m_data.left(80) << "...\"" << endl; } // CommandGroup namespace KFormDesigner { class CommandGroup::SubCommands : public KMacroCommand { public: SubCommands( const TQString & name ) : KMacroCommand(name) { } const TQPtrList& commands() const { return m_commands; } }; } CommandGroup::CommandGroup( const TQString & name, WidgetPropertySet *propSet ) : Command() , m_subCommands(new SubCommands(name)) , m_propSet(propSet) { } CommandGroup::~CommandGroup() { delete m_subCommands; } const TQPtrList& CommandGroup::commands() const { return m_subCommands->commands(); } void CommandGroup::addCommand(KCommand *command, bool allowExecute) { if (!command) return; m_subCommands->addCommand(command); if (!allowExecute) m_commandsShouldntBeExecuted.insert(command, (char*)1); } void CommandGroup::execute() { FormManager::self()->blockPropertyEditorUpdating(this); for (TQPtrListIterator it(m_subCommands->commands()); it.current(); ++it) { if (!m_commandsShouldntBeExecuted[it.current()]) it.current()->execute(); } FormManager::self()->unblockPropertyEditorUpdating(this, m_propSet); } void CommandGroup::unexecute() { FormManager::self()->blockPropertyEditorUpdating(this); m_subCommands->unexecute(); FormManager::self()->unblockPropertyEditorUpdating(this, m_propSet); } TQString CommandGroup::name() const { return m_subCommands->name(); } void CommandGroup::resetAllowExecuteFlags() { m_commandsShouldntBeExecuted.clear(); } void CommandGroup::debug() { kdDebug() << "*CommandGroup: name=\"" << name() << "\" #=" << m_subCommands->commands().count() << endl; uint i = 1; for (TQPtrListIterator it(m_subCommands->commands()); it.current(); ++it, i++) { kdDebug() << "#" << i << ":" << (m_commandsShouldntBeExecuted[it.current()] ? "!" : "") << "allowExecute:" << endl; if (dynamic_cast(it.current())) dynamic_cast(it.current())->debug(); else if (dynamic_cast(it.current())) dynamic_cast(it.current())->debug(); else kdDebug() << "(other KCommand)" << endl; } kdDebug() << "End of CommandGroup" << endl; }