File indexing completed on 2024-05-12 16:41:09
0001 /*********************************************************************************** 0002 Copyright (C) 2011-2012 by Holger Danielsson (holger.danielsson@versanet.de) 0003 ***********************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or modify * 0008 * it under the terms of the GNU General Public License as published by * 0009 * the Free Software Foundation; either version 2 of the License, or * 0010 * (at your option) any later version. * 0011 * * 0012 ***************************************************************************/ 0013 0014 0015 #include <QIcon> 0016 #include <QInputDialog> 0017 #include <QFile> 0018 #include <QFileInfo> 0019 #include <QHeaderView> 0020 #include <QDomDocument> 0021 #include <QProcessEnvironment> 0022 0023 #include <QMenu> 0024 #include <KLocalizedString> 0025 #include <KMessageBox> 0026 0027 0028 #include "dialogs/usermenu/usermenuitem.h" 0029 #include "dialogs/usermenu/usermenutree.h" 0030 0031 #include "kiledebug.h" 0032 0033 0034 // Qt::UserRole+1: menutype 0035 // Qt::UserRole+2: errorcode for menu item 0036 0037 namespace KileMenu { 0038 0039 // - Separators are shown as a horizontal line (Qt:UserRole+1) 0040 // - Menu items with errors are displayed in red (Qt:UserRole+2) 0041 void MenuentryDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const 0042 { 0043 QString menutitle = index.data(Qt::DisplayRole).toString(); 0044 int error = index.data(Qt::UserRole+2).toInt(); 0045 0046 // any errors? 0047 if (index.column()==0 && error!=UserMenuItem::MODEL_ERROR_NONE ) { 0048 QStyleOptionViewItem optionCustom = option; 0049 optionCustom.palette.setColor(QPalette::Text, Qt::red); 0050 QStyledItemDelegate::paint( painter, optionCustom, index ); 0051 } 0052 else { 0053 QStyledItemDelegate::paint( painter, option, index ); 0054 } 0055 0056 // display separators 0057 QString itemtype = index.data(Qt::UserRole+1).toString(); 0058 if ( itemtype == "separator" ) { 0059 QRect r = option.rect; 0060 int y = ( r.bottom() + r.top() ) / 2; 0061 0062 painter->save(); 0063 QPen pen = QPen(Qt::gray); 0064 painter->setPen(pen); 0065 painter->drawLine(r.left()+3,y, r.right()-20,y); 0066 painter->restore(); 0067 } 0068 0069 } 0070 ///////////////////////////// UserMenuTree ////////////////////////////// 0071 0072 UserMenuTree::UserMenuTree(QWidget *parent) 0073 : QTreeWidget(parent) 0074 { 0075 setColumnCount(2); 0076 0077 header()->setSectionResizeMode(0, QHeaderView::Stretch); 0078 header()->setSectionResizeMode(1, QHeaderView::Fixed); 0079 header()->setSectionsMovable(false); 0080 header()->setStretchLastSection(false); 0081 setColumnWidth(1,140); 0082 setItemDelegateForColumn(0, new MenuentryDelegate(parent)); 0083 0084 // drag and drop 0085 setDragEnabled(true); 0086 setDropIndicatorShown(true); 0087 //setAcceptDrops(true); 0088 setDragDropMode(QAbstractItemView::InternalMove); 0089 setDragDropOverwriteMode(false); 0090 0091 initEnvPathlist(); 0092 } 0093 0094 bool UserMenuTree::isEmpty() 0095 { 0096 return ( topLevelItemCount() == 0 ); 0097 } 0098 0099 ///////////////////////////// PATH environment variable ////////////////////////////// 0100 0101 // save PATH to search for executable files 0102 void UserMenuTree::initEnvPathlist() 0103 { 0104 QString envpath; 0105 #if QT_VERSION >= 0x040600 0106 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 0107 if ( env.contains("PATH") ) { 0108 envpath = env.value("PATH"); 0109 } 0110 #else 0111 // Returns the environment of the calling process as a list of key=value pairs. 0112 QStringList environment = QProcess::systemEnvironment(); 0113 foreach ( const QString &s, environment ) { 0114 if ( s.startsWith(QLatin1String("PATH=")) ) { 0115 envpath = s.mid(5); 0116 break; 0117 } 0118 } 0119 #endif 0120 0121 #ifdef Q_WS_WIN 0122 m_envPathlist = envpath.split(';'); 0123 #else 0124 m_envPathlist = envpath.split(':'); 0125 #endif 0126 m_envPathlist.append("."); 0127 } 0128 0129 bool UserMenuTree::isItemExecutable(const QString &filename) 0130 { 0131 if ( filename.isEmpty() ) { 0132 return false; 0133 } 0134 0135 // absolute paths can be checked immediately 0136 QFileInfo fi(filename); 0137 if ( fi.isAbsolute() ) { 0138 return fi.isExecutable(); 0139 } 0140 0141 // search in all paths 0142 for (int i=0; i<m_envPathlist.size(); ++i ) { 0143 bool executable = QFileInfo(m_envPathlist[i]+'/'+filename).isExecutable(); 0144 if ( executable ) { 0145 // move to front 0146 if ( i > 0 ) { 0147 QString temp = m_envPathlist[0]; 0148 m_envPathlist[0] = m_envPathlist[i]; 0149 m_envPathlist[i] = temp; 0150 } 0151 return true; 0152 } 0153 } 0154 0155 return false; 0156 } 0157 0158 ///////////////////////////// context menu event ////////////////////////////// 0159 0160 // build a context menu 0161 void UserMenuTree::contextMenuRequested(const QPoint &pos) 0162 { 0163 KILE_DEBUG_MAIN << "context menu requested ..." ; 0164 0165 m_popupItem = dynamic_cast<UserMenuItem*>(itemAt(pos)); 0166 if ( !m_popupItem ) { 0167 KILE_DEBUG_MAIN << "... no item found"; 0168 return; 0169 } 0170 0171 KILE_DEBUG_MAIN << "... popup item found: " << m_popupItem->text(0); 0172 bool submenu = ( m_popupItem->menutype() == UserMenuData::Submenu ); 0173 bool separator = ( m_popupItem->menutype() == UserMenuData::Separator ); 0174 0175 QMenu popup; 0176 0177 // insert standard menu items 0178 popup.addAction(QIcon::fromTheme("usermenu-insert-above.png"),i18n("Insert above"), this, [this] {insertMenuItem(m_popupItem, false);}); 0179 popup.addAction(QIcon::fromTheme("usermenu-insert-below.png"),i18n("Insert below"), this, [this] {insertMenuItem(m_popupItem, true);}); 0180 popup.addSeparator(); 0181 0182 // insert separators 0183 if ( !separator ) { 0184 popup.addAction(QIcon::fromTheme("usermenu-separator-above.png"),i18n("Insert a separator above"), this, [this] {insertSeparator(m_popupItem, false);}); 0185 popup.addAction(QIcon::fromTheme("usermenu-separator-below.png"),i18n("Insert a separator below"), this, [this] {insertSeparator(m_popupItem, true);}); 0186 popup.addSeparator(); 0187 } 0188 0189 // insert submenus 0190 popup.addAction(QIcon::fromTheme("usermenu-submenu-above.png"),i18n("Insert a submenu above"), this, [this] {insertSubmenu(m_popupItem, false);}); 0191 popup.addAction(QIcon::fromTheme("usermenu-submenu-below.png"),i18n("Insert a submenu below"), this, [this] {insertSubmenu(m_popupItem, true);}); 0192 popup.addSeparator(); 0193 0194 // insert into submenus 0195 if ( submenu ) { 0196 popup.addAction(QIcon::fromTheme("usermenu-into-submenu.png"),i18n("Insert into this submenu"), this, [this] {insertIntoSubmenu(m_popupItem, UserMenuData::Text);}); 0197 popup.addAction(i18n("Insert a separator into this submenu"), this, [this] {insertIntoSubmenu(m_popupItem, UserMenuData::Separator);}); 0198 popup.addAction(i18n("Insert a submenu into this submenu"), this, [this] {insertIntoSubmenu(m_popupItem, UserMenuData::Submenu);}); 0199 popup.addSeparator(); 0200 } 0201 0202 // delete actions 0203 popup.addAction(QIcon::fromTheme("usermenu-delete.png"),i18n("Delete this item"), this, [this] {itemDelete(m_popupItem);}); 0204 popup.addSeparator(); 0205 popup.addAction(QIcon::fromTheme("usermenu-clear.png"),i18n("Delete the complete tree"), this, [this] {deleteMenuTree();}); 0206 0207 // expand/collapse tree 0208 if ( submenu ) { 0209 popup.addSeparator(); 0210 if ( m_popupItem->isExpanded() ) { 0211 popup.addAction(i18n("Collapse submenu"), this, [this] {m_popupItem->setExpanded(false);}); 0212 } 0213 else { 0214 popup.addAction(i18n("Expand submenu"), this, [this] {m_popupItem->setExpanded(true);}); 0215 } 0216 popup.addSeparator(); 0217 popup.addAction(i18n("Collapse complete tree"), this, [this] {collapseAll();}); 0218 popup.addAction(i18n("Expand complete tree"), this, [this] {expandAll();}); 0219 } 0220 0221 // if there are any errors with this item, some info is available 0222 int error = m_popupItem->data(0,Qt::UserRole+2).toInt(); 0223 if ( error != UserMenuItem::MODEL_ERROR_NONE ) { 0224 popup.addSeparator(); 0225 popup.addAction(QIcon::fromTheme("help-about.png"),i18n("Info"), this, [this] {itemInfo(m_popupItem);}); 0226 } 0227 0228 // const QPoint& pos parameter in the customContextMenuRequested() signal is normally in widget coordinates. 0229 // But classes like QTreeWidget, which inherit from QAbstractScrollArea1 instead use the coordinates of their viewport() 0230 if ( !popup.isEmpty() ) { 0231 popup.exec( viewport()->mapToGlobal(pos) ); 0232 } 0233 } 0234 0235 ///////////////////////////// read XML ////////////////////////////// 0236 0237 // read an xml file and check for errors 0238 bool UserMenuTree::readXml(const QString &filename) 0239 { 0240 KILE_DEBUG_MAIN << "read xml file " << filename; 0241 0242 QDomDocument doc("UserMenu"); 0243 QFile file(filename); 0244 if ( !file.open(QFile::ReadOnly | QFile::Text) ) { 0245 KMessageBox::error(this, i18n("File '%1' does not exist.", filename)); 0246 return false; 0247 } 0248 if ( !doc.setContent( &file ) ) { 0249 file.close(); 0250 return false; 0251 } 0252 file.close(); 0253 0254 KILE_DEBUG_MAIN << "parse xml ..."; 0255 blockSignals(true); 0256 0257 // clear menutree 0258 clear(); 0259 0260 // read toplevelitems 0261 QDomElement root = doc.documentElement(); 0262 QDomElement e = root.firstChildElement(); 0263 while ( !e.isNull()) { 0264 QString tag = e.tagName(); 0265 0266 UserMenuItem *item = Q_NULLPTR; 0267 if ( tag == "submenu" ) { 0268 item = readXmlSubmenu(e); 0269 } 0270 else if ( tag == "separator" ) { 0271 item = readXmlSeparator(); 0272 } 0273 else { /* if ( tag == "menu" ) */ 0274 item = readXmlMenuentry(e); 0275 } 0276 0277 if ( item ) { 0278 addTopLevelItem(item); 0279 } 0280 e = e.nextSiblingElement(); 0281 } 0282 0283 // the xml menu is built, now check for errors 0284 setErrorCodes(); 0285 0286 // polish menutree 0287 expandAll(); 0288 if ( topLevelItemCount() > 0 ) { 0289 setCurrentItem( topLevelItem(0) ); 0290 } 0291 blockSignals(false); 0292 0293 return true; 0294 } 0295 0296 // a separator tag was found 0297 UserMenuItem *UserMenuTree::readXmlSeparator() 0298 { 0299 return new UserMenuItem(UserMenuData::Separator, QString()); 0300 } 0301 0302 // read tags for a submenu 0303 UserMenuItem *UserMenuTree::readXmlSubmenu(const QDomElement &element) 0304 { 0305 UserMenuItem *submenuitem = new UserMenuItem(UserMenuData::Submenu, QString()) ; 0306 0307 if ( element.hasChildNodes() ) { 0308 QDomElement e = element.firstChildElement(); 0309 while ( !e.isNull()) { 0310 UserMenuItem *item = Q_NULLPTR; 0311 0312 QString title; 0313 QString tag = e.tagName(); 0314 if ( tag == "title" ) { 0315 title = e.text(); 0316 } 0317 else if ( tag == "submenu" ) { 0318 item = readXmlSubmenu(e); 0319 } 0320 else if ( tag == "separator" ) { 0321 item = readXmlSeparator(); 0322 } 0323 else { /* if ( tag == "menu" ) */ 0324 item = readXmlMenuentry(e); 0325 } 0326 0327 submenuitem->setMenutitle(title); 0328 submenuitem->setText(0,title); 0329 0330 if ( item ) { 0331 submenuitem->addChild(item); 0332 } 0333 e = e.nextSiblingElement(); 0334 } 0335 } 0336 0337 return submenuitem; 0338 } 0339 0340 // read tags for a standard menu item 0341 UserMenuItem *UserMenuTree::readXmlMenuentry(const QDomElement &element) 0342 { 0343 QString menutypename = element.attribute("type"); 0344 UserMenuData::MenuType menutype = UserMenuData::xmlMenuType(menutypename); 0345 0346 UserMenuItem *menuentryitem = new UserMenuItem(menutype, QString()) ; 0347 0348 if ( element.hasChildNodes() ) { 0349 // default values 0350 QString title; 0351 QString plaintext; 0352 QString filename; 0353 QString parameter; 0354 QString icon; 0355 QString shortcut; 0356 bool needsSelection = false; 0357 bool useContextMenu = false; 0358 bool replaceSelection = false; 0359 bool selectInsertion = false; 0360 bool insertOutput = false; 0361 0362 // read values 0363 QDomElement e = element.firstChildElement(); 0364 while ( !e.isNull()) { 0365 QString tag = e.tagName(); 0366 QString text = e.text(); 0367 0368 int index = UserMenuData::xmlMenuTag(tag); 0369 switch (index) { 0370 case UserMenuData::XML_TITLE: 0371 title = text; 0372 break; 0373 case UserMenuData::XML_PLAINTEXT: 0374 plaintext = text; 0375 break; 0376 case UserMenuData::XML_FILENAME: 0377 filename = text; 0378 break; 0379 case UserMenuData::XML_PARAMETER: 0380 parameter = text; 0381 break; 0382 case UserMenuData::XML_ICON: 0383 icon = text; 0384 break; 0385 case UserMenuData::XML_SHORTCUT: 0386 shortcut = text; 0387 break; 0388 case UserMenuData::XML_NEEDSSELECTION: 0389 needsSelection = str2bool(text); 0390 break; 0391 case UserMenuData::XML_USECONTEXTMENU: 0392 useContextMenu = str2bool(text); 0393 break; 0394 case UserMenuData::XML_REPLACESELECTION: 0395 replaceSelection = str2bool(text); 0396 break; 0397 case UserMenuData::XML_SELECTINSERTION: 0398 selectInsertion = str2bool(text); 0399 break; 0400 case UserMenuData::XML_INSERTOUTPUT: 0401 insertOutput = str2bool(text); 0402 break; 0403 } 0404 0405 e = e.nextSiblingElement(); 0406 } 0407 0408 // save values 0409 menuentryitem->setMenutitle(title); 0410 0411 // add code newline 0412 plaintext = UserMenuData::decodeLineFeed(plaintext); 0413 menuentryitem->setPlaintext(plaintext); 0414 0415 menuentryitem->setFilename(filename); 0416 menuentryitem->setParameter(parameter); 0417 if ( !icon.isEmpty() ) { 0418 menuentryitem->setMenuicon(icon); 0419 menuentryitem->setIcon(0,QIcon::fromTheme(icon)); 0420 } 0421 if ( !shortcut.isEmpty() ) { 0422 QKeySequence seq = QKeySequence::fromString(shortcut,QKeySequence::PortableText); 0423 shortcut = seq.toString(QKeySequence::NativeText); 0424 0425 menuentryitem->setShortcut(shortcut); 0426 menuentryitem->setText(1,shortcut); 0427 } 0428 menuentryitem->setNeedsSelection(needsSelection); 0429 menuentryitem->setUseContextMenu(useContextMenu); 0430 menuentryitem->setReplaceSelection(replaceSelection); 0431 menuentryitem->setSelectInsertion(selectInsertion); 0432 menuentryitem->setInsertOutput(insertOutput); 0433 0434 menuentryitem->setText(0,title); 0435 } 0436 0437 return menuentryitem; 0438 } 0439 0440 0441 ///////////////////////////// write XML ////////////////////////////// 0442 0443 bool UserMenuTree::writeXml(const QString &filename) 0444 { 0445 KILE_DEBUG_MAIN << "write xml file " << filename; 0446 0447 QFile file(filename); 0448 if ( !file.open(QFile::WriteOnly | QFile::Text) ) { 0449 KMessageBox::error(this, i18n("File '%1' could not be opened to save the usermenu file.", filename)); 0450 return false; 0451 } 0452 0453 QXmlStreamWriter xmlWriter(&file); 0454 xmlWriter.setAutoFormatting(true); 0455 xmlWriter.setAutoFormattingIndent(2) ; 0456 0457 xmlWriter.writeStartDocument(); 0458 xmlWriter.writeStartElement("UserMenu"); 0459 0460 for (int i = 0; i < topLevelItemCount(); ++i) { 0461 writeXmlItem(&xmlWriter, dynamic_cast<UserMenuItem *>(topLevelItem(i)) ); 0462 } 0463 xmlWriter.writeEndDocument(); 0464 0465 file.close(); 0466 return true; 0467 } 0468 0469 void UserMenuTree::writeXmlItem(QXmlStreamWriter *xml, UserMenuItem *item) 0470 { 0471 switch (item->menutype()) { 0472 case UserMenuData::Separator: 0473 writeXmlSeparator(xml); 0474 break; 0475 case UserMenuData::Submenu: 0476 writeXmlSubmenu(xml,item); 0477 break; 0478 default: 0479 writeXmlMenuentry(xml,item); 0480 break; 0481 } 0482 } 0483 0484 // write xml tags for a standard menu item 0485 void UserMenuTree::writeXmlMenuentry(QXmlStreamWriter *xml, UserMenuItem *item) 0486 { 0487 int menutype = item->menutype(); 0488 QString menutypename = UserMenuData::xmlMenuTypeName(menutype); 0489 0490 xml->writeStartElement("menu"); 0491 xml->writeAttribute("type", menutypename); 0492 0493 QString menutitle = ( item->text(0) == EMPTY_MENUENTRY ) ? QString() : item->text(0); 0494 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_TITLE),menutitle); 0495 0496 if ( menutype == UserMenuData::Text ) { 0497 QString plaintext = item->plaintext(); 0498 if ( !plaintext.isEmpty() ) { 0499 // encode newline characters 0500 plaintext = UserMenuData::encodeLineFeed(plaintext); 0501 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_PLAINTEXT), plaintext); 0502 } 0503 } 0504 else { /* if ( menutype!=UserMenuData::FileContent || menutype==UserMenuData:Program) */ 0505 // both types use a filename 0506 QString filename = item->filename(); 0507 if ( !filename.isEmpty() ) { 0508 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_FILENAME), filename); 0509 0510 // but UserMenuItem::Program may have an additional parameter 0511 if ( menutype == UserMenuData::Program) { 0512 QString parameter = item->parameter(); 0513 if ( !parameter.isEmpty() ) { 0514 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_PARAMETER), parameter); 0515 } 0516 } 0517 } 0518 } 0519 0520 QString icon = item->menuicon(); 0521 if ( !icon.isEmpty() ) { 0522 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_ICON),icon); 0523 } 0524 0525 QKeySequence seq = QKeySequence::fromString( item->shortcut(), QKeySequence::NativeText ); 0526 if ( !seq.isEmpty() ) { 0527 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_SHORTCUT), seq.toString(QKeySequence::PortableText)); 0528 } 0529 0530 if ( item->needsSelection() ) { 0531 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_NEEDSSELECTION), "true"); 0532 } 0533 if ( item->useContextMenu() ) { 0534 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_USECONTEXTMENU), "true"); 0535 } 0536 if ( item->replaceSelection() ) { 0537 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_REPLACESELECTION), "true"); 0538 } 0539 if ( item->selectInsertion() ) { 0540 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_SELECTINSERTION), "true"); 0541 } 0542 if ( item->insertOutput() ) { 0543 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_INSERTOUTPUT), "true"); 0544 } 0545 0546 xml->writeEndElement(); 0547 } 0548 0549 // write xml tags for a submenu 0550 void UserMenuTree::writeXmlSubmenu(QXmlStreamWriter *xml, UserMenuItem *item) 0551 { 0552 xml->writeStartElement("submenu"); 0553 0554 QString menutitle = item->text(0); 0555 if ( menutitle == EMPTY_MENUENTRY ) { 0556 menutitle.clear(); 0557 } 0558 else if ( menutitle.right(LENGTH_SUBSTITUTE) == EMPTY_SUBMENU ) { 0559 menutitle = menutitle.left(menutitle.length()-LENGTH_SUBSTITUTE); 0560 } 0561 xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_TITLE),menutitle); 0562 0563 for ( int i=0; i<item->childCount(); ++i ) { 0564 writeXmlItem(xml, dynamic_cast<UserMenuItem *>(item->child(i)) ); 0565 } 0566 0567 xml->writeEndElement(); 0568 } 0569 0570 // write xml tag for a separator 0571 void UserMenuTree::writeXmlSeparator(QXmlStreamWriter *xml) 0572 { 0573 xml->writeStartElement("separator"); 0574 xml->writeEndElement(); 0575 } 0576 0577 ///////////////////////////// check menutree and set error codes ////////////////////////////// 0578 0579 // the complete menutree was build, now check for errors 0580 // - empty menutitles 0581 // - useless submenus without children 0582 // - empty filenames, not existing or not executable files 0583 void UserMenuTree::setErrorCodes() 0584 { 0585 KILE_DEBUG_MAIN << "check menutree for errors and set error codes ..."; 0586 0587 for (int i = 0; i < topLevelItemCount(); ++i) { 0588 UserMenuItem *item = dynamic_cast<UserMenuItem *>(topLevelItem(i)); 0589 UserMenuData::MenuType type = item->menutype(); 0590 0591 bool executable = ( type==UserMenuData::Program && isItemExecutable(item->filename()) ); 0592 item->setModelData(executable); 0593 0594 if ( type != UserMenuData::Separator ) { 0595 checkMenuTitle(item); 0596 } 0597 if ( type == UserMenuData::Submenu ) { 0598 checkSubmenu(item); 0599 } 0600 } 0601 } 0602 0603 void UserMenuTree::checkMenuTitle(UserMenuItem *item) 0604 { 0605 if ( item->menutitle().isEmpty() ) { 0606 item->setText(0,EMPTY_MENUENTRY); 0607 KILE_DEBUG_MAIN << "empty menutitle changed to " << EMPTY_MENUENTRY; 0608 } 0609 } 0610 0611 void UserMenuTree::checkSubmenu(UserMenuItem *item) 0612 { 0613 QString menutitle = item->menutitle(); 0614 int children = item->childCount(); 0615 0616 if ( menutitle.isEmpty() ) { 0617 menutitle = EMPTY_MENUENTRY; 0618 } 0619 else if ( children == 0 ) { 0620 menutitle += EMPTY_SUBMENU; 0621 } 0622 item->setText(0,menutitle); 0623 0624 for ( int i=0; i<children; ++i ) { 0625 UserMenuItem *child = dynamic_cast<UserMenuItem *>(item->child(i)); 0626 child->setModelData(); 0627 UserMenuData::MenuType type = child->menutype(); 0628 0629 if ( type != UserMenuData::Separator ) { 0630 checkMenuTitle(child); 0631 } 0632 if ( type == UserMenuData::Submenu ) { 0633 checkSubmenu(child); 0634 } 0635 } 0636 } 0637 0638 ///////////////////////////// check menutree ////////////////////////////// 0639 0640 // check for errors (true=no errors) 0641 bool UserMenuTree::errorCheck() 0642 { 0643 KILE_DEBUG_MAIN << "check menutree for errors ..."; 0644 0645 for (int i = 0; i < topLevelItemCount(); ++i) { 0646 UserMenuItem *item = dynamic_cast<UserMenuItem *>(topLevelItem(i)); 0647 UserMenuData::MenuType type = item->menutype(); 0648 0649 if ( type != UserMenuData::Separator ) { 0650 if ( item->data(0,Qt::UserRole+2).toInt() != UserMenuItem::MODEL_ERROR_NONE ) { 0651 return false; 0652 } 0653 } 0654 0655 if ( type == UserMenuData::Submenu ) { 0656 if ( checkSubmenuError(item) == false ) { 0657 return false; 0658 } 0659 } 0660 } 0661 0662 return true; 0663 } 0664 0665 bool UserMenuTree::checkSubmenuError(UserMenuItem *item) 0666 { 0667 int children = item->childCount(); 0668 for ( int i=0; i<children; ++i ) { 0669 UserMenuItem *child = dynamic_cast<UserMenuItem *>(item->child(i)); 0670 UserMenuData::MenuType type = child->menutype(); 0671 0672 if ( type != UserMenuData::Separator ) { 0673 if ( child->data(0,Qt::UserRole+2).toInt() != UserMenuItem::MODEL_ERROR_NONE ) { 0674 return false; 0675 } 0676 } 0677 0678 if ( type == UserMenuData::Submenu ) { 0679 if ( checkSubmenuError(child) == false ) { 0680 return false; 0681 } 0682 } 0683 } 0684 0685 return true; 0686 } 0687 0688 ///////////////////////////// tree ops ////////////////////////////// 0689 0690 // insert a standard menu item 0691 bool UserMenuTree::insertMenuItem(QTreeWidgetItem *current, bool below) 0692 { 0693 QString menulabel = getMenuTitle(i18n("Please enter a label for this menu item:")); 0694 if ( menulabel.isEmpty() ) { 0695 return false; 0696 } 0697 0698 if ( below ) { 0699 insertMenuItemBelow(current,UserMenuData::Text,menulabel); 0700 } 0701 else { 0702 insertMenuItemAbove(current,UserMenuData::Text,menulabel); 0703 } 0704 return true; 0705 } 0706 0707 // insert a submenu item 0708 bool UserMenuTree::insertSubmenu(QTreeWidgetItem *current, bool below) 0709 { 0710 QString menulabel = getMenuTitle(i18n("Please enter a label for this submenu:")); 0711 if ( menulabel.isEmpty() ) { 0712 return false; 0713 } 0714 0715 if ( below ) { 0716 insertMenuItemBelow(current,UserMenuData::Submenu,menulabel); 0717 } 0718 else { 0719 insertMenuItemAbove(current,UserMenuData::Submenu,menulabel); 0720 } 0721 return true; 0722 } 0723 0724 // insert a separator item 0725 bool UserMenuTree::insertSeparator(QTreeWidgetItem *current, bool below) 0726 { 0727 if(below) { 0728 insertMenuItemBelow(current,UserMenuData::Separator, QString()); 0729 } 0730 else { 0731 insertMenuItemAbove(current,UserMenuData::Separator, QString()); 0732 } 0733 return true; 0734 } 0735 0736 void UserMenuTree::insertMenuItemAbove(QTreeWidgetItem *current, UserMenuData::MenuType type, const QString &menulabel) 0737 { 0738 QTreeWidgetItem *parent = ( current ) ? current->parent() : Q_NULLPTR; 0739 int index = itemIndex(parent,current); 0740 0741 UserMenuItem *item = new UserMenuItem(type,menulabel); 0742 insertItem(parent,index,item); 0743 0744 item->setText(0,menulabel); 0745 setCurrentItem(item); 0746 } 0747 0748 void UserMenuTree::insertMenuItemBelow(QTreeWidgetItem *current, UserMenuData::MenuType type, const QString &menulabel) 0749 { 0750 UserMenuItem *item; 0751 QTreeWidgetItem *parent = ( current ) ? current->parent() : Q_NULLPTR; 0752 0753 if(!parent) { 0754 item = new UserMenuItem(this,current,type,menulabel); 0755 } 0756 else { 0757 item = new UserMenuItem(parent,current,type,menulabel); 0758 } 0759 0760 item->setText(0,menulabel); 0761 setCurrentItem(item); 0762 } 0763 0764 void UserMenuTree::insertIntoSubmenu(QTreeWidgetItem *current, UserMenuData::MenuType type) 0765 { 0766 QString menulabel; 0767 if ( type == UserMenuData::Text || type == UserMenuData::Submenu ) { 0768 menulabel = getMenuTitle(i18n("Please enter a label for this entry:")); 0769 if ( menulabel.isEmpty() ) { 0770 return; 0771 } 0772 } 0773 0774 UserMenuItem *item = new UserMenuItem(type,menulabel); 0775 insertItem(current,0,item); 0776 setCurrentItem(item); 0777 } 0778 0779 // delete an item 0780 void UserMenuTree::itemDelete(QTreeWidgetItem *current) 0781 { 0782 int children,index; 0783 QTreeWidgetItem *item, *selectitem; 0784 QTreeWidgetItem *parent = current->parent(); 0785 if(!parent) { 0786 children = topLevelItemCount(); 0787 index = indexOfTopLevelItem(current); 0788 if ( index < children-1 ) { 0789 selectitem = topLevelItem(index+1); 0790 } 0791 else if ( index > 0 ) { 0792 selectitem = topLevelItem(index-1); 0793 } 0794 else { 0795 selectitem = Q_NULLPTR; 0796 } 0797 0798 item = takeTopLevelItem(index); 0799 } 0800 else { 0801 children = parent->childCount(); 0802 index = parent->indexOfChild(current); 0803 if ( index < children-1 ) { 0804 selectitem = parent->child(index+1); 0805 } 0806 else if ( index > 0 ) { 0807 selectitem = parent->child(index-1); 0808 } 0809 else { 0810 selectitem = parent; 0811 } 0812 0813 item = parent->takeChild(index); 0814 } 0815 0816 delete item; 0817 0818 if(selectitem) { 0819 setCurrentItem(selectitem); 0820 } 0821 } 0822 0823 // move an item one position up 0824 void UserMenuTree::itemUp() 0825 { 0826 QTreeWidgetItem *current = currentItem(); 0827 UserMenuItem *aboveitem = dynamic_cast<UserMenuItem *>(itemAbove(current)); 0828 if (!aboveitem) { 0829 return; 0830 } 0831 0832 bool expanded = current->isExpanded(); 0833 blockSignals(true); 0834 0835 QTreeWidgetItem *aboveparent = aboveitem->parent(); 0836 int aboveindex = itemIndex(aboveparent,aboveitem); 0837 0838 UserMenuItem *parent = dynamic_cast<UserMenuItem *>(current->parent()); 0839 int index = itemIndex(parent,current); 0840 takeItem(parent,current); 0841 0842 if ( parent!=aboveparent && index!=0 ) { 0843 aboveindex++; 0844 } 0845 0846 if ( parent==aboveparent && aboveitem->menutype()==UserMenuData::Submenu ) { 0847 insertItem(aboveitem,0,current); 0848 } 0849 else { 0850 insertItem(aboveparent,aboveindex,current); 0851 } 0852 0853 // update model data of old and new parent, if it has changed 0854 UserMenuItem *newparent = dynamic_cast<UserMenuItem *>(current->parent()); 0855 if ( parent != newparent ) { 0856 if ( parent ) { 0857 parent->setModelData(); 0858 parent->setText(0, parent->updateMenutitle()); 0859 } 0860 if ( newparent ) { 0861 newparent->setModelData(); 0862 newparent->setText(0, newparent->updateMenutitle()); 0863 } 0864 } 0865 0866 current->setExpanded(expanded); 0867 setCurrentItem(current); 0868 blockSignals(false); 0869 } 0870 0871 // move an item one position down 0872 void UserMenuTree::itemDown() 0873 { 0874 QTreeWidgetItem *current = currentItem(); 0875 bool expanded = current->isExpanded(); 0876 blockSignals(true); 0877 0878 // get all necessary parameter 0879 UserMenuItem *parent = dynamic_cast<UserMenuItem *>(current->parent()); 0880 int index = itemIndex(parent,current); 0881 int children = numChildren(parent); 0882 0883 // successor exists? 0884 if ( index < children-1 ) { 0885 UserMenuItem *successor = dynamic_cast<UserMenuItem *>( itemAtIndex(parent,index+1) ); 0886 takeItem(parent,current); 0887 if ( successor->menutype() == UserMenuData::Submenu ) { 0888 successor->insertChild(0,current); 0889 } 0890 else { 0891 insertItem(parent,index+1,current); 0892 } 0893 } 0894 else if ( parent ) { 0895 QTreeWidgetItem *grandparent = parent->parent(); 0896 int parentindex = itemIndex(grandparent,parent); 0897 takeItem(parent,current); 0898 insertItem(grandparent,parentindex+1,current); 0899 } 0900 0901 // update model data of old and new parent, if it has changed 0902 UserMenuItem *newparent = dynamic_cast<UserMenuItem *>(current->parent()); 0903 if ( parent != newparent ) { 0904 if ( parent ) { 0905 parent->setModelData(); 0906 parent->setText(0, parent->updateMenutitle()); 0907 } 0908 if ( newparent ) { 0909 newparent->setModelData(); 0910 newparent->setText(0, newparent->updateMenutitle()); 0911 } 0912 } 0913 0914 current->setExpanded(expanded); 0915 setCurrentItem(current); 0916 blockSignals(false); 0917 } 0918 0919 ////////////////////////////// delete tree ////////////////////////////// 0920 0921 // delete the whole menutree 0922 void UserMenuTree::deleteMenuTree() 0923 { 0924 if ( KMessageBox::questionTwoActions(this, i18n("Do you really want to clear the complete menutree?"), 0925 i18n("Clear menutree"), 0926 KStandardGuiItem::clear(), KStandardGuiItem::cancel()) == KMessageBox::PrimaryAction) { 0927 blockSignals(true); 0928 clear(); 0929 blockSignals(false); 0930 } 0931 } 0932 0933 ////////////////////////////// info ////////////////////////////// 0934 0935 // prepare info for en item with errors 0936 void UserMenuTree::itemInfo(UserMenuItem *item) 0937 { 0938 int error = item->data(0,Qt::UserRole+2).toInt(); 0939 0940 QStringList list; 0941 if ( error & UserMenuItem::MODEL_ERROR_EMPTY ) { 0942 list << i18n("This menuitem has no title."); 0943 } 0944 0945 if ( error & UserMenuItem::MODEL_ERROR_SUBMENU ) { 0946 list << i18n("This submenu item is useless without children."); 0947 } 0948 0949 if ( error & UserMenuItem::MODEL_ERROR_TEXT ) { 0950 list << i18n("This item offers no text to insert."); 0951 } 0952 0953 if ( error & UserMenuItem::MODEL_ERROR_FILE_EMPTY ) { 0954 list << i18n("No file is given for this task."); 0955 } 0956 0957 if ( error & UserMenuItem::MODEL_ERROR_FILE_EXIST ) { 0958 list << i18n("The file for this item does not exist."); 0959 } 0960 0961 if ( error & UserMenuItem::MODEL_ERROR_FILE_EXECUTABLE ) { 0962 list << i18n("The file for this item is not executable."); 0963 } 0964 0965 QString msg = i18n("<p><strong>Error:</strong>"); 0966 if ( list.size() == 1 ) { 0967 msg += "<br/><br/>" + list[0] + "</p>"; 0968 } 0969 else { 0970 msg += "<ul>"; 0971 foreach ( const QString &s, list ) { 0972 msg += "<li> " + s + "</li>"; 0973 } 0974 msg += "</ul></p>"; 0975 } 0976 0977 KMessageBox::information(this, msg, i18n("Menutree Error")); 0978 } 0979 0980 ////////////////////////////// auxiliary ////////////////////////////// 0981 0982 int UserMenuTree::itemIndex(QTreeWidgetItem *parent, QTreeWidgetItem *item) 0983 { 0984 return ( parent ) ? parent->indexOfChild(item) : indexOfTopLevelItem(item); 0985 } 0986 0987 QTreeWidgetItem *UserMenuTree::itemAtIndex(QTreeWidgetItem *parent, int index) 0988 { 0989 return ( parent ) ? parent->child(index) : topLevelItem(index); 0990 } 0991 0992 int UserMenuTree::numChildren(QTreeWidgetItem *parent) 0993 { 0994 return ( parent ) ? parent->childCount() : topLevelItemCount(); 0995 } 0996 0997 void UserMenuTree::insertItem(QTreeWidgetItem *parent, int index, QTreeWidgetItem *item) 0998 { 0999 if ( parent ) { 1000 parent->insertChild(index,item); 1001 } 1002 else { 1003 insertTopLevelItem(index,item); 1004 } 1005 } 1006 1007 void UserMenuTree::takeItem(QTreeWidgetItem *parent, QTreeWidgetItem *item) 1008 { 1009 if ( parent ) { 1010 int index = parent->indexOfChild(item); 1011 parent->takeChild(index); 1012 } 1013 else { 1014 int index = indexOfTopLevelItem(item); 1015 takeTopLevelItem(index); 1016 } 1017 } 1018 1019 bool UserMenuTree::str2bool(const QString &value) 1020 { 1021 return ( value == "true" ); 1022 } 1023 1024 1025 QString UserMenuTree::getMenuTitle(const QString &title) 1026 { 1027 bool ok; 1028 QString value = QInputDialog::getText(this, i18n("Name"), title, QLineEdit::Normal, QString(), &ok); 1029 return ( ok ) ? value : QString(); 1030 1031 } 1032 1033 1034 } 1035