File indexing completed on 2024-04-28 05:49:08
0001 /* This file is part of the Kate project. 0002 * 0003 * SPDX-FileCopyrightText: 2012 Christoph Cullmann <cullmann@kde.org> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kateprojectinfoviewterminal.h" 0009 #include "kateprojectpluginview.h" 0010 0011 #include <KActionCollection> 0012 #include <KConfigGroup> 0013 #include <KLocalizedString> 0014 #include <KPluginFactory> 0015 #include <KSharedConfig> 0016 #include <KShell> 0017 #include <KTextEditor/MainWindow> 0018 #include <KXMLGUIClient> 0019 #include <KXMLGUIFactory> 0020 #include <kde_terminal_interface.h> 0021 #include <ktexteditor_utils.h> 0022 0023 #include <QTabWidget> 0024 0025 KPluginFactory *KateProjectInfoViewTerminal::s_pluginFactory = nullptr; 0026 0027 KateProjectInfoViewTerminal::KateProjectInfoViewTerminal(KateProjectPluginView *pluginView, const QString &directory) 0028 : m_pluginView(pluginView) 0029 , m_directory(directory) 0030 { 0031 /** 0032 * layout widget 0033 */ 0034 m_layout = new QVBoxLayout(this); 0035 m_layout->setSpacing(0); 0036 m_layout->setContentsMargins(0, 0, 0, 0); 0037 0038 m_showProjectInfoViewAction = Utils::toolviewShowAction(m_pluginView->mainWindow(), QStringLiteral("kateprojectinfo")); 0039 } 0040 0041 KateProjectInfoViewTerminal::~KateProjectInfoViewTerminal() 0042 { 0043 /** 0044 * avoid endless loop 0045 */ 0046 if (m_konsolePart) { 0047 disconnect(m_konsolePart, &KParts::ReadOnlyPart::destroyed, this, &KateProjectInfoViewTerminal::loadTerminal); 0048 } 0049 } 0050 0051 KPluginFactory *KateProjectInfoViewTerminal::pluginFactory() 0052 { 0053 if (s_pluginFactory) { 0054 return s_pluginFactory; 0055 } 0056 const QString konsolePart = QStringLiteral("kf6/parts/konsolepart"); 0057 return s_pluginFactory = KPluginFactory::loadFactory(konsolePart).plugin; 0058 } 0059 0060 void KateProjectInfoViewTerminal::showEvent(QShowEvent *) 0061 { 0062 /** 0063 * we delay the terminal construction until we have some part to have a usable WINDOWID, see bug 411965 0064 */ 0065 if (!m_konsolePart) { 0066 loadTerminal(); 0067 } 0068 } 0069 0070 void KateProjectInfoViewTerminal::loadTerminal() 0071 { 0072 if (hasKonsole()) { 0073 /** 0074 * null in any case, if loadTerminal fails below and we are in the destroyed event 0075 */ 0076 m_konsolePart = nullptr; 0077 setFocusProxy(nullptr); 0078 0079 /** 0080 * we shall not arrive here without a factory, if it is not there, no terminal toolview shall be created 0081 */ 0082 Q_ASSERT(pluginFactory()); 0083 0084 /** 0085 * create part 0086 */ 0087 m_konsolePart = pluginFactory()->create<KParts::ReadOnlyPart>(this); 0088 if (!m_konsolePart) { 0089 return; 0090 } 0091 0092 /** 0093 * init locale translation stuff 0094 */ 0095 // FIXME KF5 KGlobal::locale()->insertCatalog("konsole"); 0096 0097 /** 0098 * switch to right directory 0099 */ 0100 qobject_cast<TerminalInterface *>(m_konsolePart)->showShellInDir(m_directory); 0101 0102 /** 0103 * add to widget 0104 */ 0105 if (auto konsoleTabWidget = qobject_cast<QTabWidget *>(m_konsolePart->widget())) { 0106 konsoleTabWidget->setTabBarAutoHide(true); 0107 konsoleTabWidget->installEventFilter(this); 0108 } 0109 m_layout->addWidget(m_konsolePart->widget()); 0110 0111 setFocusProxy(m_konsolePart->widget()); 0112 0113 /** 0114 * guard destruction, create new terminal! 0115 */ 0116 connect(m_konsolePart, &KParts::ReadOnlyPart::destroyed, this, &KateProjectInfoViewTerminal::loadTerminal); 0117 // clang-format off 0118 connect(m_konsolePart, SIGNAL(overrideShortcut(QKeyEvent*,bool&)), this, SLOT(overrideShortcut(QKeyEvent*,bool&))); 0119 // clang-format on 0120 } 0121 } 0122 0123 void KateProjectInfoViewTerminal::overrideShortcut(QKeyEvent *keyEvent, bool &override) 0124 { 0125 if (m_showProjectInfoViewAction && !m_showProjectInfoViewAction->shortcut().isEmpty()) { 0126 int modifiers = keyEvent->modifiers(); 0127 int key = keyEvent->key(); 0128 QKeySequence k(modifiers | key); 0129 if (m_showProjectInfoViewAction->shortcut().matches(k)) { 0130 override = false; 0131 return; 0132 } 0133 } 0134 0135 /** 0136 * let konsole handle all shortcuts 0137 */ 0138 override = true; 0139 } 0140 0141 // share with konsole plugin 0142 static const QStringList s_escapeExceptions{QStringLiteral("vi"), QStringLiteral("vim"), QStringLiteral("nvim")}; 0143 0144 bool KateProjectInfoViewTerminal::ignoreEsc() const 0145 { 0146 // if konsole is not found, do not ignore esc 0147 if (!m_konsolePart && !KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("Konsole")).exists()) { 0148 return false; 0149 } 0150 0151 // If Hide with Esc is disabled in konsole settings, ignore esc press. 0152 if (!KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("Konsole")).readEntry("KonsoleEscKeyBehaviour", true)) { 0153 return true; 0154 } 0155 // Otherwise only ignore apps in given list 0156 else { 0157 const QStringList exceptList = 0158 KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("Konsole")).readEntry("KonsoleEscKeyExceptions", s_escapeExceptions); 0159 const auto app = qobject_cast<TerminalInterface *>(m_konsolePart)->foregroundProcessName(); 0160 return exceptList.contains(app); 0161 } 0162 } 0163 0164 bool KateProjectInfoViewTerminal::isLoadable() 0165 { 0166 return (pluginFactory() != nullptr); 0167 } 0168 0169 void KateProjectInfoViewTerminal::respawn(const QString &directory) 0170 { 0171 if (!isLoadable()) { 0172 return; 0173 } 0174 0175 m_directory = directory; 0176 0177 if (m_konsolePart) { 0178 disconnect(m_konsolePart, &KParts::ReadOnlyPart::destroyed, this, &KateProjectInfoViewTerminal::loadTerminal); 0179 delete m_konsolePart; 0180 } 0181 0182 loadTerminal(); 0183 } 0184 0185 static bool isCtrlShiftT(QKeyEvent *ke) 0186 { 0187 return ke->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier) && ke->key() == Qt::Key_T; 0188 } 0189 0190 bool KateProjectInfoViewTerminal::eventFilter(QObject *w, QEvent *e) 0191 { 0192 if (!m_konsolePart) { 0193 return QWidget::eventFilter(w, e); 0194 } 0195 0196 if (e->type() == QEvent::KeyPress || e->type() == QEvent::ShortcutOverride) { 0197 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e); 0198 if (isCtrlShiftT(keyEvent)) { 0199 e->accept(); 0200 auto tiface = qobject_cast<TerminalInterface *>(m_konsolePart); 0201 const auto profile = QString{}; 0202 const auto workingDir = tiface->currentWorkingDirectory(); 0203 QMetaObject::invokeMethod(m_konsolePart, "createSession", Q_ARG(QString, profile), Q_ARG(QString, workingDir)); 0204 return true; 0205 } 0206 } 0207 0208 return QWidget::eventFilter(w, e); 0209 } 0210 0211 void KateProjectInfoViewTerminal::runCommand(const QString &workingDir, const QString &cmd) 0212 { 0213 if (!m_konsolePart) { 0214 loadTerminal(); 0215 } 0216 auto terminal = qobject_cast<TerminalInterface *>(m_konsolePart); 0217 terminal->sendInput(QStringLiteral("\x05\x15")); 0218 const QString changeDirCmd = QStringLiteral("cd ") + KShell::quoteArg(workingDir) + QStringLiteral("\n"); 0219 terminal->sendInput(changeDirCmd); 0220 terminal->sendInput(cmd.trimmed() + QStringLiteral("\n")); 0221 } 0222 0223 #include "moc_kateprojectinfoviewterminal.cpp"