File indexing completed on 2024-05-12 04:38:56
0001 /* 0002 SPDX-FileCopyrightText: 2007 Dukju Ahn <dukjuahn@gmail.com> 0003 SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "vcseventwidget.h" 0009 0010 #include <QAction> 0011 #include <QClipboard> 0012 #include <QDialog> 0013 #include <QDialogButtonBox> 0014 #include <QHeaderView> 0015 #include <QMenu> 0016 #include <QPushButton> 0017 #include <QVBoxLayout> 0018 #include <QDesktopServices> 0019 0020 #include <KLocalizedString> 0021 #include <KTextToHTML> 0022 0023 #include <interfaces/iplugin.h> 0024 0025 #include "ui_vcseventwidget.h" 0026 #include "vcsdiffwidget.h" 0027 0028 #include "../interfaces/ibasicversioncontrol.h" 0029 #include "../models/vcseventmodel.h" 0030 #include "../models/vcsitemeventmodel.h" 0031 #include "../vcsevent.h" 0032 #include "../vcsjob.h" 0033 #include "../vcsrevision.h" 0034 #include "debug.h" 0035 0036 0037 namespace KDevelop 0038 { 0039 0040 class VcsEventWidgetPrivate 0041 { 0042 public: 0043 explicit VcsEventWidgetPrivate( VcsEventWidget* w ) 0044 : q( w ) 0045 { 0046 m_copyAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "Copy Revision Id"), q); 0047 m_copyAction->setShortcut(Qt::CTRL | Qt::Key_C); 0048 QObject::connect(m_copyAction, &QAction::triggered, q, [&] { copyRevision(); }); 0049 } 0050 0051 Ui::VcsEventWidget* m_ui; 0052 VcsItemEventModel* m_detailModel; 0053 VcsEventLogModel *m_logModel; 0054 QUrl m_url; 0055 QModelIndex m_contextIndex; 0056 VcsEventWidget* q; 0057 QAction* m_copyAction; 0058 IBasicVersionControl* m_iface; 0059 void eventViewCustomContextMenuRequested( const QPoint &point ); 0060 void eventViewClicked( const QModelIndex &index ); 0061 void jobReceivedResults( KDevelop::VcsJob* job ); 0062 void copyRevision(); 0063 void diffToPrevious(); 0064 void diffRevisions(); 0065 void currentRowChanged(const QModelIndex& start, const QModelIndex& end); 0066 }; 0067 0068 void VcsEventWidgetPrivate::eventViewCustomContextMenuRequested( const QPoint &point ) 0069 { 0070 m_contextIndex = m_ui->eventView->indexAt( point ); 0071 if( !m_contextIndex.isValid() ){ 0072 qCDebug(VCS) << "contextMenu is not in TreeView"; 0073 return; 0074 } 0075 0076 QMenu menu( m_ui->eventView ); 0077 menu.addAction(m_copyAction); 0078 auto diffToPreviousAction = menu.addAction(i18nc("@action:inmenu", "Diff to Previous Revision")); 0079 QObject::connect(diffToPreviousAction, &QAction::triggered, q, [&] { diffToPrevious(); }); 0080 0081 auto diffRevisionsAction = menu.addAction(i18nc("@action:inmenu", "Diff between Revisions")); 0082 QObject::connect(diffRevisionsAction, &QAction::triggered, q, [&] { diffRevisions(); }); 0083 diffRevisionsAction->setEnabled(m_ui->eventView->selectionModel()->selectedRows().size()>=2); 0084 0085 menu.exec( m_ui->eventView->viewport()->mapToGlobal(point) ); 0086 } 0087 0088 void VcsEventWidgetPrivate::currentRowChanged(const QModelIndex& start, const QModelIndex& end) 0089 { 0090 Q_UNUSED(end); 0091 if(start.isValid()) 0092 eventViewClicked(start); 0093 } 0094 0095 void VcsEventWidgetPrivate::eventViewClicked( const QModelIndex &index ) 0096 { 0097 KDevelop::VcsEvent ev = m_logModel->eventForIndex( index ); 0098 m_detailModel->removeRows(0, m_detailModel->rowCount()); 0099 0100 if( ev.revision().revisionType() != KDevelop::VcsRevision::Invalid ) 0101 { 0102 m_ui->itemEventView->setEnabled(true); 0103 m_ui->message->setEnabled(true); 0104 const KTextToHTML::Options markupOptions = KTextToHTML::PreserveSpaces; 0105 const QString markupMessage = 0106 QLatin1String("<tt>") + KTextToHTML::convertToHtml(ev.message(), markupOptions) + QLatin1String("</tt>"); 0107 m_ui->message->setHtml(markupMessage); 0108 m_detailModel->addItemEvents( ev.items() ); 0109 }else 0110 { 0111 m_ui->itemEventView->setEnabled(false); 0112 m_ui->message->setEnabled(false); 0113 m_ui->message->clear(); 0114 } 0115 0116 QHeaderView* header = m_ui->itemEventView->header(); 0117 header->setSectionResizeMode(QHeaderView::ResizeToContents); 0118 header->setStretchLastSection(true); 0119 } 0120 0121 void VcsEventWidgetPrivate::copyRevision() 0122 { 0123 qApp->clipboard()->setText(m_contextIndex.sibling(m_contextIndex.row(), 0).data().toString()); 0124 } 0125 0126 void VcsEventWidgetPrivate::diffToPrevious() 0127 { 0128 KDevelop::VcsEvent ev = m_logModel->eventForIndex( m_contextIndex ); 0129 KDevelop::VcsRevision prev = KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Previous); 0130 KDevelop::VcsJob* job = m_iface->diff( m_url, prev, ev.revision() ); 0131 0132 auto* widget = new VcsDiffWidget( job ); 0133 widget->setRevisions( prev, ev.revision() ); 0134 auto* dlg = new QDialog( q ); 0135 0136 widget->connect(widget, &VcsDiffWidget::destroyed, dlg, &QDialog::deleteLater); 0137 0138 dlg->setWindowTitle( i18nc("@title:window", "Difference To Previous") ); 0139 0140 auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); 0141 auto mainWidget = new QWidget; 0142 auto *mainLayout = new QVBoxLayout; 0143 dlg->setLayout(mainLayout); 0144 mainLayout->addWidget(mainWidget); 0145 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); 0146 okButton->setDefault(true); 0147 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0148 dlg->connect(buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept); 0149 dlg->connect(buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject); 0150 mainLayout->addWidget(widget); 0151 mainLayout->addWidget(buttonBox); 0152 0153 dlg->show(); 0154 } 0155 0156 void VcsEventWidgetPrivate::diffRevisions() 0157 { 0158 QModelIndexList l = m_ui->eventView->selectionModel()->selectedRows(); 0159 KDevelop::VcsEvent ev1 = m_logModel->eventForIndex( l.first() ); 0160 KDevelop::VcsEvent ev2 = m_logModel->eventForIndex( l.last() ); 0161 KDevelop::VcsJob* job = m_iface->diff( m_url, ev1.revision(), ev2.revision() ); 0162 0163 auto* widget = new VcsDiffWidget( job ); 0164 widget->setRevisions( ev1.revision(), ev2.revision() ); 0165 0166 auto dlg = new QDialog( q ); 0167 dlg->setWindowTitle( i18nc("@title:window", "Difference between Revisions") ); 0168 0169 widget->connect(widget, &VcsDiffWidget::destroyed, dlg, &QDialog::deleteLater); 0170 0171 auto mainLayout = new QVBoxLayout(dlg); 0172 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); 0173 auto okButton = buttonBox->button(QDialogButtonBox::Ok); 0174 okButton->setDefault(true); 0175 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0176 dlg->connect(buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept); 0177 dlg->connect(buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject); 0178 mainLayout->addWidget(buttonBox); 0179 mainLayout->addWidget(widget); 0180 dlg->show(); 0181 } 0182 0183 VcsEventWidget::VcsEventWidget( const QUrl& url, const VcsRevision& rev, KDevelop::IBasicVersionControl* iface, QWidget* parent ) 0184 : QWidget(parent) 0185 , d_ptr(new VcsEventWidgetPrivate(this)) 0186 { 0187 Q_D(VcsEventWidget); 0188 0189 d->m_iface = iface; 0190 d->m_url = url; 0191 d->m_ui = new Ui::VcsEventWidget(); 0192 d->m_ui->setupUi(this); 0193 0194 d->m_logModel = new VcsEventLogModel(iface, rev, url, this); 0195 d->m_ui->eventView->setModel( d->m_logModel ); 0196 d->m_ui->eventView->sortByColumn(0, Qt::DescendingOrder); 0197 d->m_ui->eventView->setContextMenuPolicy( Qt::CustomContextMenu ); 0198 QHeaderView* header = d->m_ui->eventView->header(); 0199 header->setSectionResizeMode( 0, QHeaderView::ResizeToContents ); 0200 header->setSectionResizeMode( 1, QHeaderView::Stretch ); 0201 header->setSectionResizeMode( 2, QHeaderView::ResizeToContents ); 0202 header->setSectionResizeMode( 3, QHeaderView::ResizeToContents ); 0203 // Select first row as soon as the model got populated 0204 connect(d->m_logModel, &QAbstractItemModel::rowsInserted, this, [this]() { 0205 Q_D(VcsEventWidget); 0206 auto view = d->m_ui->eventView; 0207 view->setCurrentIndex(view->model()->index(0, 0)); 0208 }); 0209 0210 d->m_detailModel = new VcsItemEventModel(this); 0211 d->m_ui->itemEventView->setModel( d->m_detailModel ); 0212 0213 connect(d->m_ui->eventView, &QTreeView::clicked, this, [this] (const QModelIndex& index) { 0214 Q_D(VcsEventWidget); 0215 d->eventViewClicked(index); 0216 }); 0217 connect(d->m_ui->eventView->selectionModel(), &QItemSelectionModel::currentRowChanged, 0218 this, [this] (const QModelIndex& start, const QModelIndex& end) { 0219 Q_D(VcsEventWidget); 0220 d->currentRowChanged(start, end); 0221 }); 0222 connect(d->m_ui->eventView, &QTreeView::customContextMenuRequested, 0223 this, [this] (const QPoint& point) { 0224 Q_D(VcsEventWidget); 0225 d->eventViewCustomContextMenuRequested(point); 0226 }); 0227 0228 connect(d->m_ui->message, &QTextBrowser::anchorClicked, 0229 this, [&] (const QUrl& url) { QDesktopServices::openUrl(url); }); 0230 } 0231 0232 VcsEventWidget::~VcsEventWidget() 0233 { 0234 Q_D(VcsEventWidget); 0235 0236 delete d->m_ui; 0237 } 0238 0239 } 0240 0241 0242 #include "moc_vcseventwidget.cpp"