File indexing completed on 2024-04-21 05:41:00
0001 /* 0002 SPDX-FileCopyrightText: 2011 Vishesh Yadav <vishesh3y@gmail.com> 0003 SPDX-FileCopyrightText: 2015 Tomasz Bojczuk <seelook@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "commitdialog.h" 0009 #include "hgwrapper.h" 0010 #include "fileviewhgpluginsettings.h" 0011 0012 #include <QGroupBox> 0013 #include <QGridLayout> 0014 #include <QLabel> 0015 #include <QActionGroup> 0016 #include <QPlainTextEdit> 0017 #include <QMenu> 0018 #include <QAction> 0019 #include <QLineEdit> 0020 #include <QSplitter> 0021 #include <KTextEditor/Document> 0022 #include <KTextEditor/View> 0023 #include <KTextEditor/Editor> 0024 #include <KMessageBox> 0025 #include <KLocalizedString> 0026 0027 HgCommitDialog::HgCommitDialog(QWidget *parent): 0028 DialogBase(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, parent) 0029 { 0030 // dialog properties 0031 this->setWindowTitle(xi18nc("@title:window", 0032 "<application>Hg</application> Commit")); 0033 0034 okButton()->setText(xi18nc("@action:button", "Commit")); 0035 okButton()->setDisabled(true); 0036 0037 // To show diff between commit 0038 KTextEditor::Editor *editor = KTextEditor::Editor::instance(); 0039 if (!editor) { 0040 KMessageBox::error(this, 0041 i18n("The KTextEditor component could not be found;" 0042 "\nplease check your KDE Frameworks installation.")); 0043 return; 0044 } 0045 m_fileDiffDoc = editor->createDocument(nullptr); 0046 m_fileDiffView = qobject_cast<KTextEditor::View*>(m_fileDiffDoc->createView(this)); 0047 m_fileDiffView->setStatusBarEnabled(false); 0048 m_fileDiffDoc->setReadWrite(false); 0049 0050 // Setup actions 0051 m_useCurrentBranch = new QAction(this); 0052 m_useCurrentBranch->setCheckable(true); 0053 m_useCurrentBranch->setText(xi18nc("@action:inmenu", 0054 "Commit to current branch")); 0055 0056 m_newBranch = new QAction(this); 0057 m_newBranch->setCheckable(true); 0058 m_newBranch->setText(xi18nc("@action:inmenu", 0059 "Create new branch")); 0060 0061 m_closeBranch = new QAction(this); 0062 m_closeBranch->setCheckable(true); 0063 m_closeBranch->setText(xi18nc("@action:inmenu", 0064 "Close current branch")); 0065 0066 m_branchMenu = new QMenu(this); 0067 m_branchMenu->addAction(m_useCurrentBranch); 0068 m_branchMenu->addAction(m_newBranch); 0069 m_branchMenu->addAction(m_closeBranch); 0070 0071 QActionGroup *branchActionGroup = new QActionGroup(this); 0072 branchActionGroup->addAction(m_useCurrentBranch); 0073 branchActionGroup->addAction(m_newBranch); 0074 branchActionGroup->addAction(m_closeBranch); 0075 m_useCurrentBranch->setChecked(true); 0076 connect(branchActionGroup, &QActionGroup::triggered, 0077 this, &HgCommitDialog::slotBranchActions); 0078 0079 0080 ////////////// 0081 // Setup UI // 0082 ////////////// 0083 0084 // Top bar of buttons 0085 QHBoxLayout *topBarLayout = new QHBoxLayout; 0086 m_copyMessageButton = new QPushButton(i18n("Copy Message")); 0087 m_branchButton = new QPushButton(i18n("Branch")); 0088 0089 m_copyMessageMenu = new QMenu(this); 0090 createCopyMessageMenu(); 0091 0092 topBarLayout->addWidget(new QLabel(getParentForLabel())); 0093 topBarLayout->addStretch(); 0094 topBarLayout->addWidget(m_branchButton); 0095 topBarLayout->addWidget(m_copyMessageButton); 0096 m_branchButton->setMenu(m_branchMenu); 0097 m_copyMessageButton->setMenu(m_copyMessageMenu); 0098 0099 // the commit box itself 0100 QGroupBox *messageGroupBox = new QGroupBox; 0101 QVBoxLayout *commitLayout = new QVBoxLayout; 0102 m_commitMessage = editor->createDocument(nullptr); 0103 KTextEditor::View *messageView = 0104 qobject_cast<KTextEditor::View*>(m_commitMessage->createView(this)); 0105 messageView->setStatusBarEnabled(false); 0106 messageView->setMinimumHeight(fontMetrics().height() * 4); 0107 commitLayout->addWidget(messageView); 0108 messageGroupBox->setTitle(xi18nc("@title:group", "Commit Message")); 0109 messageGroupBox->setLayout(commitLayout); 0110 0111 // Show diff here 0112 QGroupBox *diffGroupBox = new QGroupBox; 0113 QVBoxLayout *diffLayout = new QVBoxLayout(diffGroupBox); 0114 diffLayout->addWidget(m_fileDiffView); 0115 diffGroupBox->setTitle(xi18nc("@title:group", "Diff/Content")); 0116 diffGroupBox->setLayout(diffLayout); 0117 0118 // Set up layout for Status, Commit and Diff boxes 0119 m_verticalSplitter = new QSplitter(Qt::Horizontal); 0120 m_horizontalSplitter = new QSplitter(Qt::Vertical); 0121 m_horizontalSplitter->addWidget(messageGroupBox); 0122 m_horizontalSplitter->addWidget(diffGroupBox); 0123 m_statusList = new HgStatusList; 0124 m_verticalSplitter->addWidget(m_statusList); 0125 m_verticalSplitter->addWidget(m_horizontalSplitter); 0126 0127 // Set up layout and container for main dialog 0128 QVBoxLayout *mainLayout = new QVBoxLayout; 0129 mainLayout->addLayout(topBarLayout); 0130 mainLayout->addWidget(m_verticalSplitter); 0131 layout()->insertLayout(0, mainLayout); 0132 0133 slotBranchActions(m_useCurrentBranch); 0134 slotInitDiffOutput(); // initialize with whole repo diff 0135 0136 // Load saved settings 0137 FileViewHgPluginSettings *settings = FileViewHgPluginSettings::self(); 0138 this->resize(QSize(settings->commitDialogWidth(), 0139 settings->commitDialogHeight())); 0140 0141 m_verticalSplitter->setSizes(settings->verticalSplitterSizes()); 0142 m_horizontalSplitter->setSizes(settings->horizontalSplitterSizes()); 0143 0144 messageView->setFocus(); // message editor ready to get a text 0145 0146 connect(m_statusList, &HgStatusList::itemSelectionChanged, 0147 this, &HgCommitDialog::slotItemSelectionChanged); 0148 connect(m_commitMessage, &KTextEditor::Document::textChanged, 0149 this, &HgCommitDialog::slotMessageChanged); 0150 connect(this, SIGNAL(finished(int)), this, SLOT(saveGeometry())); 0151 } 0152 0153 QString HgCommitDialog::getParentForLabel() 0154 { 0155 HgWrapper *hgWrapper = HgWrapper::instance(); 0156 const QString line = QLatin1String("<b>parents:</b> ") + hgWrapper->getParentsOfHead(); 0157 return line; 0158 } 0159 0160 void HgCommitDialog::slotInitDiffOutput() 0161 { 0162 m_fileDiffDoc->setReadWrite(true); 0163 m_fileDiffDoc->setModified(false); 0164 m_fileDiffDoc->closeUrl(true); 0165 0166 QString diffOut; 0167 HgWrapper *hgWrapper = HgWrapper::instance(); 0168 hgWrapper->executeCommand(QStringLiteral("diff"), QStringList(), diffOut); 0169 m_fileDiffDoc->setHighlightingMode(QStringLiteral("diff")); 0170 m_fileDiffDoc->setText(diffOut); 0171 m_fileDiffView->setCursorPosition( KTextEditor::Cursor(0, 0) ); 0172 m_fileDiffDoc->setReadWrite(false); 0173 } 0174 0175 void HgCommitDialog::slotItemSelectionChanged(const char status, 0176 const QString &fileName) 0177 { 0178 m_fileDiffDoc->setReadWrite(true); 0179 m_fileDiffDoc->setModified(false); 0180 m_fileDiffDoc->closeUrl(true); 0181 0182 if (status != '?') { 0183 QStringList arguments; 0184 QString diffOut; 0185 HgWrapper *hgWrapper = HgWrapper::instance(); 0186 0187 arguments << fileName; 0188 hgWrapper->executeCommand(QStringLiteral("diff"), arguments, diffOut); 0189 m_fileDiffDoc->setText(diffOut); 0190 m_fileDiffDoc->setHighlightingMode(QStringLiteral("diff")); 0191 } 0192 else { 0193 QUrl url = QUrl::fromLocalFile(HgWrapper::instance()->getBaseDir()); 0194 url = url.adjusted(QUrl::StripTrailingSlash); 0195 url.setPath(url.path() + QLatin1Char('/') + fileName); 0196 m_fileDiffDoc->openUrl(url); 0197 } 0198 0199 m_fileDiffDoc->setReadWrite(false); 0200 m_fileDiffView->setCursorPosition( KTextEditor::Cursor(0, 0) ); 0201 } 0202 0203 void HgCommitDialog::slotMessageChanged() 0204 { 0205 okButton()->setDisabled(m_commitMessage->isEmpty()); 0206 } 0207 0208 void HgCommitDialog::done(int r) 0209 { 0210 if (r == QDialog::Accepted) { 0211 QStringList files; 0212 if (m_statusList->getSelectionForCommit(files)) { 0213 HgWrapper *hgWrapper = HgWrapper::instance(); 0214 if (m_branchAction == NewBranch) { 0215 if (!hgWrapper->createBranch(m_newBranchName)) { 0216 KMessageBox::error(this, 0217 i18n("Could not create branch! Aborting commit!")); 0218 return; 0219 } 0220 } 0221 bool success = hgWrapper->commit(m_commitMessage->text(), 0222 files, m_branchAction==CloseBranch); 0223 if (success) { 0224 QDialog::done(r); 0225 } 0226 else { 0227 KMessageBox::error(this, i18n("Commit unsuccessful!")); 0228 } 0229 } 0230 else { 0231 KMessageBox::error(this, i18n("No files for commit!")); 0232 } 0233 } 0234 else { 0235 QDialog::done(r); 0236 } 0237 } 0238 0239 void HgCommitDialog::saveGeometry() 0240 { 0241 FileViewHgPluginSettings *settings = FileViewHgPluginSettings::self(); 0242 settings->setCommitDialogHeight(this->height()); 0243 settings->setCommitDialogWidth(this->width()); 0244 settings->setHorizontalSplitterSizes(m_horizontalSplitter->sizes()); 0245 settings->setVerticalSplitterSizes(m_verticalSplitter->sizes()); 0246 settings->save(); 0247 } 0248 0249 void HgCommitDialog::slotBranchActions(QAction *action) 0250 { 0251 HgWrapper *hgWrapper = HgWrapper::instance(); 0252 QString currentBranch; 0253 hgWrapper->executeCommand(QStringLiteral("branch"), QStringList(), currentBranch); 0254 currentBranch.replace(QLatin1Char('\n'), QString()); 0255 currentBranch = QLatin1String(" (") + currentBranch + QLatin1Char(')'); 0256 if (action == m_useCurrentBranch) { 0257 m_branchAction = NoChanges; 0258 m_branchButton->setText(i18n("Branch: Current Branch") + currentBranch); 0259 } 0260 else if (action == m_newBranch) { 0261 NewBranchDialog diag; 0262 if (diag.exec() == QDialog::Accepted) { 0263 m_branchAction = NewBranch; 0264 m_newBranchName = diag.getBranchName(); 0265 m_branchButton->setText(i18n("Branch: ") + m_newBranchName); 0266 } 0267 else { // restore previous check state 0268 if (m_branchAction == NoChanges) { 0269 m_useCurrentBranch->setChecked(true); 0270 } 0271 else if (m_branchAction == CloseBranch) { 0272 m_closeBranch->setChecked(true); 0273 } 0274 } 0275 } 0276 else if (action == m_closeBranch) { 0277 m_branchAction = CloseBranch; 0278 m_branchButton->setText(i18n("Branch: Close Current") + currentBranch); 0279 } 0280 } 0281 0282 /*****************/ 0283 /* Branch Dialog */ 0284 /*****************/ 0285 0286 NewBranchDialog::NewBranchDialog(QWidget *parent): 0287 QDialog(parent) 0288 { 0289 // dialog properties 0290 this->setWindowTitle(xi18nc("@title:window", 0291 "<application>Hg</application> Commit: New Branch")); 0292 QDialogButtonBox *buttonBox= new QDialogButtonBox(QDialogButtonBox::Cancel, this); 0293 m_okButton = buttonBox->addButton(QDialogButtonBox::Ok); 0294 m_okButton->setDisabled(true); 0295 m_okButton->setDefault(true); 0296 0297 m_branchList = HgWrapper::instance()->getBranches(); 0298 0299 QLabel *message = new QLabel(xi18nc("@label", "Enter new branch name")); 0300 m_branchNameInput = new QLineEdit; 0301 m_errorLabel = new QLabel; 0302 0303 QVBoxLayout *layout = new QVBoxLayout; 0304 layout->addWidget(message); 0305 layout->addWidget(m_branchNameInput); 0306 layout->addWidget(m_errorLabel); 0307 layout->addWidget(buttonBox); 0308 0309 setLayout(layout); 0310 0311 connect(m_branchNameInput, &QLineEdit::textChanged, 0312 this, &NewBranchDialog::slotTextChanged); 0313 connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 0314 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0315 } 0316 0317 void NewBranchDialog::slotTextChanged(const QString &text) 0318 { 0319 if (m_branchList.contains(text)) { 0320 m_errorLabel->setText(xi18nc("@label", "<b>Branch already exists!</b>")); 0321 m_okButton->setDisabled(true); 0322 } 0323 else if (text.length() > 0) { 0324 m_errorLabel->clear(); 0325 m_okButton->setDisabled(false); 0326 } 0327 else { 0328 m_errorLabel->setText(xi18nc("@label", "<b>Enter some text!</b>")); 0329 m_okButton->setDisabled(true); 0330 } 0331 } 0332 0333 QString NewBranchDialog::getBranchName() const 0334 { 0335 return m_branchNameInput->text(); 0336 } 0337 0338 void HgCommitDialog::createCopyMessageMenu() 0339 { 0340 QActionGroup *actionGroup = new QActionGroup(this); 0341 connect(actionGroup, &QActionGroup::triggered, 0342 this, &HgCommitDialog::slotInsertCopyMessage); 0343 0344 const QStringList args{ 0345 QStringLiteral("--limit"), 0346 QStringLiteral("7"), 0347 QStringLiteral("--template"), 0348 QStringLiteral("{desc}\n"), 0349 }; 0350 // args << QLatin1String("{desc|short}\n"); 0351 0352 HgWrapper *hgw = HgWrapper::instance(); 0353 QString output; 0354 hgw->executeCommand(QStringLiteral("log"), args, output); 0355 0356 const QStringList messages = output.split(QLatin1Char('\n'), Qt::SkipEmptyParts); 0357 for (const QString &msg : messages) { 0358 QAction *action = m_copyMessageMenu->addAction(msg.left(40)); // max 40 characters 0359 action->setData(msg); // entire description into action data 0360 actionGroup->addAction(action); 0361 } 0362 } 0363 0364 void HgCommitDialog::slotInsertCopyMessage(QAction *action) 0365 { 0366 m_commitMessage->setText(action->data().toString()); 0367 } 0368 0369 0370 0371 #include "moc_commitdialog.cpp"