Warning, file /sdk/cervisia/logdialog.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 * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program; if not, write to the Free Software 0018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "logdialog.h" 0022 0023 #include <KComboBox> 0024 #include <KTextEdit> 0025 #include <QTabWidget> 0026 #include <QUrl> 0027 #include <qfile.h> 0028 #include <qfileinfo.h> 0029 #include <qlabel.h> 0030 #include <qlayout.h> 0031 #include <qpushbutton.h> 0032 #include <qsplitter.h> 0033 #include <qtextstream.h> 0034 0035 #include <KConfigGroup> 0036 #include <KHelpClient> 0037 #include <KLocalizedString> 0038 #include <kconfig.h> 0039 #include <kconfiggroup.h> 0040 #include <kfinddialog.h> 0041 #include <kmessagebox.h> 0042 #include <krun.h> 0043 #include <ktreewidgetsearchline.h> 0044 0045 #include <KGuiItem> 0046 #include <QDialogButtonBox> 0047 #include <QFileDialog> 0048 #include <QPushButton> 0049 #include <QVBoxLayout> 0050 0051 #include "annotatecontroller.h" 0052 #include "annotatedialog.h" 0053 #include "cvsserviceinterface.h" 0054 #include "debug.h" 0055 #include "diffdialog.h" 0056 #include "loglist.h" 0057 #include "logplainview.h" 0058 #include "logtree.h" 0059 #include "misc.h" 0060 #include "patchoptiondialog.h" 0061 #include "progressdialog.h" 0062 0063 LogDialog::LogDialog(KConfig &cfg, QWidget *parent) 0064 : QDialog(parent) 0065 , cvsService(0) 0066 , partConfig(cfg) 0067 { 0068 auto mainLayout = new QVBoxLayout; 0069 setLayout(mainLayout); 0070 0071 splitter = new QSplitter(Qt::Vertical, this); 0072 mainLayout->addWidget(splitter); 0073 0074 tree = new LogTreeView(this); 0075 connect(tree, SIGNAL(revisionClicked(QString, bool)), this, SLOT(revisionSelected(QString, bool))); 0076 0077 auto listWidget = new QWidget(this); 0078 auto listLayout = new QVBoxLayout(listWidget); 0079 auto searchLayout = new QHBoxLayout(); 0080 listLayout->addLayout(searchLayout); 0081 0082 list = new LogListView(partConfig, listWidget); 0083 listLayout->addWidget(list, 1); 0084 0085 auto searchLine = new KTreeWidgetSearchLine(listWidget, list); 0086 auto searchLabel = new QLabel(i18n("Search:"), listWidget); 0087 searchLabel->setBuddy(searchLine); 0088 searchLayout->addWidget(searchLabel); 0089 searchLayout->addWidget(searchLine, 1); 0090 0091 connect(list, SIGNAL(revisionClicked(QString, bool)), this, SLOT(revisionSelected(QString, bool))); 0092 0093 plain = new LogPlainView(this); 0094 connect(plain, SIGNAL(revisionClicked(QString, bool)), this, SLOT(revisionSelected(QString, bool))); 0095 0096 tabWidget = new QTabWidget; 0097 tabWidget->addTab(tree, i18n("&Tree")); 0098 tabWidget->addTab(listWidget, i18n("&List")); 0099 tabWidget->addTab(plain, i18n("CVS &Output")); 0100 splitter->addWidget(tabWidget); 0101 splitter->setStretchFactor(0, 1); 0102 0103 connect(tabWidget, &QTabWidget::currentChanged, this, &LogDialog::tabChanged); 0104 0105 tree->setWhatsThis( 0106 i18n("Choose revision A by clicking with the left " 0107 "mouse button,\nrevision B by clicking with " 0108 "the middle mouse button.")); 0109 0110 auto mainWidget = new QWidget; 0111 splitter->addWidget(mainWidget); 0112 QBoxLayout *layout = new QVBoxLayout(mainWidget); 0113 layout->setContentsMargins(0, 0, 0, 0); 0114 0115 for (int i = 0; i < 2; ++i) { 0116 if (i == 1) { 0117 auto frame = new QFrame(mainWidget); 0118 frame->setFrameStyle(QFrame::HLine | QFrame::Sunken); 0119 layout->addWidget(frame); 0120 } 0121 0122 auto grid = new QGridLayout(); 0123 layout->addLayout(grid); 0124 grid->setRowStretch(0, 0); 0125 grid->setRowStretch(1, 0); 0126 grid->setRowStretch(2, 1); 0127 grid->setColumnStretch(0, 0); 0128 grid->setColumnStretch(1, 1); 0129 grid->setColumnStretch(2, 0); 0130 grid->setColumnStretch(3, 1); 0131 grid->setColumnStretch(4, 2); 0132 0133 QString versionident = (i == 0) ? i18n("Revision A:") : i18n("Revision B:"); 0134 auto versionlabel = new QLabel(versionident, mainWidget); 0135 grid->addWidget(versionlabel, 0, 0); 0136 0137 revbox[i] = new QLabel(mainWidget); 0138 revbox[i]->setFrameStyle(QFrame::Panel | QFrame::Sunken); 0139 revbox[i]->setTextInteractionFlags(Qt::TextSelectableByMouse); 0140 grid->addWidget(revbox[i], 0, 1, Qt::AlignVCenter); 0141 0142 auto selectlabel = new QLabel(i18n("Select by tag:"), mainWidget); 0143 grid->addWidget(selectlabel, 0, 2); 0144 0145 tagcombo[i] = new KComboBox(mainWidget); 0146 QFontMetrics fm(tagcombo[i]->fontMetrics()); 0147 tagcombo[i]->setMinimumWidth(fm.width("X") * 20); 0148 grid->addWidget(tagcombo[i], 0, 3); 0149 0150 auto authorlabel = new QLabel(i18n("Author:"), mainWidget); 0151 grid->addWidget(authorlabel, 1, 0); 0152 0153 authorbox[i] = new QLabel(mainWidget); 0154 authorbox[i]->setFrameStyle(QFrame::Panel | QFrame::Sunken); 0155 authorbox[i]->setTextInteractionFlags(Qt::TextSelectableByMouse); 0156 grid->addWidget(authorbox[i], 1, 1); 0157 0158 auto datelabel = new QLabel(i18n("Date:"), mainWidget); 0159 grid->addWidget(datelabel, 1, 2); 0160 0161 datebox[i] = new QLabel(mainWidget); 0162 datebox[i]->setFrameStyle(QFrame::Panel | QFrame::Sunken); 0163 datebox[i]->setTextInteractionFlags(Qt::TextSelectableByMouse); 0164 grid->addWidget(datebox[i], 1, 3); 0165 0166 auto commentlabel = new QLabel(i18n("Comment/Tags:"), mainWidget); 0167 grid->addWidget(commentlabel, 2, 0); 0168 0169 commentbox[i] = new KTextEdit(mainWidget); 0170 commentbox[i]->setReadOnly(true); 0171 fm = commentbox[i]->fontMetrics(); 0172 commentbox[i]->setMinimumHeight(2 * fm.lineSpacing() + 10); 0173 grid->addWidget(commentbox[i], 2, 1, 1, 3); 0174 0175 tagsbox[i] = new KTextEdit(mainWidget); 0176 tagsbox[i]->setReadOnly(true); 0177 tagsbox[i]->setMinimumHeight(2 * fm.lineSpacing() + 10); 0178 grid->addWidget(tagsbox[i], 0, 4, 3, 1); 0179 } 0180 0181 buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Help | QDialogButtonBox::Close | QDialogButtonBox::Apply); 0182 0183 okButton = buttonBox->button(QDialogButtonBox::Ok); 0184 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0185 connect(okButton, &QPushButton::clicked, this, &LogDialog::slotOk); 0186 0187 user1Button = new QPushButton; 0188 buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); 0189 0190 user2Button = new QPushButton; 0191 buttonBox->addButton(user2Button, QDialogButtonBox::ActionRole); 0192 0193 user3Button = new QPushButton; 0194 buttonBox->addButton(user3Button, QDialogButtonBox::ActionRole); 0195 0196 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); 0197 0198 KGuiItem::assign(user1Button, KGuiItem(i18n("&Annotate A"))); 0199 KGuiItem::assign(user2Button, KGuiItem(i18n("&Diff"))); 0200 KGuiItem::assign(user3Button, KGuiItem(i18n("&Find"))); 0201 user3Button->setVisible(false); 0202 0203 // initially make the version info widget as small as possible 0204 splitter->setSizes(QList<int>() << height() << 10); 0205 0206 revbox[0]->setWhatsThis( 0207 i18n("This revision is used when you click " 0208 "Annotate.\nIt is also used as the first " 0209 "item of a Diff operation.")); 0210 0211 revbox[1]->setWhatsThis( 0212 i18n("This revision is used as the second " 0213 "item of a Diff operation.")); 0214 0215 connect(tagcombo[0], SIGNAL(activated(int)), this, SLOT(tagASelected(int))); 0216 connect(tagcombo[1], SIGNAL(activated(int)), this, SLOT(tagBSelected(int))); 0217 0218 connect(user1Button, SIGNAL(clicked()), this, SLOT(annotateClicked())); 0219 connect(user2Button, SIGNAL(clicked()), this, SLOT(diffClicked())); 0220 connect(user3Button, SIGNAL(clicked()), this, SLOT(findClicked())); 0221 0222 connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotPatch())); 0223 connect(buttonBox, &QDialogButtonBox::helpRequested, this, &LogDialog::slotHelp); 0224 0225 KGuiItem::assign(okButton, KGuiItem(i18n("&View A"))); 0226 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Apply), KGuiItem(i18n("Create Patch..."))); 0227 0228 mainLayout->addWidget(buttonBox); 0229 buttonBox->button(QDialogButtonBox::Close)->setDefault(true); 0230 0231 setAttribute(Qt::WA_DeleteOnClose, true); 0232 0233 KConfigGroup cg(&partConfig, "LogDialog"); 0234 tabWidget->setCurrentIndex(cg.readEntry("ShowTab", 0)); 0235 restoreGeometry(cg.readEntry<QByteArray>("geometry", QByteArray())); 0236 0237 splitter->restoreState(cg.readEntry<QByteArray>("Splitter", QByteArray())); 0238 0239 updateButtons(); 0240 } 0241 0242 //-------------------------------------------------------------------------------- 0243 0244 LogDialog::~LogDialog() 0245 { 0246 qDeleteAll(items); 0247 qDeleteAll(tags); 0248 0249 KConfigGroup cg(&partConfig, "LogDialog"); 0250 cg.writeEntry("ShowTab", tabWidget->currentIndex()); 0251 cg.writeEntry("geometry", saveGeometry()); 0252 cg.writeEntry("Splitter", splitter->saveState()); 0253 } 0254 0255 //-------------------------------------------------------------------------------- 0256 0257 bool LogDialog::parseCvsLog(OrgKdeCervisia5CvsserviceCvsserviceInterface *service, const QString &fileName) 0258 { 0259 QString rev; 0260 0261 Cervisia::LogInfo logInfo; 0262 0263 enum { Begin, Tags, Admin, Revision, Author, Branches, Comment, Finished } state; 0264 0265 // remember DBUS reference and file name for diff or annotate 0266 cvsService = service; 0267 filename = fileName; 0268 0269 setWindowTitle(i18n("CVS Log: %1", filename)); 0270 0271 QDBusReply<QDBusObjectPath> job = cvsService->log(filename); 0272 if (!job.isValid()) 0273 return false; 0274 0275 ProgressDialog dlg(this, "Logging", cvsService->service(), job, "log", i18n("CVS Log")); 0276 if (!dlg.execute()) 0277 return false; 0278 0279 // process cvs log output 0280 state = Begin; 0281 QString line; 0282 while (dlg.getLine(line)) { 0283 switch (state) { 0284 case Begin: 0285 if (line == "symbolic names:") 0286 state = Tags; 0287 break; 0288 case Tags: 0289 if (line[0] == '\t') { 0290 const QStringList strlist(splitLine(line, ':')); 0291 rev = strlist[1].simplified(); 0292 const QString tag(strlist[0].simplified()); 0293 QString branchpoint; 0294 int pos1, pos2; 0295 if ((pos2 = rev.lastIndexOf('.')) > 0 && (pos1 = rev.lastIndexOf('.', pos2 - 1)) > 0 && rev.mid(pos1 + 1, pos2 - pos1 - 1) == "0") { 0296 // For a branch tag 2.10.0.6, we want: 0297 // branchpoint = "2.10" 0298 // rev = "2.10.6" 0299 branchpoint = rev.left(pos1); 0300 rev.remove(pos1 + 1, pos2 - pos1); 0301 } 0302 if (rev != "1.1.1") { 0303 auto taginfo = new LogDialogTagInfo; 0304 taginfo->rev = rev; 0305 taginfo->tag = tag; 0306 taginfo->branchpoint = branchpoint; 0307 tags.append(taginfo); 0308 } 0309 } else { 0310 state = Admin; 0311 } 0312 break; 0313 case Admin: 0314 if (line == "----------------------------") { 0315 state = Revision; 0316 } 0317 break; 0318 case Revision: 0319 if (line.startsWith(QLatin1String("revision "))) { 0320 logInfo.m_revision = rev = line.section(' ', 1, 1); 0321 state = Author; 0322 } 0323 break; 0324 case Author: { 0325 if (line.startsWith(QLatin1String("date: "))) { 0326 QStringList strList = line.split(';'); 0327 0328 // convert date into ISO format (YYYY-MM-DDTHH:MM:SS) 0329 int len = strList[0].length(); 0330 QString dateTimeStr = strList[0].right(len - 6); // remove 'date: ' 0331 dateTimeStr.replace('/', '-'); 0332 0333 QString date = dateTimeStr.section(' ', 0, 0); 0334 QString time = dateTimeStr.section(' ', 1, 1); 0335 logInfo.m_dateTime.setTime_t(QDateTime::fromString(date + 'T' + time, Qt::ISODate).toTime_t()); 0336 0337 logInfo.m_author = strList[1].section(':', 1, 1).trimmed(); 0338 0339 state = Branches; 0340 } 0341 } break; 0342 case Branches: 0343 if (!line.startsWith(QLatin1String("branches:"))) { 0344 logInfo.m_comment = line; 0345 state = Comment; 0346 } 0347 break; 0348 case Comment: 0349 if (line == "----------------------------") { 0350 QStringList lines = dlg.getOutput(); 0351 if ((lines.count() >= 2) && // at least revision and date line must follow 0352 lines[0].startsWith(QLatin1String("revision ")) && lines[1].startsWith(QLatin1String("date: "))) { 0353 state = Revision; 0354 } 0355 } else if (line == "=============================================================================") { 0356 state = Finished; 0357 } 0358 if (state == Comment) // still in message 0359 logInfo.m_comment += '\n' + line; 0360 else { 0361 // Create tagcomment 0362 QString branchrev; 0363 int pos1, pos2; 0364 // 1.60.x.y => revision belongs to branch 1.60.0.x 0365 if ((pos2 = rev.lastIndexOf('.')) > 0 && (pos1 = rev.lastIndexOf('.', pos2 - 1)) > 0) 0366 branchrev = rev.left(pos2); 0367 0368 // Build Cervisia::TagInfo for logInfo 0369 foreach (LogDialogTagInfo *tagInfo, tags) { 0370 if (rev == tagInfo->rev) { 0371 // This never matches branch tags... 0372 logInfo.m_tags.push_back(Cervisia::TagInfo(tagInfo->tag, Cervisia::TagInfo::Tag)); 0373 } 0374 if (rev == tagInfo->branchpoint) { 0375 logInfo.m_tags.push_back(Cervisia::TagInfo(tagInfo->tag, Cervisia::TagInfo::Branch)); 0376 } 0377 if (branchrev == tagInfo->rev) { 0378 // ... and this never matches ordinary tags :-) 0379 logInfo.m_tags.push_back(Cervisia::TagInfo(tagInfo->tag, Cervisia::TagInfo::OnBranch)); 0380 } 0381 } 0382 0383 plain->addRevision(logInfo); 0384 tree->addRevision(logInfo); 0385 list->addRevision(logInfo); 0386 0387 items.append(new Cervisia::LogInfo(logInfo)); 0388 0389 // reset for next entry 0390 logInfo = Cervisia::LogInfo(); 0391 } 0392 break; 0393 case Finished:; 0394 } 0395 } 0396 0397 tagcombo[0]->addItem(QString()); 0398 tagcombo[1]->addItem(QString()); 0399 foreach (LogDialogTagInfo *tagInfo, tags) { 0400 QString str = tagInfo->tag; 0401 if (!tagInfo->branchpoint.isEmpty()) 0402 str += i18n(" (Branchpoint)"); 0403 tagcombo[0]->addItem(str); 0404 tagcombo[1]->addItem(str); 0405 } 0406 0407 plain->scrollToTop(); 0408 0409 tree->collectConnections(); 0410 tree->recomputeCellSizes(); 0411 0412 return true; // successful 0413 } 0414 0415 //-------------------------------------------------------------------------------- 0416 0417 void LogDialog::slotOk() 0418 { 0419 // make sure that the user selected a revision 0420 if (selectionA.isEmpty() && selectionB.isEmpty()) { 0421 KMessageBox::information(this, i18n("Please select revision A or B first."), "Cervisia"); 0422 return; 0423 } 0424 0425 // retrieve the selected revision 0426 QString revision; 0427 if (!selectionA.isEmpty()) 0428 revision = selectionA; 0429 else 0430 revision = selectionB; 0431 0432 // create a temporary file 0433 const QString suffix('-' + revision + '-' + QFileInfo(filename).fileName()); 0434 const QString tempFileName(::tempFileName(suffix)); 0435 0436 // retrieve the file with the selected revision from cvs 0437 // and save the content into the temporary file 0438 QDBusReply<QDBusObjectPath> job = cvsService->downloadRevision(filename, revision, tempFileName); 0439 if (!job.isValid()) 0440 return; 0441 0442 ProgressDialog dlg(this, "View", cvsService->service(), job, "view", i18n("View File")); 0443 if (dlg.execute()) { 0444 // make file read-only 0445 QFile::setPermissions(tempFileName, QFileDevice::ReadOwner); 0446 0447 // open file in preferred editor 0448 (void)new KRun(QUrl::fromLocalFile(tempFileName), 0, true); 0449 } 0450 } 0451 0452 //-------------------------------------------------------------------------------- 0453 0454 void LogDialog::slotPatch() 0455 { 0456 if (selectionA.isEmpty()) { 0457 KMessageBox::information(this, i18n("Please select revision A or revisions A and B first."), "Cervisia"); 0458 return; 0459 } 0460 0461 Cervisia::PatchOptionDialog optionDlg; 0462 if (optionDlg.exec() == QDialog::Rejected) 0463 return; 0464 0465 QString format = optionDlg.formatOption(); 0466 QString diffOptions = optionDlg.diffOptions(); 0467 0468 QDBusReply<QDBusObjectPath> job = cvsService->diff(filename, selectionA, selectionB, diffOptions, format); 0469 if (!job.isValid()) 0470 return; 0471 0472 ProgressDialog dlg(this, "Diff", cvsService->service(), job, "", i18n("CVS Diff")); 0473 if (!dlg.execute()) 0474 return; 0475 0476 QString fileName = QFileDialog::getSaveFileName(); 0477 if (fileName.isEmpty()) 0478 return; 0479 0480 if (!Cervisia::CheckOverwrite(fileName)) 0481 return; 0482 0483 QFile f(fileName); 0484 if (!f.open(QIODevice::WriteOnly)) { 0485 KMessageBox::error(this, i18n("Could not open file for writing."), "Cervisia"); 0486 return; 0487 } 0488 0489 QTextStream t(&f); 0490 QString line; 0491 while (dlg.getLine(line)) 0492 t << line << '\n'; 0493 0494 f.close(); 0495 } 0496 0497 //-------------------------------------------------------------------------------- 0498 0499 void LogDialog::slotHelp() 0500 { 0501 KHelpClient::invokeHelp(QLatin1String("browsinglogs")); 0502 } 0503 0504 //-------------------------------------------------------------------------------- 0505 0506 void LogDialog::findClicked() 0507 { 0508 KFindDialog dlg(this); 0509 if (dlg.exec() == QDialog::Accepted) 0510 plain->searchText(dlg.options(), dlg.pattern()); 0511 } 0512 0513 void LogDialog::diffClicked() 0514 { 0515 if (selectionA.isEmpty()) { 0516 KMessageBox::information(this, i18n("Please select revision A or revisions A and B first."), "Cervisia"); 0517 return; 0518 } 0519 0520 // Non-modal dialog 0521 auto l = new DiffDialog(partConfig); 0522 if (l->parseCvsDiff(cvsService, filename, selectionA, selectionB)) 0523 l->show(); 0524 else 0525 delete l; 0526 } 0527 0528 void LogDialog::annotateClicked() 0529 { 0530 auto l = new AnnotateDialog(partConfig); 0531 AnnotateController ctl(l, cvsService); 0532 ctl.showDialog(filename, selectionA); 0533 } 0534 0535 void LogDialog::revisionSelected(QString rev, bool rmb) 0536 { 0537 foreach (Cervisia::LogInfo *logInfo, items) 0538 if (logInfo->m_revision == rev) { 0539 if (rmb) 0540 selectionB = rev; 0541 else 0542 selectionA = rev; 0543 0544 revbox[rmb ? 1 : 0]->setText(rev); 0545 authorbox[rmb ? 1 : 0]->setText(logInfo->m_author); 0546 datebox[rmb ? 1 : 0]->setText(logInfo->dateTimeToString()); 0547 commentbox[rmb ? 1 : 0]->setPlainText(logInfo->m_comment); 0548 tagsbox[rmb ? 1 : 0]->setPlainText(logInfo->tagsToString()); 0549 0550 tree->setSelectedPair(selectionA, selectionB); 0551 list->setSelectedPair(selectionA, selectionB); 0552 0553 updateButtons(); 0554 return; 0555 } 0556 qCDebug(log_cervisia) << "Internal error: Revision not found " << rev << "."; 0557 } 0558 0559 void LogDialog::tagSelected(LogDialogTagInfo *tag, bool rmb) 0560 { 0561 if (tag->branchpoint.isEmpty()) 0562 revisionSelected(tag->rev, rmb); 0563 else 0564 revisionSelected(tag->branchpoint, rmb); 0565 } 0566 0567 void LogDialog::updateButtons() 0568 { 0569 // no versions selected? 0570 if (selectionA.isEmpty() && selectionB.isEmpty()) { 0571 user1Button->setEnabled(true); 0572 user2Button->setEnabled(false); 0573 okButton->setEnabled(false); // view 0574 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); // create patch 0575 } 0576 // both versions selected? 0577 else if (!selectionA.isEmpty() && !selectionB.isEmpty()) { 0578 user1Button->setEnabled(true); 0579 user2Button->setEnabled(true); 0580 okButton->setEnabled(true); // view A 0581 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); // create patch 0582 } 0583 // only single version selected? 0584 else { 0585 user1Button->setEnabled(true); 0586 user2Button->setEnabled(true); 0587 okButton->setEnabled(true); // view 0588 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); // create patch 0589 } 0590 } 0591 0592 void LogDialog::tagASelected(int n) 0593 { 0594 if (n) 0595 tagSelected(tags.at(n - 1), false); 0596 } 0597 0598 void LogDialog::tagBSelected(int n) 0599 { 0600 if (n) 0601 tagSelected(tags.at(n - 1), true); 0602 } 0603 0604 void LogDialog::tabChanged(int index) 0605 { 0606 bool isPlainView = (tabWidget->widget(index) == plain); 0607 user3Button->setVisible(isPlainView); 0608 } 0609 0610 // Local Variables: 0611 // c-basic-offset: 4 0612 // End: