Warning, file /sdk/cervisia/historydialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  Copyright (C) 1999-2002 Bernd Gehrmann
0003  *                          bernd@mail.berlios.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 Free Software
0017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0018  */
0019 
0020 #include "historydialog.h"
0021 
0022 #include <QCheckBox>
0023 #include <QDateTime>
0024 #include <QDialogButtonBox>
0025 #include <QHeaderView>
0026 #include <QLineEdit>
0027 #include <QPushButton>
0028 #include <QRegExp>
0029 #include <QTreeWidget>
0030 #include <QVBoxLayout>
0031 
0032 #include <KConfig>
0033 #include <KConfigGroup>
0034 #include <KHelpClient>
0035 #include <KLocalizedString>
0036 
0037 #include "cvsserviceinterface.h"
0038 #include "misc.h"
0039 #include "progressdialog.h"
0040 
0041 static QDateTime parseDate(const QString &date, const QString &time, const QString &_offset)
0042 {
0043     // cvs history only prints hhmm but fromString() needs hh:mm
0044     QString offset(_offset);
0045     if (!offset.contains(':') && offset.size() == 5)
0046         offset.insert(3, ':');
0047 
0048     const QDateTime dt(QDateTime::fromString(date + 'T' + time + offset, Qt::ISODate));
0049     if (!dt.isValid())
0050         return {};
0051 
0052     QDateTime dateTime;
0053     dateTime.setTime_t(dt.toTime_t());
0054 
0055     return dateTime;
0056 }
0057 
0058 class HistoryItem : public QTreeWidgetItem
0059 {
0060 public:
0061     enum { Date, Event, Author, Revision, File, Path };
0062 
0063     HistoryItem(QTreeWidget *parent, const QDateTime &date)
0064         : QTreeWidgetItem(parent)
0065         , m_date(date)
0066     {
0067     }
0068 
0069     bool operator<(const QTreeWidgetItem &other) const override;
0070 
0071     QVariant data(int column, int role) const override;
0072 
0073     bool isCommit();
0074     bool isCheckout();
0075     bool isTag();
0076     bool isOther();
0077 
0078 private:
0079     const QDateTime m_date;
0080 };
0081 
0082 bool HistoryItem::operator<(const QTreeWidgetItem &other) const
0083 {
0084     const auto &item = static_cast<const HistoryItem &>(other);
0085 
0086     switch (treeWidget()->sortColumn()) {
0087     case Date:
0088         return ::compare(m_date, item.m_date) == -1;
0089     case Revision:
0090         return ::compareRevisions(text(Revision), item.text(Revision)) == -1;
0091     }
0092 
0093     return QTreeWidgetItem::operator<(other);
0094 }
0095 
0096 QVariant HistoryItem::data(int column, int role) const
0097 {
0098     if ((role == Qt::DisplayRole) && (column == Date))
0099         return QLocale().toString(m_date);
0100 
0101     return QTreeWidgetItem::data(column, role);
0102 }
0103 
0104 bool HistoryItem::isCommit()
0105 {
0106     return text(1) == i18n("Commit, Modified ") || text(1) == i18n("Commit, Added ") || text(1) == i18n("Commit, Removed ");
0107 }
0108 
0109 bool HistoryItem::isCheckout()
0110 {
0111     return text(1) == i18n("Checkout ");
0112 }
0113 
0114 bool HistoryItem::isTag()
0115 {
0116     return text(1) == i18n("Tag");
0117 }
0118 
0119 bool HistoryItem::isOther()
0120 {
0121     return !isCommit() && !isCheckout() && !isTag();
0122 }
0123 
0124 HistoryDialog::HistoryDialog(KConfig &cfg, QWidget *parent)
0125     : QDialog(parent)
0126     , partConfig(cfg)
0127 {
0128     auto mainLayout = new QVBoxLayout;
0129     setLayout(mainLayout);
0130 
0131     listview = new QTreeWidget;
0132     listview->setSelectionMode(QAbstractItemView::NoSelection);
0133     listview->setAllColumnsShowFocus(true);
0134     listview->setRootIsDecorated(false);
0135     listview->header()->setSortIndicatorShown(true);
0136     listview->setSortingEnabled(true);
0137     listview->sortByColumn(HistoryItem::Date, Qt::DescendingOrder);
0138     listview->setHeaderLabels(QStringList() << i18n("Date") << i18n("Event") << i18n("Author") << i18n("Revision") << i18n("File") << i18n("Repo Path"));
0139     listview->setFocus();
0140     mainLayout->addWidget(listview);
0141 
0142     commit_box = new QCheckBox(i18n("Show c&ommit events"));
0143     commit_box->setChecked(true);
0144 
0145     checkout_box = new QCheckBox(i18n("Show ch&eckout events"));
0146     checkout_box->setChecked(true);
0147 
0148     tag_box = new QCheckBox(i18n("Show &tag events"));
0149     tag_box->setChecked(true);
0150 
0151     other_box = new QCheckBox(i18n("Show &other events"));
0152     other_box->setChecked(true);
0153 
0154     onlyuser_box = new QCheckBox(i18n("Only &user:"));
0155 
0156     onlyfilenames_box = new QCheckBox(i18n("Only &filenames matching:"));
0157 
0158     onlydirnames_box = new QCheckBox(i18n("Only &folders matching:"));
0159 
0160     user_edit = new QLineEdit;
0161     user_edit->setEnabled(false);
0162 
0163     filename_edit = new QLineEdit;
0164     filename_edit->setEnabled(false);
0165 
0166     dirname_edit = new QLineEdit;
0167     dirname_edit->setEnabled(false);
0168 
0169     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close);
0170     connect(buttonBox, &QDialogButtonBox::helpRequested, this, &HistoryDialog::slotHelp);
0171     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0172 
0173     connect(onlyuser_box, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
0174     connect(onlyfilenames_box, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
0175     connect(onlydirnames_box, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
0176     connect(commit_box, SIGNAL(toggled(bool)), this, SLOT(choiceChanged()));
0177     connect(checkout_box, SIGNAL(toggled(bool)), this, SLOT(choiceChanged()));
0178     connect(tag_box, SIGNAL(toggled(bool)), this, SLOT(choiceChanged()));
0179     connect(other_box, SIGNAL(toggled(bool)), this, SLOT(choiceChanged()));
0180     connect(onlyuser_box, SIGNAL(toggled(bool)), this, SLOT(choiceChanged()));
0181     connect(onlyfilenames_box, SIGNAL(toggled(bool)), this, SLOT(choiceChanged()));
0182     connect(onlydirnames_box, SIGNAL(toggled(bool)), this, SLOT(choiceChanged()));
0183     connect(user_edit, SIGNAL(returnPressed()), this, SLOT(choiceChanged()));
0184     connect(filename_edit, SIGNAL(returnPressed()), this, SLOT(choiceChanged()));
0185     connect(dirname_edit, SIGNAL(returnPressed()), this, SLOT(choiceChanged()));
0186 
0187     auto grid = new QGridLayout;
0188     mainLayout->addLayout(grid);
0189     grid->setColumnStretch(0, 1);
0190     grid->setColumnStretch(1, 0);
0191     grid->setColumnStretch(2, 4);
0192     grid->setColumnStretch(3, 1);
0193     grid->addWidget(commit_box, 0, 0);
0194     grid->addWidget(checkout_box, 1, 0);
0195     grid->addWidget(tag_box, 2, 0);
0196     grid->addWidget(other_box, 3, 0);
0197     grid->addWidget(onlyuser_box, 0, 1);
0198     grid->addWidget(user_edit, 0, 2);
0199     grid->addWidget(onlyfilenames_box, 1, 1);
0200     grid->addWidget(filename_edit, 1, 2);
0201     grid->addWidget(onlydirnames_box, 2, 1);
0202     grid->addWidget(dirname_edit, 2, 2);
0203 
0204     // no default button because "return" is needed to activate the filters (line edits)
0205     buttonBox->button(QDialogButtonBox::Help)->setAutoDefault(false);
0206     buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false);
0207 
0208     mainLayout->addWidget(buttonBox);
0209 
0210     setAttribute(Qt::WA_DeleteOnClose, true);
0211 
0212     KConfigGroup cg(&partConfig, "HistoryDialog");
0213     restoreGeometry(cg.readEntry<QByteArray>("geometry", QByteArray()));
0214 
0215     QByteArray state = cg.readEntry<QByteArray>("HistoryListView", QByteArray());
0216     listview->header()->restoreState(state);
0217 }
0218 
0219 HistoryDialog::~HistoryDialog()
0220 {
0221     KConfigGroup cg(&partConfig, "HistoryDialog");
0222     cg.writeEntry("geometry", saveGeometry());
0223 
0224     cg.writeEntry("HistoryListView", listview->header()->saveState());
0225 }
0226 
0227 void HistoryDialog::slotHelp()
0228 {
0229     KHelpClient::invokeHelp(QLatin1String("browsinghistory"));
0230 }
0231 
0232 void HistoryDialog::choiceChanged()
0233 {
0234     const QString author(user_edit->text());
0235     const QRegExp fileMatcher(filename_edit->text(), Qt::CaseSensitive, QRegExp::Wildcard);
0236     const QRegExp pathMatcher(dirname_edit->text(), Qt::CaseSensitive, QRegExp::Wildcard);
0237 
0238     const bool showCommitEvents(commit_box->isChecked());
0239     const bool showCheckoutEvents(checkout_box->isChecked());
0240     const bool showTagEvents(tag_box->isChecked());
0241     const bool showOtherEvents(other_box->isChecked());
0242     const bool filterByAuthor(onlyuser_box->isChecked() && !author.isEmpty());
0243     const bool filterByFile(onlyfilenames_box->isChecked() && !fileMatcher.isEmpty());
0244     const bool filterByPath(onlydirnames_box->isChecked() && !pathMatcher.isEmpty());
0245 
0246     for (int i = 0; i < listview->topLevelItemCount(); i++) {
0247         auto item = static_cast<HistoryItem *>(listview->topLevelItem(i));
0248 
0249         bool visible((showCommitEvents && item->isCommit()) || (showCheckoutEvents && item->isCheckout()) || (showTagEvents && item->isTag())
0250                      || (showOtherEvents && item->isOther()));
0251         visible = visible && (!filterByAuthor || author == item->text(HistoryItem::Author))
0252             && (!filterByFile || item->text(HistoryItem::File).contains(fileMatcher)) && (!filterByPath || item->text(HistoryItem::Path).contains(pathMatcher));
0253 
0254         item->setHidden(!visible);
0255     }
0256 }
0257 
0258 void HistoryDialog::toggled(bool b)
0259 {
0260     QLineEdit *edit = 0;
0261 
0262     if (sender() == onlyuser_box)
0263         edit = user_edit;
0264     else if (sender() == onlyfilenames_box)
0265         edit = filename_edit;
0266     else if (sender() == onlydirnames_box)
0267         edit = dirname_edit;
0268 
0269     if (!edit)
0270         return;
0271 
0272     edit->setEnabled(b);
0273     if (b)
0274         edit->setFocus();
0275 }
0276 
0277 bool HistoryDialog::parseHistory(OrgKdeCervisia5CvsserviceCvsserviceInterface *cvsService)
0278 {
0279     setWindowTitle(i18n("CVS History"));
0280 
0281     QDBusReply<QDBusObjectPath> job = cvsService->history();
0282     if (!job.isValid())
0283         return false;
0284 
0285     ProgressDialog dlg(this, "History", cvsService->service(), job, "history", i18n("CVS History"));
0286     if (!dlg.execute())
0287         return false;
0288 
0289     QString line;
0290     while (dlg.getLine(line)) {
0291         const QStringList list(splitLine(line));
0292         const int listSize(list.size());
0293         if (listSize < 6)
0294             continue;
0295 
0296         QString cmd = list[0];
0297         if (cmd.length() != 1)
0298             continue;
0299 
0300         int ncol;
0301         int cmd_code = cmd[0].toLatin1();
0302         switch (cmd_code) {
0303         case 'O':
0304         case 'F':
0305         case 'E':
0306             ncol = 8;
0307             break;
0308         default:
0309             ncol = 10;
0310             break;
0311         }
0312 
0313         if (ncol != (int)list.count())
0314             continue;
0315 
0316         QString event;
0317         switch (cmd_code) {
0318         case 'O':
0319             event = i18n("Checkout ");
0320             break;
0321         case 'T':
0322             event = i18n("Tag ");
0323             break;
0324         case 'F':
0325             event = i18n("Release ");
0326             break;
0327         case 'W':
0328             event = i18n("Update, Deleted ");
0329             break;
0330         case 'U':
0331             event = i18n("Update, Copied ");
0332             break;
0333         case 'G':
0334             event = i18n("Update, Merged ");
0335             break;
0336         case 'C':
0337             event = i18n("Update, Conflict ");
0338             break;
0339         case 'P':
0340             event = i18n("Update, Patched ");
0341             break;
0342         case 'M':
0343             event = i18n("Commit, Modified ");
0344             break;
0345         case 'A':
0346             event = i18n("Commit, Added ");
0347             break;
0348         case 'R':
0349             event = i18n("Commit, Removed ");
0350             break;
0351         default:
0352             event = i18n("Unknown ");
0353         }
0354 
0355         const QDateTime date(parseDate(list[1], list[2], list[3]));
0356 
0357         auto item = new HistoryItem(listview, date);
0358         item->setText(HistoryItem::Event, event);
0359         item->setText(HistoryItem::Author, list[4]);
0360         if (ncol == 10) {
0361             item->setText(HistoryItem::Revision, list[5]);
0362             if (listSize >= 8) {
0363                 item->setText(HistoryItem::File, list[6]);
0364                 item->setText(HistoryItem::Path, list[7]);
0365             }
0366         } else {
0367             item->setText(HistoryItem::Path, list[5]);
0368         }
0369     }
0370 
0371     return true;
0372 }
0373 
0374 // Local Variables:
0375 // c-basic-offset: 4
0376 // End: