diff --git a/CMakeLists.txt b/CMakeLists.txt index f4a278e1..1bea621f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,128 +1,128 @@ project(kile) cmake_minimum_required(VERSION 3.0.0) set(KILE_VERSION CACHE STRING "Kile's version; can be used to set the internal version of Kile on MacOSX") find_package(ECM 5.19.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMAddAppIcon) include(ECMOptionalAddSubdirectory) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(CMakePackageConfigHelpers) include(FeatureSummary) include(WriteBasicConfigVersionFile) include(CheckFunctionExists) include(KDEInstallDirs) include(KDECMakeSettings) kde_enable_exceptions() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) -find_package(Qt5 5.3 CONFIG REQUIRED +find_package(Qt5 5.6 CONFIG REQUIRED Core DBus Widgets Script Test ) find_package(KF5 5.31 REQUIRED COMPONENTS Config CoreAddons Crash DBusAddons DocTools GuiAddons I18n IconThemes Init KHtml KIO Parts TextEditor WindowSystem XmlGui ) find_package(Okular5 REQUIRED) set_package_properties(Okular5 PROPERTIES DESCRIPTION "Okular core library" URL "http://okular.kde.org") find_package(Poppler COMPONENTS Qt5) set_package_properties("Poppler" PROPERTIES TYPE RECOMMENDED PURPOSE "Support for PDF file operations.") if(Poppler_Qt5_FOUND) set(HAVE_POPPLER TRUE) include_directories(${Poppler_INCLUDE_DIRS}) endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config.h) # find_package(SharedMimeInfo REQUIRED) add_definitions( # -DQT_USE_QSTRINGBUILDER # -DQT_NO_CAST_FROM_ASCII # -DQT_NO_CAST_FROM_BYTEARRAY # -DQT_USE_FAST_OPERATOR_PLUS -DQT_NO_CAST_TO_ASCII -DQT_STRICT_ITERATORS -DQT_NO_URL_CAST_FROM_STRING -DQT_NO_SIGNALS_SLOTS_KEYWORDS ) if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") add_definitions(-DQT_MESSAGELOGCONTEXT) endif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") add_subdirectory(doc) add_subdirectory(src) ########### install files ############### install( FILES kile.xml DESTINATION ${XDG_MIME_INSTALL_DIR}) # update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR}) install( FILES kile.upd DESTINATION ${KDE_INSTALL_DATAROOTDIR}/kconf_update) install( PROGRAMS kile1.6_upd.pl kile1.7_upd.pl kile1.9_upd.pl kile1.9-1_upd.pl kile2.0-1_upd.pl kile2.0-2_upd.pl kile2.0-3_upd.pl kile2.0-4_upd.pl kile2.0-5_upd.pl DESTINATION ${KDE_INSTALL_DATAROOTDIR}/kconf_update) install(FILES AUTHORS ChangeLog README README.cwl kile-remote-control.txt README.MacOSX DESTINATION ${KDE_INSTALL_DATAROOTDIR}/doc/kile) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/dialogs/usermenu/usermenutree.cpp b/src/dialogs/usermenu/usermenutree.cpp index 95d6914e..992fb7aa 100644 --- a/src/dialogs/usermenu/usermenutree.cpp +++ b/src/dialogs/usermenu/usermenutree.cpp @@ -1,1110 +1,1034 @@ /*********************************************************************************** Copyright (C) 2011-2012 by Holger Danielsson (holger.danielsson@versanet.de) ***********************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include -#include #include #include #include #include #include "dialogs/usermenu/usermenuitem.h" #include "dialogs/usermenu/usermenutree.h" #include "kiledebug.h" // Qt::UserRole+1: menutype // Qt::UserRole+2: errorcode for menu item namespace KileMenu { // - Separators are shown as a horizontal line (Qt:UserRole+1) // - Menu items with errors are displayed in red (Qt:UserRole+2) void MenuentryDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const { QString menutitle = index.data(Qt::DisplayRole).toString(); int error = index.data(Qt::UserRole+2).toInt(); // any errors? if (index.column()==0 && error!=UserMenuItem::MODEL_ERROR_NONE ) { QStyleOptionViewItem optionCustom = option; optionCustom.palette.setColor(QPalette::Text, Qt::red); QStyledItemDelegate::paint( painter, optionCustom, index ); } else { QStyledItemDelegate::paint( painter, option, index ); } // display separators QString itemtype = index.data(Qt::UserRole+1).toString(); if ( itemtype == "separator" ) { QRect r = option.rect; int y = ( r.bottom() + r.top() ) / 2; painter->save(); QPen pen = QPen(Qt::gray); painter->setPen(pen); painter->drawLine(r.left()+3,y, r.right()-20,y); painter->restore(); } } ///////////////////////////// UserMenuTree ////////////////////////////// UserMenuTree::UserMenuTree(QWidget *parent) : QTreeWidget(parent) { setColumnCount(2); header()->setSectionResizeMode(0, QHeaderView::Stretch); header()->setSectionResizeMode(1, QHeaderView::Fixed); header()->setSectionsMovable(false); header()->setStretchLastSection(false); setColumnWidth(1,140); setItemDelegateForColumn(0, new MenuentryDelegate(parent)); // drag and drop setDragEnabled(true); setDropIndicatorShown(true); //setAcceptDrops(true); setDragDropMode(QAbstractItemView::InternalMove); setDragDropOverwriteMode(false); initEnvPathlist(); } bool UserMenuTree::isEmpty() { return ( topLevelItemCount() == 0 ); } ///////////////////////////// PATH environment variable ////////////////////////////// // save PATH to search for executable files void UserMenuTree::initEnvPathlist() { QString envpath; #if QT_VERSION >= 0x040600 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if ( env.contains("PATH") ) { envpath = env.value("PATH"); } #else // Returns the environment of the calling process as a list of key=value pairs. QStringList environment = QProcess::systemEnvironment(); foreach ( const QString &s, environment ) { if ( s.startsWith(QLatin1String("PATH=")) ) { envpath = s.mid(5); break; } } #endif #ifdef Q_WS_WIN m_envPathlist = envpath.split(';'); #else m_envPathlist = envpath.split(':'); #endif m_envPathlist.append("."); } bool UserMenuTree::isItemExecutable(const QString &filename) { if ( filename.isEmpty() ) { return false; } // absolute paths can be checked immediately QFileInfo fi(filename); if ( fi.isAbsolute() ) { return fi.isExecutable(); } // search in all paths for (int i=0; i 0 ) { QString temp = m_envPathlist[0]; m_envPathlist[0] = m_envPathlist[i]; m_envPathlist[i] = temp; } return true; } } return false; } ///////////////////////////// context menu event ////////////////////////////// // build a context menu void UserMenuTree::contextMenuRequested(const QPoint &pos) { KILE_DEBUG_MAIN << "context menu requested ..." ; m_popupItem = dynamic_cast(itemAt(pos)); if ( !m_popupItem ) { KILE_DEBUG_MAIN << "... no item found"; return; } KILE_DEBUG_MAIN << "... popup item found: " << m_popupItem->text(0); bool submenu = ( m_popupItem->menutype() == UserMenuData::Submenu ); bool separator = ( m_popupItem->menutype() == UserMenuData::Separator ); QMenu popup; - QAction *action = Q_NULLPTR; - QSignalMapper signalMapper; - connect(&signalMapper, SIGNAL(mapped(int)), this, SLOT(slotPopupActivated(int))); // insert standard menu items - action = popup.addAction(QIcon::fromTheme("usermenu-insert-above.png"),i18n("Insert above"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_INSERT_ABOVE); - action = popup.addAction(QIcon::fromTheme("usermenu-insert-below.png"),i18n("Insert below"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_INSERT_BELOW); + popup.addAction(QIcon::fromTheme("usermenu-insert-above.png"),i18n("Insert above"), this, [this] {insertMenuItem(m_popupItem, false);}); + popup.addAction(QIcon::fromTheme("usermenu-insert-below.png"),i18n("Insert below"), this, [this] {insertMenuItem(m_popupItem, true);}); popup.addSeparator(); // insert separators if ( !separator ) { - action = popup.addAction(QIcon::fromTheme("usermenu-separator-above.png"),i18n("Insert a separator above"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_SEPARATOR_ABOVE); - action = popup.addAction(QIcon::fromTheme("usermenu-separator-below.png"),i18n("Insert a separator below"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_SEPARATOR_BELOW); + popup.addAction(QIcon::fromTheme("usermenu-separator-above.png"),i18n("Insert a separator above"), this, [this] {insertSeparator(m_popupItem, false);}); + popup.addAction(QIcon::fromTheme("usermenu-separator-below.png"),i18n("Insert a separator below"), this, [this] {insertSeparator(m_popupItem, true);}); popup.addSeparator(); } // insert submenus - action = popup.addAction(QIcon::fromTheme("usermenu-submenu-above.png"),i18n("Insert a submenu above"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_SUBMENU_ABOVE); - action = popup.addAction(QIcon::fromTheme("usermenu-submenu-below.png"),i18n("Insert a submenu below"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_SUBMENU_BELOW); + popup.addAction(QIcon::fromTheme("usermenu-submenu-above.png"),i18n("Insert a submenu above"), this, [this] {insertSubmenu(m_popupItem, false);}); + popup.addAction(QIcon::fromTheme("usermenu-submenu-below.png"),i18n("Insert a submenu below"), this, [this] {insertSubmenu(m_popupItem, true);}); popup.addSeparator(); // insert into submenus if ( submenu ) { - action = popup.addAction(QIcon::fromTheme("usermenu-into-submenu.png"),i18n("Insert into this submenu"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_INTO_SUBMENU); - action = popup.addAction(i18n("Insert a separator into this submenu"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_SEPARATOR_INTO_SUBMENU); - action = popup.addAction(i18n("Insert a submenu into this submenu"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_SUBMENU_INTO_SUBMENU); + popup.addAction(QIcon::fromTheme("usermenu-into-submenu.png"),i18n("Insert into this submenu"), this, [this] {insertIntoSubmenu(m_popupItem, UserMenuData::Text);}); + popup.addAction(i18n("Insert a separator into this submenu"), this, [this] {insertIntoSubmenu(m_popupItem, UserMenuData::Separator);}); + popup.addAction(i18n("Insert a submenu into this submenu"), this, [this] {insertIntoSubmenu(m_popupItem, UserMenuData::Submenu);}); popup.addSeparator(); } // delete actions - action = popup.addAction(QIcon::fromTheme("usermenu-delete.png"),i18n("Delete this item"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action,POPUP_DELETE_ITEM); + popup.addAction(QIcon::fromTheme("usermenu-delete.png"),i18n("Delete this item"), this, [this] {itemDelete(m_popupItem);}); popup.addSeparator(); - action = popup.addAction(QIcon::fromTheme("usermenu-clear.png"),i18n("Delete the complete tree"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_DELETE_TREE); + popup.addAction(QIcon::fromTheme("usermenu-clear.png"),i18n("Delete the complete tree"), this, [this] {deleteMenuTree();}); // expand/collapse tree if ( submenu ) { popup.addSeparator(); if ( m_popupItem->isExpanded() ) { - action = popup.addAction(i18n("Collapse submenu"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action,POPUP_COLLAPSE_ITEM); + popup.addAction(i18n("Collapse submenu"), this, [this] {m_popupItem->setExpanded(false);}); } else { - action = popup.addAction(i18n("Expand submenu"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action,POPUP_EXPAND_ITEM); + popup.addAction(i18n("Expand submenu"), this, [this] {m_popupItem->setExpanded(true);}); } popup.addSeparator(); - action = popup.addAction(i18n("Collapse complete tree"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action,POPUP_COLLAPSE_TREE); - action = popup.addAction(i18n("Expand complete tree"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action,POPUP_EXPAND_TREE); + popup.addAction(i18n("Collapse complete tree"), this, [this] {collapseAll();}); + popup.addAction(i18n("Expand complete tree"), this, [this] {expandAll();}); } // if there are any errors with this item, some info is available int error = m_popupItem->data(0,Qt::UserRole+2).toInt(); if ( error != UserMenuItem::MODEL_ERROR_NONE ) { popup.addSeparator(); - action = popup.addAction(QIcon::fromTheme("help-about.png"),i18n("Info"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, POPUP_ITEM_INFO); + popup.addAction(QIcon::fromTheme("help-about.png"),i18n("Info"), this, [this] {itemInfo(m_popupItem);}); } // const QPoint& pos parameter in the customContextMenuRequested() signal is normally in widget coordinates. // But classes like QTreeWidget, which inherit from QAbstractScrollArea1 instead use the coordinates of their viewport() if ( !popup.isEmpty() ) { popup.exec( viewport()->mapToGlobal(pos) ); } } -// a context menu action was selected -void UserMenuTree::slotPopupActivated(int id) -{ - KILE_DEBUG_MAIN << "popup activated with id: " << id; - switch (id ) { - case POPUP_INSERT_ABOVE: - insertMenuItem (m_popupItem, false); - break; - case POPUP_INSERT_BELOW: - insertMenuItem (m_popupItem, true); - break; - case POPUP_SEPARATOR_ABOVE: - insertSeparator(m_popupItem, false); - break; - case POPUP_SEPARATOR_BELOW: - insertSeparator(m_popupItem, true); - break; - case POPUP_SUBMENU_ABOVE: - insertSubmenu (m_popupItem, false); - break; - case POPUP_SUBMENU_BELOW: - insertSubmenu (m_popupItem, true); - break; - case POPUP_INTO_SUBMENU: - insertIntoSubmenu(m_popupItem, UserMenuData::Text); - break; - case POPUP_SEPARATOR_INTO_SUBMENU: - insertIntoSubmenu(m_popupItem, UserMenuData::Separator); - break; - case POPUP_SUBMENU_INTO_SUBMENU: - insertIntoSubmenu(m_popupItem, UserMenuData::Submenu); - break; - case POPUP_DELETE_ITEM: - itemDelete(m_popupItem); - break; - case POPUP_DELETE_TREE: - deleteMenuTree(); - break; - case POPUP_COLLAPSE_ITEM: - m_popupItem->setExpanded(false); - break; - case POPUP_EXPAND_ITEM: - m_popupItem->setExpanded(true); - break; - case POPUP_COLLAPSE_TREE: - collapseAll(); - break; - case POPUP_EXPAND_TREE: - expandAll(); - break; - case POPUP_ITEM_INFO: - itemInfo(m_popupItem); - break; - } -} - ///////////////////////////// read XML ////////////////////////////// // read an xml file and check for errors bool UserMenuTree::readXml(const QString &filename) { KILE_DEBUG_MAIN << "read xml file " << filename; QDomDocument doc("UserMenu"); QFile file(filename); if ( !file.open(QFile::ReadOnly | QFile::Text) ) { KMessageBox::error(this, i18n("File '%1' does not exist.", filename)); return false; } if ( !doc.setContent( &file ) ) { file.close(); return false; } file.close(); KILE_DEBUG_MAIN << "parse xml ..."; blockSignals(true); // clear menutree clear(); // read toplevelitems QDomElement root = doc.documentElement(); QDomElement e = root.firstChildElement(); while ( !e.isNull()) { QString tag = e.tagName(); UserMenuItem *item = Q_NULLPTR; if ( tag == "submenu" ) { item = readXmlSubmenu(e); } else if ( tag == "separator" ) { item = readXmlSeparator(); } else { /* if ( tag == "menu" ) */ item = readXmlMenuentry(e); } if ( item ) { addTopLevelItem(item); } e = e.nextSiblingElement(); } // the xml menu is built, now check for errors setErrorCodes(); // polish menutree expandAll(); if ( topLevelItemCount() > 0 ) { setCurrentItem( topLevelItem(0) ); } blockSignals(false); return true; } // a separator tag was found UserMenuItem *UserMenuTree::readXmlSeparator() { return new UserMenuItem(UserMenuData::Separator, QString()); } // read tags for a submenu UserMenuItem *UserMenuTree::readXmlSubmenu(const QDomElement &element) { UserMenuItem *submenuitem = new UserMenuItem(UserMenuData::Submenu, QString()) ; QString title; if ( element.hasChildNodes() ) { QDomElement e = element.firstChildElement(); while ( !e.isNull()) { UserMenuItem *item = Q_NULLPTR; QString tag = e.tagName(); if ( tag == "title" ) { title = e.text(); } else if ( tag == "submenu" ) { item = readXmlSubmenu(e); } else if ( tag == "separator" ) { item = readXmlSeparator(); } else { /* if ( tag == "menu" ) */ item = readXmlMenuentry(e); } submenuitem->setMenutitle(title); submenuitem->setText(0,title); if ( item ) { submenuitem->addChild(item); } e = e.nextSiblingElement(); } } return submenuitem; } // read tags for a standard menu item UserMenuItem *UserMenuTree::readXmlMenuentry(const QDomElement &element) { QString menutypename = element.attribute("type"); UserMenuData::MenuType menutype = UserMenuData::xmlMenuType(menutypename); UserMenuItem *menuentryitem = new UserMenuItem(menutype, QString()) ; // default values QString title; QString plaintext; QString filename; QString parameter; QString icon; QString shortcut; bool needsSelection = false; bool useContextMenu = false; bool replaceSelection = false; bool selectInsertion = false; bool insertOutput = false; // read values if ( element.hasChildNodes() ) { QDomElement e = element.firstChildElement(); while ( !e.isNull()) { QString tag = e.tagName(); QString text = e.text(); int index = UserMenuData::xmlMenuTag(tag); switch (index) { case UserMenuData::XML_TITLE: title = text; break; case UserMenuData::XML_PLAINTEXT: plaintext = text; break; case UserMenuData::XML_FILENAME: filename = text; break; case UserMenuData::XML_PARAMETER: parameter = text; break; case UserMenuData::XML_ICON: icon = text; break; case UserMenuData::XML_SHORTCUT: shortcut = text; break; case UserMenuData::XML_NEEDSSELECTION: needsSelection = str2bool(text); break; case UserMenuData::XML_USECONTEXTMENU: useContextMenu = str2bool(text); break; case UserMenuData::XML_REPLACESELECTION: replaceSelection = str2bool(text); break; case UserMenuData::XML_SELECTINSERTION: selectInsertion = str2bool(text); break; case UserMenuData::XML_INSERTOUTPUT: insertOutput = str2bool(text); break; } e = e.nextSiblingElement(); } // save values menuentryitem->setMenutitle(title); // add code newline plaintext = UserMenuData::decodeLineFeed(plaintext); menuentryitem->setPlaintext(plaintext); menuentryitem->setFilename(filename); menuentryitem->setParameter(parameter); if ( !icon.isEmpty() ) { menuentryitem->setMenuicon(icon); menuentryitem->setIcon(0,QIcon::fromTheme(icon)); } if ( !shortcut.isEmpty() ) { QKeySequence seq = QKeySequence::fromString(shortcut,QKeySequence::PortableText); shortcut = seq.toString(QKeySequence::NativeText); menuentryitem->setShortcut(shortcut); menuentryitem->setText(1,shortcut); } menuentryitem->setNeedsSelection(needsSelection); menuentryitem->setUseContextMenu(useContextMenu); menuentryitem->setReplaceSelection(replaceSelection); menuentryitem->setSelectInsertion(selectInsertion); menuentryitem->setInsertOutput(insertOutput); menuentryitem->setText(0,title); } return menuentryitem; } ///////////////////////////// write XML ////////////////////////////// bool UserMenuTree::writeXml(const QString &filename) { KILE_DEBUG_MAIN << "write xml file " << filename; QFile file(filename); if ( !file.open(QFile::WriteOnly | QFile::Text) ) { KMessageBox::error(this, i18n("File '%1' could not be opened to save the usermenu file.", filename)); return false; } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.setAutoFormattingIndent(2) ; xmlWriter.writeStartDocument(); xmlWriter.writeStartElement("UserMenu"); for (int i = 0; i < topLevelItemCount(); ++i) { writeXmlItem(&xmlWriter, dynamic_cast(topLevelItem(i)) ); } xmlWriter.writeEndDocument(); file.close(); return true; } void UserMenuTree::writeXmlItem(QXmlStreamWriter *xml, UserMenuItem *item) { switch (item->menutype()) { case UserMenuData::Separator: writeXmlSeparator(xml); break; case UserMenuData::Submenu: writeXmlSubmenu(xml,item); break; default: writeXmlMenuentry(xml,item); break; } } // write xml tags for a standard menu item void UserMenuTree::writeXmlMenuentry(QXmlStreamWriter *xml, UserMenuItem *item) { int menutype = item->menutype(); QString menutypename = UserMenuData::xmlMenuTypeName(menutype); xml->writeStartElement("menu"); xml->writeAttribute("type", menutypename); QString menutitle = ( item->text(0) == EMPTY_MENUENTRY ) ? QString() : item->text(0); xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_TITLE),menutitle); if ( menutype == UserMenuData::Text ) { QString plaintext = item->plaintext(); if ( !plaintext.isEmpty() ) { // encode newline characters plaintext = UserMenuData::encodeLineFeed(plaintext); xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_PLAINTEXT), plaintext); } } else { /* if ( menutype!=UserMenuData::FileContent || menutype==UserMenuData:Program) */ // both types use a filename QString filename = item->filename(); if ( !filename.isEmpty() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_FILENAME), filename); // but UserMenuItem::Program may have an additional parameter if ( menutype == UserMenuData::Program) { QString parameter = item->parameter(); if ( !parameter.isEmpty() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_PARAMETER), parameter); } } } } QString icon = item->menuicon(); if ( !icon.isEmpty() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_ICON),icon); } QKeySequence seq = QKeySequence::fromString( item->shortcut(), QKeySequence::NativeText ); if ( !seq.isEmpty() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_SHORTCUT), seq.toString(QKeySequence::PortableText)); } if ( item->needsSelection() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_NEEDSSELECTION), "true"); } if ( item->useContextMenu() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_USECONTEXTMENU), "true"); } if ( item->replaceSelection() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_REPLACESELECTION), "true"); } if ( item->selectInsertion() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_SELECTINSERTION), "true"); } if ( item->insertOutput() ) { xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_INSERTOUTPUT), "true"); } xml->writeEndElement(); } // write xml tags for a submenu void UserMenuTree::writeXmlSubmenu(QXmlStreamWriter *xml, UserMenuItem *item) { xml->writeStartElement("submenu"); QString menutitle = item->text(0); if ( menutitle == EMPTY_MENUENTRY ) { menutitle.clear(); } else if ( menutitle.right(LENGTH_SUBSTITUTE) == EMPTY_SUBMENU ) { menutitle = menutitle.left(menutitle.length()-LENGTH_SUBSTITUTE); } xml->writeTextElement(UserMenuData::xmlMenuTagName(UserMenuData::XML_TITLE),menutitle); for ( int i=0; ichildCount(); ++i ) { writeXmlItem(xml, dynamic_cast(item->child(i)) ); } xml->writeEndElement(); } // write xml tag for a separator void UserMenuTree::writeXmlSeparator(QXmlStreamWriter *xml) { xml->writeStartElement("separator"); xml->writeEndElement(); } ///////////////////////////// check menutree and set error codes ////////////////////////////// // the complete menutree was build, now check for errors // - empty menutitles // - useless submenus without children // - empty filenames, not existing or not executable files void UserMenuTree::setErrorCodes() { KILE_DEBUG_MAIN << "check menutree for errors and set error codes ..."; for (int i = 0; i < topLevelItemCount(); ++i) { UserMenuItem *item = dynamic_cast(topLevelItem(i)); UserMenuData::MenuType type = item->menutype(); bool executable = ( type==UserMenuData::Program && isItemExecutable(item->filename()) ); item->setModelData(executable); if ( type != UserMenuData::Separator ) { checkMenuTitle(item); } if ( type == UserMenuData::Submenu ) { checkSubmenu(item); } } } void UserMenuTree::checkMenuTitle(UserMenuItem *item) { if ( item->menutitle().isEmpty() ) { item->setText(0,EMPTY_MENUENTRY); KILE_DEBUG_MAIN << "empty menutitle changed to " << EMPTY_MENUENTRY; } } void UserMenuTree::checkSubmenu(UserMenuItem *item) { QString menutitle = item->menutitle(); int children = item->childCount(); if ( menutitle.isEmpty() ) { menutitle = EMPTY_MENUENTRY; } else if ( children == 0 ) { menutitle += EMPTY_SUBMENU; } item->setText(0,menutitle); for ( int i=0; i(item->child(i)); child->setModelData(); UserMenuData::MenuType type = child->menutype(); if ( type != UserMenuData::Separator ) { checkMenuTitle(child); } if ( type == UserMenuData::Submenu ) { checkSubmenu(child); } } } ///////////////////////////// check menutree ////////////////////////////// // check for errors (true=no errors) bool UserMenuTree::errorCheck() { KILE_DEBUG_MAIN << "check menutree for errors ..."; for (int i = 0; i < topLevelItemCount(); ++i) { UserMenuItem *item = dynamic_cast(topLevelItem(i)); UserMenuData::MenuType type = item->menutype(); if ( type != UserMenuData::Separator ) { if ( item->data(0,Qt::UserRole+2).toInt() != UserMenuItem::MODEL_ERROR_NONE ) { return false; } } if ( type == UserMenuData::Submenu ) { if ( checkSubmenuError(item) == false ) { return false; } } } return true; } bool UserMenuTree::checkSubmenuError(UserMenuItem *item) { int children = item->childCount(); for ( int i=0; i(item->child(i)); UserMenuData::MenuType type = child->menutype(); if ( type != UserMenuData::Separator ) { if ( child->data(0,Qt::UserRole+2).toInt() != UserMenuItem::MODEL_ERROR_NONE ) { return false; } } if ( type == UserMenuData::Submenu ) { if ( checkSubmenuError(child) == false ) { return false; } } } return true; } ///////////////////////////// tree ops ////////////////////////////// // insert a standard menu item bool UserMenuTree::insertMenuItem(QTreeWidgetItem *current, bool below) { QString menulabel = getMenuTitle(i18n("Please enter a label for this menu item:")); if ( menulabel.isEmpty() ) { return false; } if ( below ) { insertMenuItemBelow(current,UserMenuData::Text,menulabel); } else { insertMenuItemAbove(current,UserMenuData::Text,menulabel); } return true; } // insert a submenu item bool UserMenuTree::insertSubmenu(QTreeWidgetItem *current, bool below) { QString menulabel = getMenuTitle(i18n("Please enter a label for this submenu:")); if ( menulabel.isEmpty() ) { return false; } if ( below ) { insertMenuItemBelow(current,UserMenuData::Submenu,menulabel); } else { insertMenuItemAbove(current,UserMenuData::Submenu,menulabel); } return true; } // insert a separator item bool UserMenuTree::insertSeparator(QTreeWidgetItem *current, bool below) { if(below) { insertMenuItemBelow(current,UserMenuData::Separator, QString()); } else { insertMenuItemAbove(current,UserMenuData::Separator, QString()); } return true; } void UserMenuTree::insertMenuItemAbove(QTreeWidgetItem *current, UserMenuData::MenuType type, const QString &menulabel) { QTreeWidgetItem *parent = ( current ) ? current->parent() : Q_NULLPTR; int index = itemIndex(parent,current); UserMenuItem *item = new UserMenuItem(type,menulabel); insertItem(parent,index,item); item->setText(0,menulabel); setCurrentItem(item); } void UserMenuTree::insertMenuItemBelow(QTreeWidgetItem *current, UserMenuData::MenuType type, const QString &menulabel) { UserMenuItem *item; QTreeWidgetItem *parent = ( current ) ? current->parent() : Q_NULLPTR; if(!parent) { item = new UserMenuItem(this,current,type,menulabel); } else { item = new UserMenuItem(parent,current,type,menulabel); } item->setText(0,menulabel); setCurrentItem(item); } void UserMenuTree::insertIntoSubmenu(QTreeWidgetItem *current, UserMenuData::MenuType type) { QString menulabel; if ( type == UserMenuData::Text || type == UserMenuData::Submenu ) { menulabel = getMenuTitle(i18n("Please enter a label for this entry:")); if ( menulabel.isEmpty() ) { return; } } UserMenuItem *item = new UserMenuItem(type,menulabel); insertItem(current,0,item); setCurrentItem(item); } // delete an item void UserMenuTree::itemDelete(QTreeWidgetItem *current) { int children,index; QTreeWidgetItem *item, *selectitem; QTreeWidgetItem *parent = current->parent(); if(!parent) { children = topLevelItemCount(); index = indexOfTopLevelItem(current); if ( index < children-1 ) { selectitem = topLevelItem(index+1); } else if ( index > 0 ) { selectitem = topLevelItem(index-1); } else { selectitem = Q_NULLPTR; } item = takeTopLevelItem(index); } else { children = parent->childCount(); index = parent->indexOfChild(current); if ( index < children-1 ) { selectitem = parent->child(index+1); } else if ( index > 0 ) { selectitem = parent->child(index-1); } else { selectitem = parent; } item = parent->takeChild(index); } delete item; if(selectitem) { setCurrentItem(selectitem); } } // move an item one position up void UserMenuTree::itemUp() { QTreeWidgetItem *current = currentItem(); UserMenuItem *aboveitem = dynamic_cast(itemAbove(current)); if (!aboveitem) { return; } bool expanded = current->isExpanded(); blockSignals(true); QTreeWidgetItem *aboveparent = aboveitem->parent(); int aboveindex = itemIndex(aboveparent,aboveitem); UserMenuItem *parent = dynamic_cast(current->parent()); int index = itemIndex(parent,current); takeItem(parent,current); if ( parent!=aboveparent && index!=0 ) { aboveindex++; } if ( parent==aboveparent && aboveitem->menutype()==UserMenuData::Submenu ) { insertItem(aboveitem,0,current); } else { insertItem(aboveparent,aboveindex,current); } // update model data of old and new parent, if it has changed UserMenuItem *newparent = dynamic_cast(current->parent()); if ( parent != newparent ) { if ( parent ) { parent->setModelData(); parent->setText(0, parent->updateMenutitle()); } if ( newparent ) { newparent->setModelData(); newparent->setText(0, newparent->updateMenutitle()); } } current->setExpanded(expanded); setCurrentItem(current); blockSignals(false); } // move an item one position down void UserMenuTree::itemDown() { QTreeWidgetItem *current = currentItem(); bool expanded = current->isExpanded(); blockSignals(true); // get all necessary parameter UserMenuItem *parent = dynamic_cast(current->parent()); int index = itemIndex(parent,current); int children = numChildren(parent); // successor exists? if ( index < children-1 ) { UserMenuItem *successor = dynamic_cast( itemAtIndex(parent,index+1) ); takeItem(parent,current); if ( successor->menutype() == UserMenuData::Submenu ) { successor->insertChild(0,current); } else { insertItem(parent,index+1,current); } } else if ( parent ) { QTreeWidgetItem *grandparent = parent->parent(); int parentindex = itemIndex(grandparent,parent); takeItem(parent,current); insertItem(grandparent,parentindex+1,current); } // update model data of old and new parent, if it has changed UserMenuItem *newparent = dynamic_cast(current->parent()); if ( parent != newparent ) { if ( parent ) { parent->setModelData(); parent->setText(0, parent->updateMenutitle()); } if ( newparent ) { newparent->setModelData(); newparent->setText(0, newparent->updateMenutitle()); } } current->setExpanded(expanded); setCurrentItem(current); blockSignals(false); } ////////////////////////////// delete tree ////////////////////////////// // delete the whole menutree void UserMenuTree::deleteMenuTree() { if ( KMessageBox::questionYesNo(this, i18n("Do you really want to clear the complete menutree?") ) == KMessageBox::Yes ) { blockSignals(true); clear(); blockSignals(false); } } ////////////////////////////// info ////////////////////////////// // prepare info for en item with errors void UserMenuTree::itemInfo(UserMenuItem *item) { int error = item->data(0,Qt::UserRole+2).toInt(); QStringList list; if ( error & UserMenuItem::MODEL_ERROR_EMPTY ) { list << i18n("This menuitem has no title."); } if ( error & UserMenuItem::MODEL_ERROR_SUBMENU ) { list << i18n("This submenu item is useless without children."); } if ( error & UserMenuItem::MODEL_ERROR_TEXT ) { list << i18n("This item offers no text to insert."); } if ( error & UserMenuItem::MODEL_ERROR_FILE_EMPTY ) { list << i18n("No file is given for this task."); } if ( error & UserMenuItem::MODEL_ERROR_FILE_EXIST ) { list << i18n("The file for this item does not exist."); } if ( error & UserMenuItem::MODEL_ERROR_FILE_EXECUTABLE ) { list << i18n("The file for this item is not executable."); } QString msg = i18n("

Error:"); if ( list.size() == 1 ) { msg += "

" + list[0] + "

"; } else { msg += "
    "; foreach ( const QString &s, list ) { msg += "
  •  " + s + "
  • "; } msg += "

"; } KMessageBox::information(this, msg, i18n("Menutree Error")); } ////////////////////////////// auxiliary ////////////////////////////// int UserMenuTree::itemIndex(QTreeWidgetItem *parent, QTreeWidgetItem *item) { return ( parent ) ? parent->indexOfChild(item) : indexOfTopLevelItem(item); } QTreeWidgetItem *UserMenuTree::itemAtIndex(QTreeWidgetItem *parent, int index) { return ( parent ) ? parent->child(index) : topLevelItem(index); } int UserMenuTree::numChildren(QTreeWidgetItem *parent) { return ( parent ) ? parent->childCount() : topLevelItemCount(); } void UserMenuTree::insertItem(QTreeWidgetItem *parent, int index, QTreeWidgetItem *item) { if ( parent ) { parent->insertChild(index,item); } else { insertTopLevelItem(index,item); } } void UserMenuTree::takeItem(QTreeWidgetItem *parent, QTreeWidgetItem *item) { if ( parent ) { int index = parent->indexOfChild(item); parent->takeChild(index); } else { int index = indexOfTopLevelItem(item); takeTopLevelItem(index); } } bool UserMenuTree::str2bool(const QString &value) { return ( value == "true" ); } QString UserMenuTree::getMenuTitle(const QString &title) { bool ok; QString value = QInputDialog::getText(this, i18n("Name"), title, QLineEdit::Normal, QString(), &ok); return ( ok ) ? value : QString(); } } diff --git a/src/dialogs/usermenu/usermenutree.h b/src/dialogs/usermenu/usermenutree.h index 6e9c8af7..8b91b792 100644 --- a/src/dialogs/usermenu/usermenutree.h +++ b/src/dialogs/usermenu/usermenutree.h @@ -1,113 +1,100 @@ /*********************************************************************************** Copyright (C) 2011-2012 by Holger Danielsson (holger.danielsson@versanet.de) ***********************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef USERMENUTREE_H #define USERMENUTREE_H #include #include #include #include #include #include namespace KileMenu { class MenuentryDelegate : public QStyledItemDelegate { public: MenuentryDelegate(QObject *parent=0) : QStyledItemDelegate(parent) {} virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override; }; class UserMenuTree : public QTreeWidget { Q_OBJECT public: explicit UserMenuTree(QWidget *parent); ~UserMenuTree() {} bool insertMenuItem(QTreeWidgetItem *current, bool below=true); bool insertSubmenu(QTreeWidgetItem *current, bool below=true); bool insertSeparator(QTreeWidgetItem *current, bool below=true); void itemDelete(QTreeWidgetItem *current); void itemUp(); void itemDown(); void contextMenuRequested(const QPoint &pos); bool readXml(const QString &filename); bool writeXml(const QString &filename); bool errorCheck(); bool isItemExecutable(const QString &filename); bool isEmpty(); -private Q_SLOTS: - void slotPopupActivated(int id); - private: - enum PopupType { POPUP_INSERT_ABOVE=0x00, POPUP_INSERT_BELOW=0x01, - POPUP_SEPARATOR_ABOVE=0x02, POPUP_SEPARATOR_BELOW=0x03, - POPUP_SUBMENU_ABOVE=0x04, POPUP_SUBMENU_BELOW=0x05, - POPUP_INTO_SUBMENU=0x06, POPUP_SEPARATOR_INTO_SUBMENU=0x07, POPUP_SUBMENU_INTO_SUBMENU=0x08, - POPUP_DELETE_ITEM=0x09, POPUP_DELETE_TREE=0x0A, - POPUP_COLLAPSE_ITEM=0x0B, POPUP_EXPAND_ITEM=0x0C, - POPUP_COLLAPSE_TREE=0x0D, POPUP_EXPAND_TREE=0x0E, - POPUP_ITEM_INFO=0x0F - }; - UserMenuItem *m_popupItem; void setErrorCodes(); bool checkSubmenuError(UserMenuItem *item); QStringList m_envPathlist; void initEnvPathlist(); void insertMenuItemAbove(QTreeWidgetItem *current, UserMenuData::MenuType type, const QString &menulabel); void insertMenuItemBelow(QTreeWidgetItem *current, UserMenuData::MenuType type, const QString &menulabel); void insertIntoSubmenu(QTreeWidgetItem *current, UserMenuData::MenuType type); void deleteMenuTree(); int itemIndex(QTreeWidgetItem *parent, QTreeWidgetItem *item); QTreeWidgetItem *itemAtIndex(QTreeWidgetItem *parent, int index); int numChildren(QTreeWidgetItem *parent); void insertItem(QTreeWidgetItem *parent, int index, QTreeWidgetItem *item); void takeItem(QTreeWidgetItem *parent, QTreeWidgetItem *item); UserMenuItem *readXmlSeparator(); UserMenuItem *readXmlSubmenu(const QDomElement &element); UserMenuItem *readXmlMenuentry(const QDomElement &element); void writeXmlItem(QXmlStreamWriter *xml, UserMenuItem *item); void writeXmlMenuentry(QXmlStreamWriter *xml, UserMenuItem *item); void writeXmlSubmenu(QXmlStreamWriter *xml, UserMenuItem *item); void writeXmlSeparator(QXmlStreamWriter *xml); void checkMenuTitle(UserMenuItem *item); void checkSubmenu(UserMenuItem *item); bool str2bool(const QString &value); QString getMenuTitle(const QString &title); void itemInfo(UserMenuItem *item); }; } #endif diff --git a/src/livepreview.h b/src/livepreview.h index cb71315a..4607a18d 100644 --- a/src/livepreview.h +++ b/src/livepreview.h @@ -1,196 +1,195 @@ /******************************************************************************** Copyright (C) 2011-2018 by Michel Ludwig (michel.ludwig@kdemail.net) ********************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef LIVEPREVIEW_H #define LIVEPREVIEW_H #include "documentinfo.h" #include "kileinfo.h" #include "kileproject.h" #include "kiletool.h" #include "editorextension.h" #include "widgets/previewwidget.h" #include #include #include -#include #include #include #include #include #include namespace KileDocument { class TextInfo; } namespace KileTool { class LivePreviewManager : public QObject { Q_OBJECT public: // has to be instatiated after the view manager only! LivePreviewManager(KileInfo *ki, KActionCollection *ac); ~LivePreviewManager(); // live preview won't be run in 'boot up' mode, which is enabled by default void disableBootUpMode(); void readConfig(KConfig *config); void writeConfig(); static void readLivePreviewStatusSettings(KConfigGroup &configGroup, LivePreviewUserStatusHandler *handler); static void writeLivePreviewStatusSettings(KConfigGroup &configGroup, LivePreviewUserStatusHandler *handler); void compilePreview(KileDocument::LaTeXInfo *info, KTextEditor::View *view); void showPreviewCompileIfNecessary(KileDocument::LaTeXInfo *info, KTextEditor::View *view); bool isLivePreviewActive() const; bool isLivePreviewPossible() const; bool isLivePreviewEnabledForCurrentDocument(); void setLivePreviewEnabledForCurrentDocument(bool b); void buildLivePreviewMenu(KConfig *config); QString getPreviewFile() const; inline QUrl getPreviewFileURL() const { return QUrl::fromLocalFile(getPreviewFile()); } Q_SIGNALS: void livePreviewSuccessful(); void livePreviewRunning(); void livePreviewStopped(); // disabled or stopped public Q_SLOTS: void handleTextChanged(KTextEditor::Document *doc); void handleDocumentSavedOrUploaded(KTextEditor::Document *doc, bool savedAs); void handleMasterDocumentChanged(); void recompileLivePreview(); void refreshLivePreview(); void showCursorPositionInDocumentViewer(); private Q_SLOTS: void handleDocumentModificationTimerTimeout(); // TextInfo* object due to the signal 'aboutToBeDestroyed(KileDocument::TextInfo*)' void removeLaTeXInfo(KileDocument::TextInfo *info); void removeProject(KileProject *project); void toolDestroyed(); void toolDone(KileTool::Base *base, int i, bool childToolSpawned); void childToolDone(KileTool::Base *base, int i, bool childToolSpawned); void handleTextViewActivated(KTextEditor::View *view, bool clearPreview = true, bool forceCompilation = false); void handleTextViewClosed(KTextEditor::View *view, bool wasActiveView); void handleDocumentOpened(KileDocument::TextInfo *info); void handleProjectOpened(KileProject *project); void handleProjectItemAdded(KileProject *project, KileProjectItem *item); void handleProjectItemRemoved(KileProject *project, KileProjectItem *item); void handleDocumentSavedAs(KTextEditor::View*, KileDocument::TextInfo*); void handleSpawnedChildTool(KileTool::Base *parent, KileTool::Base *child); void previewForCurrentDocumentActionTriggered(bool b); void livePreviewToolActionTriggered(); private: class PreviewInformation; KileInfo *m_ki; bool m_bootUpMode; QPointer m_previewStatusLed; KToggleAction *m_previewForCurrentDocumentAction; QAction *m_recompileLivePreviewAction; QTimer *m_ledBlinkingTimer, *m_documentChangedTimer; QHash m_runningPathToPreviewPathHash; QHash m_runningPreviewPathToPathHash; QString m_runningPreviewFile; KileDocument::LaTeXInfo *m_runningLaTeXInfo; KTextEditor::View *m_runningTextView; KileProject *m_runningProject; PreviewInformation *m_runningPreviewInformation; QHash m_runningTextHash; PreviewInformation *m_shownPreviewInformation; QHash m_latexInfoToPreviewInformationHash; QHash m_projectToPreviewInformationHash; PreviewInformation *m_masterDocumentPreviewInformation; // all the members required to handle tool actions for live preview QHash m_livePreviewToolToActionHash; QHash m_actionToLivePreviewToolHash; QActionGroup *m_livePreviewToolActionGroup; QLinkedList m_livePreviewToolActionList; PreviewInformation* findPreviewInformation(KileDocument::TextInfo *textInfo, KileProject* *locatedProject = Q_NULLPTR, LivePreviewUserStatusHandler* *userStatusHandler = Q_NULLPTR, LaTeXOutputHandler* *latexOutputHandler = Q_NULLPTR); bool isCurrentDocumentOrProject(KTextEditor::Document *doc); void updatePreviewInformationAfterCompilationFinished(); void displayErrorMessage(const QString &text, bool clearFirst = false); void createActions(KActionCollection *ac); void populateViewerControlToolBar(); void synchronizeViewWithCursor(KileDocument::TextInfo *info, KTextEditor::View *view, const KTextEditor::Cursor& newPosition, bool calledFromCursorPositionChange = false); void stopAndClearPreview(); void showPreviewDisabled(); void showPreviewRunning(); void showPreviewFailed(); void showPreviewSuccessful(); void showPreviewOutOfDate(); void stopLivePreview(); void clearLivePreview(); void deleteAllLivePreviewInformation(); void handleProjectItemAdditionOrRemoval(KileProject *project, KileProjectItem *item); void fillTextHashForMasterDocument(QHash &textHash); void disablePreview(); void clearRunningLivePreviewInformation(); void updateLivePreviewToolActions(LivePreviewUserStatusHandler *statusHandler); void setLivePreviewToolActionsEnabled(bool b); bool ensureDocumentIsOpenInViewer(PreviewInformation *previewInformation, bool *hadToOpen = Q_NULLPTR); void reloadDocumentInViewer(); }; } #endif diff --git a/src/widgets/projectview.cpp b/src/widgets/projectview.cpp index 3e7bca1e..9a4e93cc 100644 --- a/src/widgets/projectview.cpp +++ b/src/widgets/projectview.cpp @@ -1,910 +1,896 @@ /**************************************************************************************** begin : Tue Aug 12 2003 copyright : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) 2006 - 2010 by Michel Ludwig (michel.ludwig@kdemail.net) ****************************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "widgets/projectview.h" #include #include #include #include #include #include #include #include -#include #include #include #include #include #include "kileinfo.h" #include "documentinfo.h" #include "kiledocmanager.h" #include #include const int KPV_ID_OPEN = 0, KPV_ID_SAVE = 1, KPV_ID_CLOSE = 2, KPV_ID_OPTIONS = 3, KPV_ID_ADD = 4, KPV_ID_REMOVE = 5, KPV_ID_BUILDTREE = 6, KPV_ID_ARCHIVE = 7, KPV_ID_ADDFILES = 8, KPV_ID_INCLUDE = 9, KPV_ID_OPENWITH = 10, KPV_ID_OPENALLFILES = 11; namespace KileWidget { /* * ProjectViewItem */ ProjectViewItem::ProjectViewItem(QTreeWidget *parent, KileProjectItem *item, bool ar) : QTreeWidgetItem(parent, QStringList(item->url().fileName())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item) { setArchiveState(ar); } ProjectViewItem::ProjectViewItem(QTreeWidget *parent, QTreeWidgetItem *after, KileProjectItem *item, bool ar) : QTreeWidgetItem(parent, after), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item) { setText(0, item->url().fileName()); setArchiveState(ar); } ProjectViewItem::ProjectViewItem(QTreeWidgetItem *parent, KileProjectItem *item, bool ar) : QTreeWidgetItem(parent, QStringList(item->url().fileName())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item) { setArchiveState(ar); } //use this to create folders ProjectViewItem::ProjectViewItem(QTreeWidgetItem *parent, const QString& name) : QTreeWidgetItem(parent, QStringList(name)), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR) { } //use this to create non-project files ProjectViewItem::ProjectViewItem(QTreeWidget *parent, const QString& name) : QTreeWidgetItem(parent, QStringList(name)), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR) { } ProjectViewItem::ProjectViewItem(QTreeWidget *parent, const KileProject *project) : QTreeWidgetItem(parent, QStringList(project->name())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR) { } ProjectViewItem::~ProjectViewItem() { KILE_DEBUG_MAIN << "DELETING PROJVIEWITEM " << m_url.fileName(); } KileProjectItem* ProjectViewItem::projectItem() { return m_projectItem; } ProjectViewItem* ProjectViewItem::parent() { return dynamic_cast(QTreeWidgetItem::parent()); } ProjectViewItem* ProjectViewItem::firstChild() { return dynamic_cast(QTreeWidgetItem::child(0)); } void ProjectViewItem::setInfo(KileDocument::Info *docinfo) { m_docinfo = docinfo; } KileDocument::Info* ProjectViewItem::getInfo() { return m_docinfo; } void ProjectViewItem::setType(KileType::ProjectView type) { m_type = type; } KileType::ProjectView ProjectViewItem::type() const { return m_type; } void ProjectViewItem::urlChanged(const QUrl &url) { // don't allow empty URLs if(!url.isEmpty()) { setURL(url); setText(0, url.fileName()); } } void ProjectViewItem::nameChanged(const QString & name) { setText(0, name); } void ProjectViewItem::isrootChanged(bool isroot) { KILE_DEBUG_MAIN << "SLOT isrootChanged " << text(0) << " to " << isroot; if(isroot) { setIcon(0, QIcon::fromTheme("masteritem")); } else { if(m_projectItem && m_projectItem->type() == KileProjectItem::ProjectFile) { setIcon(0, QIcon::fromTheme("kile")); } else if(m_projectItem && m_projectItem->type() == KileProjectItem::Bibliography) { setIcon(0, QIcon::fromTheme("viewbib")); } else if(type() == KileType::ProjectItem) { setIcon(0, QIcon::fromTheme("projectitem")); } else { setIcon(0, QIcon::fromTheme("file")); } } } void ProjectViewItem::slotURLChanged(KileDocument::Info*, const QUrl &url) { urlChanged(url); } bool ProjectViewItem::operator<(const QTreeWidgetItem& other) const { try { const ProjectViewItem& otherItem = dynamic_cast(other); // order in the tree: // - first, root items without container (sorted in ascending order) // - then, container items in fixed order (images, packages, other, projectfile) if(otherItem.type() == KileType::Folder) { if(type() != KileType::Folder) { return true; } else { // 'm_folder' is set to a type from 'KileProject::Type' // we want: Image < Package < Other < ProjectFile switch(m_folder) { case KileProjectItem::Image: return true; case KileProjectItem::Package: return (otherItem.m_folder == KileProjectItem::Image) ? false : true; case KileProjectItem::Other: return (otherItem.m_folder == KileProjectItem::Image || otherItem.m_folder == KileProjectItem::Package) ? false : true; case KileProjectItem::ProjectFile: return false; default: // dummy return false; } } } else if(type() == KileType::Folder) { return false; } else { return QTreeWidgetItem::operator<(other); } } catch(std::bad_cast&) { return QTreeWidgetItem::operator<(other); } } void ProjectViewItem::setURL(const QUrl &url) { m_url = url; } const QUrl &ProjectViewItem::url() { return m_url; } void ProjectViewItem::setArchiveState(bool ar) { setText(1, ar ? "*" : ""); } void ProjectViewItem::setFolder(int folder) { m_folder = folder; } int ProjectViewItem::folder() const { return m_folder; } /* * ProjectView */ ProjectView::ProjectView(QWidget *parent, KileInfo *ki) : QTreeWidget(parent), m_ki(ki), m_nProjects(0) { setColumnCount(2); QStringList labelList; labelList << i18n("Files & Projects") << i18n("Include in Archive"); setHeaderLabels(labelList); setColumnWidth(1, 10); setFocusPolicy(Qt::ClickFocus); header()->hide(); header()->setSectionResizeMode(QHeaderView::ResizeToContents); setRootIsDecorated(true); setAllColumnsShowFocus(true); setSelectionMode(QTreeWidget::SingleSelection); connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotClicked(QTreeWidgetItem*))); setAcceptDrops(true); } void ProjectView::slotClicked(QTreeWidgetItem *item) { if(!item) { item = currentItem(); } ProjectViewItem *itm = static_cast(item); if(itm) { if(itm->type() == KileType::File) { emit(fileSelected(itm->url())); } else if(itm->type() == KileType::ProjectItem) { emit(fileSelected(itm->projectItem())); } else if(itm->type() != KileType::Folder) { // don't open project configuration files (*.kilepr) if(itm->url().toLocalFile().right(7) != ".kilepr") { //determine mimeType and open file with preferred application QMimeDatabase db; QMimeType pMime = db.mimeTypeForUrl(itm->url()); if(pMime.name().startsWith(QLatin1String("text/"))) { emit(fileSelected(itm->url())); } else { KRun::runUrl(itm->url(), pMime.name(), this, KRun::RunFlags()); } } } clearSelection(); } } void ProjectView::slotFile(int id) { ProjectViewItem *item = dynamic_cast(currentItem()); if(item) { if(item->type() == KileType::File) { switch(id) { case KPV_ID_OPEN: emit(fileSelected(item->url())); break; case KPV_ID_SAVE: emit(saveURL(item->url())); break; case KPV_ID_ADD: emit(addToProject(item->url())); break; case KPV_ID_CLOSE: emit(closeURL(item->url())); return; //don't access "item" later on default: break; } } } } void ProjectView::slotProjectItem(int id) { ProjectViewItem *item = dynamic_cast(currentItem()); if(item) { if(item->type() == KileType::ProjectItem || item->type() == KileType::ProjectExtra) { switch(id) { case KPV_ID_OPEN: emit(fileSelected(item->projectItem())); break; case KPV_ID_SAVE: emit(saveURL(item->url())); break; case KPV_ID_REMOVE: emit(removeFromProject(item->projectItem())); break; case KPV_ID_INCLUDE : if(item->text(1) == "*") { item->setText(1, ""); } else { item->setText(1, "*"); } emit(toggleArchive(item->projectItem())); break; case KPV_ID_CLOSE: emit(closeURL(item->url())); break; //we can access "item" later as it isn't deleted case KPV_ID_OPENWITH: KRun::displayOpenWithDialog(QList() << item->url(), this); break; default: break; } } } } void ProjectView::slotProject(int id) { ProjectViewItem *item = dynamic_cast(currentItem()); if(item) { if(item->type() == KileType::Project) { switch(id) { case KPV_ID_BUILDTREE: emit(buildProjectTree(item->url())); break; case KPV_ID_OPTIONS: emit(projectOptions(item->url())); break; case KPV_ID_CLOSE: emit(closeProject(item->url())); return; //don't access "item" later on case KPV_ID_ARCHIVE: emit(projectArchive(item->url())); break; case KPV_ID_ADDFILES: emit(addFiles(item->url())); break; case KPV_ID_OPENALLFILES: emit(openAllFiles(item->url())); break; default: break; } } } } void ProjectView::slotRun(int id) { ProjectViewItem *itm = dynamic_cast(currentItem()); if(!itm) { return; } if(id == 0) { KRun::displayOpenWithDialog(QList() << itm->url(), this); } else { KRun::runService(*m_offerList[id-1], QList() << itm->url(), this); } itm->setSelected(false); } void ProjectView::makeTheConnection(ProjectViewItem *item, KileDocument::TextInfo *textInfo) { KILE_DEBUG_MAIN << "\tmakeTheConnection " << item->text(0); if (item->type() == KileType::Project) { KileProject *project = m_ki->docManager()->projectFor(item->url()); if (!project) { qWarning() << "makeTheConnection COULD NOT FIND AN PROJECT OBJECT FOR " << item->url().toLocalFile(); } else { connect(project, SIGNAL(nameChanged(QString)), item, SLOT(nameChanged(QString))); } } else { if(!textInfo) { textInfo = m_ki->docManager()->textInfoFor(item->url().toLocalFile()); if(!textInfo) { KILE_DEBUG_MAIN << "\tmakeTheConnection COULD NOT FIND A DOCINFO"; return; } } item->setInfo(textInfo); connect(textInfo, SIGNAL(urlChanged(KileDocument::Info*,QUrl)), item, SLOT(slotURLChanged(KileDocument::Info*,QUrl))); connect(textInfo, SIGNAL(isrootChanged(bool)), item, SLOT(isrootChanged(bool))); //set the pixmap item->isrootChanged(textInfo->isLaTeXRoot()); } } ProjectViewItem* ProjectView::folder(const KileProjectItem *pi, ProjectViewItem *item) { ProjectViewItem *parent = parentFor(pi, item); if(!parent) { qCritical() << "no parent for " << pi->url().toLocalFile(); return Q_NULLPTR; } // we have already found the parent folder if(parent->type() == KileType::Folder) { return parent; } // we are looking at the children, if there is an existing folder for this type ProjectViewItem *folder; // determine the foldername for this type QString foldername; switch(pi->type()) { case (KileProjectItem::ProjectFile): foldername = i18n("Project File"); break; case (KileProjectItem::Package): foldername = i18n("Packages"); break; case (KileProjectItem::Image): foldername = i18n("Images"); break; case (KileProjectItem::Bibliography): foldername = i18n("Bibliography"); break; case (KileProjectItem::Other): default : foldername = i18n("Other"); break; } // if there already a folder for this type on this level? bool found = false; QTreeWidgetItemIterator it(parent); ++it; // skip 'parent' while(*it) { folder = dynamic_cast(*it); if(folder && folder->text(0) == foldername) { found = true; break; } ++it; } // if no folder was found, we must create a new one if(!found) { folder = new ProjectViewItem(parent, foldername); KILE_DEBUG_MAIN << "new folder: parent=" << parent->url().url() << ", foldername=" << foldername; folder->setFolder(pi->type()); folder->setType(KileType::Folder); } return folder; } void ProjectView::add(const KileProject *project) { ProjectViewItem *parent = new ProjectViewItem(this, project); parent->setType(KileType::Project); parent->setURL(project->url()); parent->setExpanded(true); parent->setIcon(0, QIcon::fromTheme("relation")); makeTheConnection(parent); //ProjectViewItem *nonsrc = new ProjectViewItem(parent, i18n("non-source")); //parent->setNonSrc(nonsrc); refreshProjectTree(project); ++m_nProjects; } ProjectViewItem* ProjectView::projectViewItemFor(const QUrl &url) { ProjectViewItem *item = Q_NULLPTR; //find project view item QTreeWidgetItemIterator it(this); while(*it) { item = dynamic_cast(*it); if(item && (item->type() == KileType::Project) && (item->url() == url)) { break; } ++it; } return item; } ProjectViewItem* ProjectView::itemFor(const QUrl &url) { ProjectViewItem *item = Q_NULLPTR; QTreeWidgetItemIterator it(this); while(*it) { item = static_cast(*it); if (item->url() == url) { break; } ++it; } return item; } ProjectViewItem* ProjectView::parentFor(const KileProjectItem *projitem, ProjectViewItem *projvi) { //find parent projectviewitem of projitem KileProjectItem *parpi = projitem->parent(); ProjectViewItem *parpvi = projvi, *vi; if (parpi) { //find parent viewitem that has an URL parpi->url() QTreeWidgetItemIterator it(projvi); KILE_DEBUG_MAIN << "\tlooking for " << parpi->url().toLocalFile(); while(*it) { vi = static_cast(*it); KILE_DEBUG_MAIN << "\t\t" << vi->url().toLocalFile(); if (vi->url() == parpi->url()) { parpvi = vi; KILE_DEBUG_MAIN << "\t\tfound" <type(); QTreeWidgetItemIterator it(projvi); ++it; // skip projvi while(*it) { ProjectViewItem *child = dynamic_cast(*it); if(child && (child->type() == KileType::Folder) && (child->folder() == projitem->type())) { KILE_DEBUG_MAIN << "\t\tfound"; parpvi = child; break; } ++it; } } return (!parpvi) ? projvi : parpvi; } ProjectViewItem* ProjectView::add(KileProjectItem *projitem, ProjectViewItem *projvi /* = Q_NULLPTR */) { KILE_DEBUG_MAIN << "\tprojectitem=" << projitem->path() << " projvi=" << projvi; const KileProject *project = projitem->project(); if (!projvi) { projvi = projectViewItemFor(project->url()); } KILE_DEBUG_MAIN << "\tparent projectviewitem " << projvi->url().fileName(); ProjectViewItem *item = Q_NULLPTR, *parent = Q_NULLPTR; switch (projitem->type()) { case (KileProjectItem::Source): item = new ProjectViewItem(projvi, projitem); item->setType(KileType::ProjectItem); item->setIcon(0, QIcon::fromTheme("projectitem")); break; case (KileProjectItem::Package): parent = folder(projitem, projvi); item = new ProjectViewItem(parent, projitem); item->setType(KileType::ProjectItem); item->setIcon(0, QIcon::fromTheme("projectitem")); break; default: parent = folder(projitem, projvi); item = new ProjectViewItem(parent, projitem); item->setType(KileType::ProjectExtra); if(projitem->type() == KileProjectItem::ProjectFile) { item->setIcon(0, QIcon::fromTheme("kile")); } else if(projitem->type() == KileProjectItem::Bibliography) { item->setIcon(0, QIcon::fromTheme("viewbib")); } else { item->setIcon(0, QIcon::fromTheme("file")); } break; } item->setArchiveState(projitem->archive()); item->setURL(projitem->url()); makeTheConnection(item, projitem->getInfo()); projvi->sortChildren(0, Qt::AscendingOrder); // seems to be necessary to get a correct refreh (Qt 4.4.3) bool expanded = projvi->isExpanded(); projvi->setExpanded(!expanded); projvi->setExpanded(expanded); return item; } void ProjectView::addTree(KileProjectItem *projitem, ProjectViewItem *projvi) { KILE_DEBUG_MAIN << "projitem=" << projitem << "projvi=" << projvi; ProjectViewItem * item = add(projitem, projvi); if(projitem->firstChild()) { addTree(projitem->firstChild(), item); } if (projitem->sibling()) { addTree(projitem->sibling(), projvi); } } void ProjectView::refreshProjectTree(const KileProject *project) { KILE_DEBUG_MAIN << "\tProjectView::refreshProjectTree(" << project->name() << ")"; ProjectViewItem *parent= projectViewItemFor(project->url()); //clean the tree if(parent) { KILE_DEBUG_MAIN << "\tusing parent projectviewitem " << parent->url().fileName(); parent->setFolder(-1); QList children = parent->takeChildren(); for(QList::iterator it = children.begin(); it != children.end(); ++it) { delete(*it); } } else { return; } //create the non-sources dir //ProjectViewItem *nonsrc = new ProjectViewItem(parent, i18n("non-sources")); //parent->setNonSrc(nonsrc); QList list = project->rootItems(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { addTree(*it, parent); } parent->sortChildren(0, Qt::AscendingOrder); // seems to be necessary to get a correct refreh (Qt 4.4.3) bool expanded = parent->isExpanded(); parent->setExpanded(!expanded); parent->setExpanded(expanded); } void ProjectView::add(const QUrl &url) { KILE_DEBUG_MAIN << "\tProjectView::adding item " << url.toLocalFile(); //check if file is already present QTreeWidgetItemIterator it(this); ProjectViewItem *item; while(*it) { item = static_cast(*it); if((item->type() != KileType::Project) && (item->url() == url)) { return; } ++it; } item = new ProjectViewItem(this, url.fileName()); item->setType(KileType::File); item->setURL(url); makeTheConnection(item); } void ProjectView::remove(const KileProject *project) { for(int i = 0; i < topLevelItemCount(); ++i) { ProjectViewItem *item = static_cast(topLevelItem(i)); if(item->url() == project->url()) { item->setParent(Q_NULLPTR); delete item; --m_nProjects; break; } } } /** * Removes a file from the projectview, does not remove project-items. Only files without a project. **/ void ProjectView::remove(const QUrl &url) { for(int i = 0; i < topLevelItemCount(); ++i) { ProjectViewItem *item = dynamic_cast(topLevelItem(i)); if(item && (item->type() == KileType::File) && (item->url() == url)) { item->setParent(Q_NULLPTR); delete item; break; } } } void ProjectView::removeItem(const KileProjectItem *projitem, bool open) { QTreeWidgetItemIterator it(this); ProjectViewItem *item; while(*it) { item = dynamic_cast(*it); if(item && (item->type() == KileType::ProjectItem) && (item->projectItem() == projitem)) { KILE_DEBUG_MAIN << "removing projectviewitem"; static_cast(item->parent())->removeChild(item); delete item; } ++it; } if(open) { item = new ProjectViewItem(this, projitem->url().fileName()); item->setType(KileType::File); item->setURL(projitem->url()); makeTheConnection(item); } } void ProjectView::contextMenuEvent(QContextMenuEvent *event) { - QSignalMapper signalMapper, serviceSignalMapper; QMenu popup; QAction *action = Q_NULLPTR; QTreeWidgetItem* treeWidgetItem = itemAt(event->pos()); if(!treeWidgetItem) { return; } ProjectViewItem *projectViewItem = dynamic_cast(treeWidgetItem); if(!projectViewItem) { return; } if(projectViewItem->type() == KileType::Folder) { return; } bool insertsep = false; bool isKilePrFile = false; if(projectViewItem->type() != KileType::Project && projectViewItem->projectItem() && projectViewItem->projectItem()->project()) { isKilePrFile = projectViewItem->projectItem()->project()->url() == projectViewItem->url(); } if(projectViewItem->type() == KileType::ProjectExtra && !isKilePrFile) { QMenu *servicesMenu = popup.addMenu(QIcon::fromTheme("fork"), i18n("&Open With")); - connect(&serviceSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotRun(int))); QMimeDatabase db; m_offerList = KMimeTypeTrader::self()->query(db.mimeTypeForUrl(projectViewItem->url()).name(), "Application"); for (int i = 0; i < m_offerList.count(); ++i) { action = new QAction(servicesMenu); action->setIcon(QIcon::fromTheme(m_offerList[i]->icon())); action->setText(m_offerList[i]->name()); - connect(action, SIGNAL(triggered()), &serviceSignalMapper, SLOT(map())); - serviceSignalMapper.setMapping(action, i + 1); + connect(action, &QAction::triggered, this, [this, i] { slotRun(i + 1); }); servicesMenu->addAction(action); } servicesMenu->addSeparator(); - action = servicesMenu->addAction(i18n("Other..."), &serviceSignalMapper, SLOT(map())); - serviceSignalMapper.setMapping(action, 0); + servicesMenu->addAction(i18n("Other..."), this, [this] { slotRun(0); }); insertsep = true; } if (projectViewItem->type() == KileType::File || projectViewItem->type() == KileType::ProjectItem) { if(!m_ki->isOpen(projectViewItem->url())) { - action = popup.addAction(QIcon::fromTheme("document-open"), i18n("&Open"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_OPEN); + popup.addAction(QIcon::fromTheme("document-open"), i18n("&Open"), this, [this] { slotProjectItem(KPV_ID_OPEN); }); } else { - action = popup.addAction(QIcon::fromTheme("document-save"), i18n("&Save"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_SAVE); + popup.addAction(QIcon::fromTheme("document-save"), i18n("&Save"), this, [this] { slotProjectItem(KPV_ID_SAVE); }); } insertsep = true; } if(projectViewItem->type() == KileType::File) { if(m_nProjects > 0) { if(insertsep) { popup.addSeparator(); } - action = popup.addAction(QIcon::fromTheme("project_add"), i18n("&Add to Project"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_ADD); + popup.addAction(QIcon::fromTheme("project_add"), i18n("&Add to Project"), this, [this] { slotProjectItem(KPV_ID_ADD); }); insertsep = true; } - connect(&signalMapper, SIGNAL(mapped(int)), this, SLOT(slotFile(int))); } else if(projectViewItem->type() == KileType::ProjectItem || projectViewItem->type() == KileType::ProjectExtra) { KileProjectItem *pi = projectViewItem->projectItem(); if(pi) { if(insertsep) { popup.addSeparator(); } - action = popup.addAction(i18n("&Include in Archive"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_INCLUDE); + action = popup.addAction(i18n("&Include in Archive"), this, [this] { slotProjectItem(KPV_ID_INCLUDE); }); action->setCheckable(true); action->setChecked(pi->archive()); insertsep = true; } if(!isKilePrFile) { if(insertsep) { popup.addSeparator(); } - action = popup.addAction(QIcon::fromTheme("project_remove"),i18n("&Remove From Project"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_REMOVE); + popup.addAction(QIcon::fromTheme("project_remove"),i18n("&Remove From Project"), this, [this] { slotProjectItem(KPV_ID_REMOVE); }); insertsep = true; } - connect(&signalMapper, SIGNAL(mapped(int)), this, SLOT(slotProjectItem(int))); } else if(projectViewItem->type() == KileType::Project) { if(insertsep) { popup.addSeparator(); } - action = popup.addAction(i18n("A&dd Files..."), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_ADDFILES); + popup.addAction(i18n("A&dd Files..."), this, [this] { slotProject(KPV_ID_ADDFILES); }); popup.addSeparator(); - action = popup.addAction(i18n("Open All &Project Files"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_OPENALLFILES); + popup.addAction(i18n("Open All &Project Files"), this, [this] { slotProject(KPV_ID_OPENALLFILES); }); popup.addSeparator(); - action = popup.addAction(QIcon::fromTheme("view-refresh"),i18n("Refresh Project &Tree"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_BUILDTREE); - action = popup.addAction(QIcon::fromTheme("configure"), i18n("Project &Options"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_OPTIONS); - action = popup.addAction(i18n("&Archive"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_ARCHIVE); - connect(&signalMapper, SIGNAL(mapped(int)), this, SLOT(slotProject(int))); + popup.addAction(QIcon::fromTheme("view-refresh"),i18n("Refresh Project &Tree"), this, [this] { slotProject(KPV_ID_BUILDTREE); }); + popup.addAction(QIcon::fromTheme("configure"), i18n("Project &Options"), this, [this] { slotProject(KPV_ID_OPTIONS); }); + popup.addAction(i18n("&Archive"), this, [this] { slotProject(KPV_ID_ARCHIVE); }); insertsep = true; } if((projectViewItem->type() == KileType::File) || (projectViewItem->type() == KileType::ProjectItem) || (projectViewItem->type()== KileType::Project)) { if(insertsep) { popup.addSeparator(); } - action = popup.addAction(QIcon::fromTheme("view-close"), i18n("&Close"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, KPV_ID_CLOSE); + if(projectViewItem->type() == KileType::Project) { + popup.addAction(QIcon::fromTheme("view-close"), i18n("&Close"), this, [this] { slotProject(KPV_ID_CLOSE); }); + } + else { + popup.addAction(QIcon::fromTheme("view-close"), i18n("&Close"), this, [this] { slotProjectItem(KPV_ID_CLOSE); }); + } } popup.exec(event->globalPos()); m_offerList.clear(); } void ProjectView::dragEnterEvent(QDragEnterEvent *event) { if(event->mimeData()->hasUrls()) { // only accept URL drags event->acceptProposedAction(); } } void ProjectView::dragMoveEvent(QDragMoveEvent *event) { if(event->mimeData()->hasUrls()) { // only accept URL drags event->acceptProposedAction(); } } void ProjectView::dropEvent(QDropEvent *event) { m_ki->docManager()->openDroppedURLs(event); } } diff --git a/src/widgets/structurewidget.cpp b/src/widgets/structurewidget.cpp index 39e7b7ac..6170d063 100644 --- a/src/widgets/structurewidget.cpp +++ b/src/widgets/structurewidget.cpp @@ -1,1092 +1,1038 @@ /************************************************************************************************* Copyright (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net 2005-2007 by Holger Danielsson (holger.danielsson@versanet.de) 2008-2016 by Michel Ludwig (michel.ludwig@kdemail.net) *************************************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // 2005-11-02: dani // - cleaning up source (local variables etc.) // - added different QToolTips for each item // - add more types of KilelistViewItems // - KileStruct::Sect and KileStruct::BeginFloat will remember assigned labels, // which are displayed as QToolTips, if these labels are defined in the // same or the next line // - Caption for type KileStruct::BeginFloat are displayed in the title // of this item // - \includegraphics and float environment items are displayed // - if an item has a companion label, you can use the context menu (right mouse) // to insert this label as reference, as a page reference or only the keyword // into the text or copy it to the clipboard. // - graphics files have also a context menu to open them with a special program // 2005-12-08: dani // - make some items like labels, bibitems, graphics and float environments // configurable for the user // 2005-12-16: dani // - add listview item for undefined references // 2007-02-15: dani // - class StructureViewItem gets two new members to // save the real cursor position of the command // 2007-03-12 dani // - use KileDocument::Extensions // 2007-03-17 dani // - remember how document structure is collapsed, when structure view is refreshed // 2007-03-24: dani // - preliminary minimal support for Beamer class // - \begin{frame}...\end{frame} and \frame{...} are shown in the structure view // - if a \frametitle command follows as next LaTeX command, its parameter // is taken to replace the standard title of this entry in the structure view // - \begin{block}...\end{block} is taken as child of a frame // 2007-04-06 dani // - add TODO/FIXME section to structure view #include "widgets/structurewidget.h" #include #include #include #include #include #include #include #include -#include #include #include #include #include #include "documentinfo.h" #include "errorhandler.h" #include "kileconfig.h" #include "kiledebug.h" #include "kiledocmanager.h" #include "kileinfo.h" #include "kileproject.h" #include "kiletool_enums.h" #include "parser/parsermanager.h" #include "widgets/logwidget.h" namespace KileWidget { ////////////////////// StructureViewItem with all info ////////////////////// StructureViewItem::StructureViewItem(QTreeWidgetItem* parent, const QString &title, const QUrl &url, uint line, uint column, int type, int level, uint startline, uint startcol) : QTreeWidgetItem(parent), m_title(title), m_url(url), m_line(line), m_column(column), m_type(type), m_level(level), m_startline(startline), m_startcol(startcol) { setItemEntry(); } StructureViewItem::StructureViewItem(QTreeWidget* parent, const QString& label) : QTreeWidgetItem(parent, QStringList(label)), m_title(label), m_url(QUrl()), m_line(0), m_column(0), m_type(KileStruct::None), m_level(0) { setToolTip(0, i18n("Click left to jump to the line. A double click will open\n a text file or a graphics file. When a label is assigned\nto this item, it will be shown when the mouse is over\nthis item. Items for a graphics file or an assigned label\nalso offer a context menu (right mouse button).")); } StructureViewItem::StructureViewItem(const QString& label, QTreeWidgetItem* parent) : QTreeWidgetItem(parent, QStringList(label)), m_title(label), m_url(QUrl()), m_line(0), m_column(0), m_type(KileStruct::None), m_level(0) {} void StructureViewItem::setTitle(const QString &title) { m_title = title; setItemEntry(); } void StructureViewItem::setItemEntry() { setText(0, i18nc("structure view entry: title (line)", "%1 (line %2)", m_title, QString::number(m_line))); setToolTip(0, text(0)); } void StructureViewItem::setLabel(const QString &label) { m_label = label; if(!m_label.isEmpty()) { setToolTip(0, i18n("Label: %1", m_label)); } } ////////////////////// StructureView tree widget ////////////////////// StructureView::StructureView(StructureWidget *stack, KileDocument::Info *docinfo) : QTreeWidget(stack), m_stack(stack), m_docinfo(docinfo) { stack->addWidget(this); setColumnCount(1); QStringList labelList; labelList << i18n("Structure"); setHeaderLabels(labelList); header()->hide(); header()->setSectionResizeMode(QHeaderView::ResizeToContents); setAllColumnsShowFocus(true); setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); //connect(this, SIGNAL(clicked(QListViewItem*)), m_stack, SLOT(slotClicked(QListViewItem*))); connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), m_stack, SLOT(slotDoubleClicked(QTreeWidgetItem*))); connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), m_stack, SLOT(slotClicked(QTreeWidgetItem*))); connect(m_stack, SIGNAL(configChanged()), this, SLOT(slotConfigChanged())); init(); } StructureView::~StructureView() {} void StructureView::init() { QString title = (!m_docinfo) ? i18n("No \"structure data\" to display.") : m_docinfo->url().fileName(); m_root = new StructureViewItem(this, title); if(m_docinfo) { m_root->setURL(m_docinfo->url()); m_root->setExpanded(true); m_root->setIcon(0, QIcon::fromTheme("contents")); connect(m_docinfo, SIGNAL(foundItem(QString,uint,uint,int,int,uint,uint,QString,QString)), this, SLOT(addItem(QString,uint,uint,int,int,uint,uint,QString,QString))); } m_parent[0]=m_parent[1]=m_parent[2]=m_parent[3]=m_parent[4]=m_parent[5]=m_parent[6]=m_root; m_lastType = KileStruct::None; m_lastSectioning = Q_NULLPTR; m_lastFloat = Q_NULLPTR; m_lastFrame = Q_NULLPTR; m_lastFrameEnv = Q_NULLPTR; m_stop = false; m_folders.clear(); m_references.clear(); if(m_docinfo) { m_openStructureLabels = m_docinfo->openStructureLabels(); m_openStructureReferences = m_docinfo->openStructureReferences(); m_openStructureBibitems = m_docinfo->openStructureBibitems(); m_openStructureTodo = m_docinfo->openStructureTodo(); m_showStructureLabels = m_docinfo->showStructureLabels(); } else { m_openStructureLabels = false; m_openStructureReferences = false; m_openStructureBibitems = false; m_openStructureTodo = false; m_showStructureLabels = false; } } void StructureView::updateRoot() { m_root->setURL( m_docinfo->url() ); m_root->setText(0, m_docinfo->url().fileName() ); } void StructureView::cleanUp(bool preserveState/* = true */) { KILE_DEBUG_MAIN << "==void StructureView::cleanUp()========"; if(preserveState) { saveState(); } clear(); if(m_docinfo) { disconnect(m_docinfo, 0, this, 0); } init(); } void StructureView::slotConfigChanged() { QWidget *current = m_stack->currentWidget(); if(!current) { return; } cleanUp(false); m_stack->update(m_docinfo, true); } void StructureView::contextMenuEvent(QContextMenuEvent *event) { m_stack->viewContextMenuEvent(this, event); } void StructureView::saveState() { KILE_DEBUG_MAIN << "===void StructureView::saveState()"; m_openByTitle.clear(); m_openByLine.clear(); m_openByFolders.clear(); QTreeWidgetItemIterator it(this); StructureViewItem *item = Q_NULLPTR; while(*it) { item = dynamic_cast(*it); if(item && item->child(0)) { //we don't accept duplicate entries in the map, remove this item alltogether //and rely on the openByLine map instead if(m_openByTitle.contains(item->title())) { m_openByTitle.remove(item->title()); } else { m_openByTitle[item->title()] = item->isExpanded(); } m_openByLine[item->line()] = item->isExpanded(); } ++it; } if(m_folders.contains("labels")) { m_openByFolders["labels"] = m_folders["labels"]->isExpanded(); } if(m_folders.contains("refs")) { m_openByFolders["refs"] = m_folders["refs"]->isExpanded(); } if(m_folders.contains("bibs")) { m_openByFolders["bibs"] = m_folders["bibs"]->isExpanded(); } if(m_folders.contains("todo")) { m_openByFolders["todo"] = m_folders["todo"]->isExpanded(); } if(m_folders.contains("fixme")) { m_openByFolders["fixme"] = m_folders["fixme"]->isExpanded(); } } bool StructureView::shouldBeOpen(StructureViewItem *item, const QString & folder, int level) { if(!item->parent()) { return true; } if(folder == "labels") { if(m_openByFolders.contains("labels")) { return m_openByFolders["labels"]; } else { return m_openStructureLabels; } } else if(folder == "refs") { if(m_openByFolders.contains("refs")) { return m_openByFolders["refs"]; } else { return m_openStructureReferences; } } else if(folder == "bibs") { if(m_openByFolders.contains("bibs")) { return m_openByFolders["bibs"]; } else { return m_openStructureBibitems; } } else if(folder=="todo" || folder=="fixme") { if(m_openByFolders.contains(folder)) { return m_openByFolders[folder]; } else { return m_openStructureTodo; } } if(m_openByTitle.contains(item->title())) { return m_openByTitle[item->title()]; } else if(m_openByLine.contains(item->line())) { return m_openByLine[item->line()]; //TODO check surrounding lines as well } else { return ((folder == "root") && level <= m_stack->level()); } } StructureViewItem* StructureView::createFolder(const QString &folder) { StructureViewItem *fldr = new StructureViewItem(folder); // add it as a top-level child m_root->insertChild(0, fldr); fldr->setExpanded(false); if(folder == "labels") { fldr->setText(0, i18n("Labels")); fldr->setIcon(0, QIcon::fromTheme("label")); } else if(folder == "bibs") { fldr->setText(0, i18n("BibTeX References")); fldr->setIcon(0, QIcon::fromTheme("viewbib")); } else if(folder == "refs") { fldr->setText(0, i18n("Undefined References")); fldr->setIcon(0, QIcon::fromTheme("dialog-error")); } else if(folder == "todo") { fldr->setText(0, i18n("TODO")); fldr->setIcon(0, QIcon::fromTheme("bookmarks")); } else if(folder == "fixme") { fldr->setText(0, i18n("FIXME")); fldr->setIcon(0, QIcon::fromTheme("bookmarks")); } m_folders[folder] = fldr; return m_folders[folder]; } StructureViewItem* StructureView::folder(const QString &folder) { StructureViewItem *item = m_folders[folder]; if(!item) { item = createFolder(folder); } return item; } void StructureView::activate() { if(m_stack->indexOf(this) >= 0) { m_stack->setCurrentWidget(this); } } StructureViewItem *StructureView::parentFor(int lev, const QString & fldr) { StructureViewItem *par = Q_NULLPTR; if(fldr == "root") { switch(lev) { case KileStruct::Object: case KileStruct::File: par = (!m_lastSectioning) ? m_root : m_lastSectioning; break; case 0: case 1: par = m_root; break; default: par = m_parent[lev - 2]; break; } } else { par = folder(fldr); } return par; } ////////////////////// add a new item to the tree widget ////////////////////// /* some items have a special action: - KileStruct::Sect: The new item is saved in m_lastSectioning, so that all following entries can be inserted as children. \part will drop back to level 0 of the Listview, all other sectioning commands will be children of the last sectioning item. If a \label command follows in the same or the next line, it is assigned to this item. - KileStruct::BeginFloat: The new item is saved in m_lastFloat. If a \caption command follows before the floating environment is closed, it is inserted into the title of this item. If a \label command follows, it is assigned to this float item. - KileStruct::EndFloat Reset m_lastFloat to Q_NULLPTR to close this environment. No more \caption or \label commands are assigned to this float after this. - KileStruct::Caption If a float environment is opened, the caption is assigned to the float item. A caption item has hidden attribute, so that no other action is performed and function addItem() will return immediately. - KileStruct::Label If we are inside a float, this label is assigned to this environment. If the last type was a sectioning command on the current line or the line before, the label is assigned to this sectioning item. Assigning means that a popup menu will open, when the mouse is over this item. - KileStruct::BeamerBeginFrame The new item is saved in m_lastFrameEnv. If a \frametitle command follows before the frame environment is closed, it is inserted into the title of this item. If a \label command follows, it is assigned to this float item. - KileStruct::BeamerEndFrame Reset m_lastFloatEnv to Q_NULLPTR to close this environment. No more \frametitle or \label commands are assigned to this frame after this. - KileStruct::BeamerBeginBlock Inside a beamer frame this environment is taken as child of this frame - KileStruct::BeamerFrame The new item is saved in m_lastFrame. If a \frametitle command follows immediately as next command, it is inserted into the title of this item. */ void StructureView::addItem(const QString &title, uint line, uint column, int type, int lev, uint startline, uint startcol, const QString &pix, const QString &fldr /* = "root" */) { // KILE_DEBUG_MAIN << "\t\taddItem: " << title << ", with type " << type; if(m_stop) { return; } // some types need a special action if(type == KileStruct::Reference) { m_references.prepend(KileReferenceData(title, line, column)); } else if(type==KileStruct::Caption && m_lastFloat) { QString floattitle = m_lastFloat->title(); if(floattitle == "figure" || floattitle == "table") { m_lastFloat->setTitle(floattitle+": "+title); } } else if(type == KileStruct::EndFloat) { m_lastFloat = Q_NULLPTR; } else if(type == KileStruct::BeamerFrametitle) { if(m_lastFrameEnv) { m_lastFrameEnv->setTitle(title); } else if(m_lastFrame) { m_lastFrame->setTitle(title); } } else if(type == KileStruct::BeamerEndFrame) { m_lastFrameEnv = Q_NULLPTR; } m_lastFrame = Q_NULLPTR; // that's all for hidden types: we must immediately return if(lev == KileStruct::Hidden) { //KILE_DEBUG_MAIN << "\t\thidden item: not created"; return; } //KILE_DEBUG_MAIN << "\t\tcreate new item"; // check if we have to update a label before loosing this item if(type==KileStruct::Label) { if(m_lastFloat) { m_lastFloat->setLabel(title); } else if(m_lastType == KileStruct::Sect) { // check if this is a follow up label for the last sectioning item if(m_lastSectioning && (m_lastLine == line-1 || m_lastLine==line)) { m_lastSectioning->setLabel(title); } } else if(m_lastType == KileStruct::BeamerBeginFrame && m_lastFrameEnv) { m_lastFrameEnv->setLabel(title); } if(!m_showStructureLabels) { // if we don't want to have it displayed return here return; } } // remember current type and line for the next call of addItem() m_lastType = type; m_lastLine = line; //find the parent for the new element StructureViewItem *parentItem = (type == KileStruct::BeamerBeginBlock && m_lastFrameEnv) ? m_lastFrameEnv : parentFor(lev, fldr); if(!parentItem) { KMessageBox::error(m_stack->info()->mainWindow(), i18n("Cannot create a list view item: no parent found.")); return; } // create a new item StructureViewItem *newChild = new StructureViewItem(parentItem, title, m_docinfo->url(), line, column, type, lev, startline, startcol); if(!pix.isEmpty()) { newChild->setIcon(0, QIcon::fromTheme(pix)); } //m_stop = true; //if the level is not greater than the defaultLevel //open the parentItem to make this item visible parentItem->setExpanded(shouldBeOpen(parentItem, fldr, lev)); //update the m_parent levels, such that section etc. get inserted at the correct level //m_current = newChild; if(lev > 0) { m_parent[lev - 1] = newChild; for(int l = lev; l < 7; ++l) { m_parent[l] = newChild; } } else if(lev == 0) { m_lastSectioning = Q_NULLPTR; for(int l = 0; l < 7; ++l) { m_parent[l] = m_root; } } // check if we have to remember the new item for setting a label or caption if(type == KileStruct::Sect) { m_lastSectioning = newChild; } else if(type == KileStruct::BeginFloat) { m_lastFloat = newChild; } else if(type == KileStruct::BeamerBeginFrame) { m_lastFrameEnv = newChild; } else if(type == KileStruct::BeamerFrame) { m_lastFrame = newChild; } } void StructureView::showReferences(KileInfo *ki) { // remove old listview item for references, if it exists if(m_folders.contains("refs")) { StructureViewItem *refitem = m_folders["refs"]; m_root->removeChild(refitem); delete refitem; m_folders.remove("refs"); } //KILE_DEBUG_MAIN << "==void StructureView::showReferences()========"; //KILE_DEBUG_MAIN << "\tfound " << m_references.count() << " references"; if(m_references.count() == 0) { return; } // read list with all labels QStringList list = ki->allLabels(); //KILE_DEBUG_MAIN << "\tfound " << list.count() << " labels"; QMap labelmap; for (QStringList::const_iterator itmap = list.constBegin(); itmap != list.constEnd(); ++itmap) { labelmap[(*itmap)] = true; } // now check if there are unsolved references for (QList::const_iterator it = m_references.constBegin(); it!=m_references.constEnd(); ++it) { if(!labelmap.contains((*it).name())) { StructureViewItem *refitem = folder("refs"); refitem->setExpanded(shouldBeOpen(refitem, "refs", 0)); new StructureViewItem(refitem, (*it).name(), m_docinfo->url(), (*it).line(), (*it).column(), KileStruct::Reference, KileStruct::NotSpecified, 0, 0); } } } ////////////////////// StructureWidget: QWidgetStack ////////////////////// StructureWidget::StructureWidget(KileInfo *ki, QWidget * parent, const char* name) : QStackedWidget(parent), m_ki(ki), m_docinfo(Q_NULLPTR), m_showingContextMenu(Q_NULLPTR) { setObjectName(name); KILE_DEBUG_MAIN << "==KileWidget::StructureWidget::StructureWidget()==========="; setLineWidth(0); setMidLineWidth(0); setContentsMargins(0, 0, 0, 0); setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); m_default = new StructureView(this, Q_NULLPTR); m_default->activate(); connect(m_ki->parserManager(), SIGNAL(documentParsingStarted()), this, SLOT(handleDocumentParsingStarted())); connect(m_ki->parserManager(), SIGNAL(documentParsingComplete()), this, SLOT(handleDocumentParsingCompleted())); } StructureWidget::~StructureWidget() { } int StructureWidget::level() { return KileConfig::defaultLevel(); } void StructureWidget::addDocumentInfo(KileDocument::Info *docinfo) { StructureView *view = new StructureView(this, docinfo); addWidget(view); m_map.insert(docinfo, view); } void StructureWidget::slotClicked(QTreeWidgetItem * itm) { KILE_DEBUG_MAIN << "\tStructureWidget::slotClicked"; StructureViewItem *item = dynamic_cast(itm); //return if user didn't click on an item if(!item) { return; } if(!(item->type() & KileStruct::None)) { emit(setCursor(item->url(), item->line()-1, item->column())); } else if(!item->parent()) { //root item emit(setCursor(item->url(), 0, 0)); } } void StructureWidget::slotDoubleClicked(QTreeWidgetItem * itm) { KILE_DEBUG_MAIN << "\tStructureWidget::slotDoubleClicked"; StructureViewItem *item = dynamic_cast(itm); static QRegExp suffix("\\.[\\d\\w]*$"); if (!item) { return; } KILE_DEBUG_MAIN <<"item->url() is " << item->url() << ", item->title() is " << item->title(); if(item->type() & (KileStruct::Input | KileStruct::Bibliography | KileStruct::Graphics)) { QString fname = item->title(); if(fname.indexOf(suffix) != -1) { // check if we have a suffix, if not add standard suffixes KILE_DEBUG_MAIN << "Suffix found: " << suffix.cap(0); } else { // filename in structureview entry has no extension: this shouldn't happen anymore, // because all have got one in function updateStruct(). But who knows? if(item->type() == KileStruct::Input) { fname += m_ki->extensions()->latexDocumentDefault(); } else if(item->type() == KileStruct::Bibliography) { fname += m_ki->extensions()->bibtexDefault(); } else if(item->type() == KileStruct::Graphics) { KileProjectItem *kiItem = m_ki->docManager()->itemFor(item->url()); KileProject *proj; QString extToAdd; bool fromProject = true; if(kiItem && (proj = kiItem->project())) { extToAdd = proj->defaultGraphicExt(); } if(extToAdd.isEmpty()) { extToAdd = KileConfig::svDefaultGraphicExt(); fromProject = false; } m_ki->errorHandler()->printMessage(KileTool::Info, (fromProject ? i18n("No extension specified for graphic file. Using .%1 from Project settings.", extToAdd) : i18n("No extension specified for graphic file. Using .%1 from global Structure View settings.", extToAdd)), i18n("File extension not specified")); fname += '.' + extToAdd; } else { KILE_DEBUG_MAIN << "Suffixless item with unknown type found"; } } if(QDir::isRelativePath(fname)) { // no absolute path QString fn = m_ki->getCompileName(); fname= QFileInfo(fn).path() + QDir::separator() + fname; } QFileInfo fi(fname); if(fi.isReadable()) { QUrl url = QUrl::fromLocalFile(fname); if(item->type() == KileStruct::Graphics) { QMimeDatabase db; QMimeType pMime = db.mimeTypeForUrl(url); KRun::runUrl(url, pMime.name(), this, KRun::RunFlags()); } else { emit(fileOpen(url, QString())); } } else { QString otherFilename; if(item->type() == KileStruct::Bibliography) { otherFilename = m_ki->checkOtherPaths(fi.path(), fi.fileName(), KileInfo::bibinputs); } else if(item->type() == KileStruct::Input) { otherFilename = m_ki->checkOtherPaths(fi.path(), fi.fileName(), KileInfo::texinputs); } fi.setFile(otherFilename); if(fi.isReadable()) { emit(fileOpen(QUrl::fromLocalFile(otherFilename), QString())); } else { if(KMessageBox::warningYesNo(this, i18n("Cannot find the included file. The file does not exist, is not readable or Kile is unable to determine the correct path to it. The filename causing this error was: %1.\nDo you want to create this file?", fname), i18n("Cannot Find File")) == KMessageBox::Yes) { emit(fileNew(QUrl::fromLocalFile(fname))); } } } } } // all popup items get different id's, so that we can see, what item is activated // - label: 1 - 6 // - sectioning: 10 - 16 // - graphics: 100ff void StructureWidget::viewContextMenuEvent(StructureView *view, QContextMenuEvent *event) { KILE_DEBUG_MAIN << "\tcalled"; - QSignalMapper signalMapper; - connect(&signalMapper, SIGNAL(mapped(int)), this, SLOT(slotPopupActivated(int))); QMenu popup; - QAction *action = Q_NULLPTR; m_showingContextMenu = Q_NULLPTR; m_popupItem = dynamic_cast(view->itemAt(event->pos())); if(!m_popupItem) { KILE_DEBUG_MAIN << "not a pointer to a StructureViewItem object."; return; } bool hasLabel = !(m_popupItem->label().isEmpty()); if(m_popupItem->type() == KileStruct::Sect) { if(hasLabel) { popup.addSection(i18n("Sectioning")); } - action = popup.addAction(i18n("Cu&t"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningCut); - action = popup.addAction(i18n("&Copy"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningCopy); - action = popup.addAction(i18n("&Paste below"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningPaste); + popup.addAction(i18n("Cu&t"), this, [this] { slotPopupSectioning(SectioningCut); }); + popup.addAction(i18n("&Copy"), this, [this] { slotPopupSectioning(SectioningCopy); }); + popup.addAction(i18n("&Paste below"), this, [this] { slotPopupSectioning(SectioningPaste); }); popup.addSeparator(); - action = popup.addAction(i18n("&Select"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningSelect); - action = popup.addAction(i18n("&Delete"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningDelete); + popup.addAction(i18n("&Select"), this, [this] { slotPopupSectioning(SectioningSelect); }); + popup.addAction(i18n("&Delete"), this, [this] { slotPopupSectioning(SectioningDelete); }); popup.addSeparator(); - action = popup.addAction(i18n("C&omment"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningComment); + popup.addAction(i18n("C&omment"), this, [this] { slotPopupSectioning(SectioningComment); }); popup.addSeparator(); - action = popup.addAction(i18n("Run QuickPreview"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningPreview); + popup.addAction(i18n("Run QuickPreview"), this, [this] { slotPopupSectioning(SectioningPreview); }); } else if(m_popupItem->type() == KileStruct::Graphics) { m_popupInfo = m_popupItem->title(); if(!QDir::isAbsolutePath(m_popupInfo)) { QString fn = m_ki->getCompileName(); m_popupInfo = QFileInfo(fn).path() + '/' + m_popupInfo; } QFileInfo fi(m_popupInfo); if(fi.isReadable()) { QUrl url; url.setPath(m_popupInfo); QMimeDatabase db; m_offerList = KMimeTypeTrader::self()->query(db.mimeTypeForUrl(url).name(), "Application"); for(int i = 0; i < m_offerList.count(); ++i) { - action = popup.addAction(QIcon::fromTheme(m_offerList[i]->icon()), m_offerList[i]->name(), - &signalMapper, SLOT(map())); - signalMapper.setMapping(action, i + SectioningGraphicsOfferlist); + popup.addAction(QIcon::fromTheme(m_offerList[i]->icon()), m_offerList[i]->name(), + this, [this, i] { slotPopupGraphics(i + SectioningGraphicsOfferlist); }); } popup.addSeparator(); - action = popup.addAction(i18n("Other..."), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, SectioningGraphicsOther); + popup.addAction(i18n("Other..."), this, [this] { slotPopupGraphics(SectioningGraphicsOther); }); } } if(hasLabel) { popup.addSection(i18n("Insert Label")); - action = popup.addAction(i18n("As &reference"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, 1); - action = popup.addAction(i18n("As &page reference"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, 2); - action = popup.addAction(i18n("Only the &label"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, 3); + popup.addAction(i18n("As &reference"), this, [this] { emit(sendText("\\ref{" + m_popupItem->label() + '}')); }); + popup.addAction(i18n("As &page reference"), this, [this] { emit(sendText("\\pageref{" + m_popupItem->label() + '}')); }); + popup.addAction(i18n("Only the &label"), this, [this] { emit(sendText(m_popupItem->label())); }); popup.addSeparator(); popup.addSection(i18n("Copy Label to Clipboard")); - action = popup.addAction(i18n("As reference"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, 4); - action = popup.addAction(i18n("As page reference"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, 5); - action = popup.addAction(i18n("Only the label"), &signalMapper, SLOT(map())); - signalMapper.setMapping(action, 6); + popup.addAction(i18n("As reference"), this, [this] { QApplication::clipboard()->setText("\\ref{" + m_popupItem->label() + '}'); }); + popup.addAction(i18n("As page reference"), this, [this] { QApplication::clipboard()->setText("\\pageref{" + m_popupItem->label() + '}'); }); + popup.addAction(i18n("Only the label"), this, [this] { QApplication::clipboard()->setText(m_popupItem->label()); }); } if(!popup.isEmpty()) { m_showingContextMenu = &popup; popup.exec(event->globalPos()); m_showingContextMenu = Q_NULLPTR; } } -void StructureWidget::slotPopupActivated(int id) -{ - KILE_DEBUG_MAIN << "id: " << id; - if(id >= 1 && id <= 6) { - slotPopupLabel(id); - } - else if(id >= SectioningCut && id <= SectioningPreview) { - slotPopupSectioning(id); - } - else if(id >= SectioningGraphicsOther && id <= SectioningGraphicsOfferlist + m_offerList.count()) { - slotPopupGraphics(id); - } -} - -// id's 1..6 (already checked) -void StructureWidget::slotPopupLabel(int id) -{ - KILE_DEBUG_MAIN << "\tStructureWidget::slotPopupLabel (" << id << ")"<< endl; - - QString s = m_popupItem->label(); - if(id == 1 || id == 4) { - s = "\\ref{" + s + '}'; - } - else if(id == 2 || id == 5) { - s = "\\pageref{" + s + '}'; - } - - if(id <= 3) { - emit(sendText(s)); - } - else { - QApplication::clipboard()->setText(s); - } -} - // id's 10..16 (already checked) void StructureWidget::slotPopupSectioning(int id) { KILE_DEBUG_MAIN << "\tStructureWidget::slotPopupSectioning (" << id << ")"<< endl; if(m_popupItem->level() >= 1 && m_popupItem->level() <= 7) { emit(sectioningPopup(m_popupItem, id)); } } // id's 100ff (already checked) void StructureWidget::slotPopupGraphics(int id) { KILE_DEBUG_MAIN << "\tStructureWidget::slotPopupGraphics (" << id << ")"<< endl; QUrl url; url.setPath(m_popupInfo); if(id == SectioningGraphicsOther) { KRun::displayOpenWithDialog(QList() << url, this); } else { KRun::runService(*m_offerList[id-SectioningGraphicsOfferlist], QList() << url, this); } } StructureView* StructureWidget::viewFor(KileDocument::Info *info) { if(!info) { return Q_NULLPTR; } if(!viewExistsFor(info)) { m_map.insert(info, new StructureView(this, info)); } return m_map[info]; } bool StructureWidget::viewExistsFor(KileDocument::Info *info) { if(!info) { return false; } else { return m_map.contains(info); } } void StructureWidget::closeDocumentInfo(KileDocument::Info *docinfo) { m_docinfo = Q_NULLPTR; if(m_map.contains(docinfo)) { StructureView *data = m_map[docinfo]; m_map.remove(docinfo); delete data; } if(m_map.isEmpty()) { m_default->activate(); } } void StructureWidget::clear() { QMap::iterator it; QMap::iterator itend(m_map.end()); for (it = m_map.begin(); it != itend; ++it) { if(it.value()) { delete it.value(); } } m_map.clear(); m_docinfo = Q_NULLPTR; m_default->activate(); } void StructureWidget::updateUrl(KileDocument::Info *docinfo) { StructureView *view = viewFor(docinfo); if(view) { view->updateRoot(); } } void StructureWidget::update(KileDocument::Info *docinfo) { update(docinfo, false); } void StructureWidget::update(KileDocument::Info *docinfo, bool forceParsing) { KILE_DEBUG_MAIN << "==KileWidget::StructureWidget::update(" << docinfo << ")============="; if(!docinfo) { m_default->activate(); return; } m_docinfo = docinfo; bool needParsing = forceParsing || m_docinfo->isDirty() || !viewExistsFor(docinfo); //find structview-item for this docinfo StructureView *view = viewFor(m_docinfo); if(!view) { m_default->activate(); return; } if(needParsing) { //need to reparse the doc m_docinfo->updateStruct(); } KILE_DEBUG_MAIN << "activating view"; view->activate(); } void StructureWidget::updateAfterParsing(KileDocument::Info *info, const QLinkedList& items) { KILE_DEBUG_MAIN; StructureView *view = viewFor(info); if(!view) { m_default->activate(); return; } int xtop = view->horizontalScrollBar()->value(); int ytop = view->verticalScrollBar()->value(); // avoid flickering when parsing view->setUpdatesEnabled(false); view->cleanUp(); Q_FOREACH( KileParser::StructureViewItem *item, items) { view->addItem(item->title, item->line, item->column, item->type, item->level, item->startline, item->startcol, item->pix, item->folder); } view->setUpdatesEnabled(true); view->showReferences(m_ki); view->horizontalScrollBar()->setValue(xtop); view->verticalScrollBar()->setValue(ytop); } void StructureWidget::clean(KileDocument::Info *docinfo) { KILE_DEBUG_MAIN << "==void StructureWidget::clean()========"; StructureView *view = viewFor(docinfo); if(view) { view->cleanUp(); } } void StructureWidget::updateReferences(KileDocument::Info *docinfo) { KILE_DEBUG_MAIN << "==void StructureView::updateReferences()========"; StructureView *view = viewFor(docinfo); if(view) { view->showReferences(m_ki); } } ////////////////////// StructureWidget: find sectioning ////////////////////// bool StructureWidget::findSectioning(StructureViewItem *refItem, KTextEditor::Document *doc, int row, int col, bool backwards, bool checkLevel, int §Row, int §Col) { KileDocument::TextInfo *docinfo = m_ki->docManager()->textInfoFor(doc); if(!docinfo) { return false; } if( checkLevel && !refItem ) { // only allow a refItem == Q_NULLPTR if checkLevel is false return false; } bool found = false; int foundRow, foundCol; StructureView *structurelist = viewFor(docinfo); QTreeWidgetItemIterator it(structurelist); while(*it) { StructureViewItem *item = dynamic_cast(*it); if (item && item->type() == KileStruct::Sect && (!checkLevel || item->level() <= refItem->level())) { foundRow = item->startline() - 1; foundCol = item->startcol() - 1; if(backwards) { if(foundRow < row || (foundRow==row && foundCol < col)) { sectRow = foundRow; sectCol = foundCol; found = true; } else { return found; } } else if(!backwards && (foundRow > row || (foundRow == row && foundCol > col))) { sectRow = foundRow; sectCol = foundCol; return true; } } ++it; } return found; } void StructureWidget::handleDocumentParsingStarted() { setEnabled(false); // if a context menu is showing, we better close it // as the StructureViewItems it operates on will be deleted if(m_showingContextMenu) { m_showingContextMenu->close(); } } void StructureWidget::handleDocumentParsingCompleted() { setEnabled(true); } } diff --git a/src/widgets/structurewidget.h b/src/widgets/structurewidget.h index ab3d88c7..d867d1a2 100644 --- a/src/widgets/structurewidget.h +++ b/src/widgets/structurewidget.h @@ -1,269 +1,267 @@ /************************************************************************************************** begin : Sun Dec 28 2003 copyright : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) 2005-2007 by Holger Danielsson (holger.danielsson@versanet.de) 2008-2012 by Michel Ludwig (michel.ludwig@kdemail.net) **************************************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef STRUCTUREWIDGET_H #define STRUCTUREWIDGET_H #include #include #include #include #include #include #include #include "documentinfo.h" #include "parser/latexparser.h" //2007-02-15: dani // - class StructureViewItem not only saves the cursor position of the parameter, // but also the real cursor position of the command class KileInfo; /** * ListView items that can hold some additional information appropriate for the Structure View. The * additional information is: line number, title string. **/ namespace KileWidget { class StructureViewItem : public QTreeWidgetItem { public: StructureViewItem(QTreeWidgetItem *parent, const QString &title, const QUrl &url, uint line, uint m_column, int type, int level, uint startline, uint startcol); StructureViewItem(QTreeWidget *parent, const QString &label); explicit StructureViewItem(const QString &label, QTreeWidgetItem *parent = Q_NULLPTR); /** @returns the title of this element (for a label it return the label), without the (line ...) part **/ const QString& title() const { return m_title; } /** @returns the line number of the structure element. **/ uint line() const { return m_line; } /** @returns the column number of the structure element, right after the { **/ uint column() const { return m_column; } /** @returns the type of element, see @ref KileStruct **/ int type() const { return m_type; } uint startline() const { return m_startline; } uint startcol() const { return m_startcol; } /**@returns the file in which this item was found*/ const QUrl &url() const { return m_url; } void setURL(const QUrl &url) { m_url = url; } int level() const { return m_level; } const QString &label() const { return m_label; } void setTitle(const QString &title); void setLabel(const QString &label); private: QString m_title; QUrl m_url; uint m_line; uint m_column; int m_type, m_level; uint m_startline; uint m_startcol; QString m_label; void setItemEntry(); }; class KileReferenceData { public: KileReferenceData() {} KileReferenceData(const QString &name, uint line, uint column) : m_name(name), m_line(line), m_column(column) {} ~KileReferenceData() {} const QString &name() const { return m_name; } uint line() const { return m_line; } uint column() const { return m_column; } private: QString m_name; uint m_line; uint m_column; }; class StructureWidget; //forward declaration class StructureView : public QTreeWidget { Q_OBJECT public: StructureView(StructureWidget *stack, KileDocument::Info *docinfo); ~StructureView(); void activate(); void cleanUp(bool preserveState = true); void showReferences(KileInfo *ki); QUrl url() const { return m_docinfo->url(); } void updateRoot(); public Q_SLOTS: void addItem(const QString &title, uint line, uint column, int type, int level, uint startline, uint startcol, const QString &pix, const QString &folder = "root"); void slotConfigChanged(); protected: virtual void contextMenuEvent(QContextMenuEvent *event) override; private: StructureViewItem* parentFor(int lev, const QString &fldr); void init(); StructureViewItem* createFolder(const QString &folder); StructureViewItem* folder(const QString &folder); void saveState(); bool shouldBeOpen(StructureViewItem *item, const QString &folder, int level); private: StructureWidget *m_stack; KileDocument::Info *m_docinfo; QMap m_folders; QMap m_openByTitle; QMap m_openByLine; QMap m_openByFolders; StructureViewItem *m_parent[7], *m_root; QList m_references; bool m_openStructureLabels; bool m_openStructureReferences; bool m_openStructureBibitems; bool m_openStructureTodo; bool m_showStructureLabels; int m_lastType; uint m_lastLine; StructureViewItem *m_lastSectioning; StructureViewItem *m_lastFloat; StructureViewItem *m_lastFrame; StructureViewItem *m_lastFrameEnv; bool m_stop; }; class StructureWidget : public QStackedWidget { friend class StructureView; Q_OBJECT public: StructureWidget(KileInfo*, QWidget *parent, const char *name = Q_NULLPTR); ~StructureWidget(); int level(); KileInfo *info() { return m_ki; } bool findSectioning(StructureViewItem *item, KTextEditor::Document *doc, int row, int col, bool backwards, bool checkLevel, int §Row, int §Col); void updateUrl(KileDocument::Info *docinfo); void updateAfterParsing(KileDocument::Info *info, const QLinkedList& items); enum { SectioningCut = 10, SectioningCopy = 11, SectioningPaste = 12, SectioningSelect = 13, SectioningDelete = 14, SectioningComment = 15, SectioningPreview = 16, SectioningGraphicsOther = 100, SectioningGraphicsOfferlist = 101 }; public Q_SLOTS: void slotClicked(QTreeWidgetItem *); void slotDoubleClicked(QTreeWidgetItem *); - void slotPopupActivated(int id); void addDocumentInfo(KileDocument::Info *); void closeDocumentInfo(KileDocument::Info *); void update(KileDocument::Info *); void update(KileDocument::Info *, bool); void clean(KileDocument::Info *); void updateReferences(KileDocument::Info *); /** * Clears the structure widget and empties the map between KileDocument::Info objects and their structure trees (QListViewItem). **/ void clear(); Q_SIGNALS: void sendText(const QString&); void setCursor(const QUrl&, int, int); void fileOpen(const QUrl&, const QString&); void fileNew(const QUrl&); void configChanged(); void sectioningPopup(KileWidget::StructureViewItem *item, int id); protected: void viewContextMenuEvent(StructureView *view, QContextMenuEvent *event); private: KileInfo *m_ki; KileDocument::Info *m_docinfo; QMap m_map; StructureView *m_default; StructureViewItem *m_popupItem; QMenu *m_showingContextMenu; QString m_popupInfo; KService::List m_offerList; StructureView* viewFor(KileDocument::Info *info); bool viewExistsFor(KileDocument::Info *info); - void slotPopupLabel(int id); void slotPopupSectioning(int id); void slotPopupGraphics(int id); private Q_SLOTS: void handleDocumentParsingStarted(); void handleDocumentParsingCompleted(); }; } #endif