File indexing completed on 2024-04-21 05:40:58
0001 /* 0002 SPDX-FileCopyrightText: 2010 Sebastian Doerner <sebastian@sebastian-doerner.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "checkoutdialog.h" 0008 #include "gitwrapper.h" 0009 0010 #include <KConfigGroup> 0011 #include <KLocalizedString> 0012 0013 #include <QCheckBox> 0014 #include <QComboBox> 0015 #include <QGridLayout> 0016 #include <QGroupBox> 0017 #include <QLineEdit> 0018 #include <QRadioButton> 0019 #include <QString> 0020 #include <QVBoxLayout> 0021 #include <QDialogButtonBox> 0022 #include <QPushButton> 0023 #include <QRegularExpression> 0024 0025 CheckoutDialog::CheckoutDialog(QWidget* parent): 0026 QDialog(parent, Qt::Dialog), 0027 m_userEditedNewBranchName(false) 0028 { 0029 //branch/tag selection 0030 this->setWindowTitle(xi18nc("@title:window", "<application>Git</application> Checkout")); 0031 m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); 0032 QWidget *mainWidget = new QWidget(this); 0033 QVBoxLayout *mainLayout = new QVBoxLayout; 0034 this->setLayout(mainLayout); 0035 mainLayout->addWidget(mainWidget); 0036 QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok); 0037 okButton->setDefault(true); 0038 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0039 this->connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 0040 this->connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0041 okButton->setText(i18nc("@action:button", "Checkout")); 0042 0043 QWidget *boxWidget = new QWidget(this); 0044 QVBoxLayout *boxLayout = new QVBoxLayout(boxWidget); 0045 mainLayout->addWidget(boxWidget); 0046 0047 m_branchSelectGroupBox = new QGroupBox(boxWidget); 0048 mainLayout->addWidget(m_branchSelectGroupBox); 0049 boxLayout->addWidget(m_branchSelectGroupBox); 0050 0051 QGridLayout * gridLayout = new QGridLayout(m_branchSelectGroupBox); 0052 m_branchSelectGroupBox->setLayout(gridLayout); 0053 0054 m_branchRadioButton = new QRadioButton(i18nc("@option:radio Git Checkout","Branch:"), m_branchSelectGroupBox); 0055 m_branchRadioButton->setChecked(true); 0056 gridLayout->addWidget(m_branchRadioButton,0,0); 0057 m_branchRadioButton->setFocus(); 0058 m_branchComboBox = new QComboBox(m_branchSelectGroupBox); 0059 gridLayout->addWidget(m_branchComboBox,0,1); 0060 0061 QRadioButton * tagRadioButton = new QRadioButton(i18nc("@option:radio Git Checkout", "Tag:"), m_branchSelectGroupBox); 0062 gridLayout->addWidget(tagRadioButton,1,0); 0063 m_tagComboBox = new QComboBox(m_branchSelectGroupBox); 0064 m_tagComboBox->setEnabled(false); 0065 gridLayout->addWidget(m_tagComboBox,1,1); 0066 0067 //options 0068 QGroupBox * optionsGroupBox = new QGroupBox(boxWidget); 0069 mainLayout->addWidget(optionsGroupBox); 0070 boxLayout->addWidget(optionsGroupBox); 0071 optionsGroupBox->setTitle(i18nc("@title:group", "Options")); 0072 0073 QGridLayout * optionsGridLayout = new QGridLayout(optionsGroupBox); 0074 optionsGroupBox->setLayout(optionsGridLayout); 0075 0076 m_newBranchCheckBox = new QCheckBox(i18nc("@option:check", "Create New Branch: "), optionsGroupBox); 0077 m_newBranchCheckBox->setToolTip(i18nc("@info:tooltip", "Create a new branch based on a selected branch or tag.")); 0078 optionsGridLayout->addWidget(m_newBranchCheckBox, 0,0); 0079 0080 mainLayout->addWidget(m_buttonBox); 0081 0082 m_newBranchName = new QLineEdit(optionsGroupBox); 0083 m_newBranchName->setMinimumWidth(150); 0084 m_newBranchName->setClearButtonEnabled(true); 0085 optionsGridLayout->addWidget(m_newBranchName, 0, 1); 0086 0087 //initialize alternate color scheme for errors 0088 m_errorColors = m_newBranchName->palette(); 0089 m_errorColors.setColor(QPalette::Normal, QPalette::Base, Qt::red); 0090 m_errorColors.setColor(QPalette::Inactive, QPalette::Base, Qt::red); 0091 0092 m_forceCheckBox = new QCheckBox(i18nc("@option:check", "Force"), optionsGroupBox); 0093 m_forceCheckBox->setToolTip(i18nc("@info:tooltip", "Discard local changes.")); 0094 optionsGridLayout->addWidget(m_forceCheckBox, 1,0); 0095 0096 //get branch names 0097 GitWrapper * gitWrapper = GitWrapper::instance(); 0098 int currentBranchIndex; 0099 const QStringList branches = gitWrapper->branches(¤tBranchIndex); 0100 0101 m_branchComboBox->addItems(branches); 0102 if (currentBranchIndex == -1) { 0103 m_branchComboBox->insertItem(0, QStringLiteral("(no branch)")); 0104 m_branchComboBox->setCurrentIndex(0); 0105 } else { 0106 m_branchComboBox->setCurrentIndex(currentBranchIndex); 0107 } 0108 setDefaultNewBranchName(m_branchComboBox->currentText()); 0109 0110 //keep local branches to prevent creating an equally named new branch 0111 for (const QString& b : branches) { 0112 if (!b.startsWith(QLatin1String("remotes/"))) { 0113 //you CAN create local branches called "remotes/...", but since no sane person 0114 //would do that, we save the effort of another call to "git branch" 0115 m_branchNames.insert(b); 0116 } 0117 } 0118 0119 //get tag names 0120 const QStringList tags = gitWrapper->tags(); 0121 m_tagComboBox->addItems(tags); 0122 m_tagComboBox->setCurrentIndex(m_tagComboBox->count()-1); 0123 if (m_tagComboBox->count() == 0){ 0124 tagRadioButton->setEnabled(false); 0125 const QString tooltip = i18nc("@info:tooltip", "There are no tags in this repository."); 0126 tagRadioButton->setToolTip(tooltip); 0127 m_tagComboBox->setToolTip(tooltip); 0128 } 0129 0130 //signals 0131 connect(m_branchRadioButton, &QAbstractButton::toggled, 0132 this, &CheckoutDialog::branchRadioButtonToggled); 0133 connect(m_branchComboBox, SIGNAL(currentIndexChanged(QString)), 0134 this, SLOT(setDefaultNewBranchName(QString))); 0135 connect(m_branchComboBox, SIGNAL(currentIndexChanged(QString)), 0136 this, SLOT(setOkButtonState())); 0137 connect(m_tagComboBox, SIGNAL(currentIndexChanged(QString)), 0138 this, SLOT(setDefaultNewBranchName(QString))); 0139 connect(m_newBranchCheckBox, &QCheckBox::stateChanged, 0140 this, &CheckoutDialog::newBranchCheckBoxStateToggled); 0141 connect(m_newBranchName, &QLineEdit::textChanged, 0142 this, &CheckoutDialog::setOkButtonState); 0143 connect(m_newBranchName, &QLineEdit::textEdited, 0144 this, &CheckoutDialog::noteUserEditedNewBranchName); 0145 //set initial widget states 0146 newBranchCheckBoxStateToggled(Qt::Unchecked); 0147 } 0148 0149 QString CheckoutDialog::checkoutIdentifier() const 0150 { 0151 QString identifier = m_branchComboBox->isEnabled() ? m_branchComboBox->currentText() : m_tagComboBox->currentText(); 0152 if (identifier.length()==0 || identifier.at(0)==QLatin1Char('(')) { 0153 identifier = QString(); 0154 } 0155 return identifier; 0156 } 0157 0158 bool CheckoutDialog::force() const 0159 { 0160 return m_forceCheckBox->isChecked(); 0161 } 0162 0163 QString CheckoutDialog::newBranchName() const 0164 { 0165 if (m_newBranchCheckBox->isChecked()) { 0166 return m_newBranchName->text().trimmed(); 0167 } else { 0168 return QString(); 0169 } 0170 } 0171 0172 void CheckoutDialog::branchRadioButtonToggled(bool checked) 0173 { 0174 m_branchComboBox->setEnabled(checked); 0175 m_tagComboBox->setEnabled(!checked); 0176 setDefaultNewBranchName(checked ? m_branchComboBox->currentText() : m_tagComboBox->currentText()); 0177 setOkButtonState(); 0178 } 0179 0180 void CheckoutDialog::newBranchCheckBoxStateToggled(int state) 0181 { 0182 m_newBranchName->setEnabled(state == Qt::Checked); 0183 m_branchSelectGroupBox->setTitle( 0184 state == Qt::Checked ? 0185 i18nc("@title:group", "Branch Base") : 0186 i18nc("@title:group", "Checkout")); 0187 if (state == Qt::Checked) { 0188 m_newBranchName->setFocus(Qt::TabFocusReason); 0189 } 0190 setOkButtonState(); 0191 } 0192 0193 void CheckoutDialog::setOkButtonState() 0194 { 0195 //default to enabled 0196 bool enableButton = true; 0197 bool newNameError = false; 0198 QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok); 0199 0200 //------------disable on these conditions---------------// 0201 if (m_newBranchCheckBox->isChecked()) { 0202 const QString newBranchName = m_newBranchName->text().trimmed(); 0203 if (newBranchName.isEmpty()){ 0204 enableButton = false; 0205 newNameError = true; 0206 const QString tt = i18nc("@info:tooltip", "You must enter a valid name for the new branch first."); 0207 m_newBranchName->setToolTip(tt); 0208 okButton->setToolTip(tt); 0209 } 0210 if (m_branchNames.contains(newBranchName)) { 0211 enableButton = false; 0212 newNameError = true; 0213 const QString tt = i18nc("@info:tooltip", "A branch with the name '%1' already exists.", newBranchName); 0214 m_newBranchName->setToolTip(tt); 0215 okButton->setToolTip(tt); 0216 } 0217 if (newBranchName.contains(QRegularExpression(QStringLiteral("\\s")))) { 0218 enableButton = false; 0219 newNameError = true; 0220 const QString tt = i18nc("@info:tooltip", "Branch names may not contain any whitespace."); 0221 m_newBranchName->setToolTip(tt); 0222 okButton->setToolTip(tt); 0223 } 0224 } //if we create a new branch and no valid branch is selected we create one based on the currently checked out version 0225 else if (m_branchRadioButton->isChecked() && m_branchComboBox->currentText().at(0) == QLatin1Char('(')){ 0226 enableButton = false; 0227 okButton->setToolTip(i18nc("@info:tooltip", "You must select a valid branch first.")); 0228 } 0229 //------------------------------------------------------// 0230 0231 setLineEditErrorModeActive(newNameError); 0232 okButton->setEnabled(enableButton); 0233 if (!newNameError) { 0234 m_newBranchName->setToolTip(QString()); 0235 } 0236 if (enableButton) { 0237 okButton->setToolTip(QString()); 0238 } 0239 } 0240 0241 void CheckoutDialog::setDefaultNewBranchName(const QString& baseBranchName) 0242 { 0243 if (!m_userEditedNewBranchName) { 0244 if (baseBranchName.startsWith(QLatin1Char('('))) { 0245 m_newBranchName->setText(QString()); 0246 } else { 0247 m_newBranchName->setText(i18nc("@item:intext Prepended to the current branch name " 0248 "to get the default name for a newly created branch", "branch") + QLatin1Char('_') + baseBranchName); 0249 } 0250 } 0251 } 0252 0253 void CheckoutDialog::noteUserEditedNewBranchName() 0254 { 0255 m_userEditedNewBranchName = true; 0256 } 0257 0258 void CheckoutDialog::setLineEditErrorModeActive(bool active) 0259 { 0260 m_newBranchName->setPalette(active ? m_errorColors : QPalette()); 0261 } 0262 0263 0264 #include "moc_checkoutdialog.cpp"