/* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-2006 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 "widgetfactory.h" #include #include #include #include #include #include //#ifdef KEXI_KTEXTEDIT #include //#else #include //#endif #include #include #include #include #include "richtextdialog.h" #include "editlistviewdialog.h" #include "resizehandle.h" #include "formmanager.h" #include "form.h" #include "container.h" #include "objecttree.h" #include "widgetlibrary.h" #include "utils.h" #include "widgetpropertyset.h" #include "widgetwithsubpropertiesinterface.h" #include using namespace KFormDesigner; ///// Widget Info ////////////////////////// WidgetInfo::WidgetInfo(WidgetFactory *f) : m_inheritedClass(0) , m_overriddenAlternateNames(0) , m_factory(f) , m_propertiesWithDisabledAutoSync(0) , m_customTypesForProperty(0) { } WidgetInfo::WidgetInfo(WidgetFactory *f, const char* parentFactoryName, const char* inheritedClassName) : m_parentFactoryName( TQCString("kformdesigner_")+parentFactoryName ) , m_inheritedClassName(inheritedClassName) , m_inheritedClass(0) , m_overriddenAlternateNames(0) , m_factory(f) , m_propertiesWithDisabledAutoSync(0) , m_customTypesForProperty(0) { m_class = inheritedClassName; } WidgetInfo::~WidgetInfo() { delete m_overriddenAlternateNames; delete m_propertiesWithDisabledAutoSync; delete m_customTypesForProperty; } void WidgetInfo::addAlternateClassName(const TQCString& alternateName, bool override) { m_alternateNames += alternateName; if (override) { if (!m_overriddenAlternateNames) m_overriddenAlternateNames = new TQAsciiDict(101); m_overriddenAlternateNames->insert(alternateName, (char*)1); } else { if (m_overriddenAlternateNames) m_overriddenAlternateNames->take(alternateName); } } bool WidgetInfo::isOverriddenClassName(const TQCString& alternateName) const { return m_overriddenAlternateNames && (m_overriddenAlternateNames->find(alternateName) != 0); } void WidgetInfo::setAutoSyncForProperty(const char *propertyName, tristate flag) { if (!m_propertiesWithDisabledAutoSync) { if (~flag) return; m_propertiesWithDisabledAutoSync = new TQAsciiDict(101); } if (~flag) { m_propertiesWithDisabledAutoSync->remove(propertyName); } else { m_propertiesWithDisabledAutoSync->insert(propertyName, flag==true ? (char*)1 : (char*)2); } } tristate WidgetInfo::autoSyncForProperty(const char *propertyName) const { char* flag = m_propertiesWithDisabledAutoSync ? m_propertiesWithDisabledAutoSync->find(propertyName) : 0; if (!flag) return cancelled; return flag==(char*)1 ? true : false; } void WidgetInfo::setCustomTypeForProperty(const char *propertyName, int type) { if (!propertyName || type==KoProperty::Auto) return; if (!m_customTypesForProperty) { m_customTypesForProperty = new TQMap(); } m_customTypesForProperty->replace(propertyName, type); } int WidgetInfo::customTypeForProperty(const char *propertyName) const { if (!m_customTypesForProperty || !m_customTypesForProperty->contains(propertyName)) return KoProperty::Auto; return (*m_customTypesForProperty)[propertyName]; } ///// Widget Factory ////////////////////////// WidgetFactory::WidgetFactory(TQObject *parent, const char *name) : TQObject(parent, (const char*)(TQCString("kformdesigner_")+name)) { m_showAdvancedProperties = true; m_classesByName.setAutoDelete(true); m_hiddenClasses = 0; m_guiClient = 0; } WidgetFactory::~WidgetFactory() { delete m_hiddenClasses; } void WidgetFactory::addClass(WidgetInfo *w) { WidgetInfo *oldw = m_classesByName[w->className()]; if (oldw==w) return; if (oldw) { kdWarning() << "WidgetFactory::addClass(): class with name '" << w->className() << "' already exists for factory '" << name() << "'" << endl; return; } m_classesByName.insert( w->className(), w ); } void WidgetFactory::hideClass(const char *classname) { if (!m_hiddenClasses) m_hiddenClasses = new TQAsciiDict(101, false); m_hiddenClasses->insert(classname, (char*)1); } void WidgetFactory::createEditor(const TQCString &classname, const TQString &text, TQWidget *w, Container *container, TQRect geometry, int align, bool useFrame, bool multiLine, BackgroundMode background) { //#ifdef KEXI_KTEXTEDIT if (multiLine) { KTextEdit *textedit = new KTextEdit(text, TQString(), w->parentWidget()); textedit->setTextFormat(TQt::PlainText); textedit->setAlignment(align); if (dynamic_cast(w)) { textedit->setWordWrap(dynamic_cast(w)->wordWrap()); textedit->setWrapPolicy(dynamic_cast(w)->wrapPolicy()); } textedit->setPalette(w->palette()); textedit->setFont(w->font()); textedit->setResizePolicy(TQScrollView::Manual); textedit->setGeometry(geometry); if(background == TQt::NoBackground) textedit->setBackgroundMode(w->backgroundMode()); else textedit->setBackgroundMode(background); // textedit->setPaletteBackgroundColor(textedit->colorGroup().color( TQColorGroup::Base )); textedit->setPaletteBackgroundColor(w->paletteBackgroundColor()); for(int i =0; i <= textedit->paragraphs(); i++) textedit->setParagraphBackgroundColor(i, w->paletteBackgroundColor()); textedit->selectAll(true); textedit->setColor(w->paletteForegroundColor()); textedit->selectAll(false); textedit->moveCursor(TQTextEdit::MoveEnd, false); textedit->setParagraphBackgroundColor(0, w->paletteBackgroundColor()); textedit->setVScrollBarMode(TQScrollView::AlwaysOff); //ok? textedit->setHScrollBarMode(TQScrollView::AlwaysOff); //ok? textedit->installEventFilter(this); textedit->setFrameShape(useFrame ? TQFrame::LineEditPanel : TQFrame::NoFrame); textedit->setMargin(2); //to move away from resize handle textedit->show(); textedit->setFocus(); textedit->selectAll(); setEditor(w, textedit); connect(textedit, TQT_SIGNAL(textChanged()), this, TQT_SLOT(slotTextChanged())); connect(w, TQT_SIGNAL(destroyed()), this, TQT_SLOT(widgetDestroyed())); connect(textedit, TQT_SIGNAL(destroyed()), this, TQT_SLOT(editorDeleted())); //#else } else { KLineEdit *editor = new KLineEdit(text, w->parentWidget()); editor->setAlignment(align); editor->setPalette(w->palette()); editor->setFont(w->font()); editor->setGeometry(geometry); if(background == TQt::NoBackground) editor->setBackgroundMode(w->backgroundMode()); else editor->setBackgroundMode(background); editor->installEventFilter(this); editor->setFrame(useFrame); editor->setMargin(2); //to move away from resize handle editor->show(); editor->setFocus(); editor->selectAll(); connect(editor, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(changeTextInternal(const TQString&))); connect(w, TQT_SIGNAL(destroyed()), this, TQT_SLOT(widgetDestroyed())); connect(editor, TQT_SIGNAL(destroyed()), this, TQT_SLOT(editorDeleted())); setEditor(w, editor); // m_editor = editor; } //copy properties if available WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(w); TQWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w; if (-1!=m_editor->metaObject()->findProperty("margin", true) && -1!=subwidget->metaObject()->findProperty("margin", true)) m_editor->setProperty("margin", subwidget->property("margin")); //#endif //js m_handles = new ResizeHandleSet(w, container->form(), true); m_handles = container->form()->resizeHandlesForWidget(w); if (m_handles) { m_handles->setEditingMode(true); m_handles->raise(); } ObjectTreeItem *tree = container->form()->objectTree()->lookup(w->name()); if(!tree) return; tree->eventEater()->setContainer(this); //m_widget = w; setWidget(w, container); m_editedWidgetClass = classname; m_firstText = text; // m_container = container; changeTextInternal(text); // to update size of the widget } void WidgetFactory::disableFilter(TQWidget *w, Container *container) { ObjectTreeItem *tree = container->form()->objectTree()->lookup(w->name()); if(!tree) return; tree->eventEater()->setContainer(this); w->setFocus(); //js m_handles = new ResizeHandleSet(w, container->form(), true); m_handles = container->form()->resizeHandlesForWidget(w); if (m_handles) { m_handles->setEditingMode(true); m_handles->raise(); } //m_widget = w; setWidget(w, container); // m_container = container; setEditor(w, 0); // m_editor = 0; // widget is disabled, so we re-enable it while editing if(!tree->isEnabled()) { TQPalette p = w->palette(); TQColorGroup cg = p.active(); p.setActive(p.disabled()); p.setDisabled(cg); w->setPalette(p); } connect(w, TQT_SIGNAL(destroyed()), this, TQT_SLOT(widgetDestroyed())); } bool WidgetFactory::editList(TQWidget *w, TQStringList &list) { KDialogBase dialog(w->topLevelWidget(), "stringlist_dialog", true, i18n("Edit List of Items"), KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, false); KEditListBox *edit = new KEditListBox(i18n("Contents of %1").arg(w->name()), &dialog, "editlist"); dialog.setMainWidget(edit); edit->insertStringList(list); // edit->show(); if(dialog.exec() == TQDialog::Accepted) { list = edit->items(); return true; } return false; } bool WidgetFactory::editRichText(TQWidget *w, TQString &text) { RichTextDialog dlg(w, text); if(dlg.exec()== TQDialog::Accepted) { text = dlg.text(); return true; } return false; } void WidgetFactory::editListView(TQListView *listview) { EditListViewDialog dlg(((TQWidget*)listview)->topLevelWidget()); //dlg.exec(listview); } bool WidgetFactory::eventFilter(TQObject *obj, TQEvent *ev) { if( ((ev->type() == TQEvent::Resize) || (ev->type() == TQEvent::Move) ) && (obj == m_widget) && editor(m_widget)) { // resize widget using resize handles TQWidget *ed = editor(m_widget); resizeEditor(ed, m_widget, m_widget->className()); } else if((ev->type() == TQEvent::Paint) && (obj == m_widget) && editor(m_widget)) { // paint event for container edited (eg button group) return m_container->eventFilter(obj, ev); } else if((ev->type() == TQEvent::MouseButtonPress) && (obj == m_widget) && editor(m_widget)) { // click outside editor --> cancel editing Container *cont = m_container; resetEditor(); return cont->eventFilter(obj, ev); } if(ev->type() == TQEvent::FocusOut) { TQWidget *w = editor(m_widget); if (!w) w = (TQWidget *)m_widget; if(obj != (TQObject *)w) return false; TQWidget *focus = w->topLevelWidget()->focusWidget(); if(focus && w != focus && !w->child(focus->name(), focus->className())) resetEditor(); } else if(ev->type() == TQEvent::KeyPress) { TQWidget *w = editor(m_widget); if (!w) w = (TQWidget *)m_widget; if(obj != (TQObject *)w) return false; TQKeyEvent *e = TQT_TQKEYEVENT(ev); if(((e->key() == TQt::Key_Return) || (e->key() == TQt::Key_Enter)) && (e->state() != AltButton)) resetEditor(); if(e->key() == TQt::Key_Escape) { setEditorText(m_firstText); //changeText(m_firstText); resetEditor(); } } else if(ev->type() == TQEvent::ContextMenu) { TQWidget *w = editor(m_widget); if (!w) w = (TQWidget *)m_widget; if(obj != (TQObject *)w) return false; return true; } // if(obj == m_widget) // return m_container->eventFilter(obj, ev); // else return false; } void WidgetFactory::resetEditor() { if (m_container) m_container->stopInlineEditing(); TQWidget *ed = editor(m_widget); if(m_widget) { ObjectTreeItem *tree = m_container ? m_container->form()->objectTree()->lookup(m_widget->name()) : 0; if(!tree) { kdDebug() << "WidgetFactory::resetEditor() : error cannot found a tree item " << endl; return; } tree->eventEater()->setContainer(m_container); if(m_widget) {// && !ed) setRecursiveCursor(m_widget, m_container->form()); if (m_widget->inherits("TQLineEdit") || m_widget->inherits("TQTextEdit")) { //fix weird behaviour m_widget->unsetCursor(); m_widget->setCursor(TQt::ArrowCursor); } } // disable again the widget if(!ed && !tree->isEnabled()) { TQPalette p = m_widget->palette(); TQColorGroup cg = p.active(); p.setActive(p.disabled()); p.setDisabled(cg); m_widget->setPalette(p); } } if(ed) { changeTextInternal(editorText()); disconnect(ed, 0, this, 0); ed->deleteLater(); } if(m_widget) { disconnect(m_widget, 0, this, 0); m_widget->repaint(); } //js delete m_handles; if (m_handles) { m_handles->setEditingMode(false); } setEditor(m_widget, 0); // m_editor = 0; setWidget(0, 0); //m_widget = 0; m_handles = 0; // m_container = 0; } void WidgetFactory::widgetDestroyed() { if(m_editor) { m_editor->deleteLater(); m_editor = 0; } //js delete m_handles; if (m_handles) { m_handles->setEditingMode(false); } m_widget = 0; m_handles = 0; m_container = 0; } void WidgetFactory::editorDeleted() { //js delete m_handles; if (m_handles) { m_handles->setEditingMode(false); } setEditor(m_widget, 0); setWidget(0, 0); // m_widget = 0; m_handles = 0; // m_container = 0; } void WidgetFactory::changeProperty(const char *name, const TQVariant &value, Form *form) //WidgetFactory::changeProperty(const char *name, const TQVariant &value, Container *container) { // if (!form->manager()) // return; if(form->selectedWidgets()->count() > 1) { // If eg multiple labels are selected, we only want to change the text of one of them (the one the user cliked on) if(m_widget) m_widget->setProperty(name, value); else form->selectedWidgets()->first()->setProperty(name, value); } else { WidgetPropertySet *set = KFormDesigner::FormManager::self()->propertySet(); if(set->contains(name)) (*set)[name] = value; } } /* void WidgetFactory::addPropertyDescription(Container *container, const char *prop, const TQString &desc) { WidgetPropertySet *buff = container->form()->manager()->buffer(); buff->addPropertyDescription(prop, desc); } void WidgetFactory::addValueDescription(Container *container, const char *value, const TQString &desc) { WidgetPropertySet *buff = container->form()->manager()->buffer(); buff->addValueDescription(value, desc); }*/ bool WidgetFactory::isPropertyVisible(const TQCString &classname, TQWidget *w, const TQCString &property, bool multiple, bool isTopLevel) { if (multiple) { return property=="font" || property=="paletteBackgroundColor" || property=="enabled" || property=="paletteForegroundColor" || property=="cursor" || property=="paletteBackgroundPixmap"; } // if(d->properties.isEmpty() && !isTopLevel) // d->properties << "caption" << "icon" << "sizeIncrement" << "iconText"; // if(! (d->properties.grep(property)).isEmpty() ) // return false; return isPropertyVisibleInternal(classname, w, property, isTopLevel); // return !multiple && isPropertyVisibleInternal(classname, w, property); } bool WidgetFactory::isPropertyVisibleInternal(const TQCString &, TQWidget *w, const TQCString &property, bool isTopLevel) { Q_UNUSED( w ); #ifdef KEXI_NO_CURSOR_PROPERTY //! @todo temporary unless cursor works properly in the Designer if (property=="cursor") return false; #endif if (!isTopLevel && (property=="caption" || property=="icon" || property=="sizeIncrement" || property=="iconText")) { // don't show these properties for a non-toplevel widget return false; } return true; } bool WidgetFactory::propertySetShouldBeReloadedAfterPropertyChange(const TQCString& classname, TQWidget *w, const TQCString& property) { Q_UNUSED(classname); Q_UNUSED(w); Q_UNUSED(property); return false; } void WidgetFactory::resizeEditor(TQWidget *, TQWidget *, const TQCString&) { } void WidgetFactory::slotTextChanged() { changeTextInternal(editorText()); } bool WidgetFactory::clearWidgetContent(const TQCString &, TQWidget *) { return false; } void WidgetFactory::changeTextInternal(const TQString& text) { if (changeText( text )) return; //try in inherited if (!m_editedWidgetClass.isEmpty()) { WidgetInfo *wi = m_classesByName[ m_editedWidgetClass ]; if (wi && wi->inheritedClass()) { // wi->inheritedClass()->factory()->m_container = m_container; wi->inheritedClass()->factory()->changeText( text ); } } } bool WidgetFactory::changeText(const TQString& text) { changeProperty( "text", text, m_container->form() ); return true; } bool WidgetFactory::readSpecialProperty(const TQCString &, TQDomElement &, TQWidget *, ObjectTreeItem *) { return false; } bool WidgetFactory::saveSpecialProperty(const TQCString &, const TQString &, const TQVariant&, TQWidget *, TQDomElement &, TQDomDocument &) { return false; } bool WidgetFactory::inheritsFactories() { for (TQAsciiDictIterator it(m_classesByName); it.current(); ++it) { if (!it.current()->parentFactoryName().isEmpty()) return true; } return false; } TQString WidgetFactory::editorText() const { TQWidget *ed = editor(m_widget); return dynamic_cast(ed) ? dynamic_cast(ed)->text() : dynamic_cast(ed)->text(); } void WidgetFactory::setEditorText(const TQString& text) { TQWidget *ed = editor(m_widget); if (dynamic_cast(ed)) dynamic_cast(ed)->setText(text); else dynamic_cast(ed)->setText(text); } void WidgetFactory::setEditor(TQWidget *widget, TQWidget *editor) { if (!widget) return; WidgetInfo *winfo = m_classesByName[widget->className()]; if (!winfo || winfo->parentFactoryName().isEmpty()) { m_editor = editor; } else { WidgetFactory *f = m_library->factory(winfo->parentFactoryName()); if (f!=this) f->setEditor(widget, editor); m_editor = editor; //keep a copy } } TQWidget *WidgetFactory::editor(TQWidget *widget) const { if (!widget) return 0; WidgetInfo *winfo = m_classesByName[widget->className()]; if (!winfo || winfo->parentFactoryName().isEmpty()) { return m_editor; } else { WidgetFactory *f = m_library->factoryForClassName(widget->className()); if (f!=this) return f->editor(widget); return m_editor; } } void WidgetFactory::setWidget(TQWidget *widget, Container* container) { WidgetInfo *winfo = widget ? m_classesByName[widget->className()] : 0; if (winfo && !winfo->parentFactoryName().isEmpty()) { WidgetFactory *f = m_library->factory(winfo->parentFactoryName()); if (f!=this) f->setWidget(widget, container); } m_widget = widget; //keep a copy m_container = container; } TQWidget *WidgetFactory::widget() const { return m_widget; } void WidgetFactory::setInternalProperty(const TQCString& classname, const TQCString& property, const TQString& value) { m_internalProp[classname+":"+property]=value; } void WidgetFactory::setPropertyOptions( WidgetPropertySet& /*buf*/, const WidgetInfo& /*info*/, TQWidget * /*w*/ ) { //nothing } #include "widgetfactory.moc"