diff --git a/kate/kateconfigdialog.cpp b/kate/kateconfigdialog.cpp index bfbc9bb40..527726510 100644 --- a/kate/kateconfigdialog.cpp +++ b/kate/kateconfigdialog.cpp @@ -1,417 +1,437 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 Joseph Wenninger Copyright (C) 2007 Mirko Stocker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kateconfigdialog.h" #include "ui_sessionconfigwidget.h" #include "katemainwindow.h" #include "katedocmanager.h" #include "katepluginmanager.h" #include "kateconfigplugindialogpage.h" #include "kateviewmanager.h" #include "kateapp.h" #include "katesessionmanager.h" #include "katedebug.h" #include "katequickopenmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include KateConfigDialog::KateConfigDialog(KateMainWindow *parent, KTextEditor::View *view) : KPageDialog(parent) , m_mainWindow(parent) , m_view(view) { setFaceType(Tree); setWindowTitle(i18n("Configure")); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Help); setObjectName(QStringLiteral("configdialog")); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup cgGeneral = KConfigGroup(config, "General"); buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(false); KPageWidgetItem *applicationItem = addPage(new QWidget, i18n("Application")); applicationItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-other"))); applicationItem->setHeader(i18n("Application Options")); applicationItem->setCheckable(false); applicationItem->setEnabled(false); m_applicationPage = applicationItem; //BEGIN General page QFrame *generalFrame = new QFrame; KPageWidgetItem *item = addSubPage(applicationItem, generalFrame, i18n("General")); item->setHeader(i18n("General Options")); item->setIcon(QIcon::fromTheme(QStringLiteral("go-home"))); setCurrentPage(item); QVBoxLayout *layout = new QVBoxLayout(generalFrame); layout->setContentsMargins(0, 0, 0, 0); // GROUP with the one below: "Behavior" QGroupBox *buttonGroup = new QGroupBox(i18n("&Behavior"), generalFrame); QVBoxLayout *vbox = new QVBoxLayout; layout->addWidget(buttonGroup); // modified files notification m_modNotifications = new QCheckBox( i18n("Wa&rn about files modified by foreign processes"), buttonGroup); m_modNotifications->setChecked(parent->modNotificationEnabled()); m_modNotifications->setWhatsThis(i18n( "If enabled, when Kate receives focus you will be asked what to do with " "files that have been modified on the hard disk. If not enabled, you will " "be asked what to do with a file that has been modified on the hard disk only " "when that file is tried to be saved.")); connect(m_modNotifications, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged); vbox->addWidget(m_modNotifications); // Closing last file closes Kate m_modCloseAfterLast = new QCheckBox( i18n("Close Kate entirely when the last file is closed"), buttonGroup); m_modCloseAfterLast->setChecked(parent->modCloseAfterLast()); m_modCloseAfterLast->setWhatsThis(i18n( "If enabled, Kate will shutdown when the last file being edited is closed, " "otherwise a blank page will open so that you can start a new file.")); connect(m_modCloseAfterLast, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged); vbox->addWidget(m_modCloseAfterLast); buttonGroup->setLayout(vbox); // GROUP with the one below: "Meta-information" buttonGroup = new QGroupBox(i18n("Meta-Information"), generalFrame); vbox = new QVBoxLayout; layout->addWidget(buttonGroup); // save meta infos m_saveMetaInfos = new QCheckBox(buttonGroup); m_saveMetaInfos->setText(i18n("Keep &meta-information past sessions")); m_saveMetaInfos->setChecked(KateApp::self()->documentManager()->getSaveMetaInfos()); m_saveMetaInfos->setWhatsThis(i18n( "Check this if you want document configuration like for example " "bookmarks to be saved past editor sessions. The configuration will be " "restored if the document has not changed when reopened.")); connect(m_saveMetaInfos, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged); vbox->addWidget(m_saveMetaInfos); // meta infos days QFrame *metaInfos = new QFrame(buttonGroup); QHBoxLayout *hlayout = new QHBoxLayout(metaInfos); metaInfos->setEnabled(KateApp::self()->documentManager()->getSaveMetaInfos()); QLabel *label = new QLabel(i18n("&Delete unused meta-information after:"), metaInfos); hlayout->addWidget(label); m_daysMetaInfos = new KPluralHandlingSpinBox(metaInfos); m_daysMetaInfos->setMaximum(180); m_daysMetaInfos->setSpecialValueText(i18nc("The special case of 'Delete unused meta-information after'", "(never)")); m_daysMetaInfos->setSuffix(ki18ncp("The suffix of 'Delete unused meta-information after'", " day", " days")); m_daysMetaInfos->setValue(KateApp::self()->documentManager()->getDaysMetaInfos()); hlayout->addWidget(m_daysMetaInfos); label->setBuddy(m_daysMetaInfos); connect(m_saveMetaInfos, &QCheckBox::toggled, metaInfos, &QFrame::setEnabled); connect(m_daysMetaInfos, static_cast(&KPluralHandlingSpinBox::valueChanged), this, &KateConfigDialog::slotChanged); vbox->addWidget(metaInfos); buttonGroup->setLayout(vbox); // quick search buttonGroup = new QGroupBox(i18n("&Quick Open"), generalFrame); - hlayout = new QHBoxLayout(buttonGroup); + vbox = new QVBoxLayout; + buttonGroup->setLayout(vbox); + // quick open match mode + hlayout = new QHBoxLayout; label = new QLabel(i18n("&Match Mode:"), buttonGroup); hlayout->addWidget(label); m_cmbQuickOpenMatchMode = new QComboBox(buttonGroup); hlayout->addWidget(m_cmbQuickOpenMatchMode); label->setBuddy(m_cmbQuickOpenMatchMode); m_cmbQuickOpenMatchMode->addItem(i18n("Filename"), QVariant(KateQuickOpenModel::Columns::FileName)); m_cmbQuickOpenMatchMode->addItem(i18n("Filepath"), QVariant(KateQuickOpenModel::Columns::FilePath)); m_cmbQuickOpenMatchMode->setCurrentIndex(m_cmbQuickOpenMatchMode->findData(m_mainWindow->quickOpenMatchMode())); m_mainWindow->setQuickOpenMatchMode(m_cmbQuickOpenMatchMode->currentData().toInt()); connect(m_cmbQuickOpenMatchMode, static_cast(&QComboBox::currentIndexChanged), this, &KateConfigDialog::slotChanged); + vbox->addLayout(hlayout); + // quick open list mode + hlayout = new QHBoxLayout; + label = new QLabel(i18n("&List Mode:"), buttonGroup); + hlayout->addWidget(label); + m_cmbQuickOpenListMode = new QComboBox(buttonGroup); + hlayout->addWidget(m_cmbQuickOpenListMode); + label->setBuddy(m_cmbQuickOpenListMode); + m_cmbQuickOpenListMode->addItem(i18n("Current Project Files"), QVariant(KateQuickOpenModel::List::CurrentProject)); + m_cmbQuickOpenListMode->addItem(i18n("All Projects Files"), QVariant(KateQuickOpenModel::List::AllProjects)); + m_cmbQuickOpenListMode->setCurrentIndex(m_cmbQuickOpenListMode->findData(m_mainWindow->quickOpenListMode())); + m_mainWindow->setQuickOpenListMode(m_cmbQuickOpenListMode->currentData().toInt()); + connect(m_cmbQuickOpenListMode, static_cast(&QComboBox::currentIndexChanged), this, &KateConfigDialog::slotChanged); + vbox->addLayout(hlayout); layout->addWidget(buttonGroup); layout->addStretch(1); // :-] works correct without autoadd //END General page //BEGIN Session page QWidget *sessionsPage = new QWidget(); item = addSubPage(applicationItem, sessionsPage, i18n("Sessions")); item->setHeader(i18n("Session Management")); item->setIcon(QIcon::fromTheme(QStringLiteral("view-history"))); sessionConfigUi = new Ui::SessionConfigWidget(); sessionConfigUi->setupUi(sessionsPage); // restore view config sessionConfigUi->restoreVC->setChecked( cgGeneral.readEntry("Restore Window Configuration", true) ); connect(sessionConfigUi->restoreVC, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged); sessionConfigUi->spinBoxRecentFilesCount->setValue(recentFilesMaxCount()); connect(sessionConfigUi->spinBoxRecentFilesCount, static_cast(&QSpinBox::valueChanged), this, &KateConfigDialog::slotChanged); QString sesStart (cgGeneral.readEntry ("Startup Session", "manual")); if (sesStart == QStringLiteral("new")) sessionConfigUi->startNewSessionRadioButton->setChecked (true); else if (sesStart == QStringLiteral("last")) sessionConfigUi->loadLastUserSessionRadioButton->setChecked (true); else sessionConfigUi->manuallyChooseSessionRadioButton->setChecked (true); connect(sessionConfigUi->startNewSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged); connect(sessionConfigUi->loadLastUserSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged); connect(sessionConfigUi->manuallyChooseSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged); //END Session page //BEGIN Plugins page QFrame *page = new QFrame(this); QVBoxLayout *vlayout = new QVBoxLayout(page); vlayout->setContentsMargins(0, 0, 0, 0); vlayout->setSpacing(0); KateConfigPluginPage *configPluginPage = new KateConfigPluginPage(page, this); vlayout->addWidget(configPluginPage); connect(configPluginPage, &KateConfigPluginPage::changed, this, &KateConfigDialog::slotChanged); item = addSubPage(applicationItem, page, i18n("Plugins")); item->setHeader(i18n("Plugin Manager")); item->setIcon(QIcon::fromTheme(QStringLiteral("preferences-plugin"))); KatePluginList &pluginList(KateApp::self()->pluginManager()->pluginList()); foreach(const KatePluginInfo & plugin, pluginList) { if (plugin.load) { addPluginPage(plugin.plugin); } } //END Plugins page // editor widgets from kwrite/kwdialog m_editorPage = addPage(new QWidget, i18n("Editor Component")); m_editorPage->setIcon(QIcon::fromTheme(QStringLiteral("accessories-text-editor"))); m_editorPage->setHeader(i18n("Editor Component Options")); m_editorPage->setCheckable(false); m_editorPage->setEnabled(false); addEditorPages(); connect(this, &KateConfigDialog::accepted, this, &KateConfigDialog::slotApply); connect(buttonBox()->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &KateConfigDialog::slotApply); connect(buttonBox()->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &KateConfigDialog::slotHelp); connect(this, &KateConfigDialog::currentPageChanged, this, &KateConfigDialog::slotCurrentPageChanged); m_dataChanged = false; resize(minimumSizeHint()); } KateConfigDialog::~KateConfigDialog() { delete sessionConfigUi; } void KateConfigDialog::addEditorPages() { for (int i = 0; i < KTextEditor::Editor::instance()->configPages(); ++i) { KTextEditor::ConfigPage *page = KTextEditor::Editor::instance()->configPage(i, this); connect(page, &KTextEditor::ConfigPage::changed, this, &KateConfigDialog::slotChanged); m_editorPages.push_back(page); KPageWidgetItem *item = addSubPage(m_editorPage, page, page->name()); item->setHeader(page->fullName()); item->setIcon(page->icon()); } } void KateConfigDialog::addPluginPage(KTextEditor::Plugin *plugin) { for (int i = 0; i < plugin->configPages(); i++) { QFrame *page = new QFrame(); QVBoxLayout *layout = new QVBoxLayout(page); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); KTextEditor::ConfigPage *cp = plugin->configPage(i, page); page->layout()->addWidget(cp); KPageWidgetItem *item = addSubPage(m_applicationPage, page, cp->name()); item->setHeader(cp->fullName()); item->setIcon(cp->icon()); PluginPageListItem *info = new PluginPageListItem; info->plugin = plugin; info->pageParent = page; info->pluginPage = cp; info->idInPlugin = i; info->pageWidgetItem = item; connect(info->pluginPage, &KTextEditor::ConfigPage::changed, this, &KateConfigDialog::slotChanged); m_pluginPages.insert(item, info); } } void KateConfigDialog::slotCurrentPageChanged(KPageWidgetItem *current, KPageWidgetItem * /*before*/) { PluginPageListItem *info = m_pluginPages[current]; if (!info) { return; } if (info->pluginPage) { return; } qCDebug(LOG_KATE) << "creating config page (should not get here)"; info->pluginPage = info->plugin->configPage(info->idInPlugin, info->pageParent); info->pageParent->layout()->addWidget(info->pluginPage); info->pluginPage->show(); connect(info->pluginPage, &KTextEditor::ConfigPage::changed, this, &KateConfigDialog::slotChanged); } void KateConfigDialog::removePluginPage(KTextEditor::Plugin *plugin) { QList remove; for (QHash::const_iterator it = m_pluginPages.constBegin(); it != m_pluginPages.constEnd(); ++it) { PluginPageListItem *pli = it.value(); if (!pli) { continue; } if (pli->plugin == plugin) { remove.append(it.key()); } } qCDebug(LOG_KATE) << remove.count(); while (!remove.isEmpty()) { KPageWidgetItem *wItem = remove.takeLast(); PluginPageListItem *pItem = m_pluginPages.take(wItem); delete pItem->pluginPage; delete pItem->pageParent; removePage(wItem); delete pItem; } } void KateConfigDialog::slotApply() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); // if data changed apply the kate app stuff if (m_dataChanged) { KConfigGroup cg = KConfigGroup(config, "General"); cg.writeEntry("Restore Window Configuration", sessionConfigUi->restoreVC->isChecked()); cg.writeEntry("Recent File List Entry Count", sessionConfigUi->spinBoxRecentFilesCount->value()); if (sessionConfigUi->startNewSessionRadioButton->isChecked()) { cg.writeEntry("Startup Session", "new"); } else if (sessionConfigUi->loadLastUserSessionRadioButton->isChecked()) { cg.writeEntry("Startup Session", "last"); } else { cg.writeEntry("Startup Session", "manual"); } cg.writeEntry("Save Meta Infos", m_saveMetaInfos->isChecked()); KateApp::self()->documentManager()->setSaveMetaInfos(m_saveMetaInfos->isChecked()); cg.writeEntry("Days Meta Infos", m_daysMetaInfos->value()); KateApp::self()->documentManager()->setDaysMetaInfos(m_daysMetaInfos->value()); cg.writeEntry("Modified Notification", m_modNotifications->isChecked()); m_mainWindow->setModNotificationEnabled(m_modNotifications->isChecked()); cg.writeEntry("Close After Last", m_modCloseAfterLast->isChecked()); m_mainWindow->setModCloseAfterLast(m_modCloseAfterLast->isChecked()); cg.writeEntry("Quick Open Search Mode", m_cmbQuickOpenMatchMode->currentData().toInt()); m_mainWindow->setQuickOpenMatchMode(m_cmbQuickOpenMatchMode->currentData().toInt()); + cg.writeEntry("Quick Open List Mode", m_cmbQuickOpenListMode->currentData().toInt()); + m_mainWindow->setQuickOpenListMode(m_cmbQuickOpenListMode->currentData().toInt()); + // patch document modified warn state const QList &docs = KateApp::self()->documentManager()->documentList(); foreach(KTextEditor::Document * doc, docs) if (qobject_cast(doc)) { qobject_cast(doc)->setModifiedOnDiskWarning(!m_modNotifications->isChecked()); } m_mainWindow->saveOptions(); // save plugin config !! KateSessionManager *sessionmanager = KateApp::self()->sessionManager(); KConfig *sessionConfig = sessionmanager->activeSession()->config(); KateApp::self()->pluginManager()->writeConfig(sessionConfig); } foreach(PluginPageListItem * plugin, m_pluginPages) { if (!plugin) { continue; } if (plugin->pluginPage) { plugin->pluginPage->apply(); } } // apply ktexteditor pages foreach(KTextEditor::ConfigPage * page, m_editorPages) page->apply(); config->sync(); m_dataChanged = false; buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(false); } void KateConfigDialog::slotChanged() { m_dataChanged = true; buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(true); } void KateConfigDialog::showAppPluginPage(KTextEditor::Plugin *p, uint id) { foreach(PluginPageListItem * plugin, m_pluginPages) { if ((plugin->plugin == p) && (id == plugin->idInPlugin)) { setCurrentPage(plugin->pageWidgetItem); break; } } } void KateConfigDialog::slotHelp() { QDesktopServices::openUrl(QUrl(QStringLiteral("help:/"))); } int KateConfigDialog::recentFilesMaxCount() { int maxItems = KConfigGroup(KSharedConfig::openConfig(), "General").readEntry("Recent File List Entry Count", 10); return maxItems; } diff --git a/kate/kateconfigdialog.h b/kate/kateconfigdialog.h index 990d71ed8..738021d58 100644 --- a/kate/kateconfigdialog.h +++ b/kate/kateconfigdialog.h @@ -1,101 +1,102 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 Joseph Wenninger Copyright (C) 2007 Mirko Stocker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __kate_configdialog_h__ #define __kate_configdialog_h__ #include #include #include #include #include #include class QCheckBox; class QComboBox; class QSpinBox; class KateMainWindow; class KPluralHandlingSpinBox; namespace Ui { class SessionConfigWidget; } struct PluginPageListItem { KTextEditor::Plugin *plugin; uint idInPlugin; KTextEditor::ConfigPage *pluginPage; QWidget *pageParent; KPageWidgetItem *pageWidgetItem; }; class KateConfigDialog : public KPageDialog { Q_OBJECT public: KateConfigDialog(KateMainWindow *parent, KTextEditor::View *view); ~KateConfigDialog() override; public: // static /** * Reads the value from the given open config. If not present in config yet then * the default value 10 is used. */ static int recentFilesMaxCount(); public: void addPluginPage(KTextEditor::Plugin *plugin); void removePluginPage(KTextEditor::Plugin *plugin); void showAppPluginPage(KTextEditor::Plugin *plugin, uint id); protected Q_SLOTS: void slotApply(); void slotChanged(); void slotHelp(); void slotCurrentPageChanged(KPageWidgetItem *current, KPageWidgetItem *before); private: KateMainWindow *m_mainWindow; KTextEditor::View *m_view; bool m_dataChanged; QCheckBox *m_modNotifications; QCheckBox *m_modCloseAfterLast; QCheckBox *m_saveMetaInfos; KPluralHandlingSpinBox *m_daysMetaInfos; QComboBox * m_cmbQuickOpenMatchMode; + QComboBox * m_cmbQuickOpenListMode; // Sessions Page Ui::SessionConfigWidget *sessionConfigUi; QHash m_pluginPages; QList m_editorPages; KPageWidgetItem *m_applicationPage; KPageWidgetItem *m_editorPage; void addEditorPages(); }; #endif diff --git a/kate/katemainwindow.cpp b/kate/katemainwindow.cpp index 1e9fbd492..fe785631f 100644 --- a/kate/katemainwindow.cpp +++ b/kate/katemainwindow.cpp @@ -1,1285 +1,1296 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 Anders Lund Copyright (C) 2007 Flavio Castelli This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //BEGIN Includes #include "katemainwindow.h" #include "kateconfigdialog.h" #include "katedocmanager.h" #include "katepluginmanager.h" #include "kateconfigplugindialogpage.h" #include "kateviewmanager.h" #include "kateapp.h" #include "katesavemodifieddialog.h" #include "katemwmodonhddialog.h" #include "katesessionsaction.h" #include "katesessionmanager.h" #include "kateviewspace.h" #include "katequickopen.h" #include "kateupdatedisabler.h" #include "katedebug.h" #include "katecolorschemechooser.h" #include "katefileactions.h" #include "katequickopenmodel.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 #include #include #include #include #include #include #include #include #include //END KateMwModOnHdDialog *KateMainWindow::s_modOnHdDialog = nullptr; KateContainerStackedLayout::KateContainerStackedLayout(QWidget *parent) : QStackedLayout(parent) {} QSize KateContainerStackedLayout::sizeHint() const { if (currentWidget()) { return currentWidget()->sizeHint(); } return QStackedLayout::sizeHint(); } QSize KateContainerStackedLayout::minimumSize() const { if (currentWidget()) { return currentWidget()->minimumSize(); } return QStackedLayout::minimumSize(); } KateMainWindow::KateMainWindow(KConfig *sconfig, const QString &sgroup) : KateMDI::MainWindow(nullptr) , m_modignore(false) , m_wrapper(new KTextEditor::MainWindow(this)) { /** * we don't want any flicker here */ KateUpdateDisabler disableUpdates (this); /** * get and set config revision */ static const int currentConfigRevision = 10; const int readConfigRevision = KConfigGroup(KSharedConfig::openConfig(), "General").readEntry("Config Revision", 0); KConfigGroup(KSharedConfig::openConfig(), "General").writeEntry("Config Revision", currentConfigRevision); const bool firstStart = readConfigRevision < currentConfigRevision; // start session restore if needed startRestore(sconfig, sgroup); // setup most important actions first, needed by setupMainWindow setupImportantActions(); // setup the most important widgets setupMainWindow(); // setup the actions setupActions(); setStandardToolBarMenuEnabled(true); setXMLFile(QStringLiteral("kateui.rc")); createShellGUI(true); //qCDebug(LOG_KATE) << "****************************************************************************" << sconfig; // register mainwindow in app KateApp::self()->addMainWindow(this); // enable plugin guis KateApp::self()->pluginManager()->enableAllPluginsGUI(this, sconfig); // caption update Q_FOREACH (auto doc, KateApp::self()->documentManager()->documentList()) { slotDocumentCreated(doc); } connect(KateApp::self()->documentManager(), &KateDocManager::documentCreated, this, &KateMainWindow::slotDocumentCreated); readOptions(); if (sconfig) { m_viewManager->restoreViewConfiguration(KConfigGroup(sconfig, sgroup)); } finishRestore(); m_fileOpenRecent->loadEntries(KConfigGroup(sconfig, "Recent Files")); setAcceptDrops(true); connect(KateApp::self()->sessionManager(), SIGNAL(sessionChanged()), this, SLOT(updateCaption())); connect(this, &KateMDI::MainWindow::sigShowPluginConfigPage, this, &KateMainWindow::showPluginConfigPage); // prior to this there was (possibly) no view, therefore not context menu. // Hence, we have to take care of the menu bar here toggleShowMenuBar(false); // on first start: deactivate toolbar if (firstStart) toolBar(QStringLiteral("mainToolBar"))->hide(); // pass focus to first view! if (m_viewManager->activeView()) m_viewManager->activeView()->setFocus(); } KateMainWindow::~KateMainWindow() { // first, save our fallback window size ;) KConfigGroup cfg(KSharedConfig::openConfig(), "MainWindow"); KWindowConfig::saveWindowSize(windowHandle(), cfg); // save other options ;=) saveOptions(); // unregister mainwindow in app KateApp::self()->removeMainWindow(this); // disable all plugin guis, delete all pluginViews KateApp::self()->pluginManager()->disableAllPluginsGUI(this); // manually delete quick open, it's event filters will cause crash otherwise later delete m_quickOpen; m_quickOpen = nullptr; // delete the view manager, before KateMainWindow's wrapper is dead delete m_viewManager; m_viewManager = nullptr; // kill the wrapper object, now that all views are dead delete m_wrapper; m_wrapper = nullptr; } QSize KateMainWindow::sizeHint() const { /** * have some useful size hint, else we have mini windows per default */ return (QSize(640, 480).expandedTo(minimumSizeHint())); } void KateMainWindow::setupImportantActions() { m_paShowStatusBar = KStandardAction::showStatusbar(this, SLOT(toggleShowStatusBar()), actionCollection()); m_paShowStatusBar->setWhatsThis(i18n("Use this command to show or hide the view's statusbar")); m_paShowMenuBar = KStandardAction::showMenubar(this, SLOT(toggleShowMenuBar()), actionCollection()); m_paShowTabBar = new KToggleAction(i18n("Show &Tabs"), this); actionCollection()->addAction(QStringLiteral("settings_show_tab_bar"), m_paShowTabBar); connect(m_paShowTabBar, &QAction::toggled, this, &KateMainWindow::toggleShowTabBar); m_paShowTabBar->setWhatsThis(i18n("Use this command to show or hide the tabs for the views")); m_paShowPath = new KToggleAction(i18n("Sho&w Path in Titlebar"), this); actionCollection()->addAction(QStringLiteral("settings_show_full_path"), m_paShowPath); connect(m_paShowPath, SIGNAL(toggled(bool)), this, SLOT(updateCaption())); m_paShowPath->setWhatsThis(i18n("Show the complete document path in the window caption")); // Load themes actionCollection()->addAction(QStringLiteral("colorscheme_menu"), new KateColorSchemeChooser(actionCollection())); QAction * a = actionCollection()->addAction(KStandardAction::Back, QStringLiteral("view_prev_tab")); a->setText(i18n("&Previous Tab")); a->setWhatsThis(i18n("Focus the previous tab.")); actionCollection()->setDefaultShortcuts(a, a->shortcuts() << KStandardShortcut::tabPrev()); connect(a, &QAction::triggered, this, &KateMainWindow::slotFocusPrevTab); a = actionCollection()->addAction(KStandardAction::Forward, QStringLiteral("view_next_tab")); a->setText(i18n("&Next Tab")); a->setWhatsThis(i18n("Focus the next tab.")); actionCollection()->setDefaultShortcuts(a, a->shortcuts() << KStandardShortcut::tabNext()); connect(a, &QAction::triggered, this, &KateMainWindow::slotFocusNextTab); // the quick open action is used by the KateViewSpace "quick open button" a = actionCollection()->addAction(QStringLiteral("view_quick_open")); a->setIcon(QIcon::fromTheme(QStringLiteral("quickopen"))); a->setText(i18n("&Quick Open")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_O)); connect(a, &QAction::triggered, this, &KateMainWindow::slotQuickOpen); a->setWhatsThis(i18n("Open a form to quick open documents.")); } void KateMainWindow::setupMainWindow() { setToolViewStyle(KMultiTabBar::KDEV3ICON); /** * create central stacked widget with its children */ m_mainStackedWidget = new QStackedWidget(centralWidget()); centralWidget()->layout()->addWidget(m_mainStackedWidget); (static_cast(centralWidget()->layout()))->setStretchFactor(m_mainStackedWidget, 100); m_quickOpen = new KateQuickOpen(m_mainStackedWidget, this); m_mainStackedWidget->addWidget(m_quickOpen); m_viewManager = new KateViewManager(m_mainStackedWidget, this); m_mainStackedWidget->addWidget(m_viewManager); // make view manager default visible! m_mainStackedWidget->setCurrentWidget(m_viewManager); m_bottomViewBarContainer = new QWidget(centralWidget()); centralWidget()->layout()->addWidget(m_bottomViewBarContainer); m_bottomContainerStack = new KateContainerStackedLayout(m_bottomViewBarContainer); } void KateMainWindow::setupActions() { QAction *a; actionCollection()->addAction(KStandardAction::New, QStringLiteral("file_new"), m_viewManager, SLOT(slotDocumentNew())) ->setWhatsThis(i18n("Create a new document")); actionCollection()->addAction(KStandardAction::Open, QStringLiteral("file_open"), m_viewManager, SLOT(slotDocumentOpen())) ->setWhatsThis(i18n("Open an existing document for editing")); m_fileOpenRecent = KStandardAction::openRecent(m_viewManager, SLOT(openUrl(QUrl)), this); m_fileOpenRecent->setMaxItems(KateConfigDialog::recentFilesMaxCount()); actionCollection()->addAction(m_fileOpenRecent->objectName(), m_fileOpenRecent); m_fileOpenRecent->setWhatsThis(i18n("This lists files which you have opened recently, and allows you to easily open them again.")); a = actionCollection()->addAction(QStringLiteral("file_save_all")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-save-all"))); a->setText(i18n("Save A&ll")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::Key_L)); connect(a, &QAction::triggered, KateApp::self()->documentManager(), &KateDocManager::saveAll); a->setWhatsThis(i18n("Save all open, modified documents to disk.")); a = actionCollection()->addAction(QStringLiteral("file_reload_all")); a->setText(i18n("&Reload All")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), &KateDocManager::reloadAll); a->setWhatsThis(i18n("Reload all open documents.")); a = actionCollection()->addAction(QStringLiteral("file_copy_filepath")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); a->setText(i18n("Copy File &Path")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::copyFilePathToClipboard(view->document()); }); a->setWhatsThis(i18n("Copies the file path of the current file to clipboard.")); a = actionCollection()->addAction(QStringLiteral("file_open_containing_folder")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-open-folder"))); a->setText(i18n("&Open Containing Folder")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::openContainingFolder(view->document()); }); a->setWhatsThis(i18n("Copies the file path of the current file to clipboard.")); a = actionCollection()->addAction(QStringLiteral("file_rename")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); a->setText(i18nc("@action:inmenu", "Rename...")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::renameDocumentFile(this, view->document()); }); a->setWhatsThis(i18n("Renames the file belonging to the current document.")); a = actionCollection()->addAction(QStringLiteral("file_delete")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); a->setText(i18nc("@action:inmenu", "Delete")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::deleteDocumentFile(this, view->document()); }); a->setWhatsThis(i18n("Deletes the file belonging to the current document.")); a = actionCollection()->addAction(QStringLiteral("file_properties")); a->setIcon(QIcon::fromTheme(QStringLiteral("dialog-object-properties"))); a->setText(i18n("Properties")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::openFilePropertiesDialog(view->document()); }); a->setWhatsThis(i18n("Deletes the file belonging to the current document.")); a = actionCollection()->addAction(QStringLiteral("file_compare")); a->setText(i18n("Compare")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { QMessageBox::information(this, i18n("Compare"), i18n("Use the Tabbar context menu to compare two documents")); }); a->setWhatsThis(i18n("Shows a hint how to compare documents.")); a = actionCollection()->addAction(QStringLiteral("file_close_orphaned")); a->setText(i18n("Close Orphaned")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), &KateDocManager::closeOrphaned); a->setWhatsThis(i18n("Close all documents in the file list that could not be reopened, because they are not accessible anymore.")); a = actionCollection()->addAction(KStandardAction::Close, QStringLiteral("file_close"), m_viewManager, SLOT(slotDocumentClose())); a->setIcon(QIcon::fromTheme(QStringLiteral("document-close"))); a->setWhatsThis(i18n("Close the current document.")); a = actionCollection()->addAction(QStringLiteral("file_close_other")); a->setText(i18n("Close Other")); connect(a, SIGNAL(triggered()), this, SLOT(slotDocumentCloseOther())); a->setWhatsThis(i18n("Close other open documents.")); a = actionCollection()->addAction(QStringLiteral("file_close_all")); a->setText(i18n("Clos&e All")); connect(a, &QAction::triggered, this, &KateMainWindow::slotDocumentCloseAll); a->setWhatsThis(i18n("Close all open documents.")); a = actionCollection()->addAction(KStandardAction::Quit, QStringLiteral("file_quit")); // Qt::QueuedConnection: delay real shutdown, as we are inside menu action handling (bug #185708) connect(a, &QAction::triggered, this, &KateMainWindow::slotFileQuit, Qt::QueuedConnection); a->setWhatsThis(i18n("Close this window")); a = actionCollection()->addAction(QStringLiteral("view_new_view")); a->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); a->setText(i18n("&New Window")); connect(a, &QAction::triggered, this, &KateMainWindow::newWindow); a->setWhatsThis(i18n("Create a new Kate view (a new window with the same document list).")); m_showFullScreenAction = KStandardAction::fullScreen(nullptr, nullptr, this, this); actionCollection()->addAction(m_showFullScreenAction->objectName(), m_showFullScreenAction); connect(m_showFullScreenAction, &QAction::toggled, this, &KateMainWindow::slotFullScreen); documentOpenWith = new KActionMenu(i18n("Open W&ith"), this); actionCollection()->addAction(QStringLiteral("file_open_with"), documentOpenWith); documentOpenWith->setWhatsThis(i18n("Open the current document using another application registered for its file type, or an application of your choice.")); connect(documentOpenWith->menu(), &QMenu::aboutToShow, this, &KateMainWindow::mSlotFixOpenWithMenu); connect(documentOpenWith->menu(), &QMenu::triggered, this, &KateMainWindow::slotOpenWithMenuAction); a = KStandardAction::keyBindings(this, SLOT(editKeys()), actionCollection()); a->setWhatsThis(i18n("Configure the application's keyboard shortcut assignments.")); a = KStandardAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection()); a->setWhatsThis(i18n("Configure which items should appear in the toolbar(s).")); QAction *settingsConfigure = KStandardAction::preferences(this, SLOT(slotConfigure()), actionCollection()); settingsConfigure->setWhatsThis(i18n("Configure various aspects of this application and the editing component.")); if (KateApp::self()->pluginManager()->pluginList().count() > 0) { a = actionCollection()->addAction(QStringLiteral("help_plugins_contents")); a->setText(i18n("&Plugins Handbook")); connect(a, &QAction::triggered, this, &KateMainWindow::pluginHelp); a->setWhatsThis(i18n("This shows help files for various available plugins.")); } a = actionCollection()->addAction(QStringLiteral("help_about_editor")); a->setText(i18n("&About Editor Component")); connect(a, &QAction::triggered, this, &KateMainWindow::aboutEditor); connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::slotWindowActivated); connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::slotUpdateOpenWith); connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::slotUpdateActionsNeedingUrl); connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::slotUpdateBottomViewBar); // re-route signals to our wrapper connect(m_viewManager, &KateViewManager::viewChanged, m_wrapper, &KTextEditor::MainWindow::viewChanged); connect(m_viewManager, &KateViewManager::viewCreated, m_wrapper, &KTextEditor::MainWindow::viewCreated); connect(this, &KateMainWindow::unhandledShortcutOverride, m_wrapper, &KTextEditor::MainWindow::unhandledShortcutOverride); slotWindowActivated(); // session actions a = actionCollection()->addAction(QStringLiteral("sessions_new")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); a->setText(i18nc("Menu entry Session->New", "&New")); // Qt::QueuedConnection to avoid deletion of code that is executed when reducing the amount of mainwindows. (bug #227008) connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::sessionNew, Qt::QueuedConnection); a = actionCollection()->addAction(QStringLiteral("sessions_save")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); a->setText(i18n("&Save Session")); connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::sessionSave); a = actionCollection()->addAction(QStringLiteral("sessions_save_as")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-save-as"))); a->setText(i18n("Save Session &As...")); connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::sessionSaveAs); a = actionCollection()->addAction(QStringLiteral("sessions_manage")); a->setIcon(QIcon::fromTheme(QStringLiteral("view-choose"))); a->setText(i18n("&Manage Sessions...")); // Qt::QueuedConnection to avoid deletion of code that is executed when reducing the amount of mainwindows. (bug #227008) connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::sessionManage, Qt::QueuedConnection); // quick open menu ;) a = new KateSessionsAction(i18n("&Quick Open Session"), this); actionCollection()->addAction(QStringLiteral("sessions_list"), a); } void KateMainWindow::slotDocumentCloseAll() { if (KateApp::self()->documentManager()->documentList().size() >= 1 && KMessageBox::warningContinueCancel(this, i18n("This will close all open documents. Are you sure you want to continue?"), i18n("Close all documents"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QStringLiteral("closeAll")) != KMessageBox::Cancel) { if (queryClose_internal()) { KateApp::self()->documentManager()->closeAllDocuments(false); } } } void KateMainWindow::slotDocumentCloseOther(KTextEditor::Document *document) { if (KateApp::self()->documentManager()->documentList().size() > 1 && KMessageBox::warningContinueCancel(this, i18n("This will close all open documents beside the current one. Are you sure you want to continue?"), i18n("Close all documents beside current one"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QStringLiteral("closeOther")) != KMessageBox::Cancel) { if (queryClose_internal(document)) { KateApp::self()->documentManager()->closeOtherDocuments(document); } } } void KateMainWindow::slotDocumentCloseSelected(const QList &docList) { QList documents; foreach(KTextEditor::Document * doc, docList) { if (queryClose_internal(doc)) { documents.append(doc); } } KateApp::self()->documentManager()->closeDocuments(documents); } void KateMainWindow::slotDocumentCloseOther() { slotDocumentCloseOther(m_viewManager->activeView()->document()); } bool KateMainWindow::queryClose_internal(KTextEditor::Document *doc) { int documentCount = KateApp::self()->documentManager()->documentList().size(); if (! showModOnDiskPrompt()) { return false; } QList modifiedDocuments = KateApp::self()->documentManager()->modifiedDocumentList(); modifiedDocuments.removeAll(doc); bool shutdown = (modifiedDocuments.count() == 0); if (!shutdown) { shutdown = KateSaveModifiedDialog::queryClose(this, modifiedDocuments); } if (KateApp::self()->documentManager()->documentList().size() > documentCount) { KMessageBox::information(this, i18n("New file opened while trying to close Kate, closing aborted."), i18n("Closing Aborted")); shutdown = false; } return shutdown; } /** * queryClose(), take care that after the last mainwindow the stuff is closed */ bool KateMainWindow::queryClose() { // session saving, can we close all views ? // just test, not close them actually if (qApp->isSavingSession()) { return queryClose_internal(); } // normal closing of window // allow to close all windows until the last without restrictions if (KateApp::self()->mainWindowsCount() > 1) { return true; } // last one: check if we can close all documents, try run // and save docs if we really close down ! if (queryClose_internal()) { KateApp::self()->sessionManager()->saveActiveSession(true); return true; } return false; } void KateMainWindow::newWindow() { KateApp::self()->newMainWindow(KateApp::self()->sessionManager()->activeSession()->config()); } void KateMainWindow::slotEditToolbars() { KConfigGroup cfg(KSharedConfig::openConfig(), "MainWindow"); saveMainWindowSettings(cfg); KEditToolBar dlg(factory()); connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KateMainWindow::slotNewToolbarConfig); dlg.exec(); } void KateMainWindow::reloadXmlGui() { for (KTextEditor::Document* doc : KateApp::self()->documentManager()->documentList()) { doc->reloadXML(); for (KTextEditor::View* view : doc->views()) { view->reloadXML(); } } } void KateMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(KConfigGroup(KSharedConfig::openConfig(), "MainWindow")); // we need to reload all View's XML Gui from disk to ensure toolbar // changes are applied to all views. reloadXmlGui(); } void KateMainWindow::slotFileQuit() { KateApp::self()->shutdownKate(this); } void KateMainWindow::slotFileClose() { m_viewManager->slotDocumentClose(); } void KateMainWindow::slotOpenDocument(const QUrl &url) { m_viewManager->openUrl(url, QString(), true, false); } void KateMainWindow::readOptions() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); const KConfigGroup generalGroup(config, "General"); m_modNotification = generalGroup.readEntry("Modified Notification", false); m_modCloseAfterLast = generalGroup.readEntry("Close After Last", false); KateApp::self()->documentManager()->setSaveMetaInfos(generalGroup.readEntry("Save Meta Infos", true)); KateApp::self()->documentManager()->setDaysMetaInfos(generalGroup.readEntry("Days Meta Infos", 30)); m_paShowPath->setChecked(generalGroup.readEntry("Show Full Path in Title", false)); m_paShowStatusBar->setChecked(generalGroup.readEntry("Show Status Bar", true)); m_paShowMenuBar->setChecked(generalGroup.readEntry("Show Menu Bar", true)); m_paShowTabBar->setChecked(generalGroup.readEntry("Show Tab Bar", true)); m_quickOpen->setMatchMode(generalGroup.readEntry("Quick Open Search Mode", (int)KateQuickOpenModel::Columns::FileName)); + m_quickOpen->setListMode(generalGroup.readEntry("Quick Open List Mode", (int)KateQuickOpenModel::List::CurrentProject)); // emit signal to hide/show statusbars toggleShowStatusBar(); toggleShowTabBar(); } void KateMainWindow::saveOptions() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup generalGroup(config, "General"); generalGroup.writeEntry("Save Meta Infos", KateApp::self()->documentManager()->getSaveMetaInfos()); generalGroup.writeEntry("Days Meta Infos", KateApp::self()->documentManager()->getDaysMetaInfos()); generalGroup.writeEntry("Show Full Path in Title", m_paShowPath->isChecked()); generalGroup.writeEntry("Show Status Bar", m_paShowStatusBar->isChecked()); generalGroup.writeEntry("Show Menu Bar", m_paShowMenuBar->isChecked()); generalGroup.writeEntry("Show Tab Bar", m_paShowTabBar->isChecked()); } void KateMainWindow::toggleShowMenuBar(bool showMessage) { if (m_paShowMenuBar->isChecked()) { menuBar()->show(); removeMenuBarActionFromContextMenu(); } else { if (showMessage) { const QString accel = m_paShowMenuBar->shortcut().toString(); KMessageBox::information(this, i18n("This will hide the menu bar completely." " You can show it again by typing %1.", accel), i18n("Hide menu bar"), QStringLiteral("HideMenuBarWarning")); } menuBar()->hide(); addMenuBarActionToContextMenu(); } } void KateMainWindow::addMenuBarActionToContextMenu() { if (m_viewManager->activeView()) { m_viewManager->activeView()->contextMenu()->addAction(m_paShowMenuBar); } } void KateMainWindow::removeMenuBarActionFromContextMenu() { if (m_viewManager->activeView()) { m_viewManager->activeView()->contextMenu()->removeAction(m_paShowMenuBar); } } void KateMainWindow::toggleShowStatusBar() { emit statusBarToggled(); } bool KateMainWindow::showStatusBar() { return m_paShowStatusBar->isChecked(); } void KateMainWindow::toggleShowTabBar() { emit tabBarToggled(); } bool KateMainWindow::showTabBar() { return m_paShowTabBar->isChecked(); } void KateMainWindow::slotWindowActivated() { if (m_viewManager->activeView()) { updateCaption(m_viewManager->activeView()->document()); } // show view manager in any case if (m_mainStackedWidget->currentWidget() != m_viewManager) { m_mainStackedWidget->setCurrentWidget(m_viewManager); } // update proxy centralWidget()->setFocusProxy(m_viewManager->activeView()); } void KateMainWindow::slotUpdateOpenWith() { if (m_viewManager->activeView()) { documentOpenWith->setEnabled(!m_viewManager->activeView()->document()->url().isEmpty()); } else { documentOpenWith->setEnabled(false); } } void KateMainWindow::slotUpdateActionsNeedingUrl() { auto&& view = viewManager()->activeView(); const bool hasUrl = view && !view->document()->url().isEmpty(); action("file_copy_filepath")->setEnabled(hasUrl); action("file_open_containing_folder")->setEnabled(hasUrl); action("file_rename")->setEnabled(hasUrl); action("file_delete")->setEnabled(hasUrl); action("file_properties")->setEnabled(hasUrl); } void KateMainWindow::dragEnterEvent(QDragEnterEvent *event) { if (!event->mimeData()) { return; } const bool accept = event->mimeData()->hasUrls() || event->mimeData()->hasText(); event->setAccepted(accept); } void KateMainWindow::dropEvent(QDropEvent *event) { slotDropEvent(event); } void KateMainWindow::slotDropEvent(QDropEvent *event) { if (event->mimeData() == nullptr) { return; } // // are we dropping files? // if (event->mimeData()->hasUrls()) { QList textlist = event->mimeData()->urls(); // Try to get the KTextEditor::View that sent this, and activate it, so that the file opens in the // view where it was dropped KTextEditor::View *kVsender = qobject_cast(QObject::sender()); if (kVsender != nullptr) { QWidget *parent = kVsender->parentWidget(); if (parent != nullptr) { KateViewSpace *vs = qobject_cast(parent->parentWidget()); if (vs != nullptr) { m_viewManager->setActiveSpace(vs); } } } foreach(const QUrl & url, textlist) { // if url has no file component, try and recursively scan dir KFileItem kitem(url); kitem.setDelayedMimeTypes(true); if (kitem.isDir()) { if (KMessageBox::questionYesNo(this, i18n("You dropped the directory %1 into Kate. " "Do you want to load all files contained in it ?", url.url()), i18n("Load files recursively?")) == KMessageBox::Yes) { KIO::ListJob *list_job = KIO::listRecursive(url, KIO::DefaultFlags, false); connect(list_job, &KIO::ListJob::entries, this, &KateMainWindow::slotListRecursiveEntries); } } else { m_viewManager->openUrl(url); } } } // // or are we dropping text? // else if (event->mimeData()->hasText()) { KTextEditor::Document *doc = KateApp::self()->documentManager()->createDoc(); doc->setText(event->mimeData()->text()); m_viewManager->activateView(doc); } } void KateMainWindow::slotListRecursiveEntries(KIO::Job *job, const KIO::UDSEntryList &list) { const QUrl dir = static_cast(job)->url(); foreach(const KIO::UDSEntry & entry, list) { if (!entry.isDir()) { QUrl url(dir); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1Char('/') + entry.stringValue(KIO::UDSEntry::UDS_NAME)); m_viewManager->openUrl(url); } } } void KateMainWindow::editKeys() { KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); QList clients = guiFactory()->clients(); foreach(KXMLGUIClient * client, clients) { // FIXME there appear to be invalid clients after session switching // qCDebug(LOG_KATE)<<"adding client to shortcut editor"; // qCDebug(LOG_KATE)<actionCollection(); // qCDebug(LOG_KATE)<componentData().aboutData(); // qCDebug(LOG_KATE)<componentData().aboutData()->programName(); dlg.addCollection(client->actionCollection(), client->componentName()); } dlg.configure(); // reloadXML gui clients, to ensure all clients are up-to-date reloadXmlGui(); } void KateMainWindow::openUrl(const QString &name) { m_viewManager->openUrl(QUrl(name)); } void KateMainWindow::slotConfigure() { showPluginConfigPage(nullptr, 0); } void KateMainWindow::showPluginConfigPage(KTextEditor::Plugin *configpageinterface, uint id) { if (!m_viewManager->activeView()) { return; } KateConfigDialog *dlg = new KateConfigDialog(this, m_viewManager->activeView()); if (configpageinterface) { dlg->showAppPluginPage(configpageinterface, id); } if (dlg->exec() == QDialog::Accepted) { m_fileOpenRecent->setMaxItems(KateConfigDialog::recentFilesMaxCount()); } delete dlg; m_viewManager->reactivateActiveView(); // gui (toolbars...) needs to be updated, because // of possible changes that the configure dialog // could have done on it, specially for plugins. } QUrl KateMainWindow::activeDocumentUrl() { // anders: i make this one safe, as it may be called during // startup (by the file selector) KTextEditor::View *v = m_viewManager->activeView(); if (v) { return v->document()->url(); } return QUrl(); } void KateMainWindow::mSlotFixOpenWithMenu() { // dh: in bug #307699, this slot is called when launching the Kate application // unfortunately, no one ever could reproduce except users. KTextEditor::View *activeView = m_viewManager->activeView(); if (! activeView) { return; } // cleanup menu QMenu *menu = documentOpenWith->menu(); menu->clear(); // get a list of appropriate services. QMimeDatabase db; QMimeType mime = db.mimeTypeForName(activeView->document()->mimeType()); //qCDebug(LOG_KATE) << "mime type: " << mime.name(); QAction *a = nullptr; const KService::List offers = KMimeTypeTrader::self()->query(mime.name(), QStringLiteral("Application")); // add all default open-with-actions except "Kate" for (const auto& service : offers) { if (service->name() == QStringLiteral("Kate")) { continue; } a = menu->addAction(QIcon::fromTheme(service->icon()), service->name()); a->setData(service->entryPath()); } // append "Other..." to call the KDE "open with" dialog. a = documentOpenWith->menu()->addAction(i18n("&Other...")); a->setData(QString()); } void KateMainWindow::slotOpenWithMenuAction(QAction *a) { QList list; list.append(m_viewManager->activeView()->document()->url()); const QString openWith = a->data().toString(); if (openWith.isEmpty()) { // display "open with" dialog KOpenWithDialog dlg(list); if (dlg.exec()) { KRun::runService(*dlg.service(), list, this); } return; } KService::Ptr app = KService::serviceByDesktopPath(openWith); if (app) { KRun::runService(*app, list, this); } else { KMessageBox::error(this, i18n("Application '%1' not found.", openWith), i18n("Application not found")); } } void KateMainWindow::pluginHelp() { KHelpClient::invokeHelp(QString(), QStringLiteral("kate-plugins")); } void KateMainWindow::aboutEditor() { KAboutApplicationDialog ad(KTextEditor::Editor::instance()->aboutData(), this); ad.exec(); } void KateMainWindow::slotFullScreen(bool t) { KToggleFullScreenAction::setFullScreen(this, t); QMenuBar *mb = menuBar(); if (t) { QToolButton *b = new QToolButton(mb); b->setDefaultAction(m_showFullScreenAction); b->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Ignored)); b->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); mb->setCornerWidget(b,Qt::TopRightCorner); b->setVisible(true); b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); } else { QWidget *w=mb->cornerWidget(Qt::TopRightCorner); if (w) w->deleteLater(); } } bool KateMainWindow::showModOnDiskPrompt() { KTextEditor::Document *doc; DocVector list; list.reserve(KateApp::self()->documentManager()->documentList().size()); foreach(doc, KateApp::self()->documentManager()->documentList()) { if (KateApp::self()->documentManager()->documentInfo(doc)->modifiedOnDisc && doc->isModified()) { list.append(doc); } } if (!list.isEmpty() && !m_modignore) { KateMwModOnHdDialog mhdlg(list, this); m_modignore = true; bool res = mhdlg.exec(); m_modignore = false; return res; } return true; } void KateMainWindow::slotDocumentCreated(KTextEditor::Document *doc) { connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, SIGNAL(readWriteChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, &KTextEditor::Document::documentNameChanged, this, &KateMainWindow::slotUpdateOpenWith); updateCaption(doc); } void KateMainWindow::updateCaption() { if (m_viewManager->activeView()) { updateCaption(m_viewManager->activeView()->document()); } } void KateMainWindow::updateCaption(KTextEditor::Document *doc) { if (!m_viewManager->activeView()) { setCaption(QString(), false); return; } // block signals from inactive docs if (!((KTextEditor::Document *)m_viewManager->activeView()->document() == doc)) { return; } QString c; if (m_viewManager->activeView()->document()->url().isEmpty() || (!m_paShowPath || !m_paShowPath->isChecked())) { c = ((KTextEditor::Document *)m_viewManager->activeView()->document())->documentName(); } else { c = m_viewManager->activeView()->document()->url().toString(QUrl::PreferLocalFile); const QString homePath = QDir::homePath(); if (c.startsWith(homePath)) { c = QStringLiteral("~") + c.right(c.length() - homePath.length()); } } QString sessName = KateApp::self()->sessionManager()->activeSession()->name(); if (!sessName.isEmpty()) { sessName = QStringLiteral("%1: ").arg(sessName); } QString readOnlyCaption; if (!m_viewManager->activeView()->document()->isReadWrite()) { readOnlyCaption = i18n(" [read only]"); } setCaption(sessName + c + readOnlyCaption + QStringLiteral(" [*]"), m_viewManager->activeView()->document()->isModified()); } void KateMainWindow::saveProperties(KConfigGroup &config) { saveSession(config); // store all plugin view states int id = KateApp::self()->mainWindowID(this); foreach(const KatePluginInfo & item, KateApp::self()->pluginManager()->pluginList()) { if (item.plugin && pluginViews().contains(item.plugin)) { if (auto interface = qobject_cast (pluginViews().value(item.plugin))) { KConfigGroup group(config.config(), QStringLiteral("Plugin:%1:MainWindow:%2").arg(item.saveName()).arg(id)); interface->writeSessionConfig(group); } } } saveOpenRecent(config.config()); m_viewManager->saveViewConfiguration(config); } void KateMainWindow::readProperties(const KConfigGroup &config) { // KDE5: TODO startRestore should take a const KConfigBase*, or even just a const KConfigGroup&, // but this propagates down to interfaces/kate/plugin.h so all plugins have to be ported KConfigBase *configBase = const_cast(config.config()); startRestore(configBase, config.name()); // perhaps enable plugin guis KateApp::self()->pluginManager()->enableAllPluginsGUI(this, configBase); finishRestore(); loadOpenRecent(config.config()); m_viewManager->restoreViewConfiguration(config); } void KateMainWindow::saveOpenRecent(KConfig *config) { m_fileOpenRecent->saveEntries(KConfigGroup(config, "Recent Files")); } void KateMainWindow::loadOpenRecent(const KConfig *config) { m_fileOpenRecent->loadEntries(KConfigGroup(config, "Recent Files")); } void KateMainWindow::saveGlobalProperties(KConfig *sessionConfig) { KateApp::self()->documentManager()->saveDocumentList(sessionConfig); KConfigGroup cg(sessionConfig, "General"); cg.writeEntry("Last Session", KateApp::self()->sessionManager()->activeSession()->name()); // save plugin config !! KateApp::self()->pluginManager()->writeConfig(sessionConfig); } void KateMainWindow::saveWindowConfig(const KConfigGroup &_config) { KConfigGroup config(_config); saveMainWindowSettings(config); KWindowConfig::saveWindowSize(windowHandle(), config); config.writeEntry("WindowState", int(((KParts::MainWindow *)this)->windowState())); config.sync(); } void KateMainWindow::restoreWindowConfig(const KConfigGroup &config) { setWindowState(Qt::WindowNoState); applyMainWindowSettings(config); KWindowConfig::restoreWindowSize(windowHandle(), config); setWindowState(QFlags(config.readEntry("WindowState", int(Qt::WindowActive)))); } void KateMainWindow::slotUpdateBottomViewBar() { //qCDebug(LOG_KATE)<<"slotUpdateHorizontalViewBar()"<activeView(); BarState bs = m_bottomViewBarMapping[view]; if (bs.bar() && bs.state()) { m_bottomContainerStack->setCurrentWidget(bs.bar()); m_bottomContainerStack->currentWidget()->show(); m_bottomViewBarContainer->show(); } else { QWidget *wid = m_bottomContainerStack->currentWidget(); if (wid) { wid->hide(); } //qCDebug(LOG_KATE)<hide(); } } void KateMainWindow::queueModifiedOnDisc(KTextEditor::Document *doc) { if (!m_modNotification) { return; } KateDocumentInfo *docInfo = KateApp::self()->documentManager()->documentInfo(doc); if (!docInfo) { return; } bool modOnDisk = (uint)docInfo->modifiedOnDisc; if (s_modOnHdDialog == nullptr && modOnDisk) { DocVector list; list.append(doc); s_modOnHdDialog = new KateMwModOnHdDialog(list, this); m_modignore = true; KWindowSystem::setOnAllDesktops(s_modOnHdDialog->winId(), true); s_modOnHdDialog->exec(); delete s_modOnHdDialog; // s_modOnHdDialog is set to 0 in destructor of KateMwModOnHdDialog (jowenn!!!) m_modignore = false; } else if (s_modOnHdDialog != nullptr) { s_modOnHdDialog->addDocument(doc); } } bool KateMainWindow::event(QEvent *e) { if (e->type() == QEvent::ShortcutOverride) { QKeyEvent *k = static_cast(e); emit unhandledShortcutOverride(k); } return KateMDI::MainWindow::event(e); } QObject *KateMainWindow::pluginView(const QString &name) { KTextEditor::Plugin *plugin = KateApp::self()->pluginManager()->plugin(name); if (!plugin) { return nullptr; } return m_pluginViews.contains(plugin) ? m_pluginViews.value(plugin) : nullptr; } void KateMainWindow::mousePressEvent(QMouseEvent *e) { switch(e->button()) { case Qt::ForwardButton: slotFocusNextTab(); break; case Qt::BackButton: slotFocusPrevTab(); break; default: ; } } void KateMainWindow::slotFocusPrevTab() { if (m_viewManager->activeViewSpace()) { m_viewManager->activeViewSpace()->focusPrevTab(); } } void KateMainWindow::slotFocusNextTab() { if (m_viewManager->activeViewSpace()) { m_viewManager->activeViewSpace()->focusNextTab(); } } void KateMainWindow::slotQuickOpen() { /** * toggle back to view manager when when quick open is already shown */ if (m_mainStackedWidget->currentWidget() == m_quickOpen) { m_mainStackedWidget->setCurrentWidget(m_viewManager); centralWidget()->setFocusProxy(m_viewManager); return; } /** * show quick open and pass focus to it */ m_quickOpen->update(); m_mainStackedWidget->setCurrentWidget(m_quickOpen); centralWidget()->setFocusProxy(m_quickOpen); m_quickOpen->setFocus(); } QWidget *KateMainWindow::createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KTextEditor::MainWindow::ToolViewPosition pos, const QIcon &icon, const QString &text) { // FIXME KF5 return KateMDI::MainWindow::createToolView(plugin, identifier, (KMultiTabBar::KMultiTabBarPosition)(pos), icon.pixmap(QSize(16, 16)), text); } bool KateMainWindow::moveToolView(QWidget *widget, KTextEditor::MainWindow::ToolViewPosition pos) { if (!qobject_cast(widget)) { return false; } // FIXME KF5 return KateMDI::MainWindow::moveToolView(qobject_cast(widget), (KMultiTabBar::KMultiTabBarPosition)(pos)); } bool KateMainWindow::showToolView(QWidget *widget) { if (!qobject_cast(widget)) { return false; } return KateMDI::MainWindow::showToolView(qobject_cast(widget)); } bool KateMainWindow::hideToolView(QWidget *widget) { if (!qobject_cast(widget)) { return false; } return KateMDI::MainWindow::hideToolView(qobject_cast(widget)); } void KateMainWindow::setQuickOpenMatchMode(int mode) { m_quickOpen->setMatchMode(mode); } int KateMainWindow::quickOpenMatchMode() { return m_quickOpen->matchMode(); } + +void KateMainWindow::setQuickOpenListMode(int mode) +{ + m_quickOpen->setListMode(mode); +} + +int KateMainWindow::quickOpenListMode() +{ + return m_quickOpen->listMode(); +} diff --git a/kate/katemainwindow.h b/kate/katemainwindow.h index d82ceac4f..5238095f7 100644 --- a/kate/katemainwindow.h +++ b/kate/katemainwindow.h @@ -1,596 +1,599 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 Anders Lund This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KATE_MAINWINDOW_H__ #define __KATE_MAINWINDOW_H__ #include "katemdi.h" #include "kateviewmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class QMenu; namespace KIO { class UDSEntry; typedef class QList UDSEntryList; } class KFileItem; class KRecentFilesAction; class KateViewManager; class KateMwModOnHdDialog; class KateQuickOpen; // Helper layout class to always provide minimum size class KateContainerStackedLayout : public QStackedLayout { Q_OBJECT public: KateContainerStackedLayout(QWidget *parent); QSize sizeHint() const override; QSize minimumSize() const override; }; class KateMainWindow : public KateMDI::MainWindow, virtual public KParts::PartBase { Q_OBJECT public: /** * Construct the window and restore its state from given config if any * @param sconfig session config for this window, 0 if none * @param sgroup session config group to use */ KateMainWindow(KConfig *sconfig, const QString &sgroup); /** * Destruct the nice window */ ~KateMainWindow() override; /** * Accessor methodes for interface and child objects */ public: KateViewManager *viewManager() { return m_viewManager; } /** * KTextEditor::MainWindow wrapper * @return KTextEditor::MainWindow wrapper. */ KTextEditor::MainWindow *wrapper() { return m_wrapper; } public: /** Returns the URL of the current document. * anders: I add this for use from the file selector. */ QUrl activeDocumentUrl(); /** * Prompts the user for what to do with files that are modified on disk if any. * This is optionally run when the window receives focus, and when the last * window is closed. * @return true if no documents are modified on disk, or all documents were * handled by the dialog; otherwise (the dialog was canceled) false. */ bool showModOnDiskPrompt(); public: /*reimp*/ void readProperties(const KConfigGroup &config) override; /*reimp*/ void saveProperties(KConfigGroup &config) override; /*reimp*/ void saveGlobalProperties(KConfig *sessionConfig) override; void saveOpenRecent(KConfig *config); void loadOpenRecent(const KConfig *config); public: bool queryClose_internal(KTextEditor::Document *doc = nullptr); /** * save the settings, size and state of this window in * the provided config group */ void saveWindowConfig(const KConfigGroup &); /** * restore the settings, size and state of this window from * the provided config group. */ void restoreWindowConfig(const KConfigGroup &); /** * save some global options to katerc */ void saveOptions(); private: /** * Setup actions which pointers are needed already in setupMainWindow */ void setupImportantActions(); void setupMainWindow(); void setupActions(); bool queryClose() override; void addMenuBarActionToContextMenu(); void removeMenuBarActionFromContextMenu(); /** * read some global options from katerc */ void readOptions(); void dragEnterEvent(QDragEnterEvent *) override; void dropEvent(QDropEvent *) override; public Q_SLOTS: void slotFileClose(); void slotFileQuit(); void queueModifiedOnDisc(KTextEditor::Document *doc); void slotFocusPrevTab(); void slotFocusNextTab(); /** * Show quick open */ void slotQuickOpen(); /** * Overwrite size hint for better default window sizes * @return size hint */ QSize sizeHint() const override; /** * slots used for actions in the menus/toolbars * or internal signal connections */ private Q_SLOTS: void newWindow(); void slotConfigure(); void slotOpenWithMenuAction(QAction *a); void slotEditToolbars(); void slotNewToolbarConfig(); void slotUpdateOpenWith(); void slotUpdateActionsNeedingUrl(); void slotOpenDocument(const QUrl &); void slotDropEvent(QDropEvent *); void editKeys(); void mSlotFixOpenWithMenu(); void reloadXmlGui(); /* to update the caption */ void slotDocumentCreated(KTextEditor::Document *doc); void updateCaption(KTextEditor::Document *doc); // calls updateCaption(doc) with the current document void updateCaption(); void pluginHelp(); void aboutEditor(); void slotFullScreen(bool); void slotListRecursiveEntries(KIO::Job *job, const KIO::UDSEntryList &list); private Q_SLOTS: void toggleShowMenuBar(bool showMessage = true); void toggleShowStatusBar(); void toggleShowTabBar(); public: bool showStatusBar(); bool showTabBar(); Q_SIGNALS: void statusBarToggled(); void tabBarToggled(); void unhandledShortcutOverride(QEvent *e); public: void openUrl(const QString &name = QString()); QHash &pluginViews() { return m_pluginViews; } QWidget *bottomViewBarContainer() { return m_bottomViewBarContainer; } void addToBottomViewBarContainer(KTextEditor::View *view, QWidget *bar) { m_bottomContainerStack->addWidget(bar); m_bottomViewBarMapping[view] = BarState(bar); } void hideBottomViewBarForView(KTextEditor::View *view) { BarState &state = m_bottomViewBarMapping[view]; if (state.bar()) { m_bottomContainerStack->setCurrentWidget(state.bar()); state.bar()->hide(); state.setState(false); } m_bottomViewBarContainer->hide(); } void showBottomViewBarForView(KTextEditor::View *view) { BarState &state = m_bottomViewBarMapping[view]; if (state.bar()) { m_bottomContainerStack->setCurrentWidget(state.bar()); state.bar()->show(); state.setState(true); m_bottomViewBarContainer->show(); } } void deleteBottomViewBarForView(KTextEditor::View *view) { BarState state = m_bottomViewBarMapping.take(view); if (state.bar()) { if (m_bottomContainerStack->currentWidget() == state.bar()) { m_bottomViewBarContainer->hide(); } delete state.bar(); } } bool modNotificationEnabled() const { return m_modNotification; } void setModNotificationEnabled(bool e) { m_modNotification = e; } bool modCloseAfterLast() const { return m_modCloseAfterLast; } void setModCloseAfterLast(bool e) { m_modCloseAfterLast = e; } void setQuickOpenMatchMode(int mode); int quickOpenMatchMode(); + void setQuickOpenListMode(int mode); + int quickOpenListMode(); + KRecentFilesAction *fileOpenRecent() const { return m_fileOpenRecent; } // // KTextEditor::MainWindow interface, get called by invokeMethod from our wrapper object! // public Q_SLOTS: /** * get the toplevel widget. * \return the real main window widget. */ QWidget *window() { return this; } /** * Accessor to the XMLGUIFactory. * \return the mainwindow's KXMLGUIFactory. */ KXMLGUIFactory *guiFactory() override { return KateMDI::MainWindow::guiFactory(); } /** * Get a list of all views for this main window. * @return all views */ QList views() { return viewManager()->views(); } /** * Access the active view. * \return active view */ KTextEditor::View *activeView() { return viewManager()->activeView(); } /** * Activate the view with the corresponding \p document. * If none exist for this document, create one * \param document the document * \return activated view of this document */ KTextEditor::View *activateView(KTextEditor::Document *document) { return viewManager()->activateView(document); } /** * Open the document \p url with the given \p encoding. * \param url the document's url * \param encoding the preferred encoding. If encoding is QString() the * encoding will be guessed or the default encoding will be used. * \return a pointer to the created view for the new document, if a document * with this url is already existing, its view will be activated */ KTextEditor::View *openUrl(const QUrl &url, const QString &encoding = QString()) { return viewManager()->openUrlWithView(url, encoding); } /** * Close selected view * \param view the view * \return true if view was closed */ bool closeView(KTextEditor::View *view) { m_viewManager->closeView(view); return true; } /** * Close the split view where the given view is contained. * \param view the view. * \return true if the split view was closed. */ bool closeSplitView(KTextEditor::View *view) { m_viewManager->closeViewSpace(view); return true; } /** * @returns true if the two given views share the same split view, * false otherwise. */ bool viewsInSameSplitView(KTextEditor::View *view1, KTextEditor::View *view2) { return m_viewManager->viewsInSameViewSpace(view1, view2); } /** * Split current view space according to \p orientation * \param orientation in which line split the view */ void splitView(Qt::Orientation orientation) { m_viewManager->splitViewSpace(nullptr, orientation); } /** * Try to create a view bar for the given view. * Its parameter is the view for which we want a view bar * @return suitable widget that can host view bars widgets or nullptr */ QWidget *createViewBar(KTextEditor::View *) { return bottomViewBarContainer(); } /** * Delete the view bar for the given view. * @param view view for which we want an view bar */ void deleteViewBar(KTextEditor::View *view) { deleteBottomViewBarForView(view); } /** * Add a widget to the view bar. * @param view view for which the view bar is used * @param bar bar widget, shall have the viewBarParent() as parent widget */ void addWidgetToViewBar(KTextEditor::View *view, QWidget *bar) { addToBottomViewBarContainer(view, bar); } /** * Show the view bar for the given view * @param view view for which the view bar is used */ void showViewBar(KTextEditor::View *view) { showBottomViewBarForView(view); } /** * Hide the view bar for the given view * @param view view for which the view bar is used */ void hideViewBar(KTextEditor::View *view) { hideBottomViewBarForView(view); } /** * Create a new toolview with unique \p identifier at side \p pos * with \p icon and caption \p text. Use the returned widget to embedd * your widgets. * \param plugin which owns this tool view * \param identifier unique identifier for this toolview * \param pos position for the toolview, if we are in session restore, * this is only a preference * \param icon icon to use in the sidebar for the toolview * \param text translated text (i18n()) to use in addition to icon * \return created toolview on success, otherwise NULL */ QWidget *createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KTextEditor::MainWindow::ToolViewPosition pos, const QIcon &icon, const QString &text); /** * Move the toolview \p widget to position \p pos. * \param widget the toolview to move, where the widget was constructed * by createToolView(). * \param pos new position to move widget to * \return \e true on success, otherwise \e false */ bool moveToolView(QWidget *widget, KTextEditor::MainWindow::ToolViewPosition pos); /** * Show the toolview \p widget. * \param widget the toolview to show, where the widget was constructed * by createToolView(). * \return \e true on success, otherwise \e false * \todo add focus parameter: bool showToolView (QWidget *widget, bool giveFocus ); */ bool showToolView(QWidget *widget); /** * Hide the toolview \p widget. * \param widget the toolview to hide, where the widget was constructed * by createToolView(). * \return \e true on success, otherwise \e false */ bool hideToolView(QWidget *widget); /** * Get a plugin view for the plugin with with identifier \p name. * \param name the plugin's name * \return pointer to the plugin view if a plugin with \p name is loaded and has a view for this mainwindow, * otherwise NULL */ QObject *pluginView(const QString &name); private Q_SLOTS: void slotUpdateBottomViewBar(); private Q_SLOTS: void slotDocumentCloseAll(); void slotDocumentCloseOther(); void slotDocumentCloseOther(KTextEditor::Document *document); void slotDocumentCloseSelected(const QList &); private: /** * Notify about file modifications from other processes? */ bool m_modNotification; /** * Shutdown Kate after last file is closed */ bool m_modCloseAfterLast; /** * stacked widget containing the central area, aka view manager, quickopen, ... */ QStackedWidget *m_mainStackedWidget; /** * quick open to fast switch documents */ KateQuickOpen *m_quickOpen; /** * keeps track of views */ KateViewManager *m_viewManager; KRecentFilesAction *m_fileOpenRecent; KActionMenu *documentOpenWith; KToggleAction *settingsShowFileselector; KToggleAction *m_showFullScreenAction; bool m_modignore; // all plugin views for this mainwindow, used by the pluginmanager QHash m_pluginViews; // options: show statusbar + show path KToggleAction *m_paShowPath; KToggleAction *m_paShowMenuBar; KToggleAction *m_paShowStatusBar; KToggleAction *m_paShowTabBar; QWidget *m_bottomViewBarContainer; KateContainerStackedLayout *m_bottomContainerStack; class BarState { public: BarState(): m_bar(nullptr), m_state(false) {} BarState(QWidget *bar): m_bar(bar), m_state(false) {} ~BarState() {} QWidget *bar() { return m_bar; } bool state() { return m_state; } void setState(bool state) { m_state = state; } private: QWidget *m_bar; bool m_state; }; QHash m_bottomViewBarMapping; public: static void unsetModifiedOnDiscDialogIfIf(KateMwModOnHdDialog *diag) { if (s_modOnHdDialog == diag) { s_modOnHdDialog = nullptr; } } private: static KateMwModOnHdDialog *s_modOnHdDialog; /** * Wrapper of main window for KTextEditor */ KTextEditor::MainWindow *m_wrapper; public Q_SLOTS: void showPluginConfigPage(KTextEditor::Plugin *configpageinterface, uint id); void slotWindowActivated(); protected: bool event(QEvent *e) override; void mousePressEvent(QMouseEvent *e) override; }; #endif diff --git a/kate/katequickopen.cpp b/kate/katequickopen.cpp index 8209cd122..ba8295900 100644 --- a/kate/katequickopen.cpp +++ b/kate/katequickopen.cpp @@ -1,183 +1,193 @@ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2007,2009 Joseph Wenninger */ #include "katequickopen.h" #include "katequickopenmodel.h" #include "katemainwindow.h" #include "kateviewmanager.h" #include "kateapp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QPointer) KateQuickOpen::KateQuickOpen(QWidget *parent, KateMainWindow *mainWindow) : QWidget(parent) , m_mainWindow(mainWindow) { QVBoxLayout *layout = new QVBoxLayout(); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); m_inputLine = new KLineEdit(); setFocusProxy(m_inputLine); m_inputLine->setPlaceholderText(i18n("Quick Open Search")); layout->addWidget(m_inputLine); m_listView = new QTreeView(); layout->addWidget(m_listView, 1); m_listView->setTextElideMode(Qt::ElideLeft); m_base_model = new KateQuickOpenModel(m_mainWindow, this); m_model = new QSortFilterProxyModel(this); m_model->setFilterRole(Qt::DisplayRole); m_model->setSortRole(Qt::DisplayRole); m_model->setFilterCaseSensitivity(Qt::CaseInsensitive); m_model->setSortCaseSensitivity(Qt::CaseInsensitive); m_model->setFilterKeyColumn(0); connect(m_inputLine, &KLineEdit::textChanged, m_model, &QSortFilterProxyModel::setFilterWildcard); connect(m_inputLine, &KLineEdit::returnPressed, this, &KateQuickOpen::slotReturnPressed); connect(m_model, &QSortFilterProxyModel::rowsInserted, this, &KateQuickOpen::reselectFirst); connect(m_model, &QSortFilterProxyModel::rowsRemoved, this, &KateQuickOpen::reselectFirst); connect(m_listView, &QTreeView::activated, this, &KateQuickOpen::slotReturnPressed); m_listView->setModel(m_model); m_model->setSourceModel(m_base_model); m_inputLine->installEventFilter(this); m_listView->installEventFilter(this); m_listView->setHeaderHidden(true); m_listView->setRootIsDecorated(false); } bool KateQuickOpen::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); if (obj == m_inputLine) { const bool forward2list = (keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down) || (keyEvent->key() == Qt::Key_PageUp) || (keyEvent->key() == Qt::Key_PageDown); if (forward2list) { QCoreApplication::sendEvent(m_listView, event); return true; } if (keyEvent->key() == Qt::Key_Escape) { m_mainWindow->slotWindowActivated(); m_inputLine->clear(); return true; } } else { const bool forward2input = (keyEvent->key() != Qt::Key_Up) && (keyEvent->key() != Qt::Key_Down) && (keyEvent->key() != Qt::Key_PageUp) && (keyEvent->key() != Qt::Key_PageDown) && (keyEvent->key() != Qt::Key_Tab) && (keyEvent->key() != Qt::Key_Backtab); if (forward2input) { QCoreApplication::sendEvent(m_inputLine, event); return true; } } } // hide on focus out, if neither input field nor list have focus! else if (event->type() == QEvent::FocusOut && !(m_inputLine->hasFocus() || m_listView->hasFocus())) { m_mainWindow->slotWindowActivated(); m_inputLine->clear(); return true; } return QWidget::eventFilter(obj, event); } void KateQuickOpen::reselectFirst() { int first = 0; if (m_mainWindow->viewManager()->sortedViews().size() > 1) first = 1; QModelIndex index = m_model->index(first, 0); m_listView->setCurrentIndex(index); } void KateQuickOpen::update() { m_base_model->refresh(); m_listView->resizeColumnToContents(0); // If we have a very long file name we restrict the size of the first column // to take at most half of the space. Otherwise it would look odd. int colw0 = m_listView->header()->sectionSize(0); // file name int colw1 = m_listView->header()->sectionSize(1); // file path if (colw0 > colw1) { m_listView->setColumnWidth(0, (colw0 + colw1) / 2); } reselectFirst(); } void KateQuickOpen::slotReturnPressed() { const auto index = m_listView->model()->index(m_listView->currentIndex().row(), KateQuickOpenModel::Columns::FilePath); auto url = index.data(Qt::UserRole).toUrl(); m_mainWindow->wrapper()->openUrl(url); m_mainWindow->slotWindowActivated(); m_inputLine->clear(); } void KateQuickOpen::setMatchMode(int mode) { m_model->setFilterKeyColumn(mode); } int KateQuickOpen::matchMode() { return m_model->filterKeyColumn(); } + +void KateQuickOpen::setListMode(int mode) +{ + m_base_model->setListMode(mode); +} + +int KateQuickOpen::listMode() +{ + return m_base_model->listMode(); +} diff --git a/kate/katequickopen.h b/kate/katequickopen.h index bc0dd556f..aa34b6c82 100644 --- a/kate/katequickopen.h +++ b/kate/katequickopen.h @@ -1,76 +1,79 @@ /* Copyright (C) 2007,2009 Joseph Wenninger This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KATE_QUICK_OPEN_H #define KATE_QUICK_OPEN_H #include class KateMainWindow; class KLineEdit; class QModelIndex; class QStandardItemModel; class QSortFilterProxyModel; class QTreeView; class KateQuickOpenModel; class KateQuickOpen : public QWidget { Q_OBJECT public: KateQuickOpen(QWidget *parent, KateMainWindow *mainWindow); /** * update state * will fill model with current open documents, project documents, ... */ void update(); int matchMode(); void setMatchMode(int mode); + int listMode(); + void setListMode(int mode); + protected: bool eventFilter(QObject *obj, QEvent *event) override; private Q_SLOTS: void reselectFirst(); /** * Return pressed, activate the selected document * and go back to background */ void slotReturnPressed(); private: KateMainWindow *m_mainWindow; QTreeView *m_listView; KLineEdit *m_inputLine; /** * our model we search in */ KateQuickOpenModel *m_base_model; /** * filtered model we search in */ QSortFilterProxyModel *m_model; }; #endif diff --git a/kate/katequickopenmodel.cpp b/kate/katequickopenmodel.cpp index 4dd29bc38..624452b7f 100644 --- a/kate/katequickopenmodel.cpp +++ b/kate/katequickopenmodel.cpp @@ -1,135 +1,138 @@ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2018 Tomaz Canabrava */ #include "katequickopenmodel.h" #include "katemainwindow.h" #include "kateviewmanager.h" #include "kateapp.h" #include #include KateQuickOpenModel::KateQuickOpenModel(KateMainWindow *mainWindow, QObject *parent) : QAbstractTableModel (parent), m_mainWindow(mainWindow) { } int KateQuickOpenModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) { return 0; } return m_modelEntries.size(); } int KateQuickOpenModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 2; } QVariant KateQuickOpenModel::data(const QModelIndex& idx, int role) const { if(! idx.isValid()) { return {}; } if (role != Qt::DisplayRole && role != Qt::FontRole && role != Qt::UserRole) { return {}; } auto entry = m_modelEntries.at(idx.row()); if (role == Qt::DisplayRole) { switch(idx.column()) { case Columns::FileName: return entry.fileName; case Columns::FilePath: return entry.filePath; } } else if (role == Qt::FontRole) { if (entry.bold) { QFont font; font.setBold(true); return font; } } else if (role == Qt::UserRole) { return entry.url; } return {}; } void KateQuickOpenModel::refresh() { QObject *projectView = m_mainWindow->pluginView(QStringLiteral("kateprojectplugin")); const QList sortedViews = m_mainWindow->viewManager()->sortedViews(); const QList openDocs = KateApp::self()->documentManager()->documentList(); - const QStringList projectDocs = projectView ? projectView->property("projectFiles").toStringList() : QStringList(); + const QStringList projectDocs = projectView + ? (m_listMode == CurrentProject + ? projectView->property("projectFiles") : projectView->property("allProjectsFiles")).toStringList() + : QStringList(); QVector allDocuments; allDocuments.reserve(sortedViews.size() + openDocs.size() + projectDocs.size()); size_t sort_id = (size_t)-1; for (auto *view : qAsConst(sortedViews)) { auto doc = view->document(); allDocuments.push_back({ doc->url(), doc->documentName(), doc->url().toDisplayString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile), true, sort_id --}); } for (auto *doc : qAsConst(openDocs)) { const auto normalizedUrl = doc->url().toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile); allDocuments.push_back({ doc->url(), doc->documentName(), normalizedUrl, true, 0 }); } for (const auto& file : qAsConst(projectDocs)) { QFileInfo fi(file); const auto localFile = QUrl::fromLocalFile(fi.absoluteFilePath()); allDocuments.push_back({ localFile, fi.fileName(), localFile.toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile), false, 0 }); } /** Sort the arrays by filePath. */ std::stable_sort(std::begin(allDocuments), std::end(allDocuments), [](const ModelEntry& a, const ModelEntry& b) { return a.filePath < b.filePath; }); /** remove Duplicates. * Note that the stable_sort above guarantees that the items that the * bold/sort_id fields of the items added first are correctly preserved. */ allDocuments.erase( std::unique(allDocuments.begin(), allDocuments.end(), [](const ModelEntry& a, const ModelEntry& b) { return a.filePath == b.filePath; }), std::end(allDocuments)); /** sort the arrays via boldness (open or not */ std::stable_sort(std::begin(allDocuments), std::end(allDocuments), [](const ModelEntry& a, const ModelEntry& b) { if (a.bold == b.bold) return a.sort_id > b.sort_id; return a.bold > b.bold; }); beginResetModel(); m_modelEntries = allDocuments; endResetModel(); } diff --git a/kate/katequickopenmodel.h b/kate/katequickopenmodel.h index 7d9959a08..45738aa2c 100644 --- a/kate/katequickopenmodel.h +++ b/kate/katequickopenmodel.h @@ -1,59 +1,63 @@ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2018 Tomaz Canabrava */ #ifndef KATEQUICKOPENMODEL_H #define KATEQUICKOPENMODEL_H #include #include #include #include #include "katemainwindow.h" struct ModelEntry { QUrl url; // used for actually opening a selected file (local or remote) QString fileName; // display string for left column QString filePath; // display string for right column bool bold; // format line in bold text or not size_t sort_id; }; class KateQuickOpenModel : public QAbstractTableModel { Q_OBJECT public: enum Columns : int { FileName, FilePath, Bold }; explicit KateQuickOpenModel(KateMainWindow *mainWindow, QObject *parent=nullptr); int rowCount(const QModelIndex& parent) const override; int columnCount(const QModelIndex& parent) const override; QVariant data(const QModelIndex& idx, int role) const override; void refresh(); + enum List : int { CurrentProject, AllProjects }; + int listMode() { return m_listMode; } + void setListMode(int mode) { m_listMode = mode; } private: QVector m_modelEntries; /* TODO: don't rely in a pointer to the main window. * this is bad engineering, but current code is too tight * on this and it's hard to untangle without breaking existing * code. */ KateMainWindow *m_mainWindow; + int m_listMode; }; #endif