File indexing completed on 2024-05-05 05:44:49

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 "depthselector.h"
0022 #include "ksvnwidgets/ksvndialog.h"
0023 #include "models/commitmodel.h"
0024 #include "models/commitmodelhelper.h"
0025 #include "settings/kdesvnsettings.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 <QFile>
0037 #include <QStringList>
0038 #include <QTemporaryFile>
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)
0049     , CommitMessage()
0050 {
0051     setupUi(this);
0052     m_CurrentModel = nullptr;
0053     m_SortModel = nullptr;
0054     m_LogEdit->setFocus();
0055     m_Reviewlabel->hide();
0056     m_hidden = true;
0057     hideButtons(true);
0058     m_MainSplitter->insertWidget(0, m_EditFrame);
0059     delete m_ReviewFrame;
0060     m_Reviewlabel = nullptr;
0061     m_MarkUnversioned = nullptr;
0062     m_UnmarkUnversioned = nullptr;
0063     m_DiffItem = nullptr;
0064 }
0065 
0066 Commitmsg_impl::Commitmsg_impl(const svn::CommitItemList &_items, QWidget *parent)
0067     : QWidget(parent)
0068     , CommitMessage()
0069 {
0070     setupUi(this);
0071     m_CurrentModel = nullptr;
0072     m_SortModel = nullptr;
0073     m_LogEdit->setFocus();
0074     hideButtons(true);
0075     if (!_items.isEmpty()) {
0076         m_CurrentModel = new CommitModel(_items);
0077         setupModel();
0078         m_hidden = false;
0079     } else {
0080         m_Reviewlabel->hide();
0081         m_CommitItemTree->hide();
0082         m_hidden = true;
0083     }
0084     checkSplitterSize();
0085 }
0086 
0087 Commitmsg_impl::Commitmsg_impl(const CommitActionEntries &_activatedList, const CommitActionEntries &_notActivatedList, QWidget *parent)
0088     : QWidget(parent)
0089     , CommitMessage()
0090 {
0091     setupUi(this);
0092     m_CurrentModel = nullptr;
0093     m_SortModel = nullptr;
0094     m_LogEdit->setFocus();
0095     m_hidden = false;
0096 
0097     m_CurrentModel = new CommitModelCheckitem(_activatedList, _notActivatedList);
0098     setupModel();
0099 
0100     m_HideNewItems->setChecked(Kdesvnsettings::commit_hide_new());
0101     checkSplitterSize();
0102 }
0103 
0104 Commitmsg_impl::~Commitmsg_impl()
0105 {
0106     QList<int> list = m_MainSplitter->sizes();
0107     if (!m_hidden && list.count() == 2) {
0108         Kdesvnsettings::setCommit_splitter_height(list);
0109         Kdesvnsettings::self()->save();
0110     }
0111     delete m_CurrentModel;
0112     delete m_SortModel;
0113 }
0114 
0115 void Commitmsg_impl::setupModel()
0116 {
0117     m_SortModel = new CommitFilterModel(m_CommitItemTree);
0118     m_CommitItemTree->setModel(m_SortModel);
0119     m_SortModel->setSourceModel(m_CurrentModel);
0120 
0121     m_CommitItemTree->resizeColumnToContents(m_CurrentModel->ItemColumn());
0122     m_CommitItemTree->resizeColumnToContents(m_CurrentModel->ActionColumn());
0123 
0124     m_SortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
0125     connect(m_CommitItemTree->selectionModel(), &QItemSelectionModel::currentChanged, 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 (const QString &historyEntry : qAsConst(sLogHistory)) {
0211         if (historyEntry.length() <= 40) {
0212             m_LogHistory->addItem(historyEntry);
0213         } else {
0214             m_LogHistory->addItem(historyEntry.leftRef(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,
0267                                       bool *keep_locks,
0268                                       QWidget *parent)
0269 {
0270     Commitmsg_impl *ptr = new Commitmsg_impl(_on, _off);
0271     if (callback) {
0272         connect(ptr,
0273                 SIGNAL(makeDiff(QString, svn::Revision, QString, svn::Revision, QWidget *)),
0274                 callback,
0275                 SLOT(makeDiff(QString, svn::Revision, QString, svn::Revision, QWidget *)));
0276         connect(ptr, SIGNAL(sigRevertItem(QStringList)), callback, SLOT(slotRevertItems(QStringList)));
0277         connect(callback, SIGNAL(sigItemsReverted(QStringList)), ptr, SLOT(slotItemReverted(QStringList)));
0278     }
0279     return getLogmessageInternal(ptr, ok, nullptr, keep_locks, &_result, parent);
0280 }
0281 
0282 QString Commitmsg_impl::getLogmessageInternal(Commitmsg_impl *ptr, bool *ok, svn::Depth *rec, bool *keep_locks, CommitActionEntries *result, QWidget *parent)
0283 {
0284     bool _ok, _keep_locks;
0285     svn::Depth _depth = svn::DepthUnknown;
0286     QString msg;
0287 
0288     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("logmsg_dlg_size"), parent));
0289     dlg->setWindowTitle(i18nc("@title:window", "Commit Log"));
0290     dlg->setWithCancelButton();
0291     dlg->addWidget(ptr);
0292 
0293     if (!rec) {
0294         ptr->m_DepthSelector->hide();
0295     }
0296     if (!keep_locks) {
0297         ptr->m_keepLocksButton->hide();
0298     }
0299 
0300     ptr->initHistory();
0301     if (dlg->exec() != QDialog::Accepted) {
0302         _ok = false;
0303         /* avoid compiler warnings */
0304         _keep_locks = false;
0305     } else {
0306         _ok = true;
0307         _depth = ptr->getDepth();
0308         _keep_locks = ptr->isKeeplocks();
0309         msg = ptr->getMessage();
0310     }
0311     if (dlg) {
0312         ptr->saveHistory(!_ok);
0313     }
0314 
0315     if (ok) {
0316         *ok = _ok;
0317     }
0318     if (rec) {
0319         *rec = _depth;
0320     }
0321     if (keep_locks) {
0322         *keep_locks = _keep_locks;
0323     }
0324     if (result) {
0325         *result = ptr->checkedEntries();
0326     }
0327     delete dlg;
0328     return msg;
0329 }
0330 
0331 /*!
0332     \fn Commitmsg_impl::setRecCheckboxtext(const QString&what)
0333  */
0334 void Commitmsg_impl::addItemWidget(QWidget *aWidget)
0335 {
0336     m_DepthSelector->addItemWidget(aWidget);
0337 }
0338 
0339 CommitActionEntries Commitmsg_impl::checkedEntries() const
0340 {
0341     if (m_CurrentModel) {
0342         return m_CurrentModel->checkedEntries();
0343     }
0344     return CommitActionEntries();
0345 }
0346 
0347 void Commitmsg_impl::slotUnmarkUnversioned()
0348 {
0349     markUnversioned(false);
0350 }
0351 
0352 void Commitmsg_impl::slotMarkUnversioned()
0353 {
0354     markUnversioned(true);
0355 }
0356 
0357 void Commitmsg_impl::slotDiffSelected()
0358 {
0359     CommitModelNodePtr ptr = currentCommitItem();
0360     if (!ptr) {
0361         return;
0362     }
0363     QString what = ptr->actionEntry().name();
0364     emit makeDiff(what, svn::Revision::BASE, what, svn::Revision::WORKING, parentWidget());
0365 }
0366 
0367 void Commitmsg_impl::slotRevertSelected()
0368 {
0369     CommitModelNodePtr ptr = currentCommitItem();
0370     if (!ptr) {
0371         return;
0372     }
0373     QStringList what(ptr->actionEntry().name());
0374     emit sigRevertItem(what);
0375 }
0376 
0377 CommitModelNodePtr Commitmsg_impl::currentCommitItem(int column)
0378 {
0379     CommitModelNodePtr res;
0380     if (!m_CurrentModel) {
0381         return res;
0382     }
0383     QModelIndexList _mi = m_CommitItemTree->selectionModel()->selectedRows(column);
0384     if (_mi.isEmpty()) {
0385         return res;
0386     }
0387     QModelIndex ind = m_SortModel->mapToSource(_mi[0]);
0388     if (ind.isValid()) {
0389         res = m_CurrentModel->node(ind);
0390     }
0391     return res;
0392 }
0393 
0394 void Commitmsg_impl::hideKeepsLock(bool how)
0395 {
0396     m_keepLocksButton->setVisible(!how);
0397 }
0398 
0399 void Commitmsg_impl::hideButtons(bool how)
0400 {
0401     if (!m_MarkUnversioned) {
0402         return;
0403     }
0404     if (how) {
0405         m_MarkUnversioned->hide();
0406         m_UnmarkUnversioned->hide();
0407         m_DiffItem->hide();
0408         m_HideNewItems->hide();
0409         m_SelectAllButton->hide();
0410         m_UnselectAllButton->hide();
0411     } else {
0412         m_MarkUnversioned->show();
0413         m_UnmarkUnversioned->show();
0414         m_DiffItem->show();
0415         m_HideNewItems->show();
0416         m_SelectAllButton->show();
0417         m_UnselectAllButton->show();
0418     }
0419 }
0420 
0421 /*!
0422     \fn Commitmsg_impl::markUnversioned(bool mark)
0423  */
0424 void Commitmsg_impl::markUnversioned(bool mark)
0425 {
0426     if (!m_CurrentModel) {
0427         return;
0428     }
0429     m_CurrentModel->markItems(mark, CommitActionEntry::ADD_COMMIT);
0430 }
0431 
0432 void Commitmsg_impl::slotSelectAll()
0433 {
0434     if (!m_CurrentModel) {
0435         return;
0436     }
0437     m_CurrentModel->markItems(true, CommitActionEntry::ALL);
0438 }
0439 
0440 void Commitmsg_impl::slotUnselectAll()
0441 {
0442     if (!m_CurrentModel) {
0443         return;
0444     }
0445     m_CurrentModel->markItems(false, CommitActionEntry::ALL);
0446 }
0447 
0448 void Commitmsg_impl::hideNewItems(bool hide)
0449 {
0450     if (!m_CurrentModel) {
0451         return;
0452     }
0453     Kdesvnsettings::setCommit_hide_new(hide);
0454     m_SortModel->hideItems(hide, CommitActionEntry::ADD_COMMIT);
0455     m_HideNewItems->setText(hide ? i18n("Show new items") : i18n("Hide new items"));
0456 }
0457 
0458 /*!
0459     \fn Commitmsg_impl::hideDepth(bool hide)
0460  */
0461 void Commitmsg_impl::hideDepth(bool ahide)
0462 {
0463     m_DepthSelector->hideDepth(ahide);
0464 }
0465 
0466 void Commitmsg_impl::insertFile(const QString &fname)
0467 {
0468     QFile ifs(fname);
0469     if (ifs.open(QIODevice::ReadOnly)) {
0470         QTextStream ts(&ifs);
0471         QString _content = ts.readAll();
0472         m_LogEdit->textCursor().insertText(_content);
0473     }
0474 }
0475 
0476 void Commitmsg_impl::insertFile()
0477 {
0478     QString windowTitle = i18nc("@title:window", "Select Text File to Insert");
0479     QPointer<KUrlRequesterDialog> dlg(new KUrlRequesterDialog(QUrl(), i18n("Select text file to insert:"), this));
0480     dlg->setWindowTitle(windowTitle);
0481     KFile::Mode mode = static_cast<KFile::Mode>(KFile::File);
0482     dlg->urlRequester()->setMode(mode);
0483     dlg->urlRequester()->setWindowTitle(windowTitle);
0484 
0485     if (dlg->exec() != QDialog::Accepted) {
0486         delete dlg;
0487         return;
0488     }
0489     QUrl _url = dlg->selectedUrl();
0490     delete dlg;
0491     if (_url.isEmpty() || !_url.isValid()) {
0492         return;
0493     }
0494     if (_url.isLocalFile()) {
0495         insertFile(_url.path());
0496     } else {
0497         QTemporaryFile tf;
0498         tf.open();
0499         KIO::FileCopyJob *job = KIO::file_copy(_url, QUrl::fromLocalFile(tf.fileName()));
0500         KJobWidgets::setWindow(job, this);
0501         if (job->exec()) {
0502             insertFile(tf.fileName());
0503         } else {
0504             KMessageBox::error(this, job->errorString());
0505         }
0506     }
0507 }
0508 
0509 /*!
0510     \fn Commitmsg_impl::slotItemReverted(const QStringList&)
0511  */
0512 void Commitmsg_impl::slotItemReverted(const QStringList &items)
0513 {
0514     if (!m_CurrentModel) {
0515         return;
0516     }
0517     m_CurrentModel->removeEntries(items);
0518 }
0519 
0520 void Commitmsg_impl::slotItemDoubleClicked(const QModelIndex &index)
0521 {
0522     Q_UNUSED(index);
0523     slotDiffSelected();
0524 }
0525 
0526 void Commitmsg_impl::slotCurrentItemChanged(const QModelIndex &current)
0527 {
0528     bool bDiffRevertEnabled = false;
0529 
0530     const CommitModelNodePtr node = m_CurrentModel->dataForRow(m_SortModel->mapToSource(current).row());
0531     if (!node.isNull()) {
0532         bDiffRevertEnabled = (node->actionEntry().type() == CommitActionEntry::COMMIT);
0533     }
0534     m_RevertItemButton->setEnabled(bDiffRevertEnabled);
0535     m_DiffItem->setEnabled(bDiffRevertEnabled);
0536 }
0537 
0538 #include "moc_commitmsg_impl.cpp"