File indexing completed on 2024-05-12 17:16:02

0001 /***************************************************************************
0002  *   Copyright (C) 2005-2009 by Rajko Albrecht                             *
0003  *   ral@alwins-world.de                                                   *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0019  ***************************************************************************/
0020 #include "commitmsg_impl.h"
0021 #include "models/commitmodelhelper.h"
0022 #include "models/commitmodel.h"
0023 #include "settings/kdesvnsettings.h"
0024 #include "depthselector.h"
0025 #include "ksvnwidgets/ksvndialog.h"
0026 
0027 #include <KConfig>
0028 #include <KFile>
0029 #include <KIO/FileCopyJob>
0030 #include <KJobWidgets>
0031 #include <KLocalizedString>
0032 #include <KMessageBox>
0033 #include <KUrlRequester>
0034 #include <KUrlRequesterDialog>
0035 
0036 #include <QStringList>
0037 #include <QTemporaryFile>
0038 #include <QFile>
0039 
0040 #define MAX_MESSAGE_HISTORY 10
0041 
0042 QStringList Commitmsg_impl::sLogHistory = QStringList();
0043 QString Commitmsg_impl::sLastMessage;
0044 
0045 int Commitmsg_impl::smax_message_history = 0xFFFF;
0046 
0047 Commitmsg_impl::Commitmsg_impl(QWidget *parent)
0048     : QWidget(parent), CommitMessage()
0049 {
0050     setupUi(this);
0051     m_CurrentModel = nullptr;
0052     m_SortModel = nullptr;
0053     m_LogEdit->setFocus();
0054     m_Reviewlabel->hide();
0055     m_hidden = true;
0056     hideButtons(true);
0057     m_MainSplitter->insertWidget(0, m_EditFrame);
0058     delete m_ReviewFrame;
0059     m_Reviewlabel = nullptr;
0060     m_MarkUnversioned = nullptr;
0061     m_UnmarkUnversioned = nullptr;
0062     m_DiffItem = nullptr;
0063 }
0064 
0065 Commitmsg_impl::Commitmsg_impl(const svn::CommitItemList &_items, QWidget *parent)
0066     : QWidget(parent), CommitMessage()
0067 {
0068     setupUi(this);
0069     m_CurrentModel = nullptr;
0070     m_SortModel = nullptr;
0071     m_LogEdit->setFocus();
0072     hideButtons(true);
0073     if (!_items.isEmpty()) {
0074         m_CurrentModel = new CommitModel(_items);
0075         setupModel();
0076         m_hidden = false;
0077     } else {
0078         m_Reviewlabel->hide();
0079         m_CommitItemTree->hide();
0080         m_hidden = true;
0081     }
0082     checkSplitterSize();
0083 }
0084 
0085 Commitmsg_impl::Commitmsg_impl(const CommitActionEntries &_activatedList,
0086                                const CommitActionEntries &_notActivatedList,
0087                                QWidget *parent)
0088     : QWidget(parent), CommitMessage()
0089 {
0090     setupUi(this);
0091     m_CurrentModel = nullptr;
0092     m_SortModel = nullptr;
0093     m_LogEdit->setFocus();
0094     m_hidden = false;
0095 
0096     m_CurrentModel = new CommitModelCheckitem(_activatedList, _notActivatedList);
0097     setupModel();
0098 
0099     m_HideNewItems->setChecked(Kdesvnsettings::commit_hide_new());
0100     checkSplitterSize();
0101 }
0102 
0103 Commitmsg_impl::~Commitmsg_impl()
0104 {
0105     QList<int> list = m_MainSplitter->sizes();
0106     if (!m_hidden && list.count() == 2) {
0107         Kdesvnsettings::setCommit_splitter_height(list);
0108         Kdesvnsettings::self()->save();
0109     }
0110     delete m_CurrentModel;
0111     delete m_SortModel;
0112 }
0113 
0114 void Commitmsg_impl::setupModel()
0115 {
0116     m_SortModel = new CommitFilterModel(m_CommitItemTree);
0117     m_CommitItemTree->setModel(m_SortModel);
0118     m_SortModel->setSourceModel(m_CurrentModel);
0119 
0120     m_CommitItemTree->resizeColumnToContents(m_CurrentModel->ItemColumn());
0121     m_CommitItemTree->resizeColumnToContents(m_CurrentModel->ActionColumn());
0122 
0123     m_SortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
0124     connect(m_CommitItemTree->selectionModel(), &QItemSelectionModel::currentChanged,
0125             this, &Commitmsg_impl::slotCurrentItemChanged);
0126     slotCurrentItemChanged(QModelIndex()); // update pushbuttons
0127 }
0128 
0129 void Commitmsg_impl::checkSplitterSize()
0130 {
0131     QList<int> list = Kdesvnsettings::commit_splitter_height();
0132     if (list.count() != 2) {
0133         return;
0134     }
0135     if (m_hidden) {
0136         list[1] = list[0] + list[1];
0137         list[0] = 0;
0138     }
0139     if (m_hidden || (list[0] > 0 || list[1] > 0)) {
0140         m_MainSplitter->setSizes(list);
0141     }
0142 }
0143 
0144 void Commitmsg_impl::slotHistoryActivated(int number)
0145 {
0146     if (number < 1 || number > sLogHistory.size()) {
0147         m_LogEdit->clear();
0148     } else {
0149         m_LogEdit->setText(sLogHistory[number - 1]);
0150     }
0151 }
0152 
0153 /*!
0154     \fn Commitmsg_impl::getMessage()const
0155  */
0156 QString Commitmsg_impl::getMessage()const
0157 {
0158     return m_LogEdit->toPlainText();
0159 }
0160 
0161 /*!
0162     \fn Commitmsg_impl::isRecursive()const
0163  */
0164 svn::Depth Commitmsg_impl::getDepth()const
0165 {
0166     return m_DepthSelector->getDepth();
0167 }
0168 
0169 void Commitmsg_impl::keepsLocks(bool keeps_lock)
0170 {
0171     if (keeps_lock) {
0172         m_keepLocksButton->show();
0173     } else {
0174         m_keepLocksButton->hide();
0175     }
0176 }
0177 
0178 /*!
0179     \fn Commitmsg_impl::isRecursive()const
0180  */
0181 bool Commitmsg_impl::isKeeplocks()const
0182 {
0183     return m_keepLocksButton->isChecked();
0184 }
0185 
0186 /*!
0187     \fn Commitmsg_impl::initHistory()
0188  */
0189 void Commitmsg_impl::initHistory()
0190 {
0191     if (smax_message_history == 0xFFFF) {
0192         smax_message_history = Kdesvnsettings::max_log_messages();
0193         KConfigGroup cs(Kdesvnsettings::self()->config(), "log_messages");
0194         QString s;
0195         int current = 0;
0196         QString key = QStringLiteral("log_%0").arg(current);
0197         s = cs.readEntry(key, QString());
0198         while (!s.isNull()) {
0199             if (current < smax_message_history) {
0200                 sLogHistory.push_back(s);
0201             } else {
0202                 cs.deleteEntry(key);
0203             }
0204             ++current;
0205             key = QStringLiteral("log_%0").arg(current);
0206             s = cs.readEntry(key, QString());
0207         }
0208     }
0209     QStringList::const_iterator it;
0210     for (it = sLogHistory.constBegin(); it != sLogHistory.constEnd(); ++it) {
0211         if ((*it).length() <= 40) {
0212             m_LogHistory->addItem((*it));
0213         } else {
0214             m_LogHistory->addItem((*it).left(37) + QStringLiteral("..."));
0215         }
0216     }
0217     if (!sLastMessage.isEmpty()) {
0218         m_LogEdit->setText(sLastMessage);
0219         sLastMessage.clear();
0220     }
0221 }
0222 
0223 /*!
0224     \fn Commitmsg_impl::saveHistory()
0225  */
0226 void Commitmsg_impl::saveHistory(bool canceld)
0227 {
0228     QString _text = m_LogEdit->toPlainText();
0229     if (_text.isEmpty() || _text.length() > 512) {
0230         return;
0231     }
0232     /// @todo make static threadsafe
0233     if (!canceld) {
0234         int it;
0235         if ((it = sLogHistory.indexOf(_text)) != -1) {
0236             sLogHistory.removeAt(it);
0237         }
0238         sLogHistory.push_front(_text);
0239         if (sLogHistory.size() > smax_message_history) {
0240             sLogHistory.removeLast();
0241         }
0242         KConfigGroup cs(Kdesvnsettings::self()->config(), "log_messages");
0243         for (int i = 0; i < sLogHistory.size(); ++i) {
0244             cs.writeEntry(QStringLiteral("log_%0").arg(i), sLogHistory[i]);
0245         }
0246         cs.sync();
0247     } else {
0248         sLastMessage = _text;
0249     }
0250 }
0251 
0252 QString Commitmsg_impl::getLogmessage(bool *ok, svn::Depth *rec, bool *keep_locks, QWidget *parent)
0253 {
0254     return getLogmessageInternal(new Commitmsg_impl, ok, rec, keep_locks, nullptr, parent);
0255 }
0256 
0257 QString Commitmsg_impl::getLogmessage(const svn::CommitItemList &items, bool *ok, svn::Depth *rec, bool *keep_locks, QWidget *parent)
0258 {
0259     return getLogmessageInternal(new Commitmsg_impl(items), ok, rec, keep_locks, nullptr, parent);
0260 }
0261 
0262 QString Commitmsg_impl::getLogmessage(const CommitActionEntries &_on,
0263                                       const CommitActionEntries &_off,
0264                                       QObject *callback,
0265                                       CommitActionEntries &_result,
0266                                       bool *ok, bool *keep_locks, QWidget *parent)
0267 {
0268     Commitmsg_impl *ptr = new Commitmsg_impl(_on, _off);
0269     if (callback) {
0270         connect(ptr, SIGNAL(makeDiff(QString,svn::Revision,QString,svn::Revision,QWidget*)),
0271                 callback, SLOT(makeDiff(QString,svn::Revision,QString,svn::Revision,QWidget*)));
0272         connect(ptr, SIGNAL(sigRevertItem(QStringList)),
0273                 callback, SLOT(slotRevertItems(QStringList)));
0274         connect(callback, SIGNAL(sigItemsReverted(QStringList)),
0275                 ptr, SLOT(slotItemReverted(QStringList)));
0276     }
0277     return getLogmessageInternal(ptr, ok, nullptr, keep_locks, &_result, parent);
0278 }
0279 
0280 QString Commitmsg_impl::getLogmessageInternal(Commitmsg_impl *ptr, bool *ok, svn::Depth *rec, bool *keep_locks, CommitActionEntries *result, QWidget *parent)
0281 {
0282     bool _ok, _keep_locks;
0283     svn::Depth _depth = svn::DepthUnknown;
0284     QString msg;
0285 
0286     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("logmsg_dlg_size"), parent));
0287     dlg->setWindowTitle(i18nc("@title:window", "Commit Log"));
0288     dlg->setWithCancelButton();
0289     dlg->addWidget(ptr);
0290 
0291     if (!rec) {
0292         ptr->m_DepthSelector->hide();
0293     }
0294     if (!keep_locks) {
0295         ptr->m_keepLocksButton->hide();
0296     }
0297 
0298     ptr->initHistory();
0299     if (dlg->exec() != QDialog::Accepted) {
0300         _ok = false;
0301         /* avoid compiler warnings */
0302         _keep_locks = false;
0303     } else {
0304         _ok = true;
0305         _depth = ptr->getDepth();
0306         _keep_locks = ptr->isKeeplocks();
0307         msg = ptr->getMessage();
0308     }
0309     if (dlg) {
0310         ptr->saveHistory(!_ok);
0311     }
0312 
0313     if (ok) {
0314         *ok = _ok;
0315     }
0316     if (rec) {
0317         *rec = _depth;
0318     }
0319     if (keep_locks) {
0320         *keep_locks = _keep_locks;
0321     }
0322     if (result) {
0323         *result = ptr->checkedEntries();
0324     }
0325     delete dlg;
0326     return msg;
0327 }
0328 
0329 /*!
0330     \fn Commitmsg_impl::setRecCheckboxtext(const QString&what)
0331  */
0332 void Commitmsg_impl::addItemWidget(QWidget *aWidget)
0333 {
0334     m_DepthSelector->addItemWidget(aWidget);
0335 }
0336 
0337 CommitActionEntries Commitmsg_impl::checkedEntries() const
0338 {
0339     if (m_CurrentModel) {
0340         return m_CurrentModel->checkedEntries();
0341     }
0342     return CommitActionEntries();
0343 }
0344 
0345 void Commitmsg_impl::slotUnmarkUnversioned()
0346 {
0347     markUnversioned(false);
0348 }
0349 
0350 void Commitmsg_impl::slotMarkUnversioned()
0351 {
0352     markUnversioned(true);
0353 }
0354 
0355 void Commitmsg_impl::slotDiffSelected()
0356 {
0357     CommitModelNodePtr ptr = currentCommitItem();
0358     if (!ptr) {
0359         return;
0360     }
0361     QString what = ptr->actionEntry().name();
0362     emit makeDiff(what, svn::Revision::BASE, what, svn::Revision::WORKING, parentWidget());
0363 }
0364 
0365 void Commitmsg_impl::slotRevertSelected()
0366 {
0367     CommitModelNodePtr ptr = currentCommitItem();
0368     if (!ptr) {
0369         return;
0370     }
0371     QStringList what(ptr->actionEntry().name());
0372     emit sigRevertItem(what);
0373 }
0374 
0375 CommitModelNodePtr Commitmsg_impl::currentCommitItem(int column)
0376 {
0377     CommitModelNodePtr res;
0378     if (!m_CurrentModel) {
0379         return res;
0380     }
0381     QModelIndexList _mi = m_CommitItemTree->selectionModel()->selectedRows(column);
0382     if (_mi.isEmpty()) {
0383         return res;
0384     }
0385     QModelIndex ind = m_SortModel->mapToSource(_mi[0]);
0386     if (ind.isValid()) {
0387         res = m_CurrentModel->node(ind);
0388     }
0389     return res;
0390 }
0391 
0392 void Commitmsg_impl::hideKeepsLock(bool how)
0393 {
0394     m_keepLocksButton->setVisible(!how);
0395 }
0396 
0397 void Commitmsg_impl::hideButtons(bool how)
0398 {
0399     if (!m_MarkUnversioned) {
0400         return;
0401     }
0402     if (how) {
0403         m_MarkUnversioned->hide();
0404         m_UnmarkUnversioned->hide();
0405         m_DiffItem->hide();
0406         m_HideNewItems->hide();
0407         m_SelectAllButton->hide();
0408         m_UnselectAllButton->hide();
0409     } else {
0410         m_MarkUnversioned->show();
0411         m_UnmarkUnversioned->show();
0412         m_DiffItem->show();
0413         m_HideNewItems->show();
0414         m_SelectAllButton->show();
0415         m_UnselectAllButton->show();
0416     }
0417 }
0418 
0419 /*!
0420     \fn Commitmsg_impl::markUnversioned(bool mark)
0421  */
0422 void Commitmsg_impl::markUnversioned(bool mark)
0423 {
0424     if (!m_CurrentModel) {
0425         return;
0426     }
0427     m_CurrentModel->markItems(mark, CommitActionEntry::ADD_COMMIT);
0428 }
0429 
0430 void Commitmsg_impl::slotSelectAll()
0431 {
0432     if (!m_CurrentModel) {
0433         return;
0434     }
0435     m_CurrentModel->markItems(true, CommitActionEntry::ALL);
0436 }
0437 
0438 void Commitmsg_impl::slotUnselectAll()
0439 {
0440     if (!m_CurrentModel) {
0441         return;
0442     }
0443     m_CurrentModel->markItems(false, CommitActionEntry::ALL);
0444 }
0445 
0446 void Commitmsg_impl::hideNewItems(bool hide)
0447 {
0448     if (!m_CurrentModel) {
0449         return;
0450     }
0451     Kdesvnsettings::setCommit_hide_new(hide);
0452     m_SortModel->hideItems(hide, CommitActionEntry::ADD_COMMIT);
0453     m_HideNewItems->setText(hide ? i18n("Show new items") : i18n("Hide new items"));
0454 }
0455 
0456 /*!
0457     \fn Commitmsg_impl::hideDepth(bool hide)
0458  */
0459 void Commitmsg_impl::hideDepth(bool ahide)
0460 {
0461     m_DepthSelector->hideDepth(ahide);
0462 }
0463 
0464 void Commitmsg_impl::insertFile(const QString &fname)
0465 {
0466     QFile ifs(fname);
0467     if (ifs.open(QIODevice::ReadOnly)) {
0468         QTextStream ts(&ifs);
0469         QString _content = ts.readAll();
0470         m_LogEdit->textCursor().insertText(_content);
0471     }
0472 }
0473 
0474 void Commitmsg_impl::insertFile()
0475 {
0476     QString windowTitle = i18nc("@title:window", "Select Text File to Insert");
0477     QPointer<KUrlRequesterDialog> dlg(new KUrlRequesterDialog(QUrl(), i18n("Select text file to insert:"), this));
0478     dlg->setWindowTitle(windowTitle);
0479     KFile::Mode mode = static_cast<KFile::Mode>(KFile::File);
0480     dlg->urlRequester()->setMode(mode);
0481     dlg->urlRequester()->setWindowTitle(windowTitle);
0482 
0483     if (dlg->exec() != QDialog::Accepted) {
0484         delete dlg;
0485         return;
0486     }
0487     QUrl _url = dlg->selectedUrl();
0488     delete dlg;
0489     if (_url.isEmpty() || !_url.isValid()) {
0490         return;
0491     }
0492     if (_url.isLocalFile()) {
0493         insertFile(_url.path());
0494     } else {
0495         QTemporaryFile tf;
0496         tf.open();
0497         KIO::FileCopyJob *job = KIO::file_copy(_url, QUrl::fromLocalFile(tf.fileName()));
0498         KJobWidgets::setWindow(job, this);
0499         if (job->exec()) {
0500             insertFile(tf.fileName());
0501         } else {
0502             KMessageBox::error(this, job->errorString());
0503         }
0504     }
0505 }
0506 
0507 /*!
0508     \fn Commitmsg_impl::slotItemReverted(const QStringList&)
0509  */
0510 void Commitmsg_impl::slotItemReverted(const QStringList &items)
0511 {
0512     if (!m_CurrentModel) {
0513         return;
0514     }
0515     m_CurrentModel->removeEntries(items);
0516 }
0517 
0518 void Commitmsg_impl::slotItemDoubleClicked(const QModelIndex &index)
0519 {
0520     Q_UNUSED(index);
0521     slotDiffSelected();
0522 }
0523 
0524 void Commitmsg_impl::slotCurrentItemChanged(const QModelIndex &current)
0525 {
0526     bool bDiffRevertEnabled = false;
0527 
0528     const CommitModelNodePtr node = m_CurrentModel->dataForRow(m_SortModel->mapToSource(current).row());
0529     if (!node.isNull()) {
0530         bDiffRevertEnabled = (node->actionEntry().type() == CommitActionEntry::COMMIT);
0531     }
0532     m_RevertItemButton->setEnabled(bDiffRevertEnabled);
0533     m_DiffItem->setEnabled(bDiffRevertEnabled);
0534 }