diff --git a/src/kile.cpp b/src/kile.cpp index 28dbdf1c..b26d4661 100644 --- a/src/kile.cpp +++ b/src/kile.cpp @@ -1,3061 +1,3060 @@ /**************************************************************************************** Copyright (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) (C) 2007-2018 by Michel Ludwig (michel.ludwig@kdemail.net) (C) 2007 Holger Danielsson (holger.danielsson@versanet.de) (C) 2009 Thomas Braun (thomas.braun@virtuell-zuhause.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. * * * ***************************************************************************/ // 2007-03-12 dani // - use KileDocument::Extensions #include "kile.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "abbreviationmanager.h" #include "configurationmanager.h" #include "documentinfo.h" #include "errorhandler.h" #include "kileactions.h" #include "kiledebug.h" #include "kilestdactions.h" #include "widgets/statusbar.h" #include "dialogs/configurationdialog.h" #include "kileproject.h" #include "widgets/projectview.h" #include "dialogs/projectdialogs.h" #include "kilelyxserver.h" #include "dialogs/findfilesdialog.h" #include "kiletool_enums.h" #include "kiletool.h" #include "kiletoolmanager.h" #include "kilestdtools.h" #include "widgets/outputview.h" #include "widgets/konsolewidget.h" #include "dialogs/quickdocumentdialog.h" #include "dialogs/tabbingdialog.h" #include "widgets/structurewidget.h" #include "convert.h" #include "dialogs/includegraphicsdialog.h" #include "kiledocmanager.h" #include "kileversion.h" #include "kileviewmanager.h" #include "kileconfig.h" #include "dialogs/configcheckerdialog.h" #include "widgets/sidebar.h" #include "dialogs/floatdialog.h" #include "dialogs/mathenvironmentdialog.h" #include "dialogs/tabular/newtabulardialog.h" #include "dialogs/postscriptdialog.h" #include "dialogs/pdf-wizard/pdfdialog.h" #include "latexcmd.h" #include "mainadaptor.h" #include "dialogs/statisticsdialog.h" #include "widgets/scriptsmanagementwidget.h" #include "scriptmanager.h" #include "widgets/previewwidget.h" #include "symbolviewclasses.h" #include "livepreview.h" #include "parser/parsermanager.h" #include "dialogs/usermenu/usermenudialog.h" #include "usermenu/usermenudata.h" #include "usermenu/usermenu.h" #include "utilities.h" #define LOG_TAB 0 #define OUTPUT_TAB 1 #define KONSOLE_TAB 2 #define PREVIEW_TAB 3 /* * Class Kile. */ Kile::Kile(bool allowRestore, QWidget *parent) : KParts::MainWindow(), KileInfo(this), m_toolsToolBar(Q_NULLPTR), // we have to set all of these to null as the constructor m_userHelpActionMenu(Q_NULLPTR), // might return early m_bibTagSettings(Q_NULLPTR), m_compilerActions(Q_NULLPTR), m_viewActions(Q_NULLPTR), m_convertActions(Q_NULLPTR), m_quickActions(Q_NULLPTR), m_bibTagActionMenu(Q_NULLPTR), ModeAction(Q_NULLPTR), WatchFileAction(Q_NULLPTR), m_actionMessageView(Q_NULLPTR), m_actRecentFiles(Q_NULLPTR), m_pFullScreen(Q_NULLPTR), m_sideBar(Q_NULLPTR), m_kileAbbrevView(Q_NULLPTR), m_topWidgetStack(Q_NULLPTR), m_horizontalSplitter(Q_NULLPTR), m_verticalSplitter(Q_NULLPTR), m_toolBox(Q_NULLPTR), m_commandViewToolBox(Q_NULLPTR), m_symbolViewMFUS(Q_NULLPTR), m_symbolViewRelation(Q_NULLPTR), m_symbolViewArrows(Q_NULLPTR), m_symbolViewMiscMath(Q_NULLPTR), m_symbolViewMiscText(Q_NULLPTR), m_symbolViewOperators(Q_NULLPTR), m_symbolViewUser(Q_NULLPTR), m_symbolViewDelimiters(Q_NULLPTR), m_symbolViewGreek(Q_NULLPTR), m_symbolViewSpecial(Q_NULLPTR), m_symbolViewCyrillic(Q_NULLPTR), m_commandView(Q_NULLPTR), m_latexOutputErrorToolBar(Q_NULLPTR), m_buildMenuTopLevel(Q_NULLPTR), m_buildMenuCompile(Q_NULLPTR), m_buildMenuConvert(Q_NULLPTR), m_buildMenuViewer(Q_NULLPTR), m_buildMenuOther(Q_NULLPTR), m_buildMenuQuickPreview(Q_NULLPTR), m_actRecentProjects(Q_NULLPTR), m_lyxserver(Q_NULLPTR) { setObjectName("Kile"); m_config = KSharedConfig::openConfig(); setStandardToolBarMenuEnabled(true); m_singlemode = true; m_viewManager= new KileView::Manager(this, actionCollection(), parent, "KileView::Manager"); viewManager()->setClient(this); // fail gracefully if we cannot instantiate Okular part correctly if(!m_viewManager->viewerPart()) { return; } QSplashScreen splashScreen(QPixmap(QStandardPaths::locate(QStandardPaths::DataLocation, "pics/kile_splash.png")), Qt::WindowStaysOnTopHint); if(KileConfig::showSplashScreen()) { splashScreen.show(); qApp->processEvents(); } m_codeCompletionManager = new KileCodeCompletion::Manager(this, parent); // process events for correctly displaying the splash screen qApp->processEvents(); m_latexCommands = new KileDocument::LatexCommands(m_config.data(), this); // at first (dani) m_edit = new KileDocument::EditorExtension(this); m_help = new KileHelp::Help(m_edit, this); m_errorHandler = new KileErrorHandler(this, this, actionCollection()); m_quickPreview = new KileTool::QuickPreview(this); m_extensions = new KileDocument::Extensions(); m_jScriptManager = new KileScript::Manager(this, m_config.data(), actionCollection(), parent, "KileScript::Manager"); // do initializations first m_bWatchFile = false; setStatusBar(new KileWidget::StatusBar(m_errorHandler, parent)); // process events for correctly displaying the splash screen qApp->processEvents(); connect(viewManager(), &KileView::Manager::currentViewChanged, this, &Kile::newCaption); connect(viewManager(), &KileView::Manager::currentViewChanged, this, [this](QWidget* view) { activateView(view); }); connect(viewManager(), &KileView::Manager::currentViewChanged, this, &Kile::updateModeStatus); connect(viewManager(), &KileView::Manager::updateCaption, this, &Kile::newCaption); connect(viewManager(), &KileView::Manager::updateModeStatus, this, &Kile::updateModeStatus); connect(viewManager(), &KileView::Manager::cursorPositionChanged, this, &Kile::updateStatusBarCursorPosition); connect(viewManager(), &KileView::Manager::viewModeChanged, this, &Kile::updateStatusBarViewMode); connect(viewManager(), &KileView::Manager::informationMessage, this, &Kile::updateStatusBarInformationMessage); connect(viewManager(), &KileView::Manager::selectionChanged, this, &Kile::updateStatusBarSelection); connect(docManager(), &KileDocument::Manager::documentNameChanged, this, &Kile::newCaption); connect(docManager(), &KileDocument::Manager::documentUrlChanged, this, &Kile::newCaption); connect(docManager(), &KileDocument::Manager::documentReadWriteStateChanged, this, &Kile::newCaption); m_topWidgetStack = new QStackedWidget(); m_topWidgetStack->setFocusPolicy(Qt::NoFocus); m_horizontalSplitter = new QSplitter(Qt::Horizontal); setupSideBar(); m_horizontalSplitter->addWidget(m_sideBar); m_verticalSplitter = new QSplitter(Qt::Vertical); m_horizontalSplitter->addWidget(m_verticalSplitter); viewManager()->createTabs(m_verticalSplitter); connect(viewManager(), &KileView::Manager::activateView, this, &Kile::activateView); connect(viewManager(), &KileView::Manager::startQuickPreview, this, &Kile::slotQuickPreview); connect(parserManager(), &KileParser::Manager::documentParsingStarted, this, &Kile::handleDocumentParsingStarted); connect(parserManager(), &KileParser::Manager::documentParsingComplete, this, &Kile::handleDocumentParsingComplete); // process events for correctly displaying the splash screen qApp->processEvents(); setupBottomBar(); m_verticalSplitter->addWidget(m_bottomBar); m_topWidgetStack->addWidget(m_horizontalSplitter); setCentralWidget(m_topWidgetStack); // Parser manager and view manager must be created before the tool manager! m_manager = new KileTool::Manager(this, m_config.data(), m_outputWidget, m_topWidgetStack, 10000, actionCollection()); //FIXME make timeout configurable connect(m_manager, &KileTool::Manager::jumpToFirstError, m_errorHandler, &KileErrorHandler::jumpToFirstError); connect(m_manager, &KileTool::Manager::previewDone, this, &Kile::focusPreview); m_latexOutputErrorToolBar->addAction(actionCollection()->action(QLatin1String("Stop"))); errorHandler()->setErrorHandlerToolBar(m_latexOutputErrorToolBar); // add the remaining actions to m_latexOutputErrorToolBar m_bottomBar->addExtraWidget(viewManager()->getViewerControlToolBar()); m_livePreviewManager = new KileTool::LivePreviewManager(this, actionCollection()); connect(this, &Kile::masterDocumentChanged, m_livePreviewManager, &KileTool::LivePreviewManager::handleMasterDocumentChanged); m_toolFactory = new KileTool::Factory(m_manager, m_config.data(), actionCollection()); m_manager->setFactory(m_toolFactory); setupGraphicTools(); setupPreviewTools(); setupActions(); initSelectActions(); newCaption(); m_help->setUserhelp(m_manager, m_userHelpActionMenu); // kile user help (dani) // process events for correctly displaying the splash screen qApp->processEvents(); connect(docManager(), &KileDocument::Manager::updateModeStatus, this, &Kile::updateModeStatus); connect(docManager(), &KileDocument::Manager::updateStructure, viewManager(), &KileView::Manager::updateStructure); connect(docManager(), &KileDocument::Manager::closingDocument, m_kwStructure, &KileWidget::StructureWidget::closeDocumentInfo); connect(docManager(), &KileDocument::Manager::documentInfoCreated, m_kwStructure, &KileWidget::StructureWidget::addDocumentInfo); connect(docManager(), &KileDocument::Manager::updateReferences, m_kwStructure, &KileWidget::StructureWidget::updateReferences); connect(docManager(), &KileDocument::Manager::documentModificationStatusChanged, viewManager(), &KileView::Manager::reflectDocumentModificationStatus); if(KileConfig::rCVersion() < 8) { transformOldUserSettings(); transformOldUserTags(); // before Kile 2.1 shortcuts were stored in a "Shortcuts" group inside // Kile's configuration file, but this led to problems with the way of how shortcuts // are generally stored in kdelibs; we now delete the "Shortcuts" group if it // still present in Kile's configuration file. if(m_config->hasGroup("Shortcuts")) { KConfigGroup shortcutGroup = m_config->group("Shortcuts"); actionCollection()->readSettings(&shortcutGroup); m_config->deleteGroup("Shortcuts"); } if(m_config->hasGroup("Complete")) { KConfigGroup completionGroup = m_config->group("Complete"); completionGroup.deleteEntry("maxCwlFiles"); // in Kile 3.0 the UI has been changed so that this setting is no longer // needed } } readGUISettings(); readRecentFileSettings(); readConfig(); createToolActions(); // this creates the actions for the tools and user tags, which is required before 'activePartGUI' is called setupGUI(KXmlGuiWindow::StatusBar | KXmlGuiWindow::Save, "kileui.rc"); createShellGUI(true); // do not call guiFactory()->refreshActionProperties() after this! (bug 314580) m_userMenu = new KileMenu::UserMenu(this, this); connect(m_userMenu, &KileMenu::UserMenu::sendText, this, static_cast(&Kile::insertText)); connect(m_userMenu, &KileMenu::UserMenu::updateStatus, this, &Kile::slotUpdateUserMenuStatus); updateUserDefinedMenus(); // we can only do this here after the main GUI has been set up { guiFactory()->addClient(viewManager()->viewerPart()); QMenu *documentViewerMenu = static_cast(guiFactory()->container("menu_document_viewer", this)); QMenu *popup = static_cast(guiFactory()->container("menu_okular_part_viewer", viewManager()->viewerPart())); if(documentViewerMenu && popup) { // we populate our menu with the actions from the part's menu documentViewerMenu->addActions(popup->actions()); documentViewerMenu->setEnabled(false); connect(viewManager()->viewerPart(), SIGNAL(viewerMenuStateChange(bool)), documentViewerMenu, SLOT(setEnabled(bool))); } else { if(documentViewerMenu) { documentViewerMenu->setVisible(false); } delete popup; } } resize(KileConfig::mainwindowWidth(), KileConfig::mainwindowHeight()); applyMainWindowSettings(m_config->group("KileMainWindow")); restoreLastSelectedAction(); // don't call this inside 'setupTools' as it is not compatible with KParts switching! QList sizes; int verSplitTop = KileConfig::verticalSplitterTop(); int verSplitBottom = KileConfig::verticalSplitterBottom(); sizes << verSplitTop << verSplitBottom; m_verticalSplitter->setSizes(sizes); sizes.clear(); int horSplitLeft = KileConfig::horizontalSplitterLeft(); int horSplitRight = KileConfig::horizontalSplitterRight(); if(horSplitLeft <= 0 && horSplitRight <= 0) { // compute default values horSplitLeft = m_sideBar->width(); horSplitRight = width() / 2; // leave some room for the viewer part } // the size of the third widget is computed from the sizes of the two other widgets sizes << horSplitLeft << horSplitRight << width() - (horSplitLeft + horSplitRight); m_horizontalSplitter->setSizes(sizes); show(); if(KileConfig::showSplashScreen()) { splashScreen.finish(this); } // Due to 'processEvents' being called earlier we only create the DBUS adaptor and // the LyX server when all of Kile's structures have been set up. // publish the D-Bus interfaces new MainAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject("/main", this); dbus.registerService("net.sourceforge.kile"); // register under a constant name m_lyxserver = new KileLyxServer(KileConfig::runLyxServer()); connect(m_lyxserver, &KileLyxServer::insert, this, [this](const KileAction::TagData &data) { insertTag(data); }); if(m_listUserTools.count() > 0) { KMessageBox::information(0, i18n("You have defined some tools in the User menu. From now on these tools will be available from the Build->Other menu and can be configured in the configuration dialog (go to the Settings menu and choose Configure Kile). This has some advantages; your own tools can now be used in a QuickBuild command if you wish."), i18n("User Tools Detected")); m_listUserTools.clear(); } if(KileConfig::rCVersion() < 8) { // if KileConfig::rCVersion() <= 0, then 'kilerc' is (most likely) fresh or empty, // otherwise, we have to ask the user if she wants to reset the tools if ((KileConfig::rCVersion() <= 0) || (KMessageBox::questionYesNo(mainWindow(), i18n("

The tool settings need to be reset for this version of Kile to function properly.
" "This will overwrite any changes you have made.

" "

Do you want to reset the tools now?

"), i18n("Tools need to be reset")) == KMessageBox::Yes)) { m_toolFactory->resetToolConfigurations(); } } restoreFilesAndProjects(allowRestore); initMenu(); updateModeStatus(); // finally init all actions for the ScriptManager m_jScriptManager->initScriptActions(); setUpdatesEnabled(false); setAutoSaveSettings(QLatin1String("KileMainWindow"),true); m_userMenu->refreshActionProperties(); setUpdatesEnabled(true); // finally, we check whether the system check assistant should be run, which is important for // version 3.0 regarding the newly introduced live preview feature const QString& lastVersionRunFor = KileConfig::systemCheckLastVersionRunForAtStartUp(); if(lastVersionRunFor.isEmpty() || compareVersionStrings(lastVersionRunFor, "2.9.91") < 0) { slotPerformCheck(); KileConfig::setSystemCheckLastVersionRunForAtStartUp(kileFullVersion); } if(m_livePreviewManager) { m_livePreviewManager->buildLivePreviewMenu(m_config.data()); m_livePreviewManager->disableBootUpMode(); } } Kile::~Kile() { KILE_DEBUG_MAIN << "cleaning up..." << endl; guiFactory()->removeClient(viewManager()->viewerPart()); delete m_userMenu; delete m_livePreviewManager; delete m_toolFactory; delete m_manager; delete m_quickPreview; delete m_edit; delete m_help; delete m_lyxserver; //QObject without parent, have to delete it ourselves delete m_latexCommands; delete m_extensions; delete m_viewManager; } // currently not usable due to https://bugs.kde.org/show_bug.cgi?id=194732 // void Kile::plugActionList(const QString& name, const QList& actionList) // { // plugActionList(name, actionList); // } // // void Kile::unplugActionList(const QString& name) // { // unplugActionList(name); // } void Kile::setupSideBar() { m_sideBar = new KileWidget::SideBar(m_horizontalSplitter); m_fileBrowserWidget = new KileWidget::FileBrowserWidget(m_extensions, m_sideBar); m_sideBar->addPage(m_fileBrowserWidget, QIcon::fromTheme("document-open"), i18n("Open File")); connect(m_fileBrowserWidget, &KileWidget::FileBrowserWidget::fileSelected, docManager(), [this](const KFileItem& item) { docManager()->fileSelected(item); }); setupProjectView(); setupStructureView(); setupSymbolViews(); setupScriptsManagementView(); setupCommandViewToolbox(); setupAbbreviationView(); m_sideBar->switchToTab(KileConfig::selectedLeftView()); m_sideBar->setVisible(KileConfig::sideBar()); m_sideBar->setDirectionalSize(KileConfig::sideBarSize()); } void Kile::setupProjectView() { KileWidget::ProjectView *projectView = new KileWidget::ProjectView(m_sideBar, this); // viewManager()->setProjectView(projectView); m_sideBar->addPage(projectView, QIcon::fromTheme("relation"), i18n("Files and Projects")); connect(projectView, QOverload::of(&KileWidget::ProjectView::fileSelected), docManager(), QOverload::of(&KileDocument::Manager::fileSelected)); connect(projectView, QOverload::of(&KileWidget::ProjectView::fileSelected), docManager(), QOverload::of(&KileDocument::Manager::fileSelected)); connect(projectView, &KileWidget::ProjectView::closeURL, docManager(), [this](const QUrl& url) { docManager()->fileClose(url); }); connect(projectView, &KileWidget::ProjectView::closeProject, docManager(), [this](const QUrl& url) { docManager()->projectClose(url); }); connect(projectView, &KileWidget::ProjectView::projectOptions, docManager(), [this](const QUrl& url) { docManager()->projectOptions(url); }); connect(projectView, &KileWidget::ProjectView::projectArchive, this, [this](const QUrl& url) { runArchiveTool(url); }); connect(projectView, &KileWidget::ProjectView::removeFromProject, docManager(), &KileDocument::Manager::removeFromProject); connect(projectView, &KileWidget::ProjectView::addFiles, docManager(), [this](const QUrl &url) { docManager()->projectAddFiles(url); }); connect(projectView, &KileWidget::ProjectView::openAllFiles, docManager(), [this](const QUrl &url) { docManager()->projectOpenAllFiles(url); }); connect(projectView, &KileWidget::ProjectView::toggleArchive, docManager(), &KileDocument::Manager::toggleArchive); connect(projectView, &KileWidget::ProjectView::addToProject, docManager(), [this](const QUrl &url) { docManager()->addToProject(url); }); connect(projectView, &KileWidget::ProjectView::saveURL, docManager(), &KileDocument::Manager::saveURL); connect(projectView, &KileWidget::ProjectView::buildProjectTree, docManager(), [this](const QUrl &url) { docManager()->buildProjectTree(url); }); connect(docManager(), &KileDocument::Manager::projectTreeChanged, projectView, &KileWidget::ProjectView::refreshProjectTree); connect(docManager(), QOverload::of(&KileDocument::Manager::removeFromProjectView), projectView, QOverload::of(&KileWidget::ProjectView::remove)); connect(docManager(), QOverload::of(&KileDocument::Manager::removeFromProjectView), projectView, QOverload::of(&KileWidget::ProjectView::remove)); connect(docManager(), QOverload::of(&KileDocument::Manager::addToProjectView), projectView, QOverload::of(&KileWidget::ProjectView::add)); connect(docManager(), QOverload::of(&KileDocument::Manager::addToProjectView), projectView, QOverload::of(&KileWidget::ProjectView::add)); connect(docManager(), &KileDocument::Manager::removeItemFromProjectView, projectView, &KileWidget::ProjectView::removeItem); connect(docManager(), QOverload::of(&KileDocument::Manager::addToProjectView), projectView, [projectView](KileProjectItem *item) { projectView->add(item); }); } void Kile::setupStructureView() { m_kwStructure = new KileWidget::StructureWidget(this, m_sideBar); m_sideBar->addPage(m_kwStructure, QIcon::fromTheme("view-list-tree"), i18n("Structure")); m_kwStructure->setFocusPolicy(Qt::ClickFocus); connect(configurationManager(), &KileConfiguration::Manager::configChanged, m_kwStructure, &KileWidget::StructureWidget::configChanged); connect(m_kwStructure, &KileWidget::StructureWidget::setCursor, this, &Kile::setCursor); connect(m_kwStructure, &KileWidget::StructureWidget::fileOpen, docManager(), [this](const QUrl &url, const QString &encoding) { docManager()->fileOpen(url, encoding); }); connect(m_kwStructure, &KileWidget::StructureWidget::fileNew, docManager(), [this](const QUrl &url) { docManager()->fileNew(url); }); connect(m_kwStructure, &KileWidget::StructureWidget::sendText, this, [this](const QString &text) { insertText(text); }); connect(m_kwStructure, &KileWidget::StructureWidget::sectioningPopup, m_edit, &KileDocument::EditorExtension::sectioningCommand); } void Kile::setupScriptsManagementView() { m_scriptsManagementWidget = new KileWidget::ScriptsManagement(this, m_sideBar); m_sideBar->addPage(m_scriptsManagementWidget, QIcon::fromTheme("preferences-plugin-script"), i18n("Scripts")); } void Kile::enableSymbolViewMFUS() { m_toolBox->setItemEnabled(m_toolBox->indexOf(m_symbolViewMFUS),true); connect(m_symbolViewRelation, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewOperators, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewArrows, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewMiscMath, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewMiscText, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewDelimiters, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewGreek, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewSpecial, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewCyrillic, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); connect(m_symbolViewUser, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); } void Kile::disableSymbolViewMFUS() { m_toolBox->setItemEnabled(m_toolBox->indexOf(m_symbolViewMFUS),false); m_toolBox->setItemToolTip(m_toolBox->indexOf(m_symbolViewMFUS),QString()); disconnect(m_symbolViewRelation, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewOperators, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewArrows, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewMiscMath, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewMiscText, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewDelimiters, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewGreek, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewSpecial, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewCyrillic, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); disconnect(m_symbolViewUser, &KileWidget::SymbolView::addToList, m_symbolViewMFUS, &KileWidget::SymbolView::slotAddToList); } void Kile::setupSymbolViews() { m_toolBox = new QToolBox(m_sideBar); m_sideBar->addPage(m_toolBox,QIcon::fromTheme("math0"),i18n("Symbols")); m_symbolViewMFUS = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::MFUS); m_toolBox->addItem(m_symbolViewMFUS,i18n("Most Frequently Used")); m_toolBox->setItemEnabled(m_toolBox->indexOf(m_symbolViewMFUS),false); connect(m_symbolViewMFUS, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewRelation = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::Relation); m_toolBox->addItem(m_symbolViewRelation,QIcon::fromTheme("math1"),i18n("Relation")); connect(m_symbolViewRelation, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewOperators = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::Operator); m_toolBox->addItem(m_symbolViewOperators,QIcon::fromTheme("math2"),i18n("Operators")); connect(m_symbolViewOperators, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewArrows = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::Arrow); m_toolBox->addItem(m_symbolViewArrows,QIcon::fromTheme("math3"),i18n("Arrows")); connect(m_symbolViewArrows, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewMiscMath = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::MiscMath); m_toolBox->addItem(m_symbolViewMiscMath,QIcon::fromTheme("math4"),i18n("Miscellaneous Math")); connect(m_symbolViewMiscMath, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewMiscText = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::MiscText); m_toolBox->addItem(m_symbolViewMiscText,QIcon::fromTheme("math5"),i18n("Miscellaneous Text")); connect(m_symbolViewMiscText, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewDelimiters= new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::Delimiters); m_toolBox->addItem(m_symbolViewDelimiters,QIcon::fromTheme("math6"),i18n("Delimiters")); connect(m_symbolViewDelimiters, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewGreek = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::Greek); m_toolBox->addItem(m_symbolViewGreek,QIcon::fromTheme("math7"),i18n("Greek")); connect(m_symbolViewGreek, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewSpecial = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::Special); m_toolBox->addItem(m_symbolViewSpecial,QIcon::fromTheme("math8"),i18n("Special Characters")); connect(m_symbolViewSpecial, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewCyrillic = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::Cyrillic); m_toolBox->addItem(m_symbolViewCyrillic,QIcon::fromTheme("math10"),i18n("Cyrillic Characters")); connect(m_symbolViewCyrillic, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); m_symbolViewUser = new KileWidget::SymbolView(this, m_toolBox, KileWidget::SymbolView::User); m_toolBox->addItem(m_symbolViewUser,QIcon::fromTheme("math9"),i18n("User Defined")); connect(m_symbolViewUser, &KileWidget::SymbolView::insertText, this, static_cast&)>(&Kile::insertText)); for(int i = 0; i < m_toolBox->count(); ++i) { m_toolBox->setItemToolTip(i, i18n("

Move the mouse over the icons to see the corresponding LaTeX commands.
" "Click on an image to insert the corresponding command, additionally pressing \"Shift\" inserts " "it in math mode, pressing \"Ctrl\" in curly brackets.

")); } } void Kile::setupCommandViewToolbox() { m_commandViewToolBox = new KileWidget::CommandViewToolBox(this, m_sideBar); m_sideBar->addPage(m_commandViewToolBox, QIcon::fromTheme("texlion"), i18n("LaTeX")); connect(m_commandViewToolBox, &KileWidget::CommandViewToolBox::sendText, this, QOverload::of(&Kile::insertText)); } void Kile::setupAbbreviationView() { m_kileAbbrevView = new KileWidget::AbbreviationView(abbreviationManager(), m_sideBar); connect(abbreviationManager(), &KileAbbreviation::Manager::abbreviationsChanged, m_kileAbbrevView, &KileWidget::AbbreviationView::updateAbbreviations); m_sideBar->addPage(m_kileAbbrevView, QIcon::fromTheme("complete3"), i18n("Abbreviation")); connect(m_kileAbbrevView, &KileWidget::AbbreviationView::sendText, this, QOverload::of(&Kile::insertText)); } void Kile::setupBottomBar() { m_bottomBar = new KileWidget::BottomBar(this); m_bottomBar->setFocusPolicy(Qt::ClickFocus); connect(errorHandler(), &KileErrorHandler::showingErrorMessage, this, &Kile::focusLog); QWidget *widget = new QWidget(this); QHBoxLayout *layout = new QHBoxLayout(widget); layout->setMargin(0); widget->setLayout(layout); m_latexOutputErrorToolBar = new KToolBar(widget); m_latexOutputErrorToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); m_latexOutputErrorToolBar->setIconDimensions(KIconLoader::SizeSmall); m_latexOutputErrorToolBar->setOrientation(Qt::Vertical); layout->addWidget(errorHandler()->outputWidget()); layout->addWidget(m_latexOutputErrorToolBar); m_bottomBar->addPage(widget, QIcon::fromTheme("utilities-log-viewer"), i18n("Log and Messages")); m_outputWidget = new KileWidget::OutputView(this); m_outputWidget->setFocusPolicy(Qt::ClickFocus); m_outputWidget->setMinimumHeight(40); m_outputWidget->setReadOnly(true); m_bottomBar->addPage(m_outputWidget, QIcon::fromTheme("output_win"), i18n("Output")); m_texKonsole = new KileWidget::Konsole(this, this); m_bottomBar->addPage(m_texKonsole, QIcon::fromTheme("utilities-terminal"),i18n("Konsole")); connect(viewManager(), static_cast(&KileView::Manager::currentViewChanged), m_texKonsole, static_cast(&KileWidget::Konsole::sync)); m_previewWidget = new KileWidget::PreviewWidget(this, m_bottomBar); m_bottomBar->addPage(m_previewWidget, QIcon::fromTheme ("document-preview"), i18n ("Preview")); m_bottomBar->setVisible(true); m_bottomBar->switchToTab(KileConfig::bottomBarIndex()); m_bottomBar->setDirectionalSize(KileConfig::bottomBarSize()); } void Kile::setupGraphicTools() { KileConfig::setImagemagick(!(QStandardPaths::findExecutable("identify").isNull())); } void Kile::setupPreviewTools() { // search for tools bool dvipng = !(QStandardPaths::findExecutable("dvipng").isNull()); bool convert = !(QStandardPaths::findExecutable("convert").isNull()); KileConfig::setDvipng(dvipng); KileConfig::setConvert(convert); // disable some previews, if tools are missing if ( ! dvipng ) { KileConfig::setMathgroupPreviewInWidget(false); // no mathgroup preview in bottom bar if ( ! convert ) { KileConfig::setEnvPreviewInWidget(false); // no preview in bottom bar at all KileConfig::setSelPreviewInWidget(false); } } } template QAction* Kile::createAction(const QString &text, const QString &actionName, const QString& iconName, const QKeySequence& shortcut, const ContextType* context, Func function) { QAction *action = new QAction(this); action->setText(text); connect(action, &QAction::triggered, context, function); actionCollection()->addAction(actionName, action); if(!shortcut.isEmpty()) { actionCollection()->setDefaultShortcut(action, shortcut); } if(!iconName.isEmpty()) { action->setIcon(QIcon::fromTheme(iconName)); } return action; } template QAction* Kile::createAction(KStandardAction::StandardAction actionType, const QString &actionName, const ContextType* context, Func function) { QAction *action = KStandardAction::create(actionType, context, function, this); if(!actionName.isEmpty()) { action->setObjectName(actionName); } actionCollection()->addAction(actionName, action); return action; } void Kile::setupActions() { QAction *act; createAction(KStandardAction::New, "file_new", docManager(), [this]() { docManager()->fileNew(); }); createAction(KStandardAction::Open, "file_open", docManager(), [this]() { docManager()->fileOpen(); }); m_actRecentFiles = KStandardAction::openRecent(docManager(), [this](const QUrl& url) { docManager()->fileOpen(url); }, this); m_actRecentFiles->setObjectName("file_open_recent"); actionCollection()->addAction("file_open_recent", m_actRecentFiles); connect(docManager(), &KileDocument::Manager::addToRecentFiles, this, &Kile::addRecentFile); m_actRecentFiles->loadEntries(m_config->group("Recent Files")); createAction(i18n("Save All"), "file_save_all", "document-save-all", docManager(), &KileDocument::Manager::fileSaveAll); - createAction(i18n("Save Copy As..."), "file_save_copy_as", docManager(), &KileDocument::Manager::fileSaveCopyAs); createAction(i18n("Create Template From Document..."), "template_create", docManager(), &KileDocument::Manager::createTemplate); createAction(i18n("&Remove Template..."), "template_remove", docManager(), &KileDocument::Manager::removeTemplate); createAction(KStandardAction::Close, "file_close", docManager(), [this]() { docManager()->fileClose();} ); createAction(i18n("Close All"), "file_close_all", docManager(), &KileDocument::Manager::fileCloseAll); createAction(i18n("Close All Ot&hers"), "file_close_all_others", docManager(), [this]() { docManager()->fileCloseAllOthers(); }); createAction(i18n("S&tatistics"), "Statistics", this, [this]() { showDocInfo(); }); createAction(i18n("&ASCII"), "file_export_ascii", this, [this]() { convertToASCII(); }); createAction(i18n("Latin-&1 (iso 8859-1)"), "file_export_latin1", this, [this]() { convertToEnc(); }); createAction(i18n("Latin-&2 (iso 8859-2)"), "file_export_latin2", this, [this]() { convertToEnc(); }); createAction(i18n("Latin-&3 (iso 8859-3)"), "file_export_latin3", this, [this]() { convertToEnc(); }); createAction(i18n("Latin-&4 (iso 8859-4)"), "file_export_latin4", this, [this]() { convertToEnc(); }); createAction(i18n("Latin-&5 (iso 8859-5)"), "file_export_latin5", this, [this]() { convertToEnc(); }); createAction(i18n("Latin-&9 (iso 8859-9)"), "file_export_latin9", this, [this]() { convertToEnc(); }); createAction(i18n("&Central European (cp-1250)"), "file_export_cp1250", this, [this]() { convertToEnc(); }); createAction(i18n("&Western European (cp-1252)"), "file_export_cp1252", this, [this]() { convertToEnc(); }); createAction(KStandardAction::Quit, "file_quit", this, &Kile::close); createAction(i18n("Move Tab Left"), "move_view_tab_left", "arrow-left", viewManager(), [this]() { viewManager()->moveTabLeft(); }); createAction(i18n("Move Tab Right"), "move_view_tab_right", "arrow-right", viewManager(), [this]() { viewManager()->moveTabRight(); }); createAction(i18n("Next section"), "edit_next_section", "nextsection", QKeySequence(Qt::ALT + Qt::Key_Down), m_edit, &KileDocument::EditorExtension::gotoNextSectioning); createAction(i18n("Prev section"), "edit_prev_section", "prevsection", QKeySequence(Qt::ALT + Qt::Key_Up), m_edit, &KileDocument::EditorExtension::gotoPrevSectioning); createAction(i18n("Next paragraph"), "edit_next_paragraph", "nextparagraph", QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Down), m_edit, [this]() { m_edit->gotoNextParagraph(); }); createAction(i18n("Prev paragraph"), "edit_prev_paragraph", "prevparagraph", QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Up), m_edit, [this]() { m_edit->gotoPrevParagraph(); }); createAction(i18n("Find &in Files..."), "FindInFiles", "filegrep", this, &Kile::findInFiles); createAction(i18n("Refresh Str&ucture"), "RefreshStructure", "refreshstructure", QKeySequence(Qt::Key_F12), this, &Kile::refreshStructure); //project actions createAction(i18n("&New Project..."), "project_new", "window-new", docManager(), &KileDocument::Manager::projectNew); createAction(i18n("&Open Project..."), "project_open", "project-open", docManager(), [this]() { docManager()->projectOpen(); }); m_actRecentProjects = new KRecentFilesAction(i18n("Open &Recent Project"), actionCollection()); actionCollection()->addAction("project_openrecent", m_actRecentProjects); connect(m_actRecentProjects, &KRecentFilesAction::urlSelected, docManager(), [this](const QUrl& url) { docManager()->projectOpen(url); }); connect(docManager(), &KileDocument::Manager::removeFromRecentProjects, this, &Kile::removeRecentProject); connect(docManager(), &KileDocument::Manager::addToRecentProjects, this, &Kile::addRecentProject); m_actRecentProjects->loadEntries(m_config->group("Projects")); createAction(i18n("A&dd Files to Project..."), "project_add", "project_add", docManager(), [this]() { m_docManager->projectAddFiles(); }); createAction(i18n("Refresh Project &Tree"), "project_buildtree", "project_rebuild", docManager(), [this]() { m_docManager->buildProjectTree(); }); createAction(i18n("&Archive"), "project_archive", "project_archive", this, [this]() { runArchiveTool(); }); createAction(i18n("Project &Options"), "project_options", "configure_project", docManager(), [this]() { m_docManager->projectOptions(); }); createAction(i18n("&Close Project"), "project_close", "project-development-close", docManager(), [this]() { m_docManager->projectClose(); }); // new project actions (dani) createAction(i18n("&Show Projects..."), "project_show", docManager(), &KileDocument::Manager::projectShow); createAction(i18n("Re&move Files From Project..."), "project_remove", "project_remove", docManager(), &KileDocument::Manager::projectRemoveFiles); createAction(i18n("Show Project &Files..."), "project_showfiles", "project_show", docManager(), &KileDocument::Manager::projectShowFiles); // tbraun createAction(i18n("Open All &Project Files"), "project_openallfiles", docManager(), [this]() { docManager()->projectOpenAllFiles(); }); createAction(i18n("Find in &Project..."), "project_findfiles", "projectgrep", this, &Kile::findInProjects); //build actions act = createAction(i18n("Clean"), "CleanAll", "user-trash", this, [this]() { cleanAll(); }); createAction(i18n("Next Document"), "gotoNextDocument", "go-next-view-page", QKeySequence(Qt::ALT + Qt::Key_Right), viewManager(), &KileView::Manager::gotoNextView); createAction(i18n("Previous Document"), "gotoPrevDocument", "go-previous-view-page", QKeySequence(Qt::ALT + Qt::Key_Left), viewManager(), &KileView::Manager::gotoPrevView); createAction(i18n("Focus Log/Messages View"), "focus_log", QKeySequence("CTRL+Alt+M"), this, &Kile::focusLog); createAction(i18n("Focus Output View"), "focus_output", QKeySequence("CTRL+Alt+O"), this, &Kile::focusOutput); createAction(i18n("Focus Konsole View"), "focus_konsole", QKeySequence("CTRL+Alt+K"), this, &Kile::focusKonsole); createAction(i18n("Focus Editor View"), "focus_editor", QKeySequence("CTRL+Alt+F"), this, &Kile::focusEditor); createAction(i18nc("@action: Starts the completion of the current LaTeX command", "Complete (La)TeX Command"), "edit_complete_word", "complete1", QKeySequence(Qt::SHIFT + Qt::CTRL + Qt::Key_Space), codeCompletionManager(), [this]() { codeCompletionManager()->startLaTeXCompletion(); }); createAction(i18nc("@action: Starts the input (and completion) of a LaTeX environment", "Complete LaTeX Environment"), "edit_complete_env", "complete2", QKeySequence(Qt::SHIFT + Qt::ALT + Qt::Key_Space), codeCompletionManager(), [this]() { codeCompletionManager()->startLaTeXEnvironment(); }); createAction(i18nc("@action: Starts the completion of the current abbreviation", "Complete Abbreviation"), "edit_complete_abbrev", "complete3", QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Space), codeCompletionManager(), [this]() { codeCompletionManager()->startAbbreviationCompletion(); }); createAction(i18n("Next Bullet"), "edit_next_bullet", "nextbullet", QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Right), m_edit, [this]() { m_edit->nextBullet(); }); createAction(i18n("Prev Bullet"), "edit_prev_bullet", "prevbullet", QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Left), m_edit, [this]() { m_edit->prevBullet(); }); // advanced editor (dani) createAction(i18n("Environment (inside)"), "edit_select_inside_env", "selenv_i", QKeySequence("CTRL+Alt+S, E"), m_edit, &KileDocument::EditorExtension::selectEnvInside); createAction(i18n("Environment (outside)"), "edit_select_outside_env", "selenv_o", QKeySequence("CTRL+Alt+S, F"), m_edit, &KileDocument::EditorExtension::selectEnvOutside); createAction(i18n("TeX Group (inside)"), "edit_select_inside_group", "selgroup_i", QKeySequence("CTRL+Alt+S, T"), m_edit, &KileDocument::EditorExtension::selectTexgroupInside); createAction(i18n("TeX Group (outside)"), "edit_select_outside_group", "selgroup_o", QKeySequence("CTRL+Alt+S, U"), m_edit, &KileDocument::EditorExtension::selectTexgroupOutside); createAction(i18n("Math Group"), "edit_select_mathgroup", "selmath", QKeySequence("CTRL+Alt+S, M"), m_edit, [this]() { m_edit->selectMathgroup(); }); createAction(i18n("Paragraph"), "edit_select_paragraph", "selpar", QKeySequence("CTRL+Alt+S, P"), m_edit, [this]() { m_edit->selectParagraph(); }); createAction(i18n("Line"), "edit_select_line", "selline", QKeySequence("CTRL+Alt+S, L"), m_edit, [this]() { m_edit->selectLine(); }); createAction(i18n("TeX Word"), "edit_select_word", "selword", QKeySequence("CTRL+Alt+S, W"), m_edit, [this]() { m_edit->selectWord(); }); createAction(i18n("Environment (inside)"), "edit_delete_inside_env", "delenv_i", QKeySequence("CTRL+Alt+T, E"), m_edit, &KileDocument::EditorExtension::deleteEnvInside); createAction(i18n("Environment (outside)"), "edit_delete_outside_env", "delenv_o", QKeySequence("CTRL+Alt+T, F"), m_edit, &KileDocument::EditorExtension::deleteEnvOutside); createAction(i18n("TeX Group (inside)"), "edit_delete_inside_group", "delgroup_i", QKeySequence("CTRL+Alt+T, T"), m_edit, &KileDocument::EditorExtension::deleteTexgroupInside); createAction(i18n("TeX Group (outside)"), "edit_delete_outside_group", "delgroup_o",QKeySequence("CTRL+Alt+T, U"), m_edit, &KileDocument::EditorExtension::deleteTexgroupInside); createAction(i18n("Math Group"), "edit_delete_mathgroup", "delmath", QKeySequence("CTRL+Alt+T, M"), m_edit, [this]() { m_edit->deleteMathgroup(); }); createAction(i18n("Paragraph"), "edit_delete_paragraph", "delpar", QKeySequence("CTRL+Alt+T, P"), m_edit, [this]() { m_edit->deleteParagraph(); }); createAction(i18n("To End of Line"), "edit_delete_eol", "deleol", QKeySequence("CTRL+Alt+T, L"), m_edit, [this]() { m_edit->deleteEndOfLine(); }); createAction(i18n("TeX Word"), "edit_delete_word", "delword", QKeySequence("CTRL+Alt+T, W"), m_edit, [this]() { m_edit->deleteWord(); }); createAction(i18n("Go to Begin"), "edit_begin_env", "gotobeginenv", QKeySequence("CTRL+Alt+E, B"), m_edit, &KileDocument::EditorExtension::gotoBeginEnv); createAction(i18n("Go to End"), "edit_end_env", "gotoendenv", QKeySequence("CTRL+Alt+E, E"), m_edit, &KileDocument::EditorExtension::gotoEndEnv); createAction(i18n("Match"), "edit_match_env", "matchenv", QKeySequence("CTRL+Alt+E, M"), m_edit, &KileDocument::EditorExtension::matchEnv); createAction(i18n("Close"), "edit_close_env", "closeenv", QKeySequence("CTRL+Alt+E, C"), m_edit, &KileDocument::EditorExtension::closeEnv); createAction(i18n("Close All"), "edit_closeall_env", "closeallenv", QKeySequence("CTRL+Alt+E, A"), m_edit, &KileDocument::EditorExtension::closeAllEnv); createAction(i18n("Go to Begin"), "edit_begin_group", "gotobegingroup", QKeySequence("CTRL+Alt+G, B"), m_edit, &KileDocument::EditorExtension::gotoBeginTexgroup); createAction(i18n("Go to End"), "edit_end_group", "gotoendgroup", QKeySequence("CTRL+Alt+G, E"), m_edit, &KileDocument::EditorExtension::gotoEndTexgroup); createAction(i18n("Match"), "edit_match_group", "matchgroup", QKeySequence("CTRL+Alt+G, M"), m_edit, [this]() { m_edit->matchTexgroup(); }); createAction(i18n("Close"), "edit_close_group", "closegroup", QKeySequence("CTRL+Alt+G, C"), m_edit, [this]() { m_edit->closeTexgroup(); }); createAction(i18n("Selection"), "quickpreview_selection", "preview_sel", QKeySequence("CTRL+Alt+P, S"), this, &Kile::quickPreviewSelection); createAction(i18n("Environment"), "quickpreview_environment", "preview_env",QKeySequence("CTRL+Alt+P, E"), this, &Kile::quickPreviewEnvironment); createAction(i18n("Subdocument"), "quickpreview_subdocument", "preview_subdoc",QKeySequence("CTRL+Alt+P, D"), this, &Kile::quickPreviewSubdocument); createAction(i18n("Mathgroup"), "quickpreview_math", "preview_math", QKeySequence("CTRL+Alt+P, M"), this, &Kile::quickPreviewMathgroup); KileStdActions::setupStdTags(this, this, actionCollection(), this); KileStdActions::setupMathTags(this, actionCollection()); m_bibTagActionMenu = new KActionMenu(i18n("&Bibliography"), actionCollection()); m_bibTagActionMenu->setDelayed(false); actionCollection()->addAction("menu_bibliography", m_bibTagActionMenu); createAction(i18n("Clean"), "CleanBib", this, &Kile::cleanBib); m_bibTagSettings = new KSelectAction(i18n("&Settings"),actionCollection()); actionCollection()->addAction("settings_menu_bibliography", m_bibTagSettings); act = createAction(i18n("Settings for BibTeX"), "setting_bibtex", this, &Kile::rebuildBibliographyMenu); act->setCheckable(true); m_bibTagSettings->addAction(act); act = createAction(i18n("Settings for Biblatex"), "setting_biblatex", this, &Kile::rebuildBibliographyMenu); act->setCheckable(true); m_bibTagSettings->addAction(act); m_bibTagSettings->setCurrentAction(action((QString("setting_") + KileConfig::bibliographyType()).toLatin1())); rebuildBibliographyMenu(); createAction(i18n("Quick Start"), "wizard_document", "quickwizard", this, &Kile::quickDocument); connect(docManager(), &KileDocument::Manager::startWizard, this, &Kile::quickDocument); createAction(i18n("Tabular"), "wizard_tabular", "wizard_tabular", this, &Kile::quickTabular); createAction(i18n("Array"), "wizard_array", "wizard_array", this, &Kile::quickArray); createAction(i18n("Tabbing"), "wizard_tabbing", "wizard_tabbing", this, &Kile::quickTabbing); createAction(i18n("Floats"), "wizard_float", "wizard_float", this, &Kile::quickFloat); createAction(i18n("Math"), "wizard_mathenv", "wizard_math", this, &Kile::quickMathenv); createAction(i18n("Postscript Tools"), "wizard_postscript", "wizard_pstools", this, &Kile::quickPostscript); createAction(i18n("PDF Tools"), "wizard_pdf", "wizard_pdftools", this, &Kile::quickPdf); ModeAction = new KToggleAction(i18n("Define Current Document as '&Master Document'"), actionCollection()); actionCollection()->addAction("Mode", ModeAction); ModeAction->setIcon(QIcon::fromTheme("master")); connect(ModeAction, &KToggleAction::triggered, this, &Kile::toggleMasterDocumentMode); KToggleAction *showDocumentViewer = new KToggleAction(i18n("Show Document Viewer"), actionCollection()); actionCollection()->addAction("ShowDocumentViewer", showDocumentViewer); showDocumentViewer->setChecked(KileConfig::showDocumentViewer()); connect(showDocumentViewer, &KToggleAction::toggled, viewManager(), &KileView::Manager::setDocumentViewerVisible); connect(viewManager(), &KileView::Manager::documentViewerWindowVisibilityChanged, showDocumentViewer, &KToggleAction::setChecked); KToggleAction *tact = new KToggleAction(i18n("Show S&ide Bar"), actionCollection()); actionCollection()->addAction("StructureView", tact); tact->setChecked(KileConfig::sideBar()); connect(tact, &KToggleAction::toggled, m_sideBar, &Kile::setVisible); connect(m_sideBar, &KileWidget::SideBar::visibilityChanged, this, &Kile::sideOrBottomBarChanged); m_actionMessageView = new KToggleAction(i18n("Show Mess&ages Bar"), actionCollection()); actionCollection()->addAction("MessageView", m_actionMessageView); m_actionMessageView->setChecked(true); connect(m_actionMessageView, &KToggleAction::toggled, m_bottomBar, &Kile::setVisible); connect(m_bottomBar, &KileWidget::SideBar::visibilityChanged, this, &Kile::sideOrBottomBarChanged); if(m_singlemode) { ModeAction->setChecked(false); } else { ModeAction->setChecked(true); } WatchFileAction = new KToggleAction(i18n("Watch File Mode"), actionCollection()); actionCollection()->addAction("WatchFile", WatchFileAction); WatchFileAction->setIcon(QIcon::fromTheme("watchfile")); connect(WatchFileAction, &KToggleAction::toggled, this, &Kile::toggleWatchFile); if(m_bWatchFile) { WatchFileAction->setChecked(true); } else { WatchFileAction->setChecked(false); } setHelpMenuEnabled(false); KHelpMenu *help_menu = new KHelpMenu(this, KAboutData::applicationData()); createAction(i18n("TeX Guide"), "help_tex_guide", QKeySequence("CTRL+Alt+H, G"), m_help, &KileHelp::Help::helpTexGuide); createAction(i18n("LaTeX"), "help_latex_index", QKeySequence("CTRL+Alt+H, L"), m_help, &KileHelp::Help::helpLatexIndex); createAction(i18n("LaTeX Command"), "help_latex_command", QKeySequence("CTRL+Alt+H, C"), m_help, &KileHelp::Help::helpLatexCommand); createAction(i18n("LaTeX Subject"), "help_latex_subject", QKeySequence("CTRL+Alt+H, S"), m_help, &KileHelp::Help::helpLatexSubject); createAction(i18n("LaTeX Env"), "help_latex_env", QKeySequence("CTRL+Alt+H, E"), m_help, &KileHelp::Help::helpLatexEnvironment); createAction(i18n("Context Help"), "help_context", QKeySequence("CTRL+Alt+H, K"), m_help, [this]() { m_help->helpKeyword(); }); createAction(i18n("Documentation Browser"), "help_docbrowser", QKeySequence("CTRL+Alt+H, B"), m_help, &KileHelp::Help::helpDocBrowser); createAction(i18n("LaTeX Reference"), "help_latex_reference", "help-latex", this, &Kile::helpLaTex); createAction(KStandardAction::HelpContents, help_menu, &KHelpMenu::appHelpActivated); createAction(KStandardAction::ReportBug, help_menu, &KHelpMenu::reportBug); act = createAction(KStandardAction::AboutApp, help_menu, &KHelpMenu::aboutApplication); act->setMenuRole(QAction::AboutRole); // for Mac OS X, to get the right about menu in the application menu act = createAction(KStandardAction::AboutKDE, help_menu, &KHelpMenu::aboutKDE); act->setMenuRole(QAction::NoRole); act = createAction(i18n("&About Editor Component"), "help_about_editor", this, &Kile::aboutEditorComponent); act->setMenuRole(QAction::NoRole); QAction *kileconfig = KStandardAction::preferences(this, &Kile::generalOptions, actionCollection()); kileconfig->setIcon(QIcon::fromTheme("configure-kile")); createAction(KStandardAction::KeyBindings, this, &Kile::configureKeys); createAction(KStandardAction::ConfigureToolbars, this, &Kile::configureToolbars); createAction(i18n("&System Check..."), "settings_perform_check", this, &Kile::slotPerformCheck); m_userHelpActionMenu = new KActionMenu(i18n("User Help"), actionCollection()); actionCollection()->addAction("help_userhelp", m_userHelpActionMenu); m_pFullScreen = KStandardAction::fullScreen(this, &Kile::slotToggleFullScreen, this, actionCollection()); } void Kile::rebuildBibliographyMenu() { KILE_DEBUG_MAIN << " current is " << m_bibTagSettings->currentText(); QString currentItem = m_bibTagSettings->currentText(); QString name; if( currentItem == i18n("BibTeX") ) { // avoid writing i18n'ed strings to config file name = QString("bibtex"); } else if ( currentItem == i18n("Biblatex") ) { name = QString("biblatex"); } else { KILE_DEBUG_MAIN << "wrong currentItem in bibliography settings menu"; name = QString("bibtex"); } KileConfig::setBibliographyType(name); m_bibTagActionMenu->menu()->clear(); KileStdActions::setupBibTags(this, actionCollection(),m_bibTagActionMenu); m_bibTagActionMenu->addSeparator(); m_bibTagActionMenu->addAction(action("CleanBib")); m_bibTagActionMenu->addSeparator(); m_bibTagActionMenu->addAction(action("settings_menu_bibliography")); } QAction* Kile::createToolAction(const QString& toolName) { return createAction(toolName, "tool_" + toolName, KileTool::iconFor(toolName, m_config.data()), this, [this, toolName]() { runTool(toolName); }); } void Kile::createToolActions() { QStringList tools = KileTool::toolList(m_config.data()); for (QStringList::iterator i = tools.begin(); i != tools.end(); ++i) { QString toolName = *i; if(!actionCollection()->action("tool_" + toolName)) { KILE_DEBUG_MAIN << "Creating action for tool" << toolName; createToolAction(toolName); } } } void Kile::setupTools() { KILE_DEBUG_MAIN << "==Kile::setupTools()===================" << endl; if(!m_buildMenuCompile || !m_buildMenuConvert || !m_buildMenuTopLevel || !m_buildMenuQuickPreview || !m_buildMenuViewer || !m_buildMenuOther) { KILE_DEBUG_MAIN << "BUG, menu pointers are Q_NULLPTR" << (m_buildMenuCompile == Q_NULLPTR) << (m_buildMenuConvert == Q_NULLPTR) << (m_buildMenuTopLevel == Q_NULLPTR) << (m_buildMenuQuickPreview == Q_NULLPTR) << (m_buildMenuViewer == Q_NULLPTR) << (m_buildMenuOther == Q_NULLPTR); return; } QStringList tools = KileTool::toolList(m_config.data()); QString toolMenu, grp; QList *pl; QAction *act; ToolbarSelectAction *pSelectAction = Q_NULLPTR; m_compilerActions->saveCurrentAction(); m_viewActions->saveCurrentAction(); m_convertActions->saveCurrentAction(); m_quickActions->saveCurrentAction(); // do plugActionList by hand ... foreach(act, m_listQuickActions) { m_buildMenuTopLevel->removeAction(act); } m_buildMenuCompile->clear(); m_buildMenuConvert->clear(); m_buildMenuViewer->clear(); m_buildMenuOther->clear(); m_compilerActions->removeAllActions(); m_viewActions->removeAllActions(); m_convertActions->removeAllActions(); m_quickActions->removeAllActions(); for (int i = 0; i < tools.count(); ++i) { grp = KileTool::groupFor(tools[i], m_config.data()); toolMenu = KileTool::menuFor(tools[i], m_config.data()); KILE_DEBUG_MAIN << tools[i] << " is using group: " << grp << " and menu: "<< toolMenu; if(toolMenu == "none") { continue; } if ( toolMenu == "Compile" ) { pl = &m_listCompilerActions; pSelectAction = m_compilerActions; } else if ( toolMenu == "View" ) { pl = &m_listViewerActions; pSelectAction = m_viewActions; } else if ( toolMenu == "Convert" ) { pl = &m_listConverterActions; pSelectAction = m_convertActions; } else if ( toolMenu == "Quick" ) { pl = &m_listQuickActions; pSelectAction = m_quickActions; } else { pl = &m_listOtherActions; pSelectAction = Q_NULLPTR; } KILE_DEBUG_MAIN << "\tadding " << tools[i] << " " << toolMenu << " #" << pl->count() << endl; act = actionCollection()->action("tool_" + tools[i]); if(!act) { KILE_DEBUG_MAIN << "no tool for " << tools[i]; createToolAction(tools[i]); } pl->append(act); if(pSelectAction) { pSelectAction->addAction(actionCollection()->action("tool_" + tools[i])); } } m_quickActions->addSeparator(); m_quickActions->addAction(action("quickpreview_selection")); m_quickActions->addAction(action("quickpreview_environment")); m_quickActions->addAction(action("quickpreview_subdocument")); m_quickActions->addSeparator(); m_quickActions->addAction(action("quickpreview_math")); cleanUpActionList(m_listCompilerActions, tools); cleanUpActionList(m_listViewerActions, tools); cleanUpActionList(m_listConverterActions, tools); cleanUpActionList(m_listQuickActions, tools); cleanUpActionList(m_listOtherActions, tools); m_buildMenuTopLevel->insertActions(m_buildMenuQuickPreview->menuAction(),m_listQuickActions); m_buildMenuCompile->addActions(m_listCompilerActions); m_buildMenuConvert->addActions(m_listConverterActions); m_buildMenuViewer->addActions(m_listViewerActions); m_buildMenuOther->addActions(m_listOtherActions); m_compilerActions->restoreCurrentAction(); m_viewActions->restoreCurrentAction(); m_convertActions->restoreCurrentAction(); m_quickActions->restoreCurrentAction(); } void Kile::initSelectActions() { m_compilerActions = new ToolbarSelectAction(i18n("Compile"), this); m_viewActions = new ToolbarSelectAction(i18n("View"), this); m_convertActions = new ToolbarSelectAction(i18n("Convert"), this); m_quickActions = new ToolbarSelectAction(i18n("Quick"), this); actionCollection()->setShortcutsConfigurable(m_compilerActions, false); actionCollection()->setShortcutsConfigurable(m_viewActions, false); actionCollection()->setShortcutsConfigurable(m_convertActions, false); actionCollection()->setShortcutsConfigurable(m_quickActions, false); actionCollection()->addAction("list_compiler_select", m_compilerActions); actionCollection()->addAction("list_convert_select", m_convertActions); actionCollection()->addAction("list_view_select", m_viewActions); actionCollection()->addAction("list_quick_select", m_quickActions); } void Kile::saveLastSelectedAction() { KILE_DEBUG_MAIN << "Kile::saveLastSelectedAction()" << endl; QStringList list; list << "Compile" << "Convert" << "View" << "Quick"; ToolbarSelectAction *pSelectAction = Q_NULLPTR ; KConfigGroup grp = m_config->group("ToolSelectAction"); for(QStringList::Iterator it = list.begin(); it != list.end() ; ++it) { if ( *it == "Compile" ) { pSelectAction = m_compilerActions; } else if ( *it == "View" ) { pSelectAction = m_viewActions; } else if ( *it == "Convert" ) { pSelectAction = m_convertActions; } else if ( *it == "Quick" ) { pSelectAction = m_quickActions; } KILE_DEBUG_MAIN << "current item is " << pSelectAction->currentItem(); grp.writeEntry(*it, pSelectAction->currentItem()); } } void Kile::restoreLastSelectedAction() { QStringList list; list << "Compile" << "Convert" << "View" << "Quick"; ToolbarSelectAction *pSelectAction = Q_NULLPTR; int defaultAction = 0; KConfigGroup grp = m_config->group("ToolSelectAction"); for(QStringList::Iterator it = list.begin(); it != list.end(); ++it) { if ( *it == "Compile" ) { pSelectAction = m_compilerActions; defaultAction = 9; // PDFLatex } else if ( *it == "View" ) { pSelectAction = m_viewActions; defaultAction = 4; // ViewPDF } else if ( *it == "Convert" ) { pSelectAction = m_convertActions; defaultAction = 0; } else if ( *it == "Quick" ) { pSelectAction = m_quickActions; defaultAction = 0; } int actIndex = grp.readEntry(*it, defaultAction); KILE_DEBUG_MAIN << "selecting" << actIndex << "for" << *it; pSelectAction->setCurrentItem(actIndex); } } void Kile::cleanUpActionList(QList &list, const QStringList &tools) { // KILE_DEBUG_MAIN << "cleanUpActionList tools are" << tools.join("; "); QList::iterator it, testIt; for ( it= list.begin(); it != list.end(); ++it) { QAction *act = *it; if ( act != Q_NULLPTR && !act->objectName().isEmpty() && !tools.contains(act->objectName().mid(5)) ) { if (act->associatedWidgets().contains(toolBar("toolsToolBar"))) { toolBar("toolsToolBar")->removeAction(act); } // KILE_DEBUG_MAIN << "about to delete action: " << act->objectName(); testIt = list.erase(it); if( testIt == list.end()) { break; } } } } void Kile::restoreFilesAndProjects(bool allowRestore) { if (!(allowRestore && KileConfig::restore())) { return; } QUrl url; for (int i=0; i < m_listProjectsOpenOnStart.count(); ++i) { // don't open project files as they will be opened later in this method docManager()->projectOpen(QUrl::fromUserInput(m_listProjectsOpenOnStart[i]), i, m_listProjectsOpenOnStart.count(), false); } for (int i = 0; i < m_listDocsOpenOnStart.count(); ++i) { docManager()->fileOpen(QUrl::fromUserInput(m_listDocsOpenOnStart[i]), m_listEncodingsOfDocsOpenOnStart[i]); } if (ModeAction) { ModeAction->setChecked(!m_singlemode); } updateModeStatus(); m_listProjectsOpenOnStart.clear(); m_listDocsOpenOnStart.clear(); m_listEncodingsOfDocsOpenOnStart.clear(); KILE_DEBUG_MAIN << "lastDocument=" << KileConfig::lastDocument() << endl; KTextEditor::Document *doc = docManager()->docFor(QUrl::fromUserInput(KileConfig::lastDocument())); if (doc) { viewManager()->switchToTextView(doc->url(), true); // request the focus on the view } setMasterDocumentFileName(KileConfig::singleFileMasterDocument()); } void Kile::setActive() { KILE_DEBUG_MAIN << "Activating" << endl; raise(); activateWindow(); show(); } void Kile::setLine(const QString &line) { bool ok; uint l = line.toUInt(&ok, 10); KTextEditor::View *view = viewManager()->currentTextView(); if (view && ok) { show(); raise(); activateWindow(); // be very aggressive when it comes to raising the main window to the top KWindowSystem::forceActiveWindow(winId()); focusTextView(view); editorExtension()->goToLine(l - 1, view); } } void Kile::setCursor(const QUrl &url, int parag, int index) { KTextEditor::Document *doc = docManager()->docFor(url); if(doc) { KTextEditor::View *view = (KTextEditor::View*)doc->views().first(); if(view) { view->setCursorPosition(KTextEditor::Cursor(parag, index)); focusTextView(view); } } } void Kile::runArchiveTool() { runArchiveTool(QUrl()); } void Kile::runArchiveTool(const QUrl &url) { KileTool::Archive *tool = dynamic_cast(m_manager->createTool("Archive", QString(), false)); if(!tool) { KMessageBox::error(mainWindow(), i18n("It was impossible to create the \"Archive\" tool.\n\n" "Please check and repair your installation of Kile."), i18n("Unable to Create Archive Tool")); return; } if(url.isValid()) { tool->setSource(url.toLocalFile()); } tool->prepareToRun(); m_manager->run(tool); } //TODO: move to KileView::Manager void Kile::activateView(QWidget* w, bool updateStruct /* = true */ ) //Needs to be QWidget because of QTabWidget::currentChanged { //KILE_DEBUG_MAIN << "==Kile::activateView==========================" << endl; if (!w || !w->inherits("KTextEditor::View")) { return; } //disable gui updates to avoid flickering of toolbars setUpdatesEnabled(false); QList toolBarsList = toolBars(); QHash toolBarVisibilityHash; for(QList::iterator i = toolBarsList.begin(); i != toolBarsList.end(); ++i) { KToolBar *toolBar = *i; toolBarVisibilityHash[toolBar] = toolBar->isVisible(); } KTextEditor::View* view = dynamic_cast(w); Q_ASSERT(view); for(int i = 0; i < viewManager()->textViewCount(); ++i) { KTextEditor::View *view2 = viewManager()->textView(i); if(view == view2) { continue; } guiFactory()->removeClient(view2); view2->clearFocus(); } guiFactory()->addClient(view); for(QList::iterator i = toolBarsList.begin(); i != toolBarsList.end(); ++i) { KToolBar *toolBar = *i; toolBar->setVisible(toolBarVisibilityHash[*i]); } setUpdatesEnabled(true); if(updateStruct) { viewManager()->updateStructure(); } focusTextView(view); } void Kile::updateModeStatus() { KILE_DEBUG_MAIN << "==Kile::updateModeStatus()=========="; KileProject *project = docManager()->activeProject(); QString shortName = m_masterDocumentFileName; int pos = shortName.lastIndexOf('/'); shortName.remove(0, pos + 1); if(project) { if (m_singlemode) { statusBar()->setHintText(i18n("Project: %1", project->name())); } else { statusBar()->setHintText(i18n("Project: %1 (Master document: %2)", project->name(), shortName)); } } else { if (m_singlemode) { statusBar()->setHintText(i18n("Normal mode")); } else { statusBar()->setHintText(i18n("Master document: %1", shortName)); } } if(m_singlemode) { ModeAction->setText(i18n("Define Current Document as 'Master Document'")); ModeAction->setChecked(false); } else { ModeAction->setText(i18n("Normal mode (current master document: %1)", shortName)); ModeAction->setChecked(true); } // enable or disable entries in Kile'S menu updateMenu(); KTextEditor::View *view = viewManager()->currentTextView(); // Passing Q_NULLPTR is ok updateStatusBarCursorPosition(view, (view ? view->cursorPosition() : KTextEditor::Cursor())); updateStatusBarViewMode(view); updateStatusBarSelection(view); } void Kile::openDocument(const QUrl &url) { docManager()->fileSelected(url); } void Kile::openDocument(const QString& s) { openDocument(QUrl::fromUserInput(s)); } void Kile::closeDocument() { docManager()->fileClose(); } void Kile::openProject(const QUrl &url) { docManager()->projectOpen(url); } void Kile::openProject(const QString& proj) { openProject(QUrl::fromUserInput(proj)); } void Kile::focusPreview() { m_bottomBar->switchToTab(PREVIEW_TAB); } void Kile::focusLog() { m_bottomBar->switchToTab(LOG_TAB); } void Kile::focusOutput() { m_bottomBar->switchToTab(OUTPUT_TAB); } void Kile::focusKonsole() { m_bottomBar->switchToTab(KONSOLE_TAB); } void Kile::focusEditor() { KTextEditor::View *view = viewManager()->currentTextView(); if(view) { focusTextView(view); } } void Kile::sideOrBottomBarChanged(bool visible) { if ( ! visible ) { focusEditor(); } } //FIXME: documents probably shouldn't be closed in this method yet (also see API doc of 'queryClose') bool Kile::queryClose() { KTextEditor::View *view = viewManager()->currentTextView(); if(view) { KileConfig::setLastDocument(view->document()->url().toLocalFile()); } else { KileConfig::setLastDocument(""); } //don't close Kile if embedded viewers are present KILE_DEBUG_MAIN << "==bool Kile::queryClose==========" << endl; m_listProjectsOpenOnStart.clear(); m_listDocsOpenOnStart.clear(); m_listEncodingsOfDocsOpenOnStart.clear(); for(int i = 0; i < viewManager()->textViewCount(); ++i) { KTextEditor::Document *doc = viewManager()->textView(i)->document(); const QUrl url = doc->url(); if(url.isEmpty()) { continue; } m_listDocsOpenOnStart.append(url.toLocalFile()); m_listEncodingsOfDocsOpenOnStart.append(doc->encoding()); } KILE_DEBUG_MAIN << "#projects = " << docManager()->projects().count() << endl; QList projectList = docManager()->projects(); for(QList::iterator i = projectList.begin(); i != projectList.end(); ++i) { const QUrl url = (*i)->url(); if(url.isEmpty()) { // shouldn't happen, but just in case... continue; } m_listProjectsOpenOnStart.append(url.toLocalFile()); } bool stage1 = docManager()->projectCloseAll(); bool stage2 = true; if(stage1) { stage2 = docManager()->fileCloseAll(); } bool close = stage1 && stage2; if(close) { saveSettings(); } return close; } void Kile::showDocInfo(KTextEditor::View *view) { if(!view) { view = viewManager()->currentTextView(); } if(!view) { return; } KileDocument::TextInfo *docinfo = docManager()->textInfoFor(view->document()); KileProject *project = KileInfo::docManager()->activeProject(); if(docinfo) { // we have to ensure that we always get a _valid_ docinfo object KileDialog::StatisticsDialog *dlg = new KileDialog::StatisticsDialog(project, docinfo, this, view); dlg->exec(); delete dlg; } else { qWarning() << "There is no KileDocument::Info object belonging to this document!"; } } void Kile::convertToASCII(KTextEditor::Document *doc) { if(!doc) { KTextEditor::View *view = viewManager()->currentTextView(); if(view) { doc = view->document(); } else { return; } } ConvertIO io(doc); ConvertEncToASCII conv = ConvertEncToASCII(doc->encoding(), &io); doc->setEncoding("ISO 8859-1"); conv.convert(); } void Kile::convertToEnc(KTextEditor::Document *doc) { if(!doc) { KTextEditor::View *view = viewManager()->currentTextView(); if (view) doc = view->document(); else return; } if(sender()) { ConvertIO io(doc); QString name = QString(sender()->objectName()).section('_', -1); ConvertASCIIToEnc conv = ConvertASCIIToEnc(name, &io); conv.convert(); doc->setEncoding(ConvertMap::encodingNameFor(name)); } } KileWidget::StatusBar * Kile::statusBar() { return static_cast(KXmlGuiWindow::statusBar()); } ////////////////// GENERAL SLOTS ////////////// int Kile::lineNumber() { KTextEditor::View *view = viewManager()->currentTextView(); int para = 0; if (view) { para = view->cursorPosition().line(); } return para; } void Kile::newCaption() { KTextEditor::View *view = viewManager()->currentTextView(); if(view) { const bool showFullPath = KileConfig::showFullPathInWindowTitle(); KTextEditor::Document *doc = view->document(); const QString caption = (doc->isReadWrite() ? getName(doc, !showFullPath) : i18nc("Window caption in read-only mode: [Read-Only]", "%1 [Read-Only]", getName(doc, !showFullPath))); setWindowTitle(caption); if (m_bottomBar->currentPage() && m_bottomBar->currentPage()->inherits("KileWidget::Konsole")) { m_texKonsole->sync(); } } else { setWindowTitle(""); } } void Kile::grepItemSelected(const QString &abs_filename, int line) { KILE_DEBUG_MAIN << "Open file: " << abs_filename << " (" << line << ")" << endl; docManager()->fileOpen(QUrl::fromUserInput(abs_filename)); setLine(QString::number(line)); } void Kile::findInFiles() { static QPointer dlg = 0; if (!dlg) { KILE_DEBUG_MAIN << "grep guard: create findInFiles dlg" << endl; dlg = new KileDialog::FindFilesDialog(mainWindow(), this, KileGrep::Directory); dlg->show(); connect(dlg, &KileDialog::FindFilesDialog::itemSelected, this, &Kile::grepItemSelected); } else { KILE_DEBUG_MAIN << "grep guard: show findInFiles dlg" << endl; dlg->activateWindow(); dlg->raise(); } } void Kile::findInProjects() { static QPointer project_dlg = Q_NULLPTR; if(!project_dlg) { KILE_DEBUG_MAIN << "grep guard: create findInProjects dlg" << endl; project_dlg = new KileDialog::FindFilesDialog(mainWindow(), this, KileGrep::Project); project_dlg->show(); connect(project_dlg, &KileDialog::FindFilesDialog::itemSelected, this, &Kile::grepItemSelected); } else { KILE_DEBUG_MAIN << "grep guard: show findInProjects dlg" << endl; project_dlg->activateWindow(); project_dlg->raise(); } } /////////////////// PART & EDITOR WIDGET ////////// bool Kile::resetPart() { KILE_DEBUG_MAIN << "==Kile::resetPart()=============================" << endl; statusBar()->reset(); updateModeStatus(); newCaption(); KTextEditor::View *view = viewManager()->currentTextView(); if (view) { activateView(view); } return true; } void Kile::updateUserDefinedMenus() { m_buildMenuTopLevel = dynamic_cast(m_mainWindow->guiFactory()->container("menu_build", m_mainWindow)); m_buildMenuCompile = dynamic_cast(m_mainWindow->guiFactory()->container("menu_compile", m_mainWindow)); m_buildMenuConvert = dynamic_cast(m_mainWindow->guiFactory()->container("menu_convert", m_mainWindow)); m_buildMenuViewer = dynamic_cast(m_mainWindow->guiFactory()->container("menu_viewer", m_mainWindow)); m_buildMenuOther = dynamic_cast(m_mainWindow->guiFactory()->container("menu_other", m_mainWindow)); m_buildMenuQuickPreview = dynamic_cast(m_mainWindow->guiFactory()->container("quickpreview", m_mainWindow)); m_userMenu->updateGUI(); setupTools(); } void Kile::enableGUI(bool enable) { // update action lists QList actions = actionCollection()->actions(); for(QList::iterator itact = actions.begin(); itact != actions.end(); ++itact) { if (m_dictMenuAction.contains((*itact)->objectName()) || m_dictMenuFile.contains((*itact)->objectName())) { (*itact)->setEnabled(enable); } } // update latex usermenu actions if ( m_userMenu ) { QList useractions = m_userMenu->menuActions(); foreach ( QAction *action, useractions ) { action->setEnabled(enable); } } // enable or disable userhelp entries m_help->enableUserhelpEntries(enable); QList actionList; actionList << m_listQuickActions << m_listCompilerActions << m_listConverterActions << m_listViewerActions << m_listOtherActions; // enable or disable list actions for(QList::iterator i = actionList.begin(); i != actionList.end(); ++i) { (*i)->setEnabled(enable); } // enable or disable bibliography menu entries actionList = m_bibTagActionMenu->menu()->actions(); for(QList::iterator it = actionList.begin(); it != actionList.end(); ++it) { (*it)->setEnabled(enable); } QStringList menuList; menuList << "file" << "edit" << "view" << "menu_build" << "menu_project" << "menu_latex" << "wizard" << "tools"; for(QStringList::iterator it = menuList.begin(); it != menuList.end(); ++it) { QMenu *menu = dynamic_cast(guiFactory()->container(*it, this)); if(menu) { updateMenuActivationStatus(menu); } } updateUserMenuStatus(enable); } // adds action names to their lists void Kile::initMenu() { QStringList projectlist,filelist,actionlist; projectlist << "project_add" << "project_remove" << "project_showfiles" << "project_buildtree" << "project_options" << "project_findfiles" << "project_archive" << "project_close" << "project_openallfiles" ; filelist // file << "convert" // edit << "goto_menu" << "complete" << "bullet" << "select" << "delete" << "environment" << "texgroup" // build << "quickpreview" << "menu_compile" << "menu_convert" << "menu_viewers" << "menu_other" // latex << "menu_preamble" << "menu_lists" << "menu_sectioning" << "references" << "menu_environment" << "menu_listenv" << "menu_tabularenv" << "menu_floatenv" << "menu_code" << "menu_math" << "menu_mathenv" << "menu_mathamsenv" << "menu_bibliography" << "menu_fontstyles" << "menu_spacing" ; actionlist // file << "file_save_copy_as" << "file_save_all" << "template_create" << "Statistics" << "file_close" << "file_close_all" << "file_close_all_others" // edit << "RefreshStructure" // view << "gotoPrevDocument" << "gotoNextDocument" // build << "quickpreview_selection" << "quickpreview_environment" << "quickpreview_subdocument" << "quickpreview_math" << "WatchFile" << "CleanAll" // latex << "tag_documentclass" << "tag_usepackage" << "tag_amspackages" << "tag_env_document" << "tag_author" << "tag_title" << "tag_maketitle" << "tag_titlepage" << "tag_env_abstract" << "tag_tableofcontents" << "tag_listoffigures" << "tag_listoftables" << "tag_makeindex" << "tag_printindex" << "tag_makeglossary" << "tag_env_thebibliography" << "tag_part" << "tag_chapter" << "tag_section" << "tag_subsection" << "tag_subsubsection" << "tag_paragraph" << "tag_subparagraph" << "tag_label" << "tag_ref" << "tag_pageref" << "tag_index" << "tag_footnote" << "tag_cite" // << "citeViewBib" << "tag_center" << "tag_flushleft" << "tag_flushright" << "tag_env_minipage" << "tag_quote" << "tag_quotation" << "tag_verse" << "tag_env_itemize" << "tag_env_enumerate" << "tag_env_description" << "tag_item" << "tag_env_tabular" << "tag_env_tabular*" << "tag_env_tabbing" << "tag_multicolumn" << "tag_hline" << "tag_vline" << "tag_cline" << "tag_figure" << "tag_table" << "tag_verbatim" << "tag_env_verbatim*" << "tag_verb" << "tag_verb*" << "tag_mathmode" << "tag_equation" << "tag_subscript" << "tag_superscript" << "tag_sqrt" << "tag_nroot" << "tag_left" << "tag_right" << "tag_leftright" << "tag_bigl" << "tag_bigr" << "tag_Bigl" << "tag_Bigr" << "tag_biggl" << "tag_biggr" << "tag_Biggl" << "tag_Biggr" << "tag_text" << "tag_intertext" << "tag_boxed" << "tag_frac" << "tag_dfrac" << "tag_tfrac" << "tag_binom" << "tag_dbinom" << "tag_tbinom" << "tag_xleftarrow" << "tag_xrightarrow" << "tag_mathrm" << "tag_mathit" << "tag_mathbf" << "tag_mathsf" << "tag_mathtt" << "tag_mathcal" << "tag_mathbb" << "tag_mathfrak" << "tag_acute" << "tag_grave" << "tag_tilde" << "tag_bar" << "tag_vec" << "tag_hat" << "tag_check" << "tag_breve" << "tag_dot" << "tag_ddot" << "tag_space_small" << "tag_space_medium" << "tag_space_large" << "tag_quad" << "tag_qquad" << "tag_enskip" << "tag_env_displaymath" << "tag_env_equation" << "tag_env_equation*" << "tag_env_array" << "tag_env_multline" << "tag_env_multline*" << "tag_env_split" << "tag_env_gather" << "tag_env_gather*" << "tag_env_align" << "tag_env_align*" << "tag_env_flalign" << "tag_env_flalign*" << "tag_env_alignat" << "tag_env_alignat*" << "tag_env_aligned" << "tag_env_gathered" << "tag_env_alignedat" << "tag_env_cases" << "tag_env_matrix" << "tag_env_pmatrix" << "tag_env_vmatrix" << "tag_env_VVmatrix" << "tag_env_bmatrix" << "tag_env_BBmatrix" // bibliography stuff << "menu_bibliography" << "setting_bibtex" << "setting_biblatex" << "tag_textit" << "tag_textsl" << "tag_textbf" << "tag_underline" << "tag_texttt" << "tag_textsc" << "tag_emph" << "tag_strong" << "tag_rmfamily" << "tag_sffamily" << "tag_ttfamily" << "tag_mdseries" << "tag_bfseries" << "tag_upshape" << "tag_itshape" << "tag_slshape" << "tag_scshape" << "tag_newline" << "tag_newpage" << "tag_linebreak" << "tag_pagebreak" << "tag_bigskip" << "tag_medskip" << "tag_smallskip" << "tag_hspace" << "tag_hspace*" << "tag_vspace" << "tag_vspace*" << "tag_hfill" << "tag_hrulefill" << "tag_dotfill" << "tag_vfill" << "tag_includegraphics" << "tag_include" << "tag_input" // wizard << "wizard_tabular" << "wizard_array" << "wizard_tabbing" << "wizard_float" << "wizard_mathenv" << "wizard_usermenu" << "wizard_usermenu2" // settings << "Mode" // help << "help_context" // action lists << "structure_list" << "size_list" << "other_list" << "left_list" << "right_list" // tool lists << "list_compiler_select" << "list_convert_select" << "list_view_select" << "list_quick_select" // user help << "help_userhelp" << "edit_next_bullet" << "edit_prev_bullet" << "edit_next_section" << "edit_prev_section" << "edit_next_paragraph" << "edit_prev_paragraph" << "edit_select_inside_env" << "edit_select_outside_env" << "edit_select_inside_group" << "edit_select_outside_group" << "edit_select_mathgroup" << "edit_select_paragraph" << "edit_select_line" << "edit_select_word" << "edit_delete_inside_env" << "edit_delete_outside_env" << "edit_delete_inside_group" << "edit_delete_outside_group" << "edit_delete_mathgroup" << "edit_delete_paragraph" << "edit_delete_eol" << "edit_delete_word" << "edit_complete_word" << "edit_complete_env" << "edit_complete_abbrev" << "edit_begin_env" << "edit_end_env" << "edit_match_env" << "edit_close_env" << "edit_closeall_env" << "edit_begin_group" << "edit_end_group" << "edit_match_group" << "edit_close_group" << "file_export_ascii" << "file_export_latin1" << "file_export_latin2" << "file_export_latin3" << "file_export_latin4" << "file_export_latin5" << "file_export_latin9" << "file_export_cp1250" << "file_export_cp1252" ; setMenuItems(projectlist,m_dictMenuProject); setMenuItems(filelist,m_dictMenuFile); setMenuItems(actionlist,m_dictMenuAction); } void Kile::setMenuItems(QStringList &list, QMap &dict) { for ( QStringList::Iterator it=list.begin(); it!=list.end(); ++it ) { dict[(*it)] = true; } } void Kile::updateMenu() { KILE_DEBUG_MAIN << "==Kile::updateMenu()====================" << endl; QAction *a; QMap::Iterator it; // update project menus m_actRecentProjects->setEnabled( m_actRecentProjects->items().count() > 0 ); bool project_open = ( docManager()->isProjectOpen() ) ; for ( it=m_dictMenuProject.begin(); it!=m_dictMenuProject.end(); ++it ) { a = actionCollection()->action(it.key()); if(a) { a->setEnabled(project_open); } } // project_show is only enabled, when more than 1 project is opened a = actionCollection()->action("project_show"); if(a) { a->setEnabled(project_open && docManager()->projects().count() > 1); } // update file menus m_actRecentFiles->setEnabled( m_actRecentFiles->items().count() > 0 ); bool file_open = ( viewManager()->currentTextView() ); KILE_DEBUG_MAIN << "\tprojectopen=" << project_open << " fileopen=" << file_open << endl; enableGUI(file_open); } bool Kile::updateMenuActivationStatus(QMenu *menu) { return updateMenuActivationStatus(menu, QSet()); } bool Kile::updateMenuActivationStatus(QMenu *menu, const QSet& visited) { if(visited.contains(menu)) { qWarning() << "Recursive menu structure detected - aborting!"; return true; } if(menu->objectName() == "usermenu-submenu") { menu->setEnabled(true); return true; } bool enabled = false; QList actionList = menu->actions(); for(QList::iterator it = actionList.begin(); it != actionList.end(); ++it) { QAction *action = *it; QMenu *subMenu = action->menu(); if(subMenu) { QSet newVisited(visited); newVisited.insert(menu); if(updateMenuActivationStatus(subMenu, newVisited)) { enabled = true; } } else if(!action->isSeparator() && action->isEnabled()) { enabled = true; } } menu->setEnabled(enabled); return enabled; } void Kile::updateLatexenuActivationStatus(QMenu *menu, bool state) { if ( menu->isEmpty() || !viewManager()->currentTextView() ) { state = false; } menu->menuAction()->setVisible(state); } void Kile::runTool(const QString& tool) { runToolWithConfig(tool, QString()); } void Kile::runToolWithConfig(const QString &toolName, const QString &config) { KILE_DEBUG_MAIN << toolName << config; focusLog(); KileTool::Base *tool = m_manager->createTool(toolName, config); if(!tool || (tool->requestSaveAll() && !m_docManager->fileSaveAll())) { delete tool; return; } return m_manager->run(tool); } void Kile::cleanAll(KileDocument::TextInfo *docinfo) { const QString noactivedoc = i18n("There is no active document or it is not saved."); if(!docinfo) { KTextEditor::Document *doc = activeTextDocument(); if (doc) { docinfo = docManager()->textInfoFor(doc); } else { errorHandler()->printMessage(KileTool::Error, noactivedoc, i18n("Clean")); return; } } if (docinfo) { docManager()->cleanUpTempFiles(docinfo->url(), false); } } void Kile::refreshStructure() { viewManager()->updateStructure(true); } void Kile::insertTag(const KileAction::TagData& data) { errorHandler()->clearMessages(); if(data.description.length() > 0) { focusLog(); errorHandler()->printMessage(data.description); } KTextEditor::View *view = viewManager()->currentTextView(); if(!view) { return; } focusTextView(view); editorExtension()->insertTag(data, view); } void Kile::insertTag(const QString& tagB, const QString& tagE, int dx, int dy) { insertTag(KileAction::TagData(QString(), tagB, tagE, dx, dy)); } void Kile::insertAmsTag(const KileAction::TagData& data) { insertTag(data, QStringList("amsmath")); } void Kile::insertTag(const KileAction::TagData& data,const QList &pkgs) { QStringList packages; QString pkgName; QList::const_iterator it; for(it = pkgs.begin(); it != pkgs.end() ; it++) { pkgName = (*it).name; if(!pkgName.isEmpty()) { packages.append(pkgName); } } insertTag(data,packages); } void Kile::insertTag(const KileAction::TagData& data,const QStringList &pkgs) { KILE_DEBUG_MAIN << "void Kile::insertTag(const KileAction::TagData& data,const QStringList " << pkgs.join(",") << ")" << endl; insertTag(data); KileDocument::TextInfo *docinfo = docManager()->textInfoFor(getCompileName()); if(docinfo) { QStringList packagelist = allPackages(docinfo); QStringList::const_iterator it; QStringList warnPkgs; for ( it = pkgs.begin(); it != pkgs.end(); ++it) { if(!packagelist.contains(*it)) { warnPkgs.append(*it); } } if(warnPkgs.count() > 0) { if(warnPkgs.count() == 1) { errorHandler()->printMessage(KileTool::Error, i18n("You have to include the package %1.", warnPkgs.join(",")), i18n("Insert text")); } else { errorHandler()->printMessage(KileTool::Error, i18n("You have to include the packages %1.", warnPkgs.join(",")), i18n("Insert text")); } } } } void Kile::insertText(const QString &text) { if(text.indexOf("%C")>=0) insertTag(KileAction::TagData(QString(), text, QString(), 0, 0)); else insertTag(KileAction::TagData(QString(), text, "%C", 0, 0)); } void Kile::insertText(const QString &text, const QStringList &pkgs) { insertTag(KileAction::TagData(QString(), text, "%C", 0, 0), pkgs); } void Kile::insertText(const QString &text, const QList &pkgs) { insertTag(KileAction::TagData(QString(), text, "%C", 0, 0), pkgs); } void Kile::quickDocument() { KileDialog::QuickDocument *dlg = new KileDialog::QuickDocument(m_config.data(), this, "Quick Start", i18n("Quick Start")); if(dlg->exec()) { if(!viewManager()->currentTextView()) { docManager()->createNewLaTeXDocument(); } insertTag( dlg->tagData() ); viewManager()->updateStructure(true); } delete dlg; } void Kile::quickArray() { quickTabulardialog(false); } void Kile::quickTabular() { quickTabulardialog(true); } void Kile::quickTabulardialog(bool tabularenv) { if(!viewManager()->currentTextView()) { return; } QString env; if(tabularenv) { KConfigGroup group = m_config->group("Wizard"); env = group.readEntry("TabularEnvironment", "tabular"); } else { env = "array"; } KileDialog::NewTabularDialog dlg(env, m_latexCommands, m_config.data(), this); if(dlg.exec()) { insertTag(dlg.tagData(), dlg.requiredPackages()); if(tabularenv) { KConfigGroup group = m_config->group("Wizard"); group.writeEntry("TabularEnvironment", dlg.environment()); m_config->sync(); } } } void Kile::quickTabbing() { if(!viewManager()->currentTextView()) { return; } KileDialog::QuickTabbing *dlg = new KileDialog::QuickTabbing(m_config.data(), this, this, "Tabbing", i18n("Tabbing")); if(dlg->exec()) { insertTag(dlg->tagData()); } delete dlg; } void Kile::quickFloat() { if(!viewManager()->currentTextView()) { return; } KileDialog::FloatEnvironmentDialog *dlg = new KileDialog::FloatEnvironmentDialog(m_config.data(), this, this); if(dlg->exec()) { insertTag(dlg->tagData()); } delete dlg; } void Kile::quickMathenv() { if(!viewManager()->currentTextView()) { return; } KileDialog::MathEnvironmentDialog *dlg = new KileDialog::MathEnvironmentDialog(this, m_config.data(), this, m_latexCommands); if(dlg->exec()) { insertTag(dlg->tagData()); } delete dlg; } void Kile::quickPostscript() { QString startdir = QDir::homePath(); QString texfilename; KTextEditor::View *view = viewManager()->currentTextView(); if(view) { startdir = QFileInfo(view->document()->url().toLocalFile()).path(); texfilename = getCompileName(); } KileDialog::PostscriptDialog *dlg = new KileDialog::PostscriptDialog(this, texfilename, startdir, m_extensions->latexDocuments(), errorHandler(), m_outputWidget); dlg->exec(); delete dlg; } void Kile::quickPdf() { QString startDir = QDir::homePath(); QString texFileName; KTextEditor::View *view = viewManager()->currentTextView(); if(view) { startDir = QFileInfo(view->document()->url().toLocalFile()).path(); texFileName = getCompileName(); } KileDialog::PdfDialog *dlg = new KileDialog::PdfDialog(m_mainWindow, texFileName, startDir, m_extensions->latexDocuments(), m_manager, errorHandler(), m_outputWidget); dlg->exec(); delete dlg; } void Kile::quickUserMenuDialog() { m_userMenu->removeShortcuts(); QPointer dlg = new KileMenu::UserMenuDialog(m_config.data(), this, m_userMenu, m_userMenu->xmlFile(), m_mainWindow); dlg->exec(); connect(dlg, &QDialog::finished, this, [this] (int result) { Q_UNUSED(result); // tell all the documents and views to update their action shortcuts (bug 247646) docManager()->reloadXMLOnAllDocumentsAndViews(); // a new usermenu could have been installed, even if the return value is QDialog::Rejected m_userMenu->refreshActionProperties(); }); delete dlg; } void Kile::slotUpdateUserMenuStatus() { KILE_DEBUG_MAIN << "slot update usermenu status"; updateUserMenuStatus(true); } void Kile::updateUserMenuStatus(bool state) { KILE_DEBUG_MAIN << "update usermenu status"; if(m_userMenu) { QMenu *menu = m_userMenu->getMenuItem(); if(menu) { updateLatexenuActivationStatus(menu,state); } } } void Kile::helpLaTex() { QString loc = QStandardPaths::locate(QStandardPaths::DataLocation, "help/latexhelp.html"); KileTool::Base *tool = toolManager()->createTool("ViewHTML", QString(), false); if(!tool) { errorHandler()->printMessage(KileTool::Error, i18n("Could not create the \"ViewHTML\" tool. Please reset the tools.")); return; } tool->setFlags(KileTool::NeedSourceExists | KileTool::NeedSourceRead); tool->setSource(loc); tool->setTargetPath(loc); tool->prepareToRun(); m_manager->run(tool); } void Kile::readGUISettings() { } // transform old user tags to xml file void Kile::transformOldUserTags() { KILE_DEBUG_MAIN << "Convert old user tags"; QString xmldir = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/usermenu/"; // create dir if not existing QDir testDir(xmldir); if (!testDir.exists()) { testDir.mkpath(xmldir); } KConfigGroup userGroup = m_config->group("User"); int len = userGroup.readEntry("nUserTags", 0); if ( len > 0) { QString usertagfile = "usertags.xml"; QString filename = xmldir + usertagfile; KILE_DEBUG_MAIN << "-convert user tags " << filename; QFile file(filename); if ( !file.open(QFile::WriteOnly | QFile::Text) ) { KILE_DEBUG_MAIN << "-Error - could not open file to write: " << filename; return; } KILE_DEBUG_MAIN << "Write xml: " << filename; QXmlStreamWriter xml(&file); xml.setAutoFormatting(true); xml.setAutoFormattingIndent(2) ; xml.writeStartDocument(); xml.writeStartElement("UserMenu"); for (int i = 0; i < len; ++i) { const QString tagNameConfigKey = "userTagName" + QString::number(i); const QString tagname = userGroup.readEntry(tagNameConfigKey, i18n("No Name")); const QString tagConfigKey = "userTag" + QString::number(i); QString tag = userGroup.readEntry(tagConfigKey, ""); tag = tag.replace('\n',"\\n"); xml.writeStartElement("menu"); xml.writeAttribute("type", "text"); xml.writeTextElement(KileMenu::UserMenuData::xmlMenuTagName(KileMenu::UserMenuData::XML_TITLE), tagname); xml.writeTextElement(KileMenu::UserMenuData::xmlMenuTagName(KileMenu::UserMenuData::XML_PLAINTEXT), tag); xml.writeTextElement(KileMenu::UserMenuData::xmlMenuTagName(KileMenu::UserMenuData::XML_SHORTCUT), QString("Ctrl+Shift+%1").arg(i+1)); xml.writeEndElement(); userGroup.deleteEntry(tagNameConfigKey); userGroup.deleteEntry(tagConfigKey); } xml.writeEndDocument(); file.close(); // save current xml file KileConfig::setUserMenuFile(usertagfile); } userGroup.deleteEntry("nUserTags"); } void Kile::transformOldUserSettings() { //delete old editor key if(m_config->hasGroup("Editor")) { m_config->deleteGroup("Editor"); } //convert user tools to new KileTool classes KConfigGroup userGroup = m_config->group("User"); userItem tempItem; int len = userGroup.readEntry("nUserTools", 0); for (int i=0; i< len; ++i) { tempItem.name = userGroup.readEntry("userToolName" + QString::number(i), i18n("no name")); tempItem.tag = userGroup.readEntry("userTool" + QString::number(i), ""); m_listUserTools.append(tempItem); } if(len > 0) { //move the tools userGroup.writeEntry("nUserTools", 0); for(int i = 0; i < len; ++i) { tempItem = m_listUserTools[i]; KConfigGroup toolsGroup = m_config->group("Tools"); toolsGroup.writeEntry(tempItem.name, "Default"); KileTool::setGUIOptions(tempItem.name, "Other", "preferences-other", m_config.data()); KConfigGroup group = m_config->group(KileTool::groupFor(tempItem.name, "Default")); QString bin = KRun::binaryName(tempItem.tag, false); group.writeEntry("command", bin); group.writeEntry("options", tempItem.tag.mid(bin.length())); group.writeEntry("class", "Base"); group.writeEntry("type", "Process"); group.writeEntry("from", ""); group.writeEntry("to", ""); if(i < 10) { QAction *toolAction = static_cast(actionCollection()->action("tool_" + tempItem.name)); actionCollection()->setDefaultShortcut(toolAction, "Alt+Shift+" + QString::number(i + 1)); //should be alt+shift+ } } } } void Kile::readRecentFileSettings() { KConfigGroup group = m_config->group("FilesOpenOnStart"); int n = group.readEntry("NoDOOS", 0); for (int i = 0; i < n; ++i) { const QString urlString = group.readPathEntry("DocsOpenOnStart" + QString::number(i), ""); if(urlString.isEmpty()) { continue; } m_listDocsOpenOnStart.append(urlString); m_listEncodingsOfDocsOpenOnStart.append(group.readPathEntry("EncodingsOfDocsOpenOnStart" + QString::number(i), "")); } n = group.readEntry("NoPOOS", 0); for(int i = 0; i < n; ++i) { const QString urlString = group.readPathEntry("ProjectsOpenOnStart" + QString::number(i), ""); if(urlString.isEmpty()) { continue; } m_listProjectsOpenOnStart.append(urlString); } } void Kile::readConfig() { m_codeCompletionManager->readConfig(m_config.data()); if(m_livePreviewManager) { m_livePreviewManager->readConfig(m_config.data()); } //m_edit->initDoubleQuotes(); m_edit->readConfig(); docManager()->updateInfos(); m_jScriptManager->readConfig(); docManager()->readConfig(); viewManager()->readConfig(m_horizontalSplitter); // set visible views in sidebar m_sideBar->setPageVisible(m_scriptsManagementWidget, KileConfig::scriptingEnabled()); m_sideBar->setPageVisible(m_commandViewToolBox, KileConfig::showCwlCommands()); m_sideBar->setPageVisible(m_kileAbbrevView, KileConfig::completeShowAbbrev()); m_scriptsManagementWidget->setScriptNameColumnWidth(KileConfig::scriptNameColumnWidth()); if(KileConfig::displayMFUS()) { enableSymbolViewMFUS(); } else { disableSymbolViewMFUS(); } m_commandViewToolBox->readCommandViewFiles(); abbreviationManager()->readAbbreviationFiles(); } void Kile::saveSettings() { m_fileBrowserWidget->writeConfig(); if(m_livePreviewManager) { m_livePreviewManager->writeConfig(); } m_symbolViewMFUS->writeConfig(); saveLastSelectedAction(); // Store recent files m_actRecentFiles->saveEntries(m_config->group("Recent Files")); m_actRecentProjects->saveEntries(m_config->group("Projects")); m_config->deleteGroup("FilesOpenOnStart"); if (KileConfig::restore()) { KConfigGroup configGroup = m_config->group("FilesOpenOnStart"); KileConfig::setSingleFileMasterDocument(getMasterDocumentFileName()); configGroup.writeEntry("NoDOOS", m_listDocsOpenOnStart.count()); for (int i = 0; i < m_listDocsOpenOnStart.count(); ++i) { configGroup.writePathEntry("DocsOpenOnStart" + QString::number(i), m_listDocsOpenOnStart[i]); configGroup.writePathEntry("EncodingsOfDocsOpenOnStart" + QString::number(i), m_listEncodingsOfDocsOpenOnStart[i]); } configGroup.writeEntry("NoPOOS", m_listProjectsOpenOnStart.count()); for (int i = 0; i < m_listProjectsOpenOnStart.count(); ++i) { configGroup.writePathEntry("ProjectsOpenOnStart"+QString::number(i), m_listProjectsOpenOnStart[i]); } } KConfigGroup configGroup = KSharedConfig::openConfig()->group("KileMainWindow"); saveMainWindowSettings(configGroup); docManager()->writeConfig(); viewManager()->writeConfig(); scriptManager()->writeConfig(); KileConfig::setScriptNameColumnWidth(m_scriptsManagementWidget->scriptNameColumnWidth()); KileConfig::setRCVersion(KILERC_VERSION); KileConfig::setMainwindowWidth(width()); KileConfig::setMainwindowHeight(height()); QList sizes; QList::Iterator it; sizes = m_horizontalSplitter->sizes(); it = sizes.begin(); KileConfig::setHorizontalSplitterLeft(*it); ++it; KileConfig::setHorizontalSplitterRight(*it); sizes.clear(); sizes = m_verticalSplitter->sizes(); it = sizes.begin(); KileConfig::setVerticalSplitterTop(*it); ++it; KileConfig::setVerticalSplitterBottom(*it); #ifdef __GNUC__ #warning Restoring the side bar sizes from minimized after start up does not work perfectly yet! #endif // // sync vertical splitter and size of bottom bar // int sizeBottomBar = m_bottomBar->directionalSize(); // if(m_bottomBar->isVisible()) { // sizeBottomBar = m_verSplitBottom; // } // else { // m_verSplitBottom = sizeBottomBar; // } KileConfig::setSideBar(!m_sideBar->isHidden()); // do not use 'isVisible()'! KileConfig::setSideBarSize(m_sideBar->directionalSize()); KileConfig::setBottomBar(!m_bottomBar->isHidden()); // do not use 'isVisible()'! KileConfig::setBottomBarSize(m_bottomBar->directionalSize()); KileConfig::setBottomBarIndex(m_bottomBar->currentTab()); KileConfig::setSelectedLeftView(m_sideBar->currentTab()); abbreviationManager()->saveLocalAbbreviations(); KileConfig::self()->save(); m_config->sync(); } ///////////////// OPTIONS //////////////////// void Kile::setMasterDocumentFileName(const QString& fileName) { if(fileName.isEmpty() || !viewManager()->viewForLocalFilePresent(fileName)) { return; } m_masterDocumentFileName = fileName; QString shortName = QFileInfo(m_masterDocumentFileName).fileName(); ModeAction->setText(i18n("Normal mode (current master document: %1)", shortName)); ModeAction->setChecked(true); m_singlemode = false; updateModeStatus(); emit masterDocumentChanged(); KILE_DEBUG_MAIN << "SETTING master to " << m_masterDocumentFileName << " singlemode = " << m_singlemode << endl; } void Kile::clearMasterDocument() { ModeAction->setText(i18n("Define Current Document as 'Master Document'")); ModeAction->setChecked(false); m_singlemode = true; m_masterDocumentFileName.clear(); updateModeStatus(); emit masterDocumentChanged(); KILE_DEBUG_MAIN << "CLEARING master document"; } void Kile::toggleMasterDocumentMode() { if (!m_singlemode) { clearMasterDocument(); } else if (m_singlemode && viewManager()->currentTextView()) { QString name = getName(); if(name.isEmpty()) { ModeAction->setChecked(false); KMessageBox::error(this, i18n("In order to define the current document as a master document, it has to be saved first.")); return; } setMasterDocumentFileName(name); } else { ModeAction->setChecked(false); updateModeStatus(); } } void Kile::toggleWatchFile() { m_bWatchFile=!m_bWatchFile; if (m_bWatchFile) { WatchFileAction->setChecked(true); } else { WatchFileAction->setChecked(false); } } // execute configuration dialog void Kile::generalOptions() { KileDialog::Config *dlg = new KileDialog::Config(m_config.data(), this, this); KileUtilities::scheduleCenteringOfWidget(dlg); if (dlg->exec()) { // update new settings readConfig(); saveLastSelectedAction(); // save the old current tools before calling setupTools() which calls restoreLastSelectedActions() setupTools(); m_help->update(); newCaption(); // for the 'showFullPathInWindowTitle' setting configurationManager()->emitConfigChanged(); //stop/restart LyX server if necessary if(KileConfig::runLyxServer() && !m_lyxserver->isRunning()) { m_lyxserver->start(); } if(!KileConfig::runLyxServer() && m_lyxserver->isRunning()) { m_lyxserver->stop(); } } delete dlg; } void Kile::slotPerformCheck() { // first we have to disable the live preview that may be running, and clear the master document const bool livePreviewEnabledForFreshlyOpenedDocuments = KileConfig::previewEnabledForFreshlyOpenedDocuments(); const bool livePreviewEnabledForCurrentDocument = livePreviewManager() && livePreviewManager()->isLivePreviewEnabledForCurrentDocument(); if (livePreviewManager()) { KileConfig::setPreviewEnabledForFreshlyOpenedDocuments(false); livePreviewManager()->setLivePreviewEnabledForCurrentDocument(false); } // we show the message output widget in the bottom bar and shrink the side bar int sideBarTab = m_sideBar->currentTab(); int bottomBarTab = m_bottomBar->currentTab(); m_sideBar->shrink(); m_bottomBar->switchToTab(0); // show the log widget int outputTab = m_errorHandler->currentOutputTabIndex(); m_errorHandler->showMessagesOutput(); QString currentMasterDocument = m_masterDocumentFileName; if(!m_singlemode) { clearMasterDocument(); } // we hide the editor pane and tabs m_viewManager->setTabsAndEditorVisible(false); // now, we can run the tests KileDialog::ConfigChecker *dlg = new KileDialog::ConfigChecker(this); dlg->exec(); delete dlg; m_errorHandler->clearMessages(); m_errorHandler->clearErrorOutput(); // finally, we restore the rest to what it was before launching the tests m_viewManager->setTabsAndEditorVisible(true); if(!currentMasterDocument.isEmpty()) { setMasterDocumentFileName(currentMasterDocument); } m_errorHandler->setCurrentOutputTab(outputTab); if(sideBarTab >= 0) { m_sideBar->switchToTab(sideBarTab); } if(bottomBarTab < 0) { m_bottomBar->shrink(); } else { m_bottomBar->switchToTab(bottomBarTab); } if (livePreviewManager()) { KileConfig::setPreviewEnabledForFreshlyOpenedDocuments(livePreviewEnabledForFreshlyOpenedDocuments); if(livePreviewEnabledForCurrentDocument) { livePreviewManager()->setLivePreviewEnabledForCurrentDocument(true); } } } void Kile::aboutEditorComponent() { KTextEditor::Editor *editor = m_docManager->getEditor(); if(!editor) { return; } KAboutApplicationDialog dialog(editor->aboutData(), this); dialog.exec(); } /////////////// KEYS - TOOLBARS CONFIGURATION //////////////// void Kile::configureKeys() { KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); // due to bug 280988, we can't add all the clients... // QList clients = guiFactory()->clients(); // for(QList::iterator it = clients.begin(); it != clients.end(); ++it) { // dlg.addCollection((*it)->actionCollection()); // } dlg.addCollection(mainWindow()->actionCollection()); KTextEditor::View *view = m_viewManager->currentTextView(); if(view) { dlg.addCollection(view->actionCollection()); } KParts::ReadOnlyPart *part = viewManager()->viewerPart(); if(part) { dlg.addCollection(part->actionCollection()); } dlg.configure(); // tell all the documents and views to update their action shortcuts (bug 247646) docManager()->reloadXMLOnAllDocumentsAndViews(); // tell m_userMenu that key bindings may have been changed m_userMenu->updateKeyBindings(); } void Kile::configureToolbars() { { KConfigGroup configGroup = KSharedConfig::openConfig()->group("KileMainWindow"); saveMainWindowSettings(configGroup); } KEditToolBar dlg(factory()); connect(&dlg, &KEditToolBar::newToolBarConfig, this, [this] () { setUpdatesEnabled(false); applyMainWindowSettings(m_config->group("KileMainWindow")); updateUserDefinedMenus(); setUpdatesEnabled(true); }); dlg.exec(); } //////////////////// CLEAN BIB ///////////////////// void Kile::cleanBib() { KTextEditor::View *view = viewManager()->currentTextView(); if ( ! view ) return; QRegExp reOptional( "(ALT|OPT)(\\w+)\\s*=\\s*(\\S.*)" ); QRegExp reNonEmptyEntry( ".*\\w.*" ); QString s; int i = 0; while(i < view->document()->lines()) { s = view->document()->line(i); // do we have a line that starts with ALT or OPT? if(reOptional.indexIn(s) >= 0) { // yes! capture type and entry QString type = reOptional.cap( 2 ); QString entry = reOptional.cap( 3 ); view->document()->removeLine( i ); view->document()->setModified(true); if(reNonEmptyEntry.indexIn(entry) >= 0) { type.append(" = "); type.append(entry); view->document()->insertLine(i, type); ++i; } } else { ++i; } } int j = 0; for (i = 0; i < view->document()->lines(); ++i) { j = i+1; if(j < view->document()->lines() && view->document()->line(j).contains(QRegExp("^\\s*\\}\\s*$"))) { s = view->document()->line(i); view->document()->removeLine(i); s.remove(QRegExp(",\\s*$")); view->document()->setModified(true); view->document()->insertLine(i, s); } } } void Kile::includeGraphics() { KTextEditor::View *view = viewManager()->currentTextView(); if ( !view ) return; QFileInfo fi( view->document()->url().toLocalFile() ); KileDialog::IncludeGraphics *dialog = new KileDialog::IncludeGraphics(this, fi.path(), this); if ( dialog->exec() == QDialog::Accepted ) { insertTag(dialog->getTemplate(), "%C", 0,0); docManager()->projectAddFile( dialog->getFilename(),true ); } delete dialog; } void Kile::slotToggleFullScreen() { if (!m_pFullScreen->isChecked()) { setWindowState( windowState() & ~Qt::WindowFullScreen ); } else { setWindowState( windowState() | Qt::WindowFullScreen ); } } /////////////// QuickPreview (dani) //////////////// // all calls of QuickPreview will get here, so we can decide what to do // rewritten Sep 05 2006 to work together with preview in the bottom bar void Kile::slotQuickPreview(int type) { KILE_DEBUG_MAIN << "==Kile::slotQuickPreview()==========================" << endl; KTextEditor::View *view = viewManager()->currentTextView(); if ( ! view) return; KTextEditor::Document *doc = view->document(); if ( ! doc ) return; switch ( type ) { case KileTool::qpSelection: m_quickPreview->previewSelection(view); break; case KileTool::qpEnvironment: m_quickPreview->previewEnvironment(doc); break; case KileTool::qpSubdocument: m_quickPreview->previewSubdocument(doc); break; case KileTool::qpMathgroup: m_quickPreview->previewMathgroup(doc); break; } } /* FIXME Port the citeViewBib function as soon as we got a kbib version for KDE4. void Kile::citeViewBib() { KILE_DEBUG_MAIN << "===void Kile::citeViewBib()===" << endl; DCOPClient *client = kapp->dcopClient(); QByteArray params, replyData; Q3CString replyType; QDataStream stream(params, QIODevice::WriteOnly); QCStringList functions,remoteApps,remoteObjs; const Q3CString viewBibApp = "kbib"; // currently these things are hardcoded because only kbib supports it const Q3CString viewBibObj = "kbibapp"; const Q3CString viewBibFncDef = "QString cite()"; const Q3CString viewBibFnc = "cite()"; remoteApps = client->registeredApplications(); if( !remoteApps.contains(viewBibApp) ) { errorHandler()->printMessage(KileTool::Warning, i18n("No ViewBib tool running, trying to start it now"), i18n("ViewBib Citation")); uint ret = runWith("ViewBib","KBib"); if( ret == 0 ) errorHandler()->printMessage(KileTool::Info, i18n("Please select the desired bibliographies and re-execute this command"), i18n("ViewBib Citation")); return; } remoteObjs = client->remoteObjects(viewBibApp); if( !remoteObjs.contains(viewBibObj) ) { errorHandler()->printMessage(KileTool::Warning, i18n("The ViewBib tool does not have the correct interface"), i18n("ViewBib Citation")); return; } functions = client->remoteFunctions(viewBibApp,viewBibObj); if( !functions.contains(viewBibFncDef) ) { errorHandler()->printMessage(KileTool::Warning, i18n("The ViewBib tool does not have the correct definition of the cite function"), i18n("ViewBib Citation")); return; } if ( !client->call(viewBibApp, viewBibObj, viewBibFnc, params, replyType, replyData) ) { // we should never get here qWarning() << "internal error in viewbib citation" << endl; return; } else{ QDataStream reply(replyData, QIODevice::ReadOnly); if (replyType == "QString") { QString result; reply >> result; if (result.isEmpty()) { errorHandler()->printMessage(KileTool::Warning, i18n("No reference selected.\nPlease select a reference first!"), i18n("ViewBib Citation")); } else { insertTag(KileAction::TagData(i18n("ViewBib Citation"), result, QString(), result.length())); } } } } */ void Kile::addRecentFile(const QUrl &url) { m_actRecentFiles->addUrl(url); } void Kile::removeRecentFile(const QUrl &url) { m_actRecentFiles->removeUrl(url); } void Kile::addRecentProject(const QUrl &url) { m_actRecentProjects->addUrl(url); } void Kile::removeRecentProject(const QUrl &url) { m_actRecentProjects->removeUrl(url); } void Kile::updateStatusBarCursorPosition(KTextEditor::View *view, const KTextEditor::Cursor &newPosition) { if(!view) { statusBar()->clearLineColumn(); } else { statusBar()->setLineColumn(newPosition.line() + 1, newPosition.column() + 1); } } void Kile::updateStatusBarViewMode(KTextEditor::View *view) { if(!view) { statusBar()->clearViewMode(); } else { statusBar()->setViewMode(view->viewModeHuman()); } } void Kile::updateStatusBarInformationMessage(KTextEditor::View * /* view */, const QString &message) { statusBar()->showMessage(message, 5000); } void Kile::updateStatusBarSelection(KTextEditor::View *view) { if(!view) { statusBar()->clearSelectionMode(); } else { const QString text = view->blockSelection() ? i18nc("@info:status status bar label for block selection mode", "BLOCK") + ' ' : i18nc("@info:status status bar label for line selection mode", "LINE") + ' '; statusBar()->setSelectionMode(text); } } void Kile::handleDocumentParsingStarted() { statusBar()->setParserStatus(i18n("Refreshing structure...")); } void Kile::handleDocumentParsingComplete() { statusBar()->clearParserStatus(); } diff --git a/src/kiledocmanager.cpp b/src/kiledocmanager.cpp index aa197dc1..e2b2e2c2 100644 --- a/src/kiledocmanager.cpp +++ b/src/kiledocmanager.cpp @@ -1,2634 +1,2583 @@ /***************************************************************************** * Copyright (C) 2004 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) * * (C) 2006-2018 by Michel Ludwig (michel.ludwig@kdemail.net) * * (C) 2007 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 "kiledocmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dialogs/cleandialog.h" #include "dialogs/listselector.h" #include "dialogs/managetemplatesdialog.h" #include "dialogs/newfilewizard.h" #include "dialogs/projectdialogs.h" #include "documentinfo.h" #include "errorhandler.h" #include "kileconfig.h" #include "kiledebug.h" #include "kileinfo.h" #include "kileproject.h" #include "kilestdtools.h" #include "kiletool_enums.h" #include "kiletool.h" #include "kiletoolmanager.h" #include "kileviewmanager.h" #include "livepreview.h" #include "parser/parsermanager.h" #include "scriptmanager.h" #include "templates.h" #include "widgets/filebrowserwidget.h" #include "widgets/konsolewidget.h" #include "widgets/projectview.h" #include "widgets/structurewidget.h" /* * Newly created text documents have an empty URL and a non-empty document name. */ #define MAX_NUMBER_OF_STORED_SETTINGS 50 namespace KileDocument { Manager::Manager(KileInfo *info, QObject *parent, const char *name) : QObject(parent), m_ki(info), m_progressDialog(Q_NULLPTR), m_currentlySavingAll(false), m_currentlyOpeningFile(false) { setObjectName(name); m_editor = KTextEditor::Editor::instance(); if(!m_editor) { KMessageBox::error(m_ki->mainWindow(), i18n("No editor component found. Please check your KDE installation."), i18n("No editor component found.")); } } Manager::~Manager() { KILE_DEBUG_MAIN << "==KileDocument::Manager::~Manager()========="; if(m_progressDialog.isNull()) { delete m_progressDialog.data(); } } void Manager::readConfig() { } void Manager::writeConfig() { } void Manager::trashDoc(TextInfo *docinfo, KTextEditor::Document *doc /*= Q_NULLPTR */ ) { KILE_DEBUG_MAIN << "==void Manager::trashDoc(" << docinfo->url().toLocalFile() << ")====="; if(m_ki->isOpen(docinfo->url())) { return; } if(doc) { doc = docinfo->getDoc(); } //look for doc before we detach the docinfo //if we do it the other way around, docFor will always return nil if(!doc) { doc = docFor(docinfo->url()); } KILE_DEBUG_MAIN << "DETACHING " << docinfo; docinfo->detach(); KILE_DEBUG_MAIN << "\tTRASHING " << doc; if(!doc) { return; } KILE_DEBUG_MAIN << "just checking: docinfo->getDoc() = " << docinfo->getDoc(); KILE_DEBUG_MAIN << "just checking: docFor(docinfo->url()) = " << docFor(docinfo->url()); for (int i = 0; i < m_textInfoList.count(); ++i) { if((m_textInfoList.at(i) != docinfo) && (m_textInfoList.at(i)->getDoc() == doc)) { KMessageBox::information(0, i18n("The internal structure of Kile is corrupted (probably due to a bug in Kile). Please select Save All from the File menu and close Kile.\nThe Kile team apologizes for any inconvenience and would appreciate a bug report.")); qWarning() << "docinfo " << m_textInfoList.at(i) << " url " << m_textInfoList.at(i)->url().fileName() << " has a wild pointer!!!"; } } KILE_DEBUG_MAIN << "DELETING doc"; delete doc; } // update all Info's with changed user commands void Manager::updateInfos() { for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { (*it)->updateStructLevelInfo(); } } bool Manager::isOpeningFile() { return m_currentlyOpeningFile; } KTextEditor::Editor* Manager::getEditor() { return m_editor; } KTextEditor::Document* Manager::docFor(const QUrl &url) { for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { TextInfo *info = *it; if(m_ki->similarOrEqualURL(info->url(), url)) { return info->getDoc(); } } return Q_NULLPTR; } TextInfo* Manager::getInfo() const { KTextEditor::Document *doc = m_ki->activeTextDocument(); if(doc) { return textInfoFor(doc); } else { return Q_NULLPTR; } } TextInfo* Manager::textInfoFor(const QUrl &url) { if(url.isEmpty()) { return Q_NULLPTR; } KILE_DEBUG_MAIN << "==KileInfo::textInfoFor(" << url << ")=========================="; for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { TextInfo *info = *it; if (info->url() == url) { return info; } } // the URL might belong to a TextInfo* which currently doesn't have a KTextEditor::Document* // associated with it, i.e. a project item which isn't open in the editor for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProjectItem *item = (*it)->item(url); // all project items (across different projects) that share a URL have the same TextInfo*; // so, the first one we find is good enough if(item) { KileDocument::TextInfo *info = item->getInfo(); if(info) { return info; } } } KILE_DEBUG_MAIN << "\tCOULD NOT find info for " << url; return Q_NULLPTR; } TextInfo* Manager::textInfoFor(KTextEditor::Document* doc) const { if(!doc) { return Q_NULLPTR; } // TextInfo* objects that contain KTextEditor::Document* pointers must be open in the editor, i.e. // we don't have to look through the project items for(QList::const_iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { if((*it)->getDoc() == doc) { return (*it); } } KILE_DEBUG_MAIN << "\tCOULD NOT find info for" << doc->url() << "by searching via a KTextEditor::Document*"; return Q_NULLPTR; } QUrl Manager::urlFor(TextInfo* textInfo) { KileProjectItem *item = itemFor(textInfo); QUrl url; if(item) { url = item->url(); // all items with 'textInfo' share the same URL } else { KTextEditor::Document *document = textInfo->getDoc(); if(document) { url = document->url(); } } return url; } KileProject* Manager::projectForMember(const QUrl &memberUrl) { for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if(project->contains(memberUrl)) { return project; } } return Q_NULLPTR; } KileProject* Manager::projectFor(const QUrl &projecturl) { //find project with url = projecturl for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if(project->url() == projecturl) { return project; } } return Q_NULLPTR; } KileProject* Manager::projectFor(const QString &name) { //find project with url = projecturl for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if (project->name() == name) { return project; } } return Q_NULLPTR; } KileProjectItem* Manager::itemFor(const QUrl &url, KileProject *project /*=0L*/) const { if (!project) { for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; KileProjectItem *item = project->item(url); if(item) { return item; } } return Q_NULLPTR; } else { return project->item(url); } } KileProjectItem* Manager::itemFor(TextInfo *docinfo, KileProject *project /*=0*/) const { if (!project) { for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; KileProjectItem *item = project->item(docinfo); if(item) { return item; } } return Q_NULLPTR; } else { return project->item(docinfo); } } QList Manager::itemsFor(Info *docinfo) const { if(!docinfo) { return QList(); } KILE_DEBUG_MAIN << "==KileInfo::itemsFor(" << docinfo->url().fileName() << ")============"; QList list; for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; KILE_DEBUG_MAIN << "\tproject: " << (*it)->name(); if(project->contains(docinfo)) { KILE_DEBUG_MAIN << "\t\tcontains"; list.append(project->item(docinfo)); } } return list; } QList Manager::itemsFor(const QUrl &url) const { QList list; for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if(project->contains(url)) { list.append(project->item(url)); } } return list; } bool Manager::isProjectOpen() { return ( m_projects.count() > 0 ); } KileProject* Manager::activeProject() { KTextEditor::Document *doc = m_ki->activeTextDocument(); if (doc) { return projectForMember(doc->url()); } else { return Q_NULLPTR; } } KileProjectItem* Manager::activeProjectItem() { KileProject *curpr = activeProject(); KTextEditor::Document *doc = m_ki->activeTextDocument(); if (curpr && doc) { QList list = curpr->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; if (item->url() == doc->url()) { return item; } } } return Q_NULLPTR; } TextInfo* Manager::createTextDocumentInfo(KileDocument::Type type, const QUrl &url, const QUrl& baseDirectory) { TextInfo *docinfo = Q_NULLPTR; // check whether this URL belongs to an opened project and a TextInfo* object has already // been created for that URL docinfo = textInfoFor(url); if(!docinfo) { switch(type) { case Undefined: // fall through case Text: KILE_DEBUG_MAIN << "CREATING TextInfo for " << url.url(); docinfo = new TextInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->parserManager()); break; case LaTeX: KILE_DEBUG_MAIN << "CREATING LaTeXInfo for " << url.url(); docinfo = new LaTeXInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->latexCommands(), m_ki->editorExtension(), m_ki->configurationManager(), m_ki->codeCompletionManager(), m_ki->livePreviewManager(), m_ki->viewManager(), m_ki->parserManager()); break; case BibTeX: KILE_DEBUG_MAIN << "CREATING BibInfo for " << url.url(); docinfo = new BibInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->parserManager(), m_ki->latexCommands()); break; case Script: KILE_DEBUG_MAIN << "CREATING ScriptInfo for " << url.url(); docinfo = new ScriptInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->parserManager()); break; } docinfo->setBaseDirectory(baseDirectory); emit(documentInfoCreated(docinfo)); m_textInfoList.append(docinfo); } KILE_DEBUG_MAIN << "DOCINFO: returning " << docinfo << " " << docinfo->url().fileName(); return docinfo; } void Manager::recreateTextDocumentInfo(TextInfo *oldinfo) { QList list = itemsFor(oldinfo); QUrl url = oldinfo->url(); TextInfo *newinfo = createTextDocumentInfo(m_ki->extensions()->determineDocumentType(url), url, oldinfo->getBaseDirectory()); newinfo->setDoc(oldinfo->getDoc()); for(QList::iterator it = list.begin(); it != list.end(); ++it) { (*it)->setInfo(newinfo); } removeTextDocumentInfo(oldinfo); emit(updateStructure(false, newinfo)); } bool Manager::removeTextDocumentInfo(TextInfo *docinfo, bool closingproject /* = false */) { KILE_DEBUG_MAIN << "==Manager::removeTextDocumentInfo(Info *docinfo)====="; QList itms = itemsFor(docinfo); bool oneItem = false; if(itms.count() == 1) { oneItem = true; } if(itms.count() == 0 || ( closingproject && oneItem )) { KILE_DEBUG_MAIN << "\tremoving " << docinfo << " count = " << m_textInfoList.count(); // we still have to stop parsing for 'docinfo' QUrl url = urlFor(docinfo); if(url.isValid()) { m_ki->parserManager()->stopDocumentParsing(url); } m_textInfoList.removeAll(docinfo); emit(closingDocument(docinfo)); cleanupDocumentInfoForProjectItems(docinfo); delete docinfo; return true; } KILE_DEBUG_MAIN << "\tnot removing " << docinfo; return false; } KTextEditor::Document* Manager::createDocument(const QUrl &url, TextInfo *docinfo, const QString& encoding, const QString& mode, const QString& highlight) { KILE_DEBUG_MAIN << "==KTextEditor::Document* Manager::createDocument()==========="; KTextEditor::Document *doc = Q_NULLPTR; if(!m_editor) { return Q_NULLPTR; } doc = docFor(url); if (doc) { qWarning() << url << " already has a document!"; return doc; } doc = m_editor->createDocument(Q_NULLPTR); KILE_DEBUG_MAIN << "appending document " << doc; connect(doc, &KTextEditor::Document::canceled, [=] (const QString &errMsg) { if(!errMsg.isEmpty()) { KMessageBox::error(m_ki->mainWindow(), i18n("The URL \"%1\" couldn't be opened.\n\n%2", url.toDisplayString(), errMsg), i18n("Cannot open URL")); } else { KMessageBox::error(m_ki->mainWindow(), i18n("The URL \"%1\" couldn't be opened.", url.toDisplayString()), i18n("Cannot open URL")); } }); docinfo->setDoc(doc); // do this here to set up all the signals correctly in 'TextInfo' doc->setEncoding(encoding); KILE_DEBUG_MAIN << "url is = " << docinfo->url(); if(!url.isEmpty()) { bool r = doc->openUrl(url); if(!r) { KILE_WARNING_MAIN << "couldn't open the url" << url; docinfo->detach(); delete doc; return Q_NULLPTR; } // don't add scripts to the recent files if(r && docinfo->getType() != Script) { emit(addToRecentFiles(url)); } } //handle changes of the document connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SIGNAL(documentNameChanged(KTextEditor::Document*))); connect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document*)), this, SIGNAL(documentUrlChanged(KTextEditor::Document*))); if(doc->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("readWriteChanged(KTextEditor::Document*)")) >= 0) { // signal available in KDE 4.10 connect(doc, SIGNAL(readWriteChanged(KTextEditor::Document*)), this, SIGNAL(documentReadWriteStateChanged(KTextEditor::Document*))); } connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(newDocumentStatus(KTextEditor::Document*))); KTextEditor::ModificationInterface *modificationInterface = qobject_cast(doc); if(modificationInterface) { modificationInterface->setModifiedOnDiskWarning(true); connect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SIGNAL(documentModificationStatusChanged(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason))); } if(!mode.isEmpty()) { docinfo->setMode(mode); // this ensures that mode passed with the mode parameter is actually used } if(!highlight.isEmpty()) { docinfo->setHighlightingMode(highlight); } // FIXME: the whole structure updating stuff needs to be rewritten; updates should originate from // the docinfo only, i.e. the structure view should just react to changes! connect(docinfo, SIGNAL(completed(KileDocument::Info*)), m_ki->structureWidget(), SLOT(update(KileDocument::Info*))); KILE_DEBUG_MAIN << "createDocument: url " << doc->url(); KILE_DEBUG_MAIN << "createDocument: SANITY check: " << (docinfo->getDoc() == docFor(docinfo->url())); return doc; } // WARNING: 'item' must have been set up with a TextInfo* object already KTextEditor::View* Manager::loadItem(KileDocument::Type type, KileProjectItem *item, const QString & text, bool openProjectItemViews) { KTextEditor::View *view = Q_NULLPTR; KILE_DEBUG_MAIN << "==loadItem(" << item->url() << ")======"; if(item->type() != KileProjectItem::Image) { view = loadText(type, item->url(), item->encoding(), openProjectItemViews && item->isOpen(), item->mode(), item->highlight(), text); KILE_DEBUG_MAIN << "\tloadItem: docfor = " << docFor(item->url()); TextInfo *docinfo = item->getInfo(); KILE_DEBUG_MAIN << "\tloadItem: docinfo = " << docinfo << " doc = " << docinfo->getDoc() << " docfor = " << docFor(docinfo->url()); if ( docinfo->getDoc() != docFor(docinfo->url()) ) qWarning() << "docinfo->getDoc() != docFor()"; } else { KILE_DEBUG_MAIN << "\tloadItem: no document generated"; TextInfo *docinfo = item->getInfo(); if(!docFor(item->url())) { docinfo->detach(); KILE_DEBUG_MAIN << "\t\t\tdetached"; } } return view; } KTextEditor::View* Manager::loadText(KileDocument::Type type, const QUrl &url, const QString& encoding, bool create, const QString& mode, const QString& highlight, const QString& text, int index, const QUrl &baseDirectory) { KILE_DEBUG_MAIN << "==loadText(" << url.url() << ")================="; //if doc already opened, update the structure view and return the view if(!url.isEmpty() && m_ki->isOpen(url)) { return m_ki->viewManager()->switchToTextView(url); } TextInfo *docinfo = createTextDocumentInfo(type, url, baseDirectory); KTextEditor::Document *doc = createDocument(url, docinfo, encoding, mode, highlight); if(!doc) { removeTextDocumentInfo(docinfo); return Q_NULLPTR; } m_ki->structureWidget()->clean(docinfo); if(!text.isEmpty()) { doc->setText(text); } if (doc && create) { return m_ki->viewManager()->createTextView(docinfo, index); } KILE_DEBUG_MAIN << "just after createView()"; KILE_DEBUG_MAIN << "\tdocinfo = " << docinfo << " doc = " << docinfo->getDoc() << " docfor = " << docFor(docinfo->url()); return Q_NULLPTR; } //FIXME: template stuff should be in own class KTextEditor::View* Manager::loadTemplate(TemplateItem *sel) { KILE_DEBUG_MAIN << "templateitem *sel = " << sel; QString text; if(!sel) { return Q_NULLPTR; } if (sel->name() != KileTemplate::Manager::defaultEmptyTemplateCaption() && sel->name() != KileTemplate::Manager::defaultEmptyLaTeXTemplateCaption() && sel->name() != KileTemplate::Manager::defaultEmptyBibTeXTemplateCaption()) { if(!m_editor) { return Q_NULLPTR; } //create a new document to open the template in KTextEditor::Document *tempdoc = m_editor->createDocument(Q_NULLPTR); if (!tempdoc->openUrl(QUrl::fromLocalFile(sel->path()))) { KMessageBox::error(m_ki->mainWindow(), i18n("Could not find template: %1", sel->name()), i18n("File Not Found")); } else { //substitute templates variables text = tempdoc->text(); delete tempdoc; replaceTemplateVariables(text); } } KileDocument::Type type = sel->type(); //always set the base directory for scripts return createDocumentWithText(text, type, QString(), (type == KileDocument::Script ? QUrl::fromLocalFile(m_ki->scriptManager()->getLocalScriptDirectory()) : QUrl())); } KTextEditor::View* Manager::createDocumentWithText(const QString& text, KileDocument::Type type /* = KileDocument::Undefined */, const QString& /* extension */, const QUrl &baseDirectory) { KTextEditor::View *view = loadText(type, QUrl(), QString(), true, QString(), QString(), text, -1, baseDirectory); if(view) { //FIXME this shouldn't be necessary!!! view->document()->setModified(true); newDocumentStatus(view->document()); } return view; } KTextEditor::View* Manager::createNewJScript() { KTextEditor::View *view = createDocumentWithText(QString(), Script, "js", QUrl::fromLocalFile(m_ki->scriptManager()->getLocalScriptDirectory())); emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); return view; } KTextEditor::View* Manager::createNewLaTeXDocument() { KTextEditor::View *view = createDocumentWithText(QString(), LaTeX); emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); return view; } void Manager::replaceTemplateVariables(QString &line) { line=line.replace("$$AUTHOR$$", KileConfig::author()); line=line.replace("$$DOCUMENTCLASSOPTIONS$$", KileConfig::documentClassOptions()); if (!KileConfig::templateEncoding().isEmpty()) { line=line.replace("$$INPUTENCODING$$", "\\usepackage["+ KileConfig::templateEncoding() +"]{inputenc}"); } else { line = line.remove("$$INPUTENCODING$$"); } } void Manager::createTemplate() { KTextEditor::View *view = m_ki->viewManager()->currentTextView(); if (view) { if (view->document()->isModified()) { KMessageBox::information(m_ki->mainWindow(),i18n("Please save the file first.")); return; } } else { KMessageBox::information(m_ki->mainWindow(),i18n("Open/create a document first.")); return; } QUrl url = view->document()->url(); KileDocument::Type type = m_ki->extensions()->determineDocumentType(url); if(type == KileDocument::Undefined || type == KileDocument::Text) { KMessageBox::information(m_ki->mainWindow(),i18n("A template for this type of document cannot be created.")); return; } ManageTemplatesDialog mtd(m_ki->templateManager(), url, i18n("Create Template From Document")); mtd.exec(); } void Manager::removeTemplate() { ManageTemplatesDialog mtd(m_ki->templateManager(), i18n("Remove Template")); mtd.exec(); } void Manager::fileNew(KileDocument::Type type) { NewFileWizard *nfw = new NewFileWizard(m_ki->templateManager(), type, m_ki->mainWindow()); if(nfw->exec()) { KTextEditor::View *view = loadTemplate(nfw->getSelection()); if(view) { if(nfw->useWizard()) { emit(startWizard()); } emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); } } delete nfw; } void Manager::fileNewScript() { fileNew(KileDocument::Script); } void Manager::fileNew(const QUrl &url) { //create an empty file QFile file(url.toLocalFile()); file.open(QIODevice::ReadWrite); file.close(); fileOpen(url, QString()); } void Manager::fileOpen() { //determine the starting dir for the file dialog QString compileName = m_ki->getCompileName(); QString currentDir; if(QFileInfo(compileName).exists()) { currentDir = QFileInfo(compileName).absolutePath(); } else { currentDir = m_ki->fileSelector()->currentUrl().toLocalFile(); } // use a filter for fileOpen dialog Extensions *extensions = m_ki->extensions(); QString filter = extensions->fileFilterKDEStyle(true, {KileDocument::Extensions::TEX, KileDocument::Extensions::PACKAGES, KileDocument::Extensions::BIB, KileDocument::Extensions::METAPOST }); // try to get the current encoding, this is kind of ugly ... QString encoding = m_ki->toolManager()->config()->group("Kate Document Defaults").readEntry("Encoding",""); //get the URLs KEncodingFileDialog::Result result = KEncodingFileDialog::getOpenUrlsAndEncoding(encoding, QUrl::fromLocalFile(currentDir), filter, m_ki->mainWindow(), i18n("Open Files")); //open them const QList& urls = result.URLs; for (QList::ConstIterator i = urls.begin(); i != urls.end(); ++i) { const QUrl& url = *i; if(m_ki->extensions()->isProjectFile(url)) { // this can happen... (bug 317432) KILE_DEBUG_MAIN << "file is a project file:" << url; projectOpen(url); continue; } fileOpen(url, result.encoding); } } void Manager::fileSelected(const KFileItem& file) { fileSelected(file.url()); } void Manager::fileSelected(const KileProjectItem * item) { fileOpen(item->url(), item->encoding()); } void Manager::fileSelected(const QUrl &url) { fileOpen(url, QString()); } void Manager::saveURL(const QUrl &url) { KTextEditor::Document *doc = docFor(url); if(doc) { doc->save(); } } void Manager::newDocumentStatus(KTextEditor::Document *doc) { KILE_DEBUG_MAIN << "void Manager::newDocumentStatus(Kate::Document)" << endl; if(!doc) { return; } // sync terminal m_ki->texKonsole()->sync(); emit(documentModificationStatusChanged(doc, doc->isModified(), KTextEditor::ModificationInterface::OnDiskUnmodified)); } bool Manager::fileSaveAll(bool disUntitled) { // this can occur when autosaving should take place when we // are still busy with it (KIO::NetAccess keeps the event loop running) if(m_currentlySavingAll) { return true; } m_currentlySavingAll = true; KTextEditor::View *view = Q_NULLPTR; QFileInfo fi; bool oneSaveFailed = false; QUrl url, backupUrl; KILE_DEBUG_MAIN << "===Kile::fileSaveAll(disUntitled = " << disUntitled <<")"; for(int i = 0; i < m_ki->viewManager()->textViewCount(); ++i) { view = m_ki->viewManager()->textView(i); if(view && view->document()->isModified()) { url = view->document()->url(); fi.setFile(url.toLocalFile()); if(!disUntitled || !(disUntitled && url.isEmpty())) { // either we don't disregard untitled docs, or the doc has a title KILE_DEBUG_MAIN << "trying to save: " << url.toLocalFile(); bool saveResult = view->document()->documentSave(); fi.refresh(); if(!saveResult) { oneSaveFailed = true; m_ki->errorHandler()->printMessage(KileTool::Error, i18n("Kile encountered problems while saving the file %1. Do you have enough free disk space left?", url.toDisplayString()), i18n("Saving")); } } } } /* This may look superfluos but actually it is not, in the case of multiple modified docs it ensures that the structure view keeps synchronized with the currentTextView And if we only have one masterdoc or none nothing goes wrong. */ emit(updateStructure(false, Q_NULLPTR)); m_currentlySavingAll = false; return !oneSaveFailed; } void Manager::fileSaveCompiledDocument() { const QString compiledDocumentFileName = m_ki->livePreviewManager()->getPreviewFile(); QFileInfo fileInfo(compiledDocumentFileName); if(!fileInfo.exists() || !fileInfo.isReadable()) { KILE_WARNING_MAIN << "file doesn't exist or cannot be read:" << compiledDocumentFileName; return; } QMimeDatabase db; QStringList nameFilters; { QMimeType detectedMimeType = db.mimeTypeForFile(fileInfo); if(!detectedMimeType.isDefault()) { // All files (*) nameFilters << detectedMimeType.filterString(); } } nameFilters << i18n("Any files (*)"); QFileDialog *dlg = new QFileDialog(m_ki->mainWindow(), i18n("Save Compiled Document As...")); dlg->setModal(true); dlg->setNameFilters(nameFilters); dlg->selectFile(fileInfo.fileName()); dlg->setAcceptMode(QFileDialog::AcceptSave); connect(dlg, &QFileDialog::urlSelected, this, [compiledDocumentFileName](const QUrl& url) { if(!url.isValid()) { return; } // the QFileDialog will take care of asking for overwrite permission (if the chosen file exists already) KIO::CopyJob *copyJob = KIO::copy(QUrl::fromLocalFile(compiledDocumentFileName), url, KIO::Overwrite); connect(copyJob, &KIO::CopyJob::finished, copyJob, &QObject::deleteLater); }); dlg->exec(); } TextInfo* Manager::fileOpen(const QUrl &url, const QString& encoding, int index) { m_currentlyOpeningFile = true; KILE_DEBUG_MAIN << "==Kile::fileOpen=========================="; if(url.isLocalFile() && QFileInfo(url.toLocalFile()).isDir()) { KILE_DEBUG_MAIN << "tried to open directory" << url; KMessageBox::error(m_ki->mainWindow(), i18n("The URL \"%1\" cannot be opened\nas it is a directory.", url.toDisplayString()), i18n("Cannot open directory")); m_currentlyOpeningFile = false; // has to be before the 'switchToTextView' call as // it emits signals that are handled by the live preview manager return Q_NULLPTR; } KILE_DEBUG_MAIN << "url is " << url.url(); const QUrl realurl = symlinkFreeURL(url); KILE_DEBUG_MAIN << "symlink free url is " << realurl.url(); if(m_ki->isOpen(realurl)) { m_currentlyOpeningFile = false; // has to be before the 'switchToTextView' call as // it emits signals that are handled by the live preview manager m_ki->viewManager()->switchToTextView(realurl); return textInfoFor(realurl); } KTextEditor::View *view = loadText(m_ki->extensions()->determineDocumentType(realurl), realurl, encoding, true, QString(), QString(), QString(), index); if(!view) { m_currentlyOpeningFile = false; // has to be before the 'switchToTextView' call as // it emits signals that are handled by the live preview manager return Q_NULLPTR; } QList itemList = itemsFor(realurl); TextInfo *textInfo = textInfoFor(realurl); for(QList::iterator it = itemList.begin(); it != itemList.end(); ++it) { (*it)->setInfo(textInfo); } if(itemList.isEmpty()) { emit addToProjectView(realurl); loadDocumentAndViewSettings(textInfo); } else if(view) { KileProjectItem *item = itemList.first(); item->loadDocumentAndViewSettings(); } emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); // update undefined references in this file emit(updateReferences(textInfoFor(realurl))); m_currentlyOpeningFile = false; emit documentOpened(textInfo); return textInfo; } bool Manager::fileSave(KTextEditor::View *view) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!view && var.isValid()) { view = var.value(); // the 'data' property for the relevant actions is cleared // inside the view manager } } if(!view) { view = m_ki->viewManager()->currentTextView(); } if(!view) { return false; } QUrl url = view->document()->url(); if(url.isEmpty()) { // newly created document return fileSaveAs(view); } else { bool ret = view->document()->documentSave(); emit(updateStructure(false, textInfoFor(view->document()))); return ret; } } bool Manager::fileSaveAs(KTextEditor::View* view) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!view && var.isValid()) { view = var.value(); // the 'data' property for the relevant actions is cleared // inside the view manager } } if(!view) { view = m_ki->viewManager()->currentTextView(); } if(!view) { return false; } KTextEditor::Document* doc = view->document(); Q_ASSERT(doc); KileDocument::TextInfo* info = textInfoFor(doc); Q_ASSERT(info); QUrl startUrl = info->url(); QUrl oldURL = info->url(); if(startUrl.isEmpty()) { QUrl baseDirectory = info->getBaseDirectory(); if(baseDirectory.isEmpty()) { startUrl = QUrl("kfiledialog:///KILE_LATEX_SAVE_DIR"); } else { startUrl = baseDirectory; } } KILE_DEBUG_MAIN << "startUrl is " << startUrl; KEncodingFileDialog::Result result; QUrl saveURL; while(true) { QString filter = m_ki->extensions()->fileFilterKDEStyle(true, info->getFileFilter()); result = KEncodingFileDialog::getSaveUrlAndEncoding(doc->encoding(), startUrl, filter, m_ki->mainWindow(), i18n("Save File")); if(result.URLs.isEmpty() || result.URLs.first().isEmpty()) { return false; } saveURL = result.URLs.first(); if(info->getType() == KileDocument::LaTeX) { saveURL = Info::makeValidTeXURL(saveURL, m_ki->mainWindow(), m_ki->extensions()->isTexFile(saveURL), false); // don't check for file existence } if(!checkForFileOverwritePermission(saveURL)) { continue; } break; } doc->setEncoding(result.encoding); if(!doc->saveAs(saveURL)) { return false; } if(oldURL != saveURL) { if(info->isDocumentTypePromotionAllowed()) { recreateTextDocumentInfo(info); info = textInfoFor(doc); } m_ki->structureWidget()->updateUrl(info); emit addToRecentFiles(saveURL); emit addToProjectView(doc->url()); } emit(documentSavedAs(view, info)); return true; } bool Manager::checkForFileOverwritePermission(const QUrl& url) { auto statJob = KIO::stat(url, KIO::StatJob::SourceSide, 0); KJobWidgets::setWindow(statJob, m_ki->mainWindow()); if (statJob->exec()) { // check for writing possibility int r = KMessageBox::warningContinueCancel(m_ki->mainWindow(), i18n("A file with the name \"%1\" exists already. Do you want to overwrite it?", url.fileName()), i18n("Overwrite File?"), KStandardGuiItem::overwrite()); if(r != KMessageBox::Continue) { return false; } } return true; } -void Manager::fileSaveCopyAs() -{ - KTextEditor::View *view = Q_NULLPTR; - // the 'data' property can be set by the view manager - QAction *action = dynamic_cast(QObject::sender()); - if(action) { - QVariant var = action->data(); - if(var.isValid()) { - view = var.value(); - // the 'data' property for the relevant actions is cleared - // inside the view manager - } - } - if(!view) { - view = m_ki->viewManager()->currentTextView(); - } - if(!view) { - return; - } - - KTextEditor::Document *doc = view->document(); - - if(!doc) { - return; - } - - KileDocument::TextInfo *originalInfo = textInfoFor(doc); - - if(!originalInfo) { - return; - } - - view = createDocumentWithText(doc->text(),originalInfo->getType()); - - KileDocument::TextInfo *newInfo = textInfoFor(view->document()); - - if(originalInfo->url().isEmpty()) { // untitled doc - newInfo->setBaseDirectory(m_ki->fileSelector()->currentUrl()); - } - else { - newInfo->setBaseDirectory(originalInfo->url()); - } - - fileSaveAs(view); - - doc = view->document(); - if(doc && !doc->isModified()) { // fileSaveAs was successful - fileClose(doc); - } -} - bool Manager::fileCloseAllOthers(KTextEditor::View *currentView) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!currentView && var.isValid()) { // the 'data' property for the relevant actions is cleared // inside the view manager currentView = var.value(); } } if(!currentView) { currentView = m_ki->viewManager()->currentTextView(); } if(!currentView) { return false; } QList viewList; for(int i = 0; i < m_ki->viewManager()->textViewCount(); ++i) { KTextEditor::View *view = m_ki->viewManager()->textView(i); if(currentView == view) { continue; } viewList.push_back(view); } for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { if (!fileClose(*it)) { return false; } } return true; } bool Manager::fileCloseAll() { KTextEditor::View * view = m_ki->viewManager()->currentTextView(); //assumes one view per doc here while(m_ki->viewManager()->textViewCount() > 0) { view = m_ki->viewManager()->textView(0); if (!fileClose(view->document())) { return false; } } return true; } bool Manager::fileClose(const QUrl &url) { KTextEditor::Document *doc = docFor(url); if(!doc) { return true; } else { return fileClose(doc); } } bool Manager::fileClose(KTextEditor::View *view) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!view && var.isValid()) { view = var.value(); // the 'data' property for the relevant actions is cleared // inside the view manager } } if(!view) { view = m_ki->viewManager()->currentTextView(); } if(!view) { return false; } return fileClose(view->document()); } bool Manager::fileClose(KTextEditor::Document *doc /* = 0L*/, bool closingproject /*= false*/) { KILE_DEBUG_MAIN << "==Kile::fileClose=========================="; if(!doc) { doc = m_ki->activeTextDocument(); } if(!doc) { return true; } //FIXME: remove from docinfo map, remove from dirwatch KILE_DEBUG_MAIN << "doc->url().toLocalFile()=" << doc->url().toLocalFile(); const QUrl url = doc->url(); TextInfo *docinfo= textInfoFor(doc); if(!docinfo) { qWarning() << "no DOCINFO for " << url.url(); return true; } bool inProject = false; QList items = itemsFor(docinfo); for(QList::iterator it = items.begin(); it != items.end(); ++it) { KileProjectItem *item = *it; //FIXME: refactor here if(item && doc) { storeProjectItem(item, doc); inProject = true; } } if(!inProject) { KILE_DEBUG_MAIN << "not in project"; saveDocumentAndViewSettings(docinfo); } if(doc->closeUrl()) { // docinfo may have been recreated from 'Untitled' doc to a named doc if(url.isEmpty()) { docinfo= textInfoFor(doc); } if(KileConfig::cleanUpAfterClose()) { cleanUpTempFiles(url, true); // yes we pass here url and not docinfo->url() } //FIXME: use signal/slot if( doc->views().count() > 0) { m_ki->viewManager()->removeView(doc->views().first()); } //remove the decorations trashDoc(docinfo, doc); m_ki->structureWidget()->clean(docinfo); removeTextDocumentInfo(docinfo, closingproject); emit removeFromProjectView(url); emit updateModeStatus(); } else { return false; } return true; } void Manager::buildProjectTree(const QUrl &url) { KileProject * project = projectFor(url); if (project) { buildProjectTree(project); } } void Manager::buildProjectTree(KileProject *project) { if(!project) { project = activeProject(); } if(!project) { project = selectProject(i18n("Refresh Project Tree")); } if (project) { //TODO: update structure for all docs project->buildProjectTree(); } else if (m_projects.count() == 0) { KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to build the tree for, then choose Refresh Project Tree again."),i18n( "Could Not Refresh Project Tree")); } } void Manager::projectNew() { KileNewProjectDialog *dlg = new KileNewProjectDialog(m_ki->templateManager(), m_ki->extensions(), m_ki->mainWindow()); if (dlg->exec()) { TextInfo *newTextInfo = Q_NULLPTR; KileProject *project = dlg->project(); //add the project file to the project KileProjectItem *item = new KileProjectItem(project, project->url()); createTextInfoForProjectItem(item); item->setOpenState(false); projectOpenItem(item); if(dlg->createNewFile()) { m_currentlyOpeningFile = true; // don't let live preview interfere QString filename = dlg->file(); //create the new document and fill it with the template KTextEditor::View *view = loadTemplate(dlg->getSelection()); if(view) { //derive the URL from the base url of the project QUrl url = project->baseURL(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + filename); newTextInfo = textInfoFor(view->document()); //save the new file //FIXME: this needs proper error handling view->document()->saveAs(url); emit(documentModificationStatusChanged(view->document(), false, KTextEditor::ModificationInterface::OnDiskUnmodified)); //add this file to the project item = new KileProjectItem(project, url); item->setInfo(newTextInfo); //docinfo->updateStruct(m_kwStructure->level()); emit(updateStructure(false, newTextInfo)); } m_currentlyOpeningFile = false; } project->buildProjectTree(); project->save(); addProject(project); emit(updateModeStatus()); emit(addToRecentProjects(project->url())); if(newTextInfo) { emit documentOpened(newTextInfo); } } } void Manager::addProject(KileProject *project) { KILE_DEBUG_MAIN << "==void Manager::addProject(const KileProject *project)=========="; m_projects.append(project); KILE_DEBUG_MAIN << "\tnow " << m_projects.count() << " projects"; emit addToProjectView(project); connect(project, SIGNAL(projectTreeChanged(const KileProject *)), this, SIGNAL(projectTreeChanged(const KileProject *))); } KileProject* Manager::selectProject(const QString& caption) { QStringList list; for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { list.append((*it)->name()); } KileProject *project = Q_NULLPTR; QString name; if (list.count() > 1) { KileListSelector *dlg = new KileListSelector(list, caption, i18n("Select Project"), true, m_ki->mainWindow()); if (dlg->exec()) { if(!dlg->hasSelection()) { return Q_NULLPTR; } name = dlg->selectedItems().first(); } delete dlg; } else if (list.count() == 0) { return Q_NULLPTR; } else { name = m_projects.first()->name(); } project = projectFor(name); return project; } void Manager::addToProject(const QUrl &url) { KILE_DEBUG_MAIN << "===Kile::addToProject(const QUrl &url =" << url.url() << ")"; KileProject *project = selectProject(i18n("Add to Project")); if (project) { addToProject(project, url); } } void Manager::addToProject(KileProject* project, const QUrl &url) { const QUrl realurl = symlinkFreeURL(url); QFileInfo fi(realurl.toLocalFile()); if (project->contains(realurl)) { m_ki->errorHandler()->printMessage(KileTool::Info, i18n("The file %1 is already member of the project %2", realurl.fileName(), project->name()), i18n("Add to Project")); return; } else if(!fi.exists() || !fi.isReadable()) { m_ki->errorHandler()->printMessage(KileTool::Info, i18n("The file %1 can not be added because it does not exist or is not readable", realurl.fileName()), i18n("Add to Project")); return; } KileProjectItem *item = new KileProjectItem(project, realurl); createTextInfoForProjectItem(item); item->setOpenState(m_ki->isOpen(realurl)); projectOpenItem(item); emit addToProjectView(item); buildProjectTree(project); } void Manager::removeFromProject(KileProjectItem *item) { if (item && item->project()) { KILE_DEBUG_MAIN << "\tprojecturl = " << item->project()->url().toLocalFile() << ", url = " << item->url().toLocalFile(); if (item->project()->url() == item->url()) { KMessageBox::error(m_ki->mainWindow(), i18n("This file is the project file, which holds all the information about your project. As such, it cannot be removed from the project."), i18n("Cannot Remove File From Project")); return; } emit removeItemFromProjectView(item, m_ki->isOpen(item->url())); KileProject *project = item->project(); project->remove(item); // update undefined references in all project files updateProjectReferences(project); project->buildProjectTree(); } } // WARNING: 'item' must have been set up with a TextInfo* object already void Manager::projectOpenItem(KileProjectItem *item, bool openProjectItemViews) { KILE_DEBUG_MAIN << "==Kile::projectOpenItem=========================="; KILE_DEBUG_MAIN << "\titem:" << item->url().toLocalFile(); if (m_ki->isOpen(item->url())) { //remove item from projectview (this file was opened before as a normal file) emit removeFromProjectView(item->url()); } KileDocument::TextInfo* itemInfo = item->getInfo(); Q_ASSERT(itemInfo); if(item->isOpen()) { KTextEditor::View *view = loadItem(m_ki->extensions()->determineDocumentType(item->url()), item, QString(), openProjectItemViews); if (view) { item->loadDocumentAndViewSettings(); } // make sure that the item has been parsed, even if it isn't shown; // this is necessary to identify the correct LaTeX root document (bug 233667); m_ki->structureWidget()->update(itemInfo, true); } else if(item->type() == KileProjectItem::Source || item->type() == KileProjectItem::Package || item->type() == KileProjectItem::Bibliography) { // 'item' is not shown (and it is either a LaTeX source file or package), i.e. its // contents won't be loaded into a KTextEditor::Document; so, we have to do it: // we are loading the contents of the project item into the docinfo // for a moment itemInfo->setDocumentContents(loadTextURLContents(item->url(), item->encoding())); // in order to pass the contents to the parser m_ki->structureWidget()->update(itemInfo, true); // now we don't need the contents anymore itemInfo->setDocumentContents(QStringList()); } } void Manager::createTextInfoForProjectItem(KileProjectItem *item) { item->setInfo(createTextDocumentInfo(m_ki->extensions()->determineDocumentType(item->url()), item->url(), item->project()->baseURL())); } void Manager::projectOpen(const QUrl &url, int step, int max, bool openProjectItemViews) { KILE_DEBUG_MAIN << "==Kile::projectOpen=========================="; KILE_DEBUG_MAIN << "\tfilename: " << url.fileName(); const QUrl realurl = symlinkFreeURL(url); if(m_ki->projectIsOpen(realurl)) { if(m_progressDialog) { m_progressDialog->hide(); } KMessageBox::information(m_ki->mainWindow(), i18n("

The project \"%1\" is already open.

" "

If you wanted to reload the project, close the project before you re-open it.

", url.fileName()), i18n("Project Already Open")); return; } QFileInfo fi(realurl.toLocalFile()); if(!fi.isReadable()) { if(m_progressDialog) { m_progressDialog->hide(); } if (KMessageBox::warningYesNo(m_ki->mainWindow(), i18n("

The project file for the project \"%1\" does not exist or it is not readable.

" "

Do you want to remove this project from the recent projects list?

", url.fileName()), i18n("Could Not Open Project")) == KMessageBox::Yes) { emit(removeFromRecentProjects(realurl)); } return; } if(!m_progressDialog) { createProgressDialog(); } KileProject *kp = new KileProject(realurl, m_ki->extensions()); if(!kp->appearsToBeValidProjectFile()) { if(m_progressDialog) { m_progressDialog->hide(); } KMessageBox::sorry(m_ki->mainWindow(), i18n("

The file \"%1\" cannot be opened as it does not appear to be a project file.

", url.fileName()), i18n("Impossible to Open Project File")); delete kp; return; } if(kp->getProjectFileVersion() > KILE_PROJECTFILE_VERSION) { if(m_progressDialog) { m_progressDialog->hide(); } KMessageBox::sorry(m_ki->mainWindow(), i18n("

The project \"%1\" cannot be opened as it was created
by a newer version of Kile.

", url.fileName()), i18n("Impossible to Open Project")); delete kp; return; } if(!kp->isOfCurrentVersion()) { if(m_progressDialog) { m_progressDialog->hide(); } if(KMessageBox::questionYesNo(m_ki->mainWindow(), i18n("

The project file \"%1\" was created by a previous version of Kile.
" "It needs to be updated before it can be opened.

" "

Do you want to update it?

", url.fileName()), i18n("Project File Needs to be Updated")) == KMessageBox::No) { delete kp; return; } if(!kp->migrateProjectFileToCurrentVersion()) { if (KMessageBox::warningYesNo(m_ki->mainWindow(), i18n("

The project file \"%1\" could be not updated.

" "

Do you want to remove this project from the recent projects list?

", url.fileName()), i18n("Could Not Update Project File")) == KMessageBox::Yes) { emit(removeFromRecentProjects(realurl)); } delete kp; return; } } m_progressDialog->show(); kp->load(); if(kp->isInvalid()) { if(m_progressDialog) { m_progressDialog->hide(); } delete kp; return; } emit(addToRecentProjects(realurl)); QList list = kp->items(); int project_steps = list.count(); m_progressDialog->setMaximum(project_steps * max); project_steps *= step; m_progressDialog->setValue(project_steps); // open the project files in the correct order QVector givenPositionVector(list.count(), Q_NULLPTR); QList notCorrectlyOrderedList; for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; int order = item->order(); if(order >= 0 && order >= list.count()) { order = -1; } if(!item->isOpen() || order < 0 || givenPositionVector[order] != Q_NULLPTR) { notCorrectlyOrderedList.push_back(item); } else { givenPositionVector[order] = item; } } QList orderedList; for(int i = 0; i < givenPositionVector.size(); ++i) { KileProjectItem *item = givenPositionVector[i]; if(item) { orderedList.push_back(item); } } for(QList::iterator i = notCorrectlyOrderedList.begin(); i != notCorrectlyOrderedList.end(); ++i) { orderedList.push_back(*i); } addProject(kp); // for the parsing to work correctly, all ProjectItems need to have TextInfo* objects, but // the URL of 'item' might already be associated with a TextInfo* object; for example, through // a stand-alone document currently being open already, or through a project item that belongs to // a different project // => 'createTextDocumentInfo' will take care of that situation as well for (QList::iterator i = orderedList.begin(); i != orderedList.end(); ++i) { createTextInfoForProjectItem(*i); } unsigned int counter = 1; for (QList::iterator i = orderedList.begin(); i != orderedList.end(); ++i) { projectOpenItem(*i, openProjectItemViews); m_progressDialog->setValue(counter + project_steps); qApp->processEvents(); ++counter; } kp->buildProjectTree(); emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); // update undefined references in all project files updateProjectReferences(kp); m_ki->viewManager()->switchToTextView(kp->lastDocument()); emit(projectOpened(kp)); } // as all labels are gathered in the project, we can check for unsolved references void Manager::updateProjectReferences(KileProject *project) { QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { emit(updateReferences((*it)->getInfo())); } } void Manager::projectOpen() { KILE_DEBUG_MAIN << "==Kile::projectOpen=========================="; QUrl url = QFileDialog::getOpenFileUrl(m_ki->mainWindow(), i18n("Open Project"), QUrl::fromLocalFile(KileConfig::defaultProjectLocation()), m_ki->extensions()->fileFilterQtStyle(false, {KileDocument::Extensions::KILE_PROJECT})); if(!url.isEmpty()) { projectOpen(url); } } void Manager::projectSave(KileProject *project /* = 0 */) { KILE_DEBUG_MAIN << "==Kile::projectSave=========================="; if (!project) { //find the project that corresponds to the active doc project= activeProject(); } if(!project) { project = selectProject(i18n("Save Project")); } if(project) { QList list = project->items(); KTextEditor::Document *doc = Q_NULLPTR; KileProjectItem *item = Q_NULLPTR; TextInfo *docinfo = Q_NULLPTR; // determine the order in which the project items are opened QVector viewPositionVector(m_ki->viewManager()->getTabCount(), Q_NULLPTR); for(QList::iterator i = list.begin(); i != list.end(); ++i) { docinfo = (*i)->getInfo(); if(docinfo) { KTextEditor::View *view = m_ki->viewManager()->textView(docinfo); if(view) { int position = m_ki->viewManager()->tabIndexOf(view); if(position >= 0 && position < viewPositionVector.size()) { viewPositionVector[position] = *i; } } } } int position = 0; for(int i = 0; i < viewPositionVector.size(); ++i) { if(viewPositionVector[i] != Q_NULLPTR) { viewPositionVector[i]->setOrder(position); ++position; } } //update the open-state of the items for (QList::iterator i = list.begin(); i != list.end(); ++i) { item = *i; KILE_DEBUG_MAIN << "\tsetOpenState(" << (*i)->url().toLocalFile() << ") to " << m_ki->isOpen(item->url()); item->setOpenState(m_ki->isOpen(item->url())); docinfo = item->getInfo(); if(docinfo) { doc = docinfo->getDoc(); } if(doc) { storeProjectItem(item, doc); } doc = Q_NULLPTR; docinfo = Q_NULLPTR; } project->save(); } else { KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to save, then choose Save Project again."),i18n( "Could Determine Active Project")); } } void Manager::projectAddFiles(const QUrl &url) { KileProject *project = projectFor(url); if (project) { projectAddFiles(project,url); } } void Manager::projectAddFiles(KileProject *project,const QUrl &fileUrl) { KILE_DEBUG_MAIN << "==Kile::projectAddFiles()=========================="; if(project == 0) { project = activeProject(); } if(project == 0) { project = selectProject(i18n("Add Files to Project")); } if (project) { QString currentDir; if(fileUrl.isEmpty()) { currentDir = QFileInfo(project->url().path()).dir().dirName(); } else { currentDir = fileUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path(); } KILE_DEBUG_MAIN << "currentDir is " << currentDir; QFileDialog *dlg = new QFileDialog(m_ki->mainWindow(), i18n("Add Files"), currentDir, m_ki->extensions()->fileFilterQtStyle(true, {})); dlg->setModal(true); dlg->setFileMode(QFileDialog::ExistingFiles); dlg->setLabelText(QFileDialog::Accept, i18n("Add")); if(dlg->exec()) { QList urls = dlg->selectedUrls(); for(int i=0; i < urls.count(); ++i) { addToProject(project, urls[i]); } // update undefined references in all project files updateProjectReferences(project); } delete dlg; //open them } else if (m_projects.count() == 0) { KMessageBox::error(m_ki->mainWindow(), i18n("There are no projects opened. Please open the project you want to add files to, then choose Add Files again."),i18n( "Could Not Determine Active Project")); } } void Manager::toggleArchive(KileProjectItem *item) { item->setArchive(!item->archive()); } void Manager::projectOptions(const QUrl &url) { KileProject *project = projectFor(url); if (project) { projectOptions(project); } } void Manager::projectOptions(KileProject *project /* = 0*/) { KILE_DEBUG_MAIN << "==Kile::projectOptions=========================="; if(!project) { project = activeProject(); } if(!project) { project = selectProject(i18n("Project Options For")); } if (project) { KILE_DEBUG_MAIN << "\t" << project->name(); KileProjectOptionsDialog *dlg = new KileProjectOptionsDialog(project, m_ki->extensions(), m_ki->mainWindow()); dlg->exec(); } else if (m_projects.count() == 0) { KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to modify, then choose Project Options again."),i18n( "Could Not Determine Active Project")); } } bool Manager::projectCloseAll() { KILE_DEBUG_MAIN << "==Kile::projectCloseAll=========================="; while(m_projects.size() > 0) { if(!projectClose(m_projects.first()->url())) { return false; } } return true; } bool Manager::projectClose(const QUrl &url) { KILE_DEBUG_MAIN << "==Kile::projectClose=========================="; KileProject *project = 0; if (url.isEmpty()) { project = activeProject(); if (!project) { project = selectProject(i18n("Close Project")); } } else { project = projectFor(url); } if(project) { KILE_DEBUG_MAIN << "\tclosing:" << project->name(); project->setLastDocument(QUrl::fromLocalFile(m_ki->getName())); projectSave(project); QList list = project->items(); bool close = true; KTextEditor::Document *doc = Q_NULLPTR; TextInfo *docinfo = Q_NULLPTR; for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; doc = Q_NULLPTR; docinfo = item->getInfo(); if (docinfo) { doc = docinfo->getDoc(); } else { continue; } if (doc) { KILE_DEBUG_MAIN << "\t\tclosing item " << doc->url().toLocalFile(); bool r = fileClose(doc, true); close = close && r; if (!close) { break; } } else { // we still need to delete the TextInfo object removeTextDocumentInfo(docinfo, true); } } if (close) { m_projects.removeAll(project); emit removeFromProjectView(project); delete project; emit(updateModeStatus()); return true; } else return false; } else if (m_projects.count() == 0) KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to close, then choose Close Project again."),i18n( "Could Not Close Project")); return true; } void Manager::storeProjectItem(KileProjectItem *item, KTextEditor::Document *doc) { KILE_DEBUG_MAIN << "===Kile::storeProjectItem=============="; KILE_DEBUG_MAIN << "\titem = " << item << ", doc = " << doc; item->setEncoding(doc->encoding()); item->setMode(doc->mode()); item->setHighlight(doc->highlightingMode()); item->saveDocumentAndViewSettings(); } void Manager::cleanUpTempFiles(const QUrl &url, bool silent) { KILE_DEBUG_MAIN << "===void Manager::cleanUpTempFiles(const QUrl " << url.toLocalFile() << ", bool " << silent << ")==="; if( url.isEmpty() ) return; QStringList extlist; QFileInfo fi(url.toLocalFile()); const QStringList templist = KileConfig::cleanUpFileExtensions().split(' '); const QString fileName = fi.fileName(); const QString dirPath = fi.absolutePath(); const QString baseName = fi.completeBaseName(); for (int i = 0; i < templist.count(); ++i) { fi.setFile( dirPath + '/' + baseName + templist[i] ); if(fi.exists()) { extlist.append(templist[i]); } } if(!silent && fileName.isEmpty()) { return; } if (!silent && extlist.count() > 0) { KILE_DEBUG_MAIN << "not silent"; KileDialog::Clean *dialog = new KileDialog::Clean(m_ki->mainWindow(), fileName, extlist); if (dialog->exec() == QDialog::Accepted) { extlist = dialog->cleanList(); } else { delete dialog; return; } delete dialog; } if(extlist.count() == 0) { m_ki->errorHandler()->printMessage(KileTool::Warning, i18n("Nothing to clean for %1", fileName), i18n("Clean")); } else { for(int i = 0; i < extlist.count(); ++i) { QFile file(dirPath + '/' + baseName + extlist[i]); KILE_DEBUG_MAIN << "About to remove file = " << file.fileName(); file.remove(); } m_ki->errorHandler()->printMessage(KileTool::Info, i18n("Cleaning %1: %2", fileName, extlist.join(" ")), i18n("Clean")); } } void Manager::openDroppedURLs(QDropEvent *e) { QList urls = e->mimeData()->urls(); Extensions *extensions = m_ki->extensions(); for(QList::iterator i = urls.begin(); i != urls.end(); ++i) { QUrl url = *i; if(extensions->isProjectFile(url)) { projectOpen(url); } else { fileOpen(url); } } } void Manager::reloadXMLOnAllDocumentsAndViews() { for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { KTextEditor::Document *doc = (*it)->getDoc(); // FIXME: 'doc' can be null, for example if it belongs to a project item // which has been closed, but this should be improved in the sense // that 'm_textInfoList' should only contain 'TextInfo' objects which // contain valid pointers to 'KTextEditor::Document' objects. if(!doc) { continue; } doc->reloadXML(); QList views = doc->views(); for(QList::iterator viewIt = views.begin(); viewIt != views.end(); ++viewIt) { (*viewIt)->reloadXML(); } } } void Manager::handleParsingComplete(const QUrl &url, KileParser::ParserOutput* output) { KILE_DEBUG_MAIN << url << output; if(!output) { KILE_DEBUG_MAIN << "NULL output given"; return; } KileDocument::TextInfo *textInfo = textInfoFor(url); if(!textInfo) { KileProjectItem* item = itemFor(url); if(item) { textInfo = item->getInfo(); } if(!textInfo) { // this can happen for instance when the document is closed // while the parser is still running KILE_DEBUG_MAIN << "no TextInfo object found for" << url << "found"; return; } } textInfo->installParserOutput(output); m_ki->structureWidget()->updateAfterParsing(textInfo, output->structureViewItems); delete(output); } // Show all opened projects and switch to another one, if you want void Manager::projectShow() { if(m_projects.count() <= 1) { return; } // select the new project KileProject *project = selectProject(i18n("Switch Project")); if(!project || project==activeProject()) { return; } // get last opened document const QUrl lastdoc = project->lastDocument(); KileProjectItem *docitem = (!lastdoc.isEmpty()) ? itemFor(lastdoc, project) : Q_NULLPTR; // if not, we search for the first opened tex file of this project // if no file is opened, we take the first tex file mentioned in the list KileProjectItem *first_texitem = Q_NULLPTR; if(!docitem) { QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; QString itempath = item->path(); // called from QAction 'Show projects...': find the first opened // LaTeX document or, if that fails, any other opened file QStringList extlist = (m_ki->extensions()->latexDocuments() + ' ' + m_ki->extensions()->latexPackages()).split(' '); for(QStringList::Iterator it=extlist.begin(); it!=extlist.end(); ++it) { if(itempath.indexOf( (*it), -(*it).length() ) >= 0) { if (m_ki->isOpen(item->url())) { docitem = item; break; } else if(!first_texitem) { first_texitem = item; } } } if(docitem) { break; } } } // did we find one opened file or must we take the first entry if(!docitem) { if(!first_texitem) { return; } docitem = first_texitem; } // ok, we can switch to another project now if (m_ki->isOpen(docitem->url())) { m_ki->viewManager()->switchToTextView(docitem->url()); } else { fileOpen(docitem->url(), docitem->encoding()); } } void Manager::projectRemoveFiles() { QList itemsList = selectProjectFileItems(i18n("Select Files to Remove")); if(itemsList.count() > 0) { for(QList::iterator it = itemsList.begin(); it != itemsList.end(); ++it) { removeFromProject(*it); } } } void Manager::projectShowFiles() { KileProjectItem *item = selectProjectFileItem( i18n("Select File") ); if(item) { if (item->type() == KileProjectItem::ProjectFile) { dontOpenWarning(item, i18n("Show Project Files"), i18n("project configuration file")); } else if(item->type() == KileProjectItem::Image) { dontOpenWarning(item, i18n("Show Project Files"), i18n("graphics file")); } else { // ok, we can switch to another file if (m_ki->isOpen(item->url())) { m_ki->viewManager()->switchToTextView(item->url()); } else { fileOpen(item->url(), item->encoding() ); } } } } void Manager::projectOpenAllFiles() { KileProject *project = selectProject(i18n("Select Project")); if(project) { projectOpenAllFiles(project->url()); } } void Manager::projectOpenAllFiles(const QUrl &url) { KileProject* project; KTextEditor::Document* doc = Q_NULLPTR; if(!url.isValid()) { return; } project = projectFor(url); if(!project) return; if(m_ki->viewManager()->currentTextView()) { doc = m_ki->viewManager()->currentTextView()->document(); } // we remember the actual view, so the user gets the same view back after opening QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; if (item->type()==KileProjectItem::ProjectFile) { dontOpenWarning( item, i18n("Open All Project Files"), i18n("project configuration file") ); } else if(item->type()==KileProjectItem::Image) { dontOpenWarning( item, i18n("Open All Project Files"), i18n("graphics file") ); } else if(!m_ki->isOpen(item->url())) { fileOpen(item->url(), item->encoding()); } } if(doc) { // we have a doc so switch back to original view m_ki->viewManager()->switchToTextView(doc->url()); } } QStringList Manager::getProjectFiles() { QStringList filelist; KileProject *project = activeProject(); if ( project ) { QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; if(item->type() != KileProjectItem::ProjectFile && item->type() != KileProjectItem::Image) { filelist << item->url().toLocalFile(); } } } return filelist; } void Manager::dontOpenWarning(KileProjectItem *item, const QString &action, const QString &filetype) { m_ki->errorHandler()->printMessage(KileTool::Info, i18n("not opened: %1 (%2)", item->url().toLocalFile(), filetype), action); } KileProjectItem* Manager::selectProjectFileItem(const QString &label) { // select a project KileProject *project = selectProject(i18n("Select Project")); if(!project) { return Q_NULLPTR; } // get a list of files QStringList filelist; QMap map; QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; filelist << item->path(); map[item->path()] = item; } // select one of these files KileProjectItem *item = Q_NULLPTR; KileListSelector *dlg = new KileListSelector(filelist, i18n("Project Files"), label, true, m_ki->mainWindow()); if(dlg->exec()) { if(dlg->hasSelection()) { QString name = dlg->selectedItems().first(); if(map.contains(name)) { item = map[name]; } else { KMessageBox::error(m_ki->mainWindow(), i18n("Could not determine the selected file."),i18n( "Project Error")); } } } delete dlg; return item; } QList Manager::selectProjectFileItems(const QString &label) { KileProject *project = selectProject(i18n("Select Project")); if(!project) { return QList(); } QStringList filelist; QMap map; QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; filelist << item->path(); map[item->path()] = item; } QList itemsList; KileListSelector *dlg = new KileListSelector(filelist, i18n("Project Files"), label, true, m_ki->mainWindow()); dlg->setSelectionMode(QAbstractItemView::ExtendedSelection); if(dlg->exec()) { if(dlg->hasSelection()) { QStringList selectedfiles = dlg->selectedItems(); for(QStringList::Iterator it = selectedfiles.begin(); it != selectedfiles.end(); ++it ) { if(map.contains(*it)) { itemsList.append(map[(*it)]); } else { KMessageBox::error(m_ki->mainWindow(), i18n("Could not determine the selected file."), i18n( "Project Error")); } } } } delete dlg; return itemsList; } // add a new file to the project // - only when there is an active project // - if the file doesn't already belong to it (checked by addToProject) void Manager::projectAddFile(QString filename, bool graphics) { KILE_DEBUG_MAIN << "===Kile::projectAddFile=============="; KileProject *project = activeProject(); if(!project) { return; } QFileInfo fi(filename); if(!fi.exists()) { if(graphics) { return; } // called from InputDialog after a \input- or \include command: // - if the chosen file has an extension: accept // - if not we add the default TeX extension: accept if it exists else reject QString ext = fi.completeSuffix(); if ( ! ext.isEmpty() ) { return; } filename += m_ki->extensions()->latexDocumentDefault(); if ( QFileInfo(filename).exists() ) { return; } } //ok, we have a project and an existing file KILE_DEBUG_MAIN << "\tadd file: " << filename; m_ki->viewManager()->updateStructure(false); QUrl url; url.setPath(filename); addToProject(project, url); } const QUrl Manager::symlinkFreeURL(const QUrl &url) { #ifdef Q_OS_WIN //TODO: maybe actually do something here? Seems unncecessary given Windows' lack of symlinks though... //Also: the else'd code below fails badly on Windows return url; #else KILE_DEBUG_MAIN << "===symlinkFreeURL=="; if(!url.isLocalFile()) { return url; } QDir dir(url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); QString filename = url.toLocalFile(); // if the directory does not exist we return the old url (just to be sure) if(dir.exists()) { filename= dir.canonicalPath() + '/' + url.fileName(); } else { KILE_DEBUG_MAIN << "directory " << url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() << "does not exist"; } QFileInfo fi(filename); if (fi.isSymLink()) { filename = fi.symLinkTarget(); } return QUrl::fromLocalFile(filename); #endif //def Q_OS_WIN } void Manager::cleanupDocumentInfoForProjectItems(KileDocument::Info *info) { QList itemsList = itemsFor(info); for(QList::iterator it = itemsList.begin(); it != itemsList.end(); ++it) { (*it)->setInfo(Q_NULLPTR); } } void Manager::createProgressDialog() { //TODO this is a dangerous dialog and should be removed in the long-term: // the dialog disables all close events unless all files are loaded, // thus if there is a loading error, the only way to abort loading gracefully is to // terminate the application m_progressDialog = new KileWidget::ProgressDialog(m_ki->mainWindow()); QLabel *label = new QLabel(m_progressDialog); label->setText(i18n("Opening Project...")); m_progressDialog->setLabel(label); m_progressDialog->setModal(true); m_progressDialog->setLabelText(i18n("Scanning project files...")); m_progressDialog->setAutoClose(true); m_progressDialog->setMinimumDuration(2000); m_progressDialog->hide(); } void Manager::loadDocumentAndViewSettings(KileDocument::TextInfo *textInfo) { KTextEditor::Document *document = textInfo->getDoc(); if(!document) { return; } KConfigGroup configGroup = configGroupForDocumentSettings(document); if(!configGroup.exists()) { return; } document->readSessionConfig(configGroup, QSet() << "SkipEncoding" << "SkipUrl"); { LaTeXInfo *latexInfo = dynamic_cast(textInfo); if(latexInfo) { KileTool::LivePreviewManager::readLivePreviewStatusSettings(configGroup, latexInfo); } } { LaTeXOutputHandler *h = dynamic_cast(textInfo); if(h) { h->readBibliographyBackendSettings(configGroup); } } QList viewList = document->views(); int i = 0; for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { KTextEditor::View *view = *it; configGroup = configGroupForViewSettings(document, i); view->readSessionConfig(configGroup); ++i; } } void Manager::saveDocumentAndViewSettings(KileDocument::TextInfo *textInfo) { KTextEditor::Document *document = textInfo->getDoc(); if(!document) { return; } KConfigGroup configGroup = configGroupForDocumentSettings(document); QUrl url = document->url(); url.setPassword(""); // we don't want the password to appear in the configuration file deleteDocumentAndViewSettingsGroups(url); document->writeSessionConfig(configGroup, QSet() << "SkipEncoding" << "SkipUrl"); { LaTeXInfo *latexInfo = dynamic_cast(textInfo); if(latexInfo) { KileTool::LivePreviewManager::writeLivePreviewStatusSettings(configGroup, latexInfo); } } { LaTeXOutputHandler *h = dynamic_cast(textInfo); if(h) { h->writeBibliographyBackendSettings(configGroup); } } QList viewList = document->views(); int i = 0; for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { configGroup = configGroupForViewSettings(document, i); (*it)->writeSessionConfig(configGroup); ++i; } // finally remove the config groups for the oldest documents that exceed MAX_NUMBER_OF_STORED_SETTINGS configGroup = KSharedConfig::openConfig()->group("Session Settings"); QList urlList = QUrl::fromStringList(configGroup.readEntry("Saved Documents", QStringList())); urlList.removeAll(url); urlList.push_front(url); // remove excess elements if(urlList.length() > MAX_NUMBER_OF_STORED_SETTINGS) { int excessNumber = urlList.length() - MAX_NUMBER_OF_STORED_SETTINGS; for(; excessNumber > 0; --excessNumber) { QUrl url = urlList.takeLast(); deleteDocumentAndViewSettingsGroups(url); } } configGroup.writeEntry("Documents", url); configGroup.writeEntry("Saved Documents", QUrl::toStringList(urlList)); } KConfigGroup Manager::configGroupForDocumentSettings(KTextEditor::Document *doc) const { return KSharedConfig::openConfig()->group(configGroupNameForDocumentSettings(doc->url())); } QString Manager::configGroupNameForDocumentSettings(const QUrl &url) const { QUrl url2 = url; url2.setPassword(""); return "Document-Settings,URL=" + url2.url(); } KConfigGroup Manager::configGroupForViewSettings(KTextEditor::Document *doc, int viewIndex) const { return KSharedConfig::openConfig()->group(configGroupNameForViewSettings(doc->url(), viewIndex)); } QString Manager::configGroupNameForViewSettings(const QUrl &url, int viewIndex) const { QUrl url2 = url; url2.setPassword(""); return "View-Settings,View=" + QString::number(viewIndex) + ",URL=" + url2.url(); } void Manager::deleteDocumentAndViewSettingsGroups(const QUrl &url) { QString urlString = url.url(); const QStringList groupList = KSharedConfig::openConfig()->groupList(); for(auto groupName : groupList) { if(!KSharedConfig::openConfig()->hasGroup(groupName)) { // 'groupName' might have been deleted continue; // work around bug 384039 } if(groupName.startsWith("Document-Settings") || groupName.startsWith("View-Settings")) { int urlIndex = groupName.indexOf("URL="); if(urlIndex >= 0 && groupName.mid(urlIndex + 4) == urlString) { KSharedConfig::openConfig()->deleteGroup(groupName); } } } } QStringList Manager::loadTextURLContents(const QUrl &url, const QString& encoding) { QTemporaryFile *temporaryFile = Q_NULLPTR; QString localFileName; if(url.isLocalFile()) { localFileName = url.path(); } else { // only use KIO when we have to temporaryFile = new QTemporaryFile(); if(!temporaryFile->open()) { KILE_DEBUG_MAIN << "Cannot create temporary file for" << url; delete temporaryFile; return QStringList(); } localFileName = temporaryFile->fileName(); auto downloadJob = KIO::file_copy(url, QUrl::fromLocalFile(localFileName), 0600, KIO::Overwrite); KJobWidgets::setWindow(downloadJob, m_ki->mainWindow()); // FIXME: 'exec' should not be used! if (!downloadJob->exec()) { KILE_DEBUG_MAIN << "Cannot download resource: " << url; KILE_DEBUG_MAIN << downloadJob->errorString(); delete temporaryFile; return QStringList(); } } QFile localFile(localFileName); if (!localFile.open(QIODevice::ReadOnly | QIODevice::Text)) { KILE_DEBUG_MAIN << "Cannot open source file: " << localFileName; delete temporaryFile; return QStringList(); } QStringList res; QTextStream stream(&localFile); if(!encoding.isEmpty()) { stream.setCodec(encoding.toLatin1()); } while(!stream.atEnd()) { res.append(stream.readLine()); } delete temporaryFile; return res; } } diff --git a/src/kiledocmanager.h b/src/kiledocmanager.h index 4d75c717..b848de93 100644 --- a/src/kiledocmanager.h +++ b/src/kiledocmanager.h @@ -1,312 +1,311 @@ /************************************************************************** * Copyright (C) 2004 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) * * (C) 2006-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 KILEDOCUMENTKILEDOCMANAGER_H #define KILEDOCUMENTKILEDOCMANAGER_H #include #include #include #include #include #include #include "kileconstants.h" #include "kileproject.h" #include "widgets/progressdialog.h" class QUrl; class KFileItem; class QProgressDialog; namespace KTextEditor { class Document; class View; } class TemplateItem; class KileInfo; class KileProjectItem; namespace KileParser { class ParserOutput; } namespace KileDocument { class Info; class TextInfo; /** * The design of the document manager is based on the following invariants: * - Several projects can be open simultaneously * - For every URL there can only be at most one associated KileDocument::Info* object, but * there can be several KileProject* items (each one belonging to a different project) * - It is guaranteed that every project item that represents textual data contains a TextInfo* object **/ class Manager : public QObject { Q_OBJECT public: explicit Manager(KileInfo *info, QObject *parent = Q_NULLPTR, const char *name = Q_NULLPTR); ~Manager(); void readConfig(); void writeConfig(); public Q_SLOTS: KTextEditor::View* createNewJScript(); KTextEditor::View* createNewLaTeXDocument(); //files void newDocumentStatus(KTextEditor::Document *doc); /** * Creates a new file on disk. **/ void fileNew(const QUrl&); void fileNewScript(); void fileNew(KileDocument::Type type = LaTeX); void fileSelected(const QUrl&); void fileSelected(const KileProjectItem *item); void fileSelected(const KFileItem& file); void fileOpen(); inline TextInfo* fileOpen(const QString& localFile, const QString& encoding = QString(), int index = -1) { return fileOpen(QUrl::fromLocalFile(localFile), encoding, index); } TextInfo* fileOpen(const QUrl &url, const QString& encoding = QString(), int index = -1); bool fileSave(KTextEditor::View* = Q_NULLPTR); bool fileSaveAs(KTextEditor::View* = Q_NULLPTR); - void fileSaveCopyAs(); void saveURL(const QUrl&); bool fileSaveAll(bool disUntitled = false); void fileSaveCompiledDocument(); bool fileCloseAllOthers(KTextEditor::View *view = Q_NULLPTR); bool fileCloseAll(); bool fileClose(const QUrl &url); bool fileClose(KTextEditor::View *view = Q_NULLPTR); bool fileClose(KTextEditor::Document *doc, bool closingproject = false); //templates KTextEditor::View* loadTemplate(TemplateItem*); void createTemplate(); void removeTemplate(); void replaceTemplateVariables(QString &line); //projects void projectNew(); void projectOpen(); /** * @param openProjectItemViews Opens project files in the editor iff openProjectItemViews is set to 'true'. **/ void projectOpen(const QUrl&, int step = 0, int max = 1, bool openProjectItemViews = true); /** * Saves the state of the project, if @param project is zero, the active project is saved. **/ void projectSave(KileProject* project = Q_NULLPTR); void projectAddFiles(const QUrl&); void projectAddFiles(KileProject* project = Q_NULLPTR,const QUrl &url = QUrl()); void toggleArchive(KileProjectItem *); void buildProjectTree(KileProject *project = Q_NULLPTR); void buildProjectTree(const QUrl&); void projectOptions(const QUrl&); void projectOptions(KileProject *project = Q_NULLPTR); bool projectClose(const QUrl &url = QUrl()); bool projectCloseAll(); void projectShow(); void projectRemoveFiles(); void projectShowFiles(); void projectAddFile(QString filename, bool graphics=false); void projectOpenAllFiles(); void projectOpenAllFiles(const QUrl&); KileProject* selectProject(const QString&); void addProject(KileProject *project); void addToProject(const QUrl&); void addToProject(KileProject*, const QUrl&); void removeFromProject(KileProjectItem *item); void storeProjectItem(KileProjectItem *item, KTextEditor::Document *doc); void cleanUpTempFiles(const QUrl &url, bool silent = false); void openDroppedURLs(QDropEvent *e); void reloadXMLOnAllDocumentsAndViews(); void handleParsingComplete(const QUrl &url, KileParser::ParserOutput* output); Q_SIGNALS: void projectTreeChanged(const KileProject*); void closingDocument(KileDocument::Info*); void documentInfoCreated(KileDocument::Info*); void updateStructure(bool needToParse, KileDocument::Info*); void updateModeStatus(); void updateReferences(KileDocument::Info*); void documentModificationStatusChanged(KTextEditor::Document*, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason); void documentUrlChanged(KTextEditor::Document*); void documentNameChanged(KTextEditor::Document*); void documentReadWriteStateChanged(KTextEditor::Document*); void addToRecentFiles(const QUrl&); void addToRecentProjects(const QUrl&); void removeFromRecentProjects(const QUrl&); void startWizard(); void removeFromProjectView(const QUrl&); void removeFromProjectView(const KileProject*); void removeItemFromProjectView(const KileProjectItem*, bool); void addToProjectView(const QUrl&); void addToProjectView(KileProjectItem *item); void addToProjectView(const KileProject*); void documentSavedAs(KTextEditor::View*, KileDocument::TextInfo*); void projectOpened(KileProject *project); void documentOpened(KileDocument::TextInfo *textInfo); public: bool isOpeningFile(); KTextEditor::Editor* getEditor(); QList projects() { return m_projects; } QList textDocumentInfos() { return m_textInfoList; } KTextEditor::Document* docFor(const QUrl &url); TextInfo* getInfo() const; inline TextInfo* textInfoFor(const QString& localFile) { return textInfoFor(QUrl::fromLocalFile(localFile)); } TextInfo* textInfoFor(const QUrl &url); TextInfo* textInfoFor(KTextEditor::Document* doc) const; QUrl urlFor(TextInfo* textInfo); void updateInfos(); KileProject* projectForMember(const QUrl &memberUrl); KileProject* projectFor(const QUrl &projecturl); KileProject* projectFor(const QString & name); KileProject* activeProject(); bool isProjectOpen(); void updateProjectReferences(KileProject *project); QStringList getProjectFiles(); KileProjectItem* activeProjectItem(); /** * Finds the project item for the file with URL @param url. * @returns a pointer to the project item, 0 if this file does not belong to a project **/ KileProjectItem* itemFor(const QUrl &url, KileProject *project = Q_NULLPTR) const; KileProjectItem* itemFor(TextInfo *docinfo, KileProject *project = Q_NULLPTR) const; KileProjectItem* selectProjectFileItem(const QString &label); QList selectProjectFileItems(const QString &label); /** * The next method returns a list as several projects can be open simultaneously, i.e. * one URL can be associated with several project item belonging to different projects. **/ QList itemsFor(Info *docinfo) const; QList itemsFor(const QUrl &url) const; static const QUrl symlinkFreeURL(const QUrl &url); protected: /** * @param openProjectItemViews Opens project files in the editor iff openProjectItemViews is set to 'true'. **/ void projectOpenItem(KileProjectItem *item, bool openProjectItemViews = true); void createTextInfoForProjectItem(KileProjectItem *item); void trashDoc(TextInfo *docinfo, KTextEditor::Document *doc = Q_NULLPTR); TextInfo* createTextDocumentInfo(KileDocument::Type type, const QUrl &url, const QUrl& baseDirectory = QUrl()); void recreateTextDocumentInfo(TextInfo *oldinfo); /** * Tries to remove and delete a TextInfo object. The TextInfo object will only be deleted if it isn't referenced * by any project item or if it is only referenced by a project that should be closed. * @param closingproject Indicates whether the TextInfo object should be removed as part of a project close * operation. * @warning This method does not close or delete any Kate documents that are associated with the TextInfo object ! **/ bool removeTextDocumentInfo(TextInfo *docinfo, bool closingproject = false); KTextEditor::Document* createDocument(const QUrl &url, TextInfo *docinfo, const QString& encoding, const QString& mode, const QString& highlight); /** * Creates a document with the specified text. * * @param extension The extension of the file that should be created without leading "." **/ KTextEditor::View* createDocumentWithText(const QString& text, KileDocument::Type type = KileDocument::Text, const QString& extension = QString(), const QUrl &baseDirectory = QUrl()); KTextEditor::View* loadText(KileDocument::Type type, const QUrl &url, const QString& encoding = QString(), bool create = true, const QString& mode = QString(), const QString& highlight = QString(), const QString &text = QString(), int index = -1, const QUrl& baseDirectory = QUrl()); KTextEditor::View* loadItem(KileDocument::Type type, KileProjectItem *item, const QString& text = QString(), bool openProjectItemViews = true); QStringList loadTextURLContents(const QUrl &url, const QString& encoding); private: KTextEditor::Editor *m_editor; QList m_textInfoList; KileInfo *m_ki; QList m_projects; QPointer m_progressDialog; unsigned int m_autoSaveLock; bool m_currentlySavingAll, m_currentlyOpeningFile; void dontOpenWarning(KileProjectItem *item, const QString &action, const QString &filetype); void cleanupDocumentInfoForProjectItems(KileDocument::Info *info); void createProgressDialog(); QStringList autosaveWarnings; void loadDocumentAndViewSettings(KileDocument::TextInfo *textInfo); void saveDocumentAndViewSettings(KileDocument::TextInfo *textInfo); KConfigGroup configGroupForDocumentSettings(KTextEditor::Document *doc) const; QString configGroupNameForDocumentSettings(const QUrl &url) const; KConfigGroup configGroupForViewSettings(KTextEditor::Document *doc, int viewIndex) const; QString configGroupNameForViewSettings(const QUrl &url, int viewIndex) const; void deleteDocumentAndViewSettingsGroups(const QUrl &url); bool checkForFileOverwritePermission(const QUrl& url); }; } #endif diff --git a/src/kileui.rc b/src/kileui.rc index 3403241d..b213ce1b 100644 --- a/src/kileui.rc +++ b/src/kileui.rc @@ -1,591 +1,590 @@ - + &File - Con&vert To &Edit &Go to Co&mplete &Bullets &Select D&elete Environmen&t Te&X Group &View Document Viewer B&uild Live Preview Quick Preview &Compile C&onvert &View O&ther Pro&ject LaTe&X &Preamble Tables and Lists &Sectioning &References &Environment &List Environment &Tabular Environment &Floating Environment &Code Environment &Math Commands Braces AMS Text and Boxes AMS Fraction AMS Binomial Expression AMS Arrows Math &Font Styles Math &Accents Math &Spaces Standard Math &Environments &AMS Math Environments &Align Environments &Center Environments Multi &Line Environments &Matrix Environments &Font Styles Font Family Font Series Font Shape Spa&cing Page- and Linebreaks Space Rubber Lengths User Menu &Wizard &Settings &Help TeX Documentation diff --git a/src/kileviewmanager.cpp b/src/kileviewmanager.cpp index fec4cd98..a173f004 100644 --- a/src/kileviewmanager.cpp +++ b/src/kileviewmanager.cpp @@ -1,1319 +1,1317 @@ /************************************************************************** * Copyright (C) 2004 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) * * (C) 2006-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. * * * ***************************************************************************/ #include "kileviewmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //for QTimer::singleShot trick #include #include "editorkeysequencemanager.h" #include "kileinfo.h" #include "kileconstants.h" #include "kileproject.h" #include "kiledocmanager.h" #include "kileextensions.h" #include "kiletool_enums.h" #include "usermenu/usermenu.h" #include "livepreview.h" #include "widgets/projectview.h" #include "widgets/structurewidget.h" #include "editorextension.h" #include "plaintolatexconverter.h" #include "widgets/previewwidget.h" #include "quickpreview.h" #include "codecompletion.h" namespace KileView { bool sortDocuments(const KTextEditor::View * const lhs, const KTextEditor::View * const rhs) { return lhs->document()->documentName().compare(rhs->document()->documentName(), Qt::CaseInsensitive) < 0; } //BEGIN DocumentViewerWindow DocumentViewerWindow::DocumentViewerWindow(QWidget *parent, Qt::WindowFlags f) : KMainWindow(parent, f) { } DocumentViewerWindow::~DocumentViewerWindow() { } void DocumentViewerWindow::showEvent(QShowEvent *event) { KMainWindow::showEvent(event); emit visibilityChanged(true); } void DocumentViewerWindow::closeEvent(QCloseEvent *event) { KMainWindow::closeEvent(event); emit visibilityChanged(false); } //END DocumentViewerWindow Manager::Manager(KileInfo *info, KActionCollection *actionCollection, QObject *parent, const char *name) : QObject(parent), m_ki(info), // m_projectview(Q_NULLPTR), m_tabsAndEditorWidget(Q_NULLPTR), m_tabBar(Q_NULLPTR), m_documentListButton(Q_NULLPTR), m_viewerPartWindow(Q_NULLPTR), m_widgetStack(Q_NULLPTR), m_pasteAsLaTeXAction(Q_NULLPTR), m_convertToLaTeXAction(Q_NULLPTR), m_quickPreviewAction(Q_NULLPTR), m_showCursorPositionInViewerAction(Q_NULLPTR), m_viewerControlToolBar(Q_NULLPTR), m_cursorPositionChangedTimer(Q_NULLPTR), m_clearLastShownSourceLocationTimer(Q_NULLPTR), m_synchronizeViewWithCursorAction(Q_NULLPTR) { setObjectName(name); createViewerPart(actionCollection); m_showCursorPositionInViewerAction = new QAction(QIcon::fromTheme("go-jump-symbolic"), i18n("Show Cursor Position in Viewer"), this); connect(m_showCursorPositionInViewerAction, &QAction::triggered, this, &KileView::Manager::showCursorPositionInDocumentViewer); actionCollection->addAction("show_cursor_position_in_document_viewer", m_showCursorPositionInViewerAction); m_synchronizeViewWithCursorAction = new KToggleAction(i18n("Synchronize Cursor Position with Viewer"), this); connect(m_synchronizeViewWithCursorAction, &KToggleAction::toggled, this, &KileView::Manager::synchronizeViewWithCursorActionToggled); connect(m_synchronizeViewWithCursorAction, &KToggleAction::changed, this, [=] () { m_showCursorPositionInViewerAction->setEnabled(!m_synchronizeViewWithCursorAction->isChecked()); }); actionCollection->addAction("synchronize_cursor_with_document_viewer", m_synchronizeViewWithCursorAction); m_cursorPositionChangedTimer = new QTimer(this); m_cursorPositionChangedTimer->setSingleShot(true); connect(m_cursorPositionChangedTimer, &QTimer::timeout, this, &KileView::Manager::handleCursorPositionChangedTimeout); m_clearLastShownSourceLocationTimer = new QTimer(this); m_clearLastShownSourceLocationTimer->setInterval(3000); m_clearLastShownSourceLocationTimer->setSingleShot(true); connect(m_clearLastShownSourceLocationTimer, &QTimer::timeout, this, &KileView::Manager::clearLastShownSourceLocationInDocumentViewer); createViewerControlToolBar(); } Manager::~Manager() { KILE_DEBUG_MAIN; // the parent of the widget might be Q_NULLPTR; see 'destroyDocumentViewerWindow()' if(m_viewerPart) { delete m_viewerPart->widget(); delete m_viewerPart; } destroyDocumentViewerWindow(); } KTextEditor::View * Manager::textViewAtTab(int index) const { return m_tabBar->tabData(index).value(); } void Manager::createViewerControlToolBar() { m_viewerControlToolBar = new KToolBar(Q_NULLPTR, false, false); m_viewerControlToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); m_viewerControlToolBar->setFloatable(false); m_viewerControlToolBar->setMovable(false); m_viewerControlToolBar->setIconDimensions(KIconLoader::SizeSmall); m_viewerControlToolBar->addAction(m_showCursorPositionInViewerAction); } void Manager::setClient(KXMLGUIClient *client) { m_client = client; if(Q_NULLPTR == m_client->actionCollection()->action("popup_pasteaslatex")) { m_pasteAsLaTeXAction = new QAction(i18n("Paste as LaTe&X"), this); connect(m_pasteAsLaTeXAction, &QAction::triggered, this, &Manager::pasteAsLaTeX); } if(Q_NULLPTR == m_client->actionCollection()->action("popup_converttolatex")) { m_convertToLaTeXAction = new QAction(i18n("Convert Selection to &LaTeX"), this); connect(m_convertToLaTeXAction, &QAction::triggered, this, &Manager::convertSelectionToLaTeX); } if(Q_NULLPTR == m_client->actionCollection()->action("popup_quickpreview")) { m_quickPreviewAction = new QAction(this); connect(m_quickPreviewAction, &QAction::triggered, this, &Manager::quickPreviewPopup); } } void Manager::readConfig(QSplitter *splitter) { // we might have to change the location of the viewer part setupViewerPart(splitter); setDocumentViewerVisible(KileConfig::showDocumentViewer()); m_synchronizeViewWithCursorAction->setChecked(KileConfig::synchronizeCursorWithView()); Okular::ViewerInterface *viewerInterface = dynamic_cast(m_viewerPart.data()); if(viewerInterface && !m_ki->livePreviewManager()->isLivePreviewActive()) { viewerInterface->setWatchFileModeEnabled(KileConfig::watchFileForDocumentViewer()); // also reload the document; this is necessary for switching back on watch-file mode as otherwise // it would only enabled after the document has been reloaded anyway if(m_viewerPart->url().isValid()) { m_viewerPart->openUrl(m_viewerPart->url()); } } } void Manager::writeConfig() { if(m_viewerPart) { KileConfig::setShowDocumentViewer(isViewerPartShown()); } if(m_viewerPartWindow) { KConfigGroup group(KSharedConfig::openConfig(), "KileDocumentViewerWindow"); m_viewerPartWindow->saveMainWindowSettings(group); } KileConfig::setSynchronizeCursorWithView(m_synchronizeViewWithCursorAction->isChecked()); } void Manager::setTabsAndEditorVisible(bool b) { m_tabsAndEditorWidget->setVisible(b); } QWidget * Manager::createTabs(QWidget *parent) { m_widgetStack = new QStackedWidget(parent); DropWidget *emptyDropWidget = new DropWidget(m_widgetStack); m_widgetStack->insertWidget(0, emptyDropWidget); connect(emptyDropWidget, &KileView::DropWidget::testCanDecode, this, static_cast(&Manager::testCanDecodeURLs)); connect(emptyDropWidget, &KileView::DropWidget::receivedDropEvent, m_ki->docManager(), &KileDocument::Manager::openDroppedURLs); connect(emptyDropWidget, &KileView::DropWidget::mouseDoubleClick, [=]() { m_ki->docManager()->fileNew(); }); m_tabBar = new QTabBar(parent); QWidget *tabBarWidget = new QWidget(); tabBarWidget->setLayout(new QHBoxLayout); tabBarWidget->layout()->setSpacing(0); tabBarWidget->layout()->setContentsMargins(0, 0, 0, 0); KAcceleratorManager::setNoAccel(m_tabBar); // quick menu for all open documents m_documentListButton = new QToolButton(parent); m_documentListButton->setIcon(QIcon::fromTheme("format-list-unordered")); m_documentListButton->setMenu(new QMenu(parent)); m_documentListButton->setPopupMode(QToolButton::InstantPopup); m_documentListButton->setAutoRaise(true); m_documentListButton->setToolTip(i18n("Show sorted list of opened documents")); m_documentListButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); // lambda: update context menu connect(m_documentListButton->menu(), &QMenu::aboutToShow, [=]() { qDeleteAll(m_documentListButton->menu()->actions()); m_documentListButton->menu()->clear(); // create a lexicographically sorted list QVector views; views.reserve(m_tabBar->count()); for(int i = 0; i < m_tabBar->count(); ++i) { views << textViewAtTab(i); } std::sort(views.begin(), views.end(), sortDocuments); foreach(KTextEditor::View* view, views) { QAction *action = m_documentListButton->menu()->addAction(view->document()->documentName()); action->setData(QVariant::fromValue(view)); } }); // lambda: handle context menu action triggers connect(m_documentListButton->menu(), &QMenu::triggered, [=](QAction *action) { KTextEditor::View *view = action->data().value(); Q_ASSERT(view); m_tabBar->setCurrentIndex(tabIndexOf(view)); }); // lambda: menu button is enabled if and only if at least two documents are open connect(this, &KileView::Manager::textViewCreated, [=]() { m_documentListButton->setEnabled(m_tabBar->count() > 1); }); connect(this, &KileView::Manager::textViewClosed, [=]() { m_documentListButton->setEnabled(m_tabBar->count() > 1); m_cursorPositionChangedTimer->stop(); }); connect(this, &KileView::Manager::textViewClosed, [=]() { m_documentListButton->setEnabled(m_tabBar->count() > 1); }); tabBarWidget->layout()->addWidget(m_documentListButton); // tabbar m_tabBar->setFocusPolicy(Qt::ClickFocus); m_tabBar->setMovable(true); m_tabBar->setTabsClosable(true); m_tabBar->setUsesScrollButtons(true); m_tabBar->setFocus(); m_tabBar->setContextMenuPolicy(Qt::CustomContextMenu); tabBarWidget->layout()->addWidget(m_tabBar); // connect tabbar with document views connect(m_tabBar, &QTabBar::currentChanged, this, &Manager::currentTabChanged); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &Manager::closeTab); connect(m_tabBar, &QTabBar::customContextMenuRequested, this, &Manager::tabContext); // main widget in which we put everything m_tabsAndEditorWidget = new QWidget(parent); m_tabsAndEditorWidget->setLayout(new QVBoxLayout); m_tabsAndEditorWidget->layout()->setSpacing(0); m_tabsAndEditorWidget->layout()->setContentsMargins(0, 0, 0, 0); m_tabsAndEditorWidget->layout()->addWidget(tabBarWidget); m_tabsAndEditorWidget->layout()->addWidget(m_widgetStack); return m_tabsAndEditorWidget; } void Manager::closeTab(int index) { QWidget *widget = textViewAtTab(index); if(widget->inherits("KTextEditor::View")) { KTextEditor::View *view = static_cast(widget); m_ki->docManager()->fileClose(view->document()); } } void Manager::currentTabChanged(int index) { QWidget *newlyActivatedWidget = textViewAtTab(index); if(!newlyActivatedWidget) { return; } QWidget *oldViewWidget = m_widgetStack->widget(1); if(oldViewWidget == newlyActivatedWidget) { return; } if(oldViewWidget) { m_widgetStack->removeWidget(oldViewWidget); } m_widgetStack->insertWidget(1, newlyActivatedWidget); m_widgetStack->setCurrentIndex(1); emit currentViewChanged(newlyActivatedWidget); KTextEditor::View *view = dynamic_cast(newlyActivatedWidget); if(view) { emit textViewActivated(view); } } void Manager::handleCursorPositionChangedTimeout() { if(m_ki->livePreviewManager()->isLivePreviewEnabledForCurrentDocument()) { m_ki->livePreviewManager()->showCursorPositionInDocumentViewer(); } } void Manager::handleCursorPositionChanged(KTextEditor::View *view, const KTextEditor::Cursor &pos) { Q_UNUSED(view); Q_UNUSED(pos); if(!m_synchronizeViewWithCursorAction->isChecked()) { return; } m_cursorPositionChangedTimer->start(100); } KTextEditor::View * Manager::createTextView(KileDocument::TextInfo *info, int index) { KTextEditor::Document *doc = info->getDoc(); KTextEditor::View *view = info->createView(m_tabBar, Q_NULLPTR); Q_ASSERT(view); if(!view) { KMessageBox::error(m_ki->mainWindow(), i18n("Could not create an editor view."), i18n("Fatal Error")); } //install a key sequence recorder on the view view->focusProxy()->installEventFilter(new KileEditorKeySequence::Recorder(view, m_ki->editorKeySequenceManager())); // in the case of simple text documents, we mimic the behaviour of LaTeX documents if(info->getType() == KileDocument::Text) { // view->focusProxy()->installEventFilter(m_ki->eventFilter()); } index = m_tabBar->insertTab(index, QString()); // if index=-1 for appending tab, it gets assigned a new index m_tabBar->setTabData(index, QVariant::fromValue(view)); connect(view, &KTextEditor::View::cursorPositionChanged, this, &Manager::cursorPositionChanged); connect(view, &KTextEditor::View::viewModeChanged, this, &Manager::viewModeChanged); connect(view, &KTextEditor::View::selectionChanged, this, &Manager::selectionChanged); connect(view, &KTextEditor::View::viewModeChanged, this, &Manager::updateCaption); connect(view, &KTextEditor::View::viewInputModeChanged, this, &Manager::updateModeStatus); //TODO KF5: signals not available anymore // connect(view, SIGNAL(informationMessage(KTextEditor::View*,const QString&)), this, SIGNAL(informationMessage(KTextEditor::View*,const QString&))); // connect(view, SIGNAL(dropEventPass(QDropEvent *)), m_ki->docManager(), SLOT(openDroppedURLs(QDropEvent *))); connect(view, &KTextEditor::View::textInserted, m_ki->codeCompletionManager(), &KileCodeCompletion::Manager::textInserted); connect(doc, &KTextEditor::Document::documentNameChanged, this, &Manager::updateTabTexts); connect(doc, &KTextEditor::Document::documentUrlChanged, this, &Manager::updateTabTexts); connect(this, &KileView::Manager::textViewClosed, m_cursorPositionChangedTimer, &QTimer::stop); // code completion KTextEditor::CodeCompletionInterface *completionInterface = qobject_cast(view); if(completionInterface) { completionInterface->setAutomaticInvocationEnabled(true); } // install a working text editor part popup dialog thingy installContextMenu(view); // delete the 'Configure Editor...' action delete view->actionCollection()->action("set_confdlg"); - // delete the "save copy as" action as we have our own - delete view->actionCollection()->action("file_save_copy_as"); // delete the "save as with encoding" action as it's too technical for Kile // also, there is currently no way to preset the desired extension in the save-as dialog // (the functionality is still available via Tools/Encoding + save) delete view->actionCollection()->action("file_save_as_with_encoding"); // use Kile's save and save-as functions instead of the text editor's QAction *action = view->actionCollection()->action(KStandardAction::name(KStandardAction::Save)); if(action) { KILE_DEBUG_MAIN << " reconnect action 'file_save'..."; disconnect(action, &QAction::triggered, 0, 0); connect(action, &QAction::triggered, [=]() { m_ki->docManager()->fileSave(); }); } action = view->actionCollection()->action(KStandardAction::name(KStandardAction::SaveAs)); if(action) { KILE_DEBUG_MAIN << " reconnect action 'file_save_as'..."; disconnect(action, &QAction::triggered, 0, 0); connect(action, &QAction::triggered, [=]() { m_ki->docManager()->fileSaveAs(); }); } updateTabTexts(doc); // we do this twice as otherwise the tool tip for the first view did not appear (Qt issue ?) // (BUG 205245) updateTabTexts(doc); m_tabBar->setCurrentIndex(index); if(m_tabBar->count() == 1) { // when the tab bar is empty initially, 'setCurrentIndex' won't have any effect currentTabChanged(0); // at this point; so we do it manually } //activate the newly created view emit(textViewCreated(view)); emit(activateView(view, false)); emit(updateCaption()); //make sure the caption gets updated reflectDocumentModificationStatus(view->document(), false, KTextEditor::ModificationInterface::OnDiskUnmodified); return view; } void Manager::installContextMenu(KTextEditor::View *view) { QMenu *popupMenu = view->defaultContextMenu(); if(popupMenu) { connect(popupMenu, &QMenu::aboutToShow, this, &Manager::onTextEditorPopupMenuRequest); // install some more actions on it popupMenu->addSeparator(); popupMenu->addAction(m_pasteAsLaTeXAction); popupMenu->addAction(m_convertToLaTeXAction); popupMenu->addSeparator(); popupMenu->addAction(m_quickPreviewAction); // insert actions from user-defined latex menu KileMenu::UserMenu *usermenu = m_ki->userMenu(); if(usermenu) { KILE_DEBUG_MAIN << "Insert actions from user-defined latex menu"; popupMenu->addSeparator(); foreach(QAction *action, usermenu->contextMenuActions()) { if(action) { popupMenu->addAction(action); } else { popupMenu->addSeparator(); } } } view->setContextMenu(popupMenu); } } void Manager::tabContext(const QPoint &pos) { KILE_DEBUG_MAIN << pos; const int tabUnderPos = m_tabBar->tabAt(pos); if(tabUnderPos < 0) { KILE_DEBUG_MAIN << tabUnderPos; return; } KTextEditor::View *view = textViewAtTab(tabUnderPos); if(!view || !view->document()) { return; } QMenu tabMenu; tabMenu.addSection(m_ki->getShortName(view->document())); // 'action1' can become null if it belongs to a view that has been closed, for example QPointer action1 = m_ki->mainWindow()->action("move_view_tab_left"); action1->setData(qVariantFromValue(view)); tabMenu.addAction(action1); QPointer action2 = m_ki->mainWindow()->action("move_view_tab_right"); action2->setData(qVariantFromValue(view)); tabMenu.addAction(action2); tabMenu.addSeparator(); QPointer action3; if(view->document()->isModified()) { action3 = view->actionCollection()->action(KStandardAction::name(KStandardAction::Save)); action3->setData(qVariantFromValue(view)); tabMenu.addAction(action3); } QPointer action4 = view->actionCollection()->action(KStandardAction::name(KStandardAction::SaveAs)); action4->setData(qVariantFromValue(view)); tabMenu.addAction(action4); QPointer action5 = m_ki->mainWindow()->action("file_save_copy_as"); action5->setData(qVariantFromValue(view)); tabMenu.addAction(action5); tabMenu.addSeparator(); QPointer action6 = m_ki->mainWindow()->action("file_close"); action6->setData(qVariantFromValue(view)); tabMenu.addAction(action6); QPointer action7 = m_ki->mainWindow()->action("file_close_all_others"); action7->setData(qVariantFromValue(view)); tabMenu.addAction(action7); /* FIXME create proper actions which delete/add the current file without asking stupidly QAction* removeAction = m_ki->mainWindow()->action("project_remove"); QAction* addAction = m_ki->mainWindow()->action("project_add"); tabMenu.insertSeparator(addAction); tabMenu.addAction(addAction); tabMenu.addAction(removeAction);*/ tabMenu.exec(m_tabBar->mapToGlobal(pos)); if(action1) { action1->setData(QVariant()); } if(action2) { action2->setData(QVariant()); } if(action3) { action3->setData(QVariant()); } if(action4) { action4->setData(QVariant()); } if(action5) { action5->setData(QVariant()); } if(action6) { action6->setData(QVariant()); } if(action7) { action7->setData(QVariant()); } } void Manager::removeView(KTextEditor::View *view) { if(view) { m_client->factory()->removeClient(view); const bool isActiveView = (KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView() == view); m_tabBar->removeTab(tabIndexOf(view)); emit(updateCaption()); //make sure the caption gets updated if(m_tabBar->count() == 0) { m_ki->structureWidget()->clear(); m_widgetStack->setCurrentIndex(0); // if there are no open views, then show the DropWidget } emit(textViewClosed(view, isActiveView)); delete view; } else { KILE_DEBUG_MAIN << "View should be removed but is Q_NULLPTR"; } } KTextEditor::View * Manager::currentTextView() const { return textViewAtTab(m_tabBar->currentIndex()); } KTextEditor::View * Manager::textView(int index) const { Q_ASSERT(textViewAtTab(index)); return textViewAtTab(index); } KTextEditor::View * Manager::textView(KileDocument::TextInfo *info) const { KTextEditor::Document *doc = info->getDoc(); if(!doc) { return Q_NULLPTR; } for(int i = 0; i < m_tabBar->count(); ++i) { KTextEditor::View *view = textViewAtTab(i); if(!view) { continue; } if(view->document() == doc) { return view; } } return Q_NULLPTR; } int Manager::textViewCount() const { return m_tabBar->count(); } int Manager::tabIndexOf(KTextEditor::View* view) const { for(int i = 0; i < m_tabBar->count(); ++i) { if(textViewAtTab(i) == view) { return i; } } return -1; } unsigned int Manager::getTabCount() const { return m_tabBar->count(); } KTextEditor::View * Manager::switchToTextView(const QUrl &url, bool requestFocus) { return switchToTextView(m_ki->docManager()->docFor(url), requestFocus); } KTextEditor::View * Manager::switchToTextView(KTextEditor::Document *doc, bool requestFocus) { KTextEditor::View *view = Q_NULLPTR; if(doc) { if(doc->views().count() > 0) { view = doc->views().first(); if(view) { switchToTextView(view, requestFocus); } } } return view; } void Manager::switchToTextView(KTextEditor::View *view, bool requestFocus) { int index = tabIndexOf(view); if(index < 0) { return; } m_tabBar->setCurrentIndex(index); if(requestFocus) { focusTextView(view); } } void Manager::setTabIcon(QWidget *view, const QIcon& icon) { m_tabBar->setTabIcon(tabIndexOf(qobject_cast(view)), icon); } void Manager::updateStructure(bool parse /* = false */, KileDocument::Info *docinfo /* = Q_NULLPTR */) { if(!docinfo) { docinfo = m_ki->docManager()->getInfo(); } if(docinfo) { m_ki->structureWidget()->update(docinfo, parse); } if(m_tabBar->count() == 0) { m_ki->structureWidget()->clear(); } } void Manager::gotoNextView() { if(m_tabBar->count() < 2) { return; } int cPage = m_tabBar->currentIndex() + 1; if(cPage >= m_tabBar->count()) { m_tabBar->setCurrentIndex(0); } else { m_tabBar->setCurrentIndex(cPage); } } void Manager::gotoPrevView() { if(m_tabBar->count() < 2) { return; } int cPage = m_tabBar->currentIndex() - 1; if(cPage < 0) { m_tabBar->setCurrentIndex(m_tabBar->count() - 1); } else { m_tabBar->setCurrentIndex(cPage); } } void Manager::moveTabLeft(QWidget *widget) { if(m_tabBar->count() < 2) { return; } // the 'data' property can be set by 'tabContext' QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!widget && var.isValid()) { // the action's 'data' property is cleared // when the context menu is destroyed widget = var.value(); } } if(!widget) { widget = currentTextView(); } if(!widget) { return; } int currentIndex = tabIndexOf(qobject_cast(widget)); int newIndex = (currentIndex == 0 ? m_tabBar->count() - 1 : currentIndex - 1); m_tabBar->moveTab(currentIndex, newIndex); } void Manager::moveTabRight(QWidget *widget) { if(m_tabBar->count() < 2) { return; } // the 'data' property can be set by 'tabContext' QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!widget && var.isValid()) { // the action's 'data' property is cleared // when the context menu is destroyed widget = var.value(); } } if(!widget) { widget = currentTextView(); } if(!widget) { return; } int currentIndex = tabIndexOf(qobject_cast(widget)); int newIndex = (currentIndex == m_tabBar->count() - 1 ? 0 : currentIndex + 1); m_tabBar->moveTab(currentIndex, newIndex); } void Manager::reflectDocumentModificationStatus(KTextEditor::Document *doc, bool isModified, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason) { QIcon icon; if(reason == KTextEditor::ModificationInterface::OnDiskUnmodified && isModified) { //nothing icon = QIcon::fromTheme("modified"); // This icon is taken from Kate. Therefore // our thanks go to the authors of Kate. } else if(reason == KTextEditor::ModificationInterface::OnDiskModified || reason == KTextEditor::ModificationInterface::OnDiskCreated) { //dirty file icon = QIcon::fromTheme("modonhd"); // This icon is taken from Kate. Therefore // our thanks go to the authors of Kate. } else if(reason == KTextEditor::ModificationInterface::OnDiskDeleted) { //file deleted icon = QIcon::fromTheme("process-stop"); } else if(m_ki->extensions()->isScriptFile(doc->url())) { icon = QIcon::fromTheme("js"); } else { icon = QIcon::fromTheme(KIO::iconNameForUrl(doc->url())); } const QList &viewsList = doc->views(); for(QList::const_iterator i = viewsList.begin(); i != viewsList.end(); ++i) { setTabIcon(*i, icon); } } /** * Adds/removes the "Convert to LaTeX" entry in Kate's popup menu according to the selection. */ void Manager::onTextEditorPopupMenuRequest() { KTextEditor::View *view = currentTextView(); if(!view) { return; } const QString quickPreviewSelection = i18n("&QuickPreview Selection"); const QString quickPreviewEnvironment = i18n("&QuickPreview Environment"); const QString quickPreviewMath = i18n("&QuickPreview Math"); // Setting up the "QuickPreview selection" entry if(view->selection()) { m_quickPreviewAction->setText(quickPreviewSelection); m_quickPreviewAction->setEnabled(true); } else if(m_ki->editorExtension()->hasMathgroup(view)) { m_quickPreviewAction->setText(quickPreviewMath); m_quickPreviewAction->setEnabled(true); } else if(m_ki->editorExtension()->hasEnvironment(view)) { m_quickPreviewAction->setText(quickPreviewEnvironment); m_quickPreviewAction->setEnabled(true); } else { m_quickPreviewAction->setText(quickPreviewSelection); m_quickPreviewAction->setEnabled(false); } // Setting up the "Convert to LaTeX" entry m_convertToLaTeXAction->setEnabled(view->selection()); // Setting up the "Paste as LaTeX" entry QClipboard *clipboard = QApplication::clipboard(); if(clipboard) { m_pasteAsLaTeXAction->setEnabled(!clipboard->text().isEmpty()); } } void Manager::convertSelectionToLaTeX(void) { KTextEditor::View *view = currentTextView(); if(view == Q_NULLPTR) { return; } KTextEditor::Document *doc = view->document(); if(doc == Q_NULLPTR) { return; } // Getting the selection KTextEditor::Range range = view->selectionRange(); uint selStartLine = range.start().line(), selStartCol = range.start().column(); uint selEndLine = range.end().line(), selEndCol = range.start().column(); /* Variable to "restore" the selection after replacement: if {} was selected, we increase the selection of two characters */ uint newSelEndCol; PlainToLaTeXConverter cvt; // "Notifying" the editor that what we're about to do must be seen as ONE operation KTextEditor::Document::EditingTransaction transaction(doc); // Processing the first line int firstLineLength; if(selStartLine != selEndLine) { firstLineLength = doc->lineLength(selStartLine); } else { firstLineLength = selEndCol; } QString firstLine = doc->text(KTextEditor::Range(selStartLine, selStartCol, selStartLine, firstLineLength)); QString firstLineCvt = cvt.ConvertToLaTeX(firstLine); doc->removeText(KTextEditor::Range(selStartLine, selStartCol, selStartLine, firstLineLength)); doc->insertText(KTextEditor::Cursor(selStartLine, selStartCol), firstLineCvt); newSelEndCol = selStartCol + firstLineCvt.length(); // Processing the intermediate lines for(uint nLine = selStartLine + 1; nLine < selEndLine; ++nLine) { QString line = doc->line(nLine); QString newLine = cvt.ConvertToLaTeX(line); doc->removeLine(nLine); doc->insertLine(nLine, newLine); } // Processing the final line if(selStartLine != selEndLine) { QString lastLine = doc->text(KTextEditor::Range(selEndLine, 0, selEndLine, selEndCol)); QString lastLineCvt = cvt.ConvertToLaTeX(lastLine); doc->removeText(KTextEditor::Range(selEndLine, 0, selEndLine, selEndCol)); doc->insertText(KTextEditor::Cursor(selEndLine, 0), lastLineCvt); newSelEndCol = lastLineCvt.length(); } // End of the "atomic edit operation" transaction.finish(); view->setSelection(KTextEditor::Range(selStartLine, selStartCol, selEndLine, newSelEndCol)); } /** * Pastes the clipboard's contents as LaTeX (ie. % -> \%, etc.). */ void Manager::pasteAsLaTeX(void) { KTextEditor::View *view = currentTextView(); if(!view) { return; } KTextEditor::Document *doc = view->document(); if(!doc) { return; } // Getting a proper text insertion point BEFORE the atomic editing operation uint cursorLine, cursorCol; if(view->selection()) { KTextEditor::Range range = view->selectionRange(); cursorLine = range.start().line(); cursorCol = range.start().column(); } else { KTextEditor::Cursor cursor = view->cursorPosition(); cursorLine = cursor.line(); cursorCol = cursor.column(); } // "Notifying" the editor that what we're about to do must be seen as ONE operation KTextEditor::Document::EditingTransaction transaction(doc); // If there is a selection, one must remove it if(view->selection()) { doc->removeText(view->selectionRange()); } PlainToLaTeXConverter cvt; QString toPaste = cvt.ConvertToLaTeX(QApplication::clipboard()->text()); doc->insertText(KTextEditor::Cursor(cursorLine, cursorCol), toPaste); // End of the "atomic edit operation" transaction.finish(); } void Manager::quickPreviewPopup() { KTextEditor::View *view = currentTextView(); if(!view) { return; } if(view->selection()) { emit(startQuickPreview(KileTool::qpSelection)); } else if(m_ki->editorExtension()->hasMathgroup(view)) { emit(startQuickPreview(KileTool::qpMathgroup)); } else if(m_ki->editorExtension()->hasEnvironment(view)) { emit(startQuickPreview(KileTool::qpEnvironment)); } } void Manager::testCanDecodeURLs(const QDragEnterEvent *e, bool &accept) { accept = e->mimeData()->hasUrls(); // only accept URL drops } void Manager::testCanDecodeURLs(const QDragMoveEvent *e, bool &accept) { accept = e->mimeData()->hasUrls(); // only accept URL drops } void Manager::replaceLoadedURL(QWidget *w, QDropEvent *e) { QList urls = e->mimeData()->urls(); if(urls.isEmpty()) { return; } int index = tabIndexOf(qobject_cast(w)); KileDocument::Extensions *extensions = m_ki->extensions(); bool hasReplacedTab = false; for(QList::iterator i = urls.begin(); i != urls.end(); ++i) { QUrl url = *i; if(extensions->isProjectFile(url)) { m_ki->docManager()->projectOpen(url); } else if(!hasReplacedTab) { closeTab(index); m_ki->docManager()->fileOpen(url, QString(), index); hasReplacedTab = true; } else { m_ki->docManager()->fileOpen(url); } } } void Manager::updateTabTexts(KTextEditor::Document *changedDoc) { const QList &viewsList = changedDoc->views(); for(QList::const_iterator i = viewsList.begin(); i != viewsList.end(); ++i) { QString documentName = changedDoc->documentName(); if(documentName.isEmpty()) { documentName = i18n("Untitled"); } const int viewIndex = tabIndexOf(*i); m_tabBar->setTabText(viewIndex, documentName); m_tabBar->setTabToolTip(viewIndex, changedDoc->url().toString()); } } DropWidget::DropWidget(QWidget *parent, const char *name, Qt::WindowFlags f) : QWidget(parent, f) { setObjectName(name); setAcceptDrops(true); } DropWidget::~DropWidget() { } void DropWidget::dragEnterEvent(QDragEnterEvent *e) { bool b; emit testCanDecode(e, b); if(b) { e->acceptProposedAction(); } } void DropWidget::dropEvent(QDropEvent *e) { emit receivedDropEvent(e); } void DropWidget::mouseDoubleClickEvent(QMouseEvent *e) { Q_UNUSED(e); emit mouseDoubleClick(); } void Manager::installEventFilter(KTextEditor::View *view, QObject *eventFilter) { QWidget *focusProxy = view->focusProxy(); if(focusProxy) { focusProxy->installEventFilter(eventFilter); } else { view->installEventFilter(eventFilter); } } void Manager::removeEventFilter(KTextEditor::View *view, QObject *eventFilter) { QWidget *focusProxy = view->focusProxy(); if(focusProxy) { focusProxy->removeEventFilter(eventFilter); } else { view->removeEventFilter(eventFilter); } } //BEGIN ViewerPart methods void Manager::createViewerPart(KActionCollection *actionCollection) { m_viewerPart = Q_NULLPTR; KPluginLoader pluginLoader(OKULAR_LIBRARY_NAME); KPluginFactory *factory = pluginLoader.factory(); if(!factory) { KILE_DEBUG_MAIN << "Could not find the Okular library."; m_viewerPart = Q_NULLPTR; return; } else { QVariantList argList; argList << "ViewerWidget" << "ConfigFileName=kile-livepreview-okularpartrc"; m_viewerPart = factory->create(this, argList); Okular::ViewerInterface *viewerInterface = dynamic_cast(m_viewerPart.data()); if(!viewerInterface) { // OkularPart doesn't provide the ViewerInterface delete m_viewerPart; m_viewerPart = Q_NULLPTR; return; } viewerInterface->setWatchFileModeEnabled(false); viewerInterface->setShowSourceLocationsGraphically(true); connect(m_viewerPart, SIGNAL(openSourceReference(const QString&, int, int)), this, SLOT(handleActivatedSourceReference(const QString&, int, int))); QAction *paPrintCompiledDocument = actionCollection->addAction(KStandardAction::Print, "print_compiled_document", m_viewerPart, SLOT(slotPrint())); paPrintCompiledDocument->setText(i18n("Print Compiled Document...")); paPrintCompiledDocument->setShortcut(QKeySequence()); paPrintCompiledDocument->setEnabled(false); connect(m_viewerPart, SIGNAL(enablePrintAction(bool)), paPrintCompiledDocument, SLOT(setEnabled(bool))); QAction *printPreviewAction = m_viewerPart->actionCollection()->action("file_print_preview"); if(printPreviewAction) { printPreviewAction->setText(i18n("Print Preview For Compiled Document...")); } } } void Manager::setupViewerPart(QSplitter *splitter) { if(!m_viewerPart) { return; } if(KileConfig::showDocumentViewerInExternalWindow()) { if(m_viewerPartWindow && m_viewerPart->widget()->window() == m_viewerPartWindow) { // nothing to be done return; } m_viewerPartWindow = new DocumentViewerWindow(); m_viewerPartWindow->setObjectName("KileDocumentViewerWindow"); m_viewerPartWindow->setCentralWidget(m_viewerPart->widget()); m_viewerPartWindow->setAttribute(Qt::WA_DeleteOnClose, false); m_viewerPartWindow->setAttribute(Qt::WA_QuitOnClose, false); connect(m_viewerPartWindow, &KileView::DocumentViewerWindow::visibilityChanged, this, &Manager::documentViewerWindowVisibilityChanged); m_viewerPartWindow->setWindowTitle(i18n("Document Viewer")); m_viewerPartWindow->applyMainWindowSettings(KSharedConfig::openConfig()->group("KileDocumentViewerWindow")); } else { if(m_viewerPart->widget()->parent() && m_viewerPart->widget()->parent() != m_viewerPartWindow) { // nothing to be done return; } splitter->addWidget(m_viewerPart->widget()); // remove it from the window first! destroyDocumentViewerWindow(); } } void Manager::destroyDocumentViewerWindow() { if(!m_viewerPartWindow) { return; } KConfigGroup group(KSharedConfig::openConfig(), "KileDocumentViewerWindow"); m_viewerPartWindow->saveMainWindowSettings(group); // we don't want it to influence the document viewer visibility setting as // this is a forced close disconnect(m_viewerPartWindow, &KileView::DocumentViewerWindow::visibilityChanged, this, &Manager::documentViewerWindowVisibilityChanged); m_viewerPartWindow->hide(); delete m_viewerPartWindow; m_viewerPartWindow = Q_NULLPTR; } void Manager::handleActivatedSourceReference(const QString& absFileName, int line, int col) { KILE_DEBUG_MAIN << "absFileName:" << absFileName << "line:" << line << "column:" << col; QFileInfo fileInfo(absFileName); if(!fileInfo.isFile() || !fileInfo.isReadable()) { qWarning() << "Got passed an unreadable file:" << absFileName; return; } KileDocument::TextInfo *textInfo = m_ki->docManager()->textInfoFor(absFileName); // check whether the file or the project item associated with 'absFileName' is already open if(!textInfo || !m_ki->isOpen(absFileName)) { m_ki->docManager()->fileOpen(absFileName); textInfo = m_ki->docManager()->textInfoFor(absFileName); } if(!textInfo) { KILE_DEBUG_MAIN << "no document found!"; return; } KTextEditor::View *view = textView(textInfo); if(!view) { KILE_DEBUG_MAIN << "no view found!"; return; } view->setCursorPosition(KTextEditor::Cursor(line, col)); switchToTextView(view, true); } void Manager::showCursorPositionInDocumentViewer() { if(m_ki->livePreviewManager()->isLivePreviewEnabledForCurrentDocument()) { m_ki->livePreviewManager()->showCursorPositionInDocumentViewer(); } } void Manager::synchronizeViewWithCursorActionToggled(bool checked) { m_showCursorPositionInViewerAction->setEnabled(!checked); if(checked) { showCursorPositionInDocumentViewer(); } } void Manager::setDocumentViewerVisible(bool b) { if(!m_viewerPart) { return; } KileConfig::setShowDocumentViewer(b); if(m_viewerPartWindow) { m_viewerPartWindow->setVisible(b); } m_viewerPart->widget()->setVisible(b); } bool Manager::isViewerPartShown() const { if(!m_viewerPart) { return false; } if(m_viewerPartWindow) { return !m_viewerPartWindow->isHidden(); } else { return !m_viewerPart->widget()->isHidden(); } } bool Manager::openInDocumentViewer(const QUrl &url) { Okular::ViewerInterface *v = dynamic_cast(m_viewerPart.data()); if(!v) { return false; } bool r = m_viewerPart->openUrl(url); v->clearLastShownSourceLocation(); return r; } void Manager::clearLastShownSourceLocationInDocumentViewer() { Okular::ViewerInterface *v = dynamic_cast(m_viewerPart.data()); if(v) { v->clearLastShownSourceLocation(); } } void Manager::showSourceLocationInDocumentViewer(const QString& fileName, int line, int column) { Okular::ViewerInterface *v = dynamic_cast(m_viewerPart.data()); if(v) { m_clearLastShownSourceLocationTimer->stop(); v->showSourceLocation(fileName, line, column, true); m_clearLastShownSourceLocationTimer->start(); } } void Manager::setLivePreviewModeForDocumentViewer(bool b) { Okular::ViewerInterface *viewerInterface = dynamic_cast(m_viewerPart.data()); if(viewerInterface) { if(b) { viewerInterface->setWatchFileModeEnabled(false); } else { viewerInterface->setWatchFileModeEnabled(KileConfig::watchFileForDocumentViewer()); } } } KToolBar* Manager::getViewerControlToolBar() { return m_viewerControlToolBar; } bool Manager::isSynchronisingCursorWithDocumentViewer() const { return m_synchronizeViewWithCursorAction->isChecked(); } //END ViewerPart methods bool Manager::viewForLocalFilePresent(const QString& localFileName) { for(int i = 0; i < m_tabBar->count(); ++i) { KTextEditor::View *view = textViewAtTab(i); if(!view) { continue; } if(view->document()->url().toLocalFile() == localFileName) { return true; } } return false; } } void focusTextView(KTextEditor::View *view) { // we work around a potential Qt bug here which can result in dead keys // being treated as 'alive' keys in some circumstances, probably when 'setFocus' // is called when the widget hasn't been shown yet (see bug 269590) QTimer::singleShot(0, view, SLOT(setFocus())); }