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