File indexing completed on 2024-05-12 16:39:52
0001 /* This file is part of the KDE project 0002 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr> 0003 Copyright (C) 2008-2010 Jarosław Staniek <staniek@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "WidgetTreeWidget.h" 0022 0023 #include <QContextMenuEvent> 0024 #include <QDebug> 0025 0026 #include <KIconEffect> 0027 #include <KLocalizedString> 0028 0029 #include <KexiIcon.h> 0030 0031 #include "objecttree.h" 0032 #include "form.h" 0033 #include "container.h" 0034 #include "widgetlibrary.h" 0035 #include "commands.h" 0036 0037 using namespace KFormDesigner; 0038 0039 class Q_DECL_HIDDEN WidgetTreeWidgetItem::Private 0040 { 0041 public: 0042 Private(ObjectTreeItem *data_, 0043 LoadTreeFlags loadTreeFlags_); 0044 ~Private(); 0045 0046 ObjectTreeItem *data; 0047 QString customSortingKey; 0048 LoadTreeFlags loadTreeFlags; 0049 }; 0050 0051 WidgetTreeWidgetItem::Private::Private(ObjectTreeItem *data_, LoadTreeFlags loadTreeFlags_) 0052 :data(data_), loadTreeFlags(loadTreeFlags_) 0053 { 0054 0055 } 0056 0057 WidgetTreeWidgetItem::Private::~Private() 0058 { 0059 0060 } 0061 0062 WidgetTreeWidgetItem::WidgetTreeWidgetItem(WidgetTreeWidgetItem *parent, ObjectTreeItem *data, 0063 LoadTreeFlags loadTreeFlags, int forcedTabPageIndex, const QString& forcedTabPageName) 0064 : QTreeWidgetItem(parent) 0065 ,d(new Private(data, loadTreeFlags)) 0066 { 0067 init(forcedTabPageIndex, forcedTabPageName); 0068 } 0069 0070 WidgetTreeWidgetItem::WidgetTreeWidgetItem(QTreeWidget *tree, ObjectTreeItem *data, 0071 LoadTreeFlags loadTreeFlags, int forcedTabPageIndex, const QString& forcedTabPageName) 0072 : QTreeWidgetItem(tree) 0073 , d(new Private(data, loadTreeFlags)) 0074 { 0075 init(forcedTabPageIndex, forcedTabPageName); 0076 } 0077 0078 WidgetTreeWidgetItem::~WidgetTreeWidgetItem() 0079 { 0080 delete d; 0081 } 0082 0083 void WidgetTreeWidgetItem::init(int forcedTabPageIndex, const QString& forcedTabPageName) 0084 { 0085 if (d->data) { 0086 initTextAndIcon(forcedTabPageIndex, forcedTabPageName); 0087 } 0088 } 0089 0090 void WidgetTreeWidgetItem::initTextAndIcon(int forcedTabPageIndex, const QString& forcedTabPageName) 0091 { 0092 QString itemName; 0093 QString itemClass; 0094 QString iconName; 0095 Qt::ItemFlags itemFlags = flags(); 0096 WidgetTreeWidget *widgetTreeWidget = qobject_cast<WidgetTreeWidget*>(treeWidget()); 0097 ObjectTreeItem* selectable = widgetTreeWidget ? widgetTreeWidget->selectableItem(d->data) : d->data; 0098 if (selectable != d->data) { 0099 //qDebug() << "****" << (d->loadTreeFlags & LoadTreeForAddedTabPage) << selectable->widget(); 0100 if (qobject_cast<QTabWidget*>(selectable->widget())) { 0101 // tab widget's page 0102 const QTabWidget* tabWidget = qobject_cast<QTabWidget*>(selectable->widget()); 0103 int tabIndex = tabWidget->indexOf(d->data->widget()); 0104 if (tabIndex == -1 && (d->loadTreeFlags & LoadTreeForAddedTabPage)) { // tab appended 0105 if (forcedTabPageIndex >= 0) 0106 tabIndex = forcedTabPageIndex; 0107 else 0108 tabIndex = tabWidget->count(); 0109 } 0110 //qDebug() << tabIndex; 0111 if (tabIndex >= 0) { 0112 if (forcedTabPageName.isEmpty()) { 0113 itemName = tabWidget->tabText(tabIndex); 0114 if (itemName.isEmpty()) { 0115 itemName = forcedTabPageName; 0116 if (itemName.isEmpty()) 0117 itemName = xi18n("Page %1", tabIndex + 1); 0118 } 0119 else { 0120 itemName.remove('&'); 0121 } 0122 } 0123 else 0124 itemName = forcedTabPageName; 0125 itemClass = xi18nc("Tab widget's page", "Tab Page"); 0126 d->customSortingKey = QString("tab%1").arg(tabIndex); 0127 //qDebug() << "d->customSortingKey" << d->customSortingKey; 0128 itemFlags |= Qt::ItemIsSelectable; 0129 itemFlags ^= Qt::ItemIsSelectable; 0130 iconName = KexiIconName("tabwidget-tab"); 0131 } 0132 } 0133 } 0134 // defaults: 0135 if (itemName.isEmpty()) { 0136 itemName = d->data->name(); 0137 } 0138 if (itemClass.isEmpty()) { 0139 itemClass = d->data->className(); 0140 } 0141 if (iconName.isEmpty()) { 0142 if (widgetTreeWidget) { 0143 iconName = widgetTreeWidget->iconNameForClass(d->data->widget()->metaObject()->className()); 0144 } 0145 } 0146 // set: 0147 if (itemFlags != flags()) { 0148 setFlags(itemFlags); 0149 } 0150 setText(0, itemName); 0151 setText(1, itemClass); 0152 if (!iconName.isEmpty()) { 0153 QPixmap icon(koSmallIconCStr(iconName)); 0154 if (!(itemFlags & Qt::ItemIsSelectable)) { 0155 KIconEffect::semiTransparent(icon); 0156 } 0157 setIcon(0, icon); 0158 } 0159 if (!(itemFlags & Qt::ItemIsSelectable)) { 0160 setForeground(0, treeWidget()->palette().color(QPalette::Disabled, QPalette::Text)); 0161 setForeground(1, treeWidget()->palette().color(QPalette::Disabled, QPalette::Text)); 0162 } 0163 } 0164 0165 QString WidgetTreeWidgetItem::name() const 0166 { 0167 if (d->data) 0168 return d->data->name(); 0169 else 0170 return QString(); 0171 } 0172 0173 bool WidgetTreeWidgetItem::operator<( const QTreeWidgetItem & other ) const 0174 { 0175 const WidgetTreeWidgetItem *otherItem = dynamic_cast<const WidgetTreeWidgetItem*>(&other); 0176 if (!otherItem) 0177 return QTreeWidgetItem::operator<(other); 0178 return d->customSortingKey < otherItem->customSortingKey(); 0179 } 0180 0181 ObjectTreeItem* WidgetTreeWidgetItem::data() const 0182 { 0183 return d->data; 0184 } 0185 0186 QString WidgetTreeWidgetItem::customSortingKey() const 0187 { 0188 return d->customSortingKey; 0189 } 0190 0191 // WidgetTreeWidget itself ----------------------------------------------------------------------------------------------- 0192 0193 class Q_DECL_HIDDEN WidgetTreeWidget::Private 0194 { 0195 public: 0196 explicit Private(Options o); 0197 ~Private(); 0198 0199 Form *form; 0200 Options options; 0201 0202 //! Used to temporarily disable slotSelectionChanged() when reloading contents in setForm(). 0203 bool slotSelectionChanged_enabled; 0204 //! Used to temporarily disable selectWidget(). 0205 bool selectWidget_enabled; 0206 }; 0207 0208 WidgetTreeWidget::Private::Private(Options o) 0209 :form(0), options(o), slotSelectionChanged_enabled(true), selectWidget_enabled(true) 0210 { 0211 0212 } 0213 0214 WidgetTreeWidget::Private::~Private() 0215 { 0216 0217 } 0218 0219 WidgetTreeWidget::WidgetTreeWidget(QWidget *parent, Options options) 0220 : QTreeWidget(parent), d(new Private(options)) 0221 { 0222 setRootIsDecorated(false); 0223 setHeaderLabels(QStringList() << xi18n("Widget name") << xi18nc("Widget's type", "Type")); 0224 installEventFilter(this); 0225 0226 if (!(d->options & DisableSelection)) { 0227 setSelectionMode(ExtendedSelection); 0228 connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged())); 0229 } 0230 0231 setAllColumnsShowFocus(true); 0232 setExpandsOnDoubleClick(false); 0233 setIndentation(indentation() / 2); 0234 } 0235 0236 WidgetTreeWidget::~WidgetTreeWidget() 0237 { 0238 delete d; 0239 } 0240 0241 WidgetTreeWidgetItem* WidgetTreeWidget::selectedItem() const 0242 { 0243 if (selectedItems().count() != 1) 0244 return 0; 0245 WidgetTreeWidgetItem *item = static_cast<WidgetTreeWidgetItem*>(selectedItems().first()); 0246 return item; 0247 } 0248 0249 QString WidgetTreeWidget::iconNameForClass(const QByteArray& classname) const 0250 { 0251 return d->form->library()->iconName(classname); 0252 } 0253 0254 ObjectTreeItem* WidgetTreeWidget::selectableItem(ObjectTreeItem* item) 0255 { 0256 return d->form->library()->selectableItem(item); 0257 } 0258 0259 void WidgetTreeWidget::handleContextMenuEvent(QContextMenuEvent* e) 0260 { 0261 if (!d->form) 0262 return; 0263 WidgetTreeWidgetItem *item = static_cast<WidgetTreeWidgetItem*>(itemAt(e->pos())); 0264 if (!item) 0265 return; 0266 WidgetTreeWidgetItem *newItem = static_cast<WidgetTreeWidgetItem*>(tryToAlterSelection(item)); 0267 QWidget *w = newItem->data()->widget(); 0268 if (!w) 0269 return; 0270 d->form->createContextMenu(w, d->form->activeContainer(), e->pos(), Form::WidgetTreeContextMenuTarget); 0271 } 0272 0273 void WidgetTreeWidget::contextMenuEvent(QContextMenuEvent* e) 0274 { 0275 if (!(d->options & DisableContextMenu)) { 0276 handleContextMenuEvent(e); 0277 } 0278 QAbstractScrollArea::contextMenuEvent(e); 0279 } 0280 0281 WidgetTreeWidgetItem* WidgetTreeWidget::findItem(const QString& name) 0282 { 0283 QTreeWidgetItemIterator it(this); 0284 while (*it) { 0285 WidgetTreeWidgetItem *item = static_cast<WidgetTreeWidgetItem*>(*it); 0286 if (item->name() == name) { 0287 return item; 0288 } 0289 ++it; 0290 } 0291 return 0; 0292 } 0293 0294 WidgetTreeWidgetItem* WidgetTreeWidget::findItemByFirstColumn(const QString& text) 0295 { 0296 QTreeWidgetItemIterator it(this); 0297 while (*it) { 0298 WidgetTreeWidgetItem *item = static_cast<WidgetTreeWidgetItem*>(*it); 0299 if (item->text(0) == text) { 0300 return item; 0301 } 0302 ++it; 0303 } 0304 return 0; 0305 } 0306 0307 void WidgetTreeWidget::selectWidget(QWidget *w, KFormDesigner::Form::WidgetSelectionFlags flags) 0308 { 0309 if (!d->selectWidget_enabled) 0310 return; 0311 blockSignals(true); // to avoid recursion 0312 0313 if (!w) { 0314 clearSelection(); 0315 blockSignals(false); 0316 return; 0317 } 0318 0319 if (selectedItems().count() == 0) { 0320 flags |= Form::ReplacePreviousSelection; 0321 } 0322 0323 if ((flags & Form::ReplacePreviousSelection)) 0324 clearSelection(); 0325 0326 QTreeWidgetItem *item = findItem(w->objectName()); 0327 if ((flags & Form::ReplacePreviousSelection)) { 0328 setCurrentItem(item); 0329 item->setSelected(true); 0330 } else { 0331 item->setSelected(true); 0332 } 0333 0334 blockSignals(false); 0335 } 0336 0337 void WidgetTreeWidget::selectWidgetForItem(QTreeWidgetItem *item) 0338 { 0339 WidgetTreeWidgetItem *it = dynamic_cast<WidgetTreeWidgetItem*>(item); 0340 if (!it) 0341 return; 0342 QWidget *w = it->data()->widget(); 0343 if (w && !d->form->selectedWidgets()->contains(w)) { 0344 d->form->selectWidget(w, Form::AddToPreviousSelection | Form::DontRaise | Form::LastSelection); 0345 } 0346 } 0347 0348 void WidgetTreeWidget::activateTabPageIfNeeded(QTreeWidgetItem* item) 0349 { 0350 WidgetTreeWidgetItem *childItem = dynamic_cast<WidgetTreeWidgetItem*>(item); 0351 if (!childItem) 0352 return; 0353 WidgetTreeWidgetItem *parentItem = dynamic_cast<WidgetTreeWidgetItem*>(item->parent()); 0354 while (childItem && parentItem) { 0355 if (parentItem && qobject_cast<QTabWidget*>(parentItem->data()->widget())) { 0356 qobject_cast<QTabWidget*>(parentItem->data()->widget())->setCurrentWidget( 0357 childItem->data()->widget()); 0358 } 0359 childItem = parentItem; 0360 parentItem = dynamic_cast<WidgetTreeWidgetItem*>(parentItem->parent()); 0361 } 0362 } 0363 0364 QTreeWidgetItem* WidgetTreeWidget::tryToAlterSelection(QTreeWidgetItem* current) 0365 { 0366 activateTabPageIfNeeded(current); 0367 0368 if ( current 0369 && !(current->flags() & Qt::ItemIsSelectable) 0370 && current->parent() 0371 && (current->parent()->flags() & Qt::ItemIsSelectable) 0372 ) 0373 { 0374 d->slotSelectionChanged_enabled = false; 0375 foreach (QTreeWidgetItem *selectedItem, selectedItems()) { 0376 selectedItem->setSelected(false); 0377 } 0378 selectWidgetForItem(current->parent()); 0379 setCurrentItem(current->parent()); 0380 current->parent()->setSelected(true); 0381 d->slotSelectionChanged_enabled = true; 0382 return current->parent(); 0383 } 0384 return current; 0385 } 0386 0387 void WidgetTreeWidget::slotSelectionChanged() 0388 { 0389 if (!d->form || !d->slotSelectionChanged_enabled) 0390 return; 0391 const bool hadFocus = hasFocus(); 0392 const QList<QTreeWidgetItem*> list( selectedItems() ); 0393 d->selectWidget_enabled = false; // to avoid execution seleting form's item 0394 // on the tree when selectFormWidget() is called 0395 d->form->selectFormWidget(); 0396 d->selectWidget_enabled = true; 0397 foreach (QTreeWidgetItem *item, list) { 0398 selectWidgetForItem(item); 0399 } 0400 tryToAlterSelection(currentItem()); 0401 if (hadFocus) 0402 setFocus(); //restore focus 0403 } 0404 0405 void WidgetTreeWidget::addItem(KFormDesigner::ObjectTreeItem *item) 0406 { 0407 WidgetTreeWidgetItem *parent = findItem(item->parent()->name()); 0408 if (!parent) 0409 return; 0410 0411 WidgetTreeWidgetItem::LoadTreeFlags flags; 0412 const KUndo2Command *topCommand = d->form->command(d->form->commandsCount() - 1); 0413 if (dynamic_cast<const InsertPageCommand*>(topCommand)) { 0414 //qDebug() << "InsertPageCommand"; 0415 flags |= WidgetTreeWidgetItem::LoadTreeForAddedTabPage; 0416 } else if (dynamic_cast<const RemovePageCommand*>(topCommand)) { 0417 //qDebug() << "undoing RemovePageCommand"; 0418 flags |= WidgetTreeWidgetItem::LoadTreeForAddedTabPage; 0419 } 0420 loadTree(item, parent, flags); 0421 } 0422 0423 void WidgetTreeWidget::removeItem(KFormDesigner::ObjectTreeItem *item) 0424 { 0425 if (!item) 0426 return; 0427 const KUndo2Command *topCommand = d->form->command(d->form->commandsCount() - 1); 0428 if (dynamic_cast<const RemovePageCommand*>(topCommand)) { 0429 //qDebug() << "RemovePageCommand"; 0430 } 0431 WidgetTreeWidgetItem *it = findItem(item->name()); 0432 0433 if (!it) { 0434 qWarning() << "cannot remove item with name" << item->name(); 0435 return; 0436 } 0437 0438 QTreeWidgetItem * parent = it->parent(); 0439 parent->takeChild(parent->indexOfChild(it)); 0440 0441 delete it; 0442 } 0443 0444 void WidgetTreeWidget::renameItem(const QByteArray &oldname, const QByteArray &newname) 0445 { 0446 if (findItemByFirstColumn(newname)) { 0447 qWarning() << "item with name" << newname << "already exists, cannot rename"; 0448 return; 0449 } 0450 WidgetTreeWidgetItem *item = findItemByFirstColumn(oldname); 0451 if (!item) 0452 return; 0453 item->setText(0, newname); 0454 } 0455 0456 void WidgetTreeWidget::setForm(Form *form) 0457 { 0458 d->slotSelectionChanged_enabled = false; 0459 if (d->form) { 0460 disconnect(d->form, SIGNAL(destroying()), this, SLOT(slotBeforeFormDestroyed())); 0461 disconnect(d->form, SIGNAL(selectionChanged(QWidget*,KFormDesigner::Form::WidgetSelectionFlags)), 0462 this, SLOT(selectWidget(QWidget*,KFormDesigner::Form::WidgetSelectionFlags))); 0463 disconnect(d->form, SIGNAL(childRemoved(KFormDesigner::ObjectTreeItem*)), 0464 this, SLOT(removeItem(KFormDesigner::ObjectTreeItem*))); 0465 disconnect(d->form, SIGNAL(childAdded(KFormDesigner::ObjectTreeItem*)), 0466 this, SLOT(addItem(KFormDesigner::ObjectTreeItem*))); 0467 disconnect(d->form, SIGNAL(widgetNameChanged(QByteArray,QByteArray)), 0468 this, SLOT(renameItem(QByteArray,QByteArray))); 0469 0470 } 0471 d->form = form; 0472 clear(); 0473 0474 if (!d->form) 0475 return; 0476 0477 connect(d->form, SIGNAL(destroying()), this, SLOT(slotBeforeFormDestroyed())); 0478 connect(d->form, SIGNAL(selectionChanged(QWidget*,KFormDesigner::Form::WidgetSelectionFlags)), 0479 this, SLOT(selectWidget(QWidget*,KFormDesigner::Form::WidgetSelectionFlags))); 0480 connect(d->form, SIGNAL(childRemoved(KFormDesigner::ObjectTreeItem*)), 0481 this, SLOT(removeItem(KFormDesigner::ObjectTreeItem*))); 0482 connect(d->form, SIGNAL(childAdded(KFormDesigner::ObjectTreeItem*)), 0483 this, SLOT(addItem(KFormDesigner::ObjectTreeItem*))); 0484 connect(d->form, SIGNAL(widgetNameChanged(QByteArray,QByteArray)), 0485 this, SLOT(renameItem(QByteArray,QByteArray))); 0486 0487 ObjectTree *tree = d->form->objectTree(); 0488 QTreeWidgetItem *root = invisibleRootItem(); 0489 loadTree(tree, static_cast<WidgetTreeWidgetItem*>(root)); 0490 sortItems(0, Qt::AscendingOrder); 0491 0492 if (!form->selectedWidgets()->isEmpty()) 0493 selectWidget(form->selectedWidgets()->first()); 0494 else 0495 selectWidget(form->widget()); 0496 d->slotSelectionChanged_enabled = true; 0497 resizeColumnToContents(0); 0498 } 0499 0500 void WidgetTreeWidget::slotBeforeFormDestroyed() 0501 { 0502 setForm(0); 0503 } 0504 0505 void WidgetTreeWidget::loadTree(ObjectTreeItem *item, WidgetTreeWidgetItem *parent, 0506 WidgetTreeWidgetItem::LoadTreeFlags flags) 0507 { 0508 if (!item) 0509 return; 0510 0511 const KUndo2Command *topCommand = d->form->command(d->form->commandsCount() - 1); 0512 const RemovePageCommand* removePageCommand 0513 = dynamic_cast<const RemovePageCommand*>(topCommand); 0514 int forcedTabPageIndex; 0515 QString forcedTabPageName; 0516 if (removePageCommand) { 0517 //qDebug() << "undoing RemovePageCommand - fixing item name and index"; 0518 forcedTabPageIndex = removePageCommand->pageIndex(); 0519 forcedTabPageName = removePageCommand->pageName(); 0520 } 0521 else 0522 forcedTabPageIndex = -1; 0523 0524 WidgetTreeWidgetItem *treeItem = new WidgetTreeWidgetItem(parent, item, flags, 0525 forcedTabPageIndex, forcedTabPageName); 0526 treeItem->setExpanded(true); 0527 0528 ObjectTreeList *list = item->children(); 0529 if (flags & WidgetTreeWidgetItem::LoadTreeForAddedTabPage) 0530 flags ^= WidgetTreeWidgetItem::LoadTreeForAddedTabPage; // this flag does not propagate to children 0531 foreach (ObjectTreeItem *titem, *list) { 0532 loadTree(titem, treeItem); 0533 } 0534 } 0535