File indexing completed on 2024-04-28 17:06:04
0001 /* 0002 SPDX-FileCopyrightText: 2000 Shie Erlich <krusader@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2000 Rafi Yanai <krusader@users.sourceforge.net> 0004 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "kcmdline.h" 0010 0011 // QtCore 0012 #include <QDir> 0013 #include <QStringList> 0014 #include <QUrl> 0015 // QtGui 0016 #include <QFontDatabase> 0017 #include <QFontMetrics> 0018 #include <QIcon> 0019 #include <QImage> 0020 #include <QKeyEvent> 0021 // QtWidgets 0022 #include <QFrame> 0023 #include <QGridLayout> 0024 #include <QLabel> 0025 #include <QSizePolicy> 0026 0027 #include <KConfigCore/KSharedConfig> 0028 #include <KI18n/KLocalizedString> 0029 #include <utility> 0030 0031 #include "../ActionMan/addplaceholderpopup.h" 0032 #include "../compat.h" 0033 #include "../defaults.h" 0034 #include "../icon.h" 0035 #include "../krglobal.h" 0036 #include "../krservices.h" 0037 #include "../krslots.h" 0038 #include "../krusaderview.h" 0039 #include "kcmdmodebutton.h" 0040 0041 CmdLineCombo::CmdLineCombo(QWidget *parent) 0042 : KrHistoryComboBox(parent) 0043 , _handlingLineEditResize(false) 0044 { 0045 lineEdit()->installEventFilter(this); 0046 _pathLabel = new QLabel(this); 0047 _pathLabel->setWhatsThis(i18n("Name of folder where command will be processed.")); 0048 _pathLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); 0049 } 0050 0051 bool CmdLineCombo::eventFilter(QObject *watched, QEvent *e) 0052 { 0053 if (watched == lineEdit() && (e->type() == QEvent::Move || e->type() == QEvent::Resize)) { 0054 if (!_handlingLineEditResize) { // avoid infinite recursion 0055 _handlingLineEditResize = true; 0056 updateLineEditGeometry(); 0057 _handlingLineEditResize = false; 0058 } 0059 } 0060 return false; 0061 } 0062 0063 void CmdLineCombo::setPath(QString path) 0064 { 0065 _path = std::move(path); 0066 doLayout(); 0067 } 0068 0069 void CmdLineCombo::updateLineEditGeometry() 0070 { 0071 QRect r = lineEdit()->geometry(); 0072 r.setLeft(_pathLabel->geometry().right()); 0073 lineEdit()->setGeometry(r); 0074 } 0075 0076 void CmdLineCombo::doLayout() 0077 { 0078 QString pathNameLabel = _path; 0079 QFontMetrics fm(_pathLabel->fontMetrics()); 0080 int textWidth = fm.horizontalAdvance(_path); 0081 int maxWidth = (width() + _pathLabel->width()) * 2 / 5; 0082 int letters = _path.length() / 2; 0083 0084 while (letters && textWidth > maxWidth) { 0085 pathNameLabel = _path.left(letters) + "..." + _path.right(letters); 0086 letters--; 0087 textWidth = fm.horizontalAdvance(pathNameLabel); 0088 } 0089 0090 _pathLabel->setText(pathNameLabel + "> "); 0091 _pathLabel->adjustSize(); 0092 0093 QStyleOptionComboBox opt; 0094 initStyleOption(&opt); 0095 QRect labelRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this); 0096 labelRect.adjust(2, 0, 0, 0); 0097 labelRect.setWidth(_pathLabel->width()); 0098 _pathLabel->setGeometry(labelRect); 0099 0100 updateLineEditGeometry(); 0101 } 0102 0103 void CmdLineCombo::resizeEvent(QResizeEvent *e) 0104 { 0105 KrHistoryComboBox::resizeEvent(e); 0106 doLayout(); 0107 } 0108 0109 void CmdLineCombo::keyPressEvent(QKeyEvent *e) 0110 { 0111 switch (e->key()) { 0112 case Qt::Key_Enter: 0113 case Qt::Key_Return: 0114 if (e->modifiers() & Qt::ControlModifier) { 0115 SLOTS->insertFileName((e->modifiers() & Qt::ShiftModifier) != 0); 0116 break; 0117 } 0118 KrHistoryComboBox::keyPressEvent(e); 0119 break; 0120 case Qt::Key_Down: 0121 if (e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { 0122 MAIN_VIEW->focusTerminalEmulator(); 0123 return; 0124 } else 0125 KrHistoryComboBox::keyPressEvent(e); 0126 break; 0127 case Qt::Key_Up: 0128 if (e->modifiers() == Qt::ControlModifier || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { 0129 emit returnToPanel(); 0130 return; 0131 } else 0132 KrHistoryComboBox::keyPressEvent(e); 0133 break; 0134 case Qt::Key_Escape: 0135 if (e->modifiers() == 0) { 0136 emit returnToPanel(); 0137 return; 0138 } else 0139 KrHistoryComboBox::keyPressEvent(e); 0140 break; 0141 default: 0142 KrHistoryComboBox::keyPressEvent(e); 0143 } 0144 } 0145 0146 KCMDLine::KCMDLine(QWidget *parent) 0147 : QWidget(parent) 0148 { 0149 auto *layout = new QGridLayout(this); 0150 layout->setSpacing(0); 0151 layout->setContentsMargins(0, 0, 0, 0); 0152 0153 int height = QFontMetrics(QFontDatabase::systemFont(QFontDatabase::GeneralFont)).height(); 0154 height = height + 5 * (height > 14) + 6; 0155 0156 // and editable command line 0157 completion.setMode(KUrlCompletion::FileCompletion); 0158 cmdLine = new CmdLineCombo(this); 0159 cmdLine->setMaxCount(100); // remember 100 commands 0160 cmdLine->setMinimumContentsLength(10); 0161 cmdLine->setDuplicatesEnabled(false); 0162 cmdLine->setMaximumHeight(height); 0163 cmdLine->setCompletionObject(&completion); 0164 cmdLine->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); 0165 // load the history 0166 KConfigGroup grpSvr(krConfig, "Private"); 0167 QStringList list = grpSvr.readEntry("cmdline history", QStringList()); 0168 cmdLine->setHistoryItems(list); 0169 0170 connect(cmdLine, QOverload<const QString &>::of(&CmdLineCombo::returnPressed), this, &KCMDLine::slotRun); 0171 connect(cmdLine, QOverload<const QString &>::of(&CmdLineCombo::returnPressed), cmdLine->lineEdit(), &QLineEdit::clear); 0172 connect(cmdLine, &CmdLineCombo::returnToPanel, this, &KCMDLine::slotReturnFocus); 0173 0174 cmdLine->setWhatsThis( 0175 i18n("<qt><p>Well, it is actually quite simple: you type your command here and Krusader obeys.</p><p><b>Tip</b>: move within command line history with " 0176 "<Up> and <Down> arrows.</p></qt>")); 0177 layout->addWidget(cmdLine, 0, 1); 0178 0179 buttonAddPlaceholder = new QToolButton(this); 0180 buttonAddPlaceholder->setAutoRaise(true); 0181 buttonAddPlaceholder->setIcon(Icon("list-add")); 0182 connect(buttonAddPlaceholder, &QToolButton::clicked, this, &KCMDLine::addPlaceholder); 0183 buttonAddPlaceholder->setWhatsThis(i18n("Add <b>Placeholders</b> for the selected files in the panel.")); 0184 0185 layout->addWidget(buttonAddPlaceholder, 0, 2); 0186 0187 // a run in terminal button 0188 terminal = new KCMDModeButton(this); 0189 terminal->setAutoRaise(true); 0190 layout->addWidget(terminal, 0, 3); 0191 0192 layout->activate(); 0193 } 0194 0195 KCMDLine::~KCMDLine() 0196 { 0197 KConfigGroup grpSvr(krConfig, "Private"); 0198 QStringList list = cmdLine->historyItems(); 0199 // qWarning() << list[0]; 0200 grpSvr.writeEntry("cmdline history", list); 0201 krConfig->sync(); 0202 } 0203 0204 void KCMDLine::addPlaceholder() 0205 { 0206 AddPlaceholderPopup popup(this); 0207 QString exp = popup.getPlaceholder(buttonAddPlaceholder->mapToGlobal(QPoint(0, 0))); 0208 this->addText(exp); 0209 } 0210 0211 void KCMDLine::setCurrent(const QString &path) 0212 { 0213 cmdLine->setPath(path); 0214 0215 completion.setDir(QUrl::fromLocalFile(path)); 0216 // make sure our command is executed in the right directory 0217 // This line is important for Krusader overall functions -> do not remove ! 0218 QDir::setCurrent(path); 0219 } 0220 0221 void KCMDLine::slotRun() 0222 { 0223 const QString command1(cmdLine->currentText()); 0224 if (command1.isEmpty()) 0225 return; 0226 0227 cmdLine->addToHistory(command1); 0228 // bugfix by aardvark: current editline is destroyed by addToHistory() in some cases 0229 cmdLine->setEditText(command1); 0230 0231 if (command1.simplified().left(3) == "cd ") { // cd command effect the active panel 0232 QString dir = command1.right(command1.length() - command1.indexOf(" ")).trimmed(); 0233 if (dir == "~") 0234 dir = QDir::homePath(); 0235 else if (dir.left(1) != "/" && !dir.contains(":/")) 0236 dir = cmdLine->path() + (cmdLine->path() == "/" ? "" : "/") + dir; 0237 SLOTS->refresh(QUrl::fromUserInput(dir, QDir::currentPath(), QUrl::AssumeLocalFile)); 0238 } else { 0239 exec(); 0240 cmdLine->clearEditText(); 0241 } 0242 } 0243 0244 void KCMDLine::slotReturnFocus() 0245 { 0246 MAIN_VIEW->cmdLineUnFocus(); 0247 } 0248 0249 static const KrActionBase::ExecType execModesMenu[] = { 0250 KrActionBase::Normal, 0251 KrActionBase::CollectOutputSeparateStderr, 0252 KrActionBase::CollectOutput, 0253 KrActionBase::Terminal, 0254 KrActionBase::RunInTE, 0255 }; 0256 0257 QString KCMDLine::command() const 0258 { 0259 return cmdLine->currentText(); 0260 } 0261 0262 KrActionBase::ExecType KCMDLine::execType() const 0263 { 0264 KConfigGroup grp(krConfig, "Private"); 0265 int i = grp.readEntry("Command Execution Mode", (int)0); 0266 return execModesMenu[i]; 0267 } 0268 0269 QString KCMDLine::startpath() const 0270 { 0271 return cmdLine->path(); 0272 // return path->text().left(path->text().length() - 1); 0273 } 0274 0275 QString KCMDLine::user() const 0276 { 0277 return QString(); 0278 } 0279 0280 QString KCMDLine::text() const 0281 { 0282 return cmdLine->currentText(); 0283 } 0284 0285 bool KCMDLine::acceptURLs() const 0286 { 0287 return false; 0288 } 0289 0290 bool KCMDLine::confirmExecution() const 0291 { 0292 return false; 0293 } 0294 0295 bool KCMDLine::doSubstitution() const 0296 { 0297 return true; 0298 } 0299 0300 void KCMDLine::setText(const QString &text) 0301 { 0302 cmdLine->lineEdit()->setText(text); 0303 }