diff --git a/src/svnfrontend/database/dbsettings.cpp b/src/svnfrontend/database/dbsettings.cpp index 75cba5c7..4ea652dc 100644 --- a/src/svnfrontend/database/dbsettings.cpp +++ b/src/svnfrontend/database/dbsettings.cpp @@ -1,85 +1,85 @@ /*************************************************************************** * Copyright (C) 2005-2009 by Rajko Albrecht ral@alwins-world.de * * http://kdesvn.alwins-world.de/ * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public * * License along with this program (in the file GPL.txt); if not, * * write to the Free Software Foundation, Inc., 51 Franklin St, * * Fifth Floor, Boston, MA 02110-1301 USA * * * * This software consists of voluntary contributions made by many * * individuals. For exact contribution history, see the revision * * history and logs, available at http://kdesvn.alwins-world.de. * ***************************************************************************/ #include "dbsettings.h" #include "ui_dbsettings.h" #include "svnqt/cache/ReposConfig.h" #include DbSettings::DbSettings(const QString &repository, QWidget *parent) : KSvnDialog(QLatin1String("db_settings_dlg"), parent) , m_repository(repository) , m_ui(new Ui::DbSettings) { m_ui->setupUi(this); setDefaultButton(m_ui->buttonBox->button(QDialogButtonBox::Ok)); - connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &DbSettings::accept); + connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &DbSettings::reject); setWindowTitle(i18nc("@title:window", "Settings for %1", repository)); init(); } DbSettings::~DbSettings() { delete m_ui; } void DbSettings::init() { m_ui->dbcfg_exclude_box->setItems(svn::cache::ReposConfig::self()->readEntry(m_repository, "tree_exclude_list", QStringList())); m_ui->dbcfg_exclude_userslog->setItems(svn::cache::ReposConfig::self()->readEntry(m_repository, "exclude_log_users", QStringList())); m_ui->dbcfg_exclude_log_pattern->setItems(svn::cache::ReposConfig::self()->readEntry(m_repository, "exclude_log_pattern", QStringList())); m_ui->dbcfg_noCacheUpdate->setChecked(svn::cache::ReposConfig::self()->readEntry(m_repository, "no_update_cache", false)); m_ui->dbcfg_filter_empty_author->setChecked(svn::cache::ReposConfig::self()->readEntry(m_repository, "filter_empty_author", false)); } void DbSettings::store_list(KEditListWidget *which, const QString &key) { if (!which || key.isEmpty()) { return; } const QStringList _v = which->items(); if (!_v.isEmpty()) { svn::cache::ReposConfig::self()->setValue(m_repository, key, _v); } else { svn::cache::ReposConfig::self()->eraseValue(m_repository, key); } } void DbSettings::accept() { store_list(m_ui->dbcfg_exclude_box, "tree_exclude_list"); store_list(m_ui->dbcfg_exclude_userslog, "exclude_log_users"); store_list(m_ui->dbcfg_exclude_log_pattern, "exclude_log_pattern"); svn::cache::ReposConfig::self()->setValue(m_repository, "no_update_cache", m_ui->dbcfg_noCacheUpdate->isChecked()); svn::cache::ReposConfig::self()->setValue(m_repository, "filter_empty_author", m_ui->dbcfg_filter_empty_author->isChecked()); KSvnDialog::accept(); } void DbSettings::showSettings(const QString &repository, QWidget *parent) { QPointer dlg(new DbSettings(repository, parent ? parent : QApplication::activeModalWidget())); dlg->exec(); delete dlg; } diff --git a/src/svnfrontend/editpropsdlg.cpp b/src/svnfrontend/editpropsdlg.cpp index 955dc467..b4429cb4 100644 --- a/src/svnfrontend/editpropsdlg.cpp +++ b/src/svnfrontend/editpropsdlg.cpp @@ -1,194 +1,195 @@ /*************************************************************************** * Copyright (C) 2005-2009 by Rajko Albrecht * * ral@alwins-world.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "editpropsdlg.h" #include "ui_editpropsdlg.h" #include EditPropsDlg::EditPropsDlg(bool bAddMode, QWidget *parent) : KSvnDialog(QLatin1String("modify_properties"), parent) , m_isDir(false) , m_ui(new Ui::EditPropsDlg) { m_ui->setupUi(this); if (bAddMode) { setWindowTitle(i18nc("@title:window", "Add Property")); } connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(m_ui->helpButton, &QAbstractButton::clicked, this, &EditPropsDlg::showHelp); m_ui->helpButton->setIcon(QIcon::fromTheme(QStringLiteral("help-hint"))); /// @TODO Read these values from a text or config file fileProperties += QStringLiteral("svn:eol-style"); fileProperties += QStringLiteral("svn:executable"); fileProperties += QStringLiteral("svn:keywords"); fileProperties += QStringLiteral("svn:needs-lock"); fileProperties += QStringLiteral("svn:mime-type"); fileComments += i18n("One of 'native', 'LF', 'CR', 'CRLF'."); fileComments += i18n("If present, make the file executable.
" "This property can not be set on a directory. " "A non-recursive attempt will fail, and a recursive attempt " "will set the property only on the file children of the folder."); fileComments += i18n("Keywords to be expanded into the contents of a file.
" "They can be inserted into documents by placing a keyword anchor " "which is formatted as $KeywordName$.
" "Valid keywords are:
" "URL/HeadURL The URL for the head revision of the project.
" "Author/LastChangedBy The last person to change the file.
" "Date/LastChangedDate The date/time the object was last modified.
" "Revision/Rev/LastChangedRevision The last revision the object changed.
" "Id A compressed summary of the previous 4 keywords."); fileComments += i18n("Set this to any value (e.g. '*') to enforce locking for this file.
" "The file will be set read-only when checked out or updated, " "indicating that a user must acquire a lock on the file before " "they can edit and commit changes."); fileComments += i18n("The mimetype of the file. Used to determine " "whether to merge the file and how to serve it from " "Apache. A mimetype beginning with 'text/' (or an absent " "mimetype) is treated as text. Anything else is treated as binary."); dirProperties += QStringLiteral("svn:eol-style"); dirProperties += QStringLiteral("svn:executable"); dirProperties += QStringLiteral("svn:externals"); dirProperties += QStringLiteral("svn:ignore"); dirProperties += QStringLiteral("svn:mime-type"); dirProperties += QStringLiteral("bugtraq:label"); dirProperties += QStringLiteral("bugtraq:url"); dirProperties += QStringLiteral("bugtraq:message"); dirProperties += QStringLiteral("bugtraq:warnifnoissue"); dirProperties += QStringLiteral("bugtraq:number"); dirProperties += QStringLiteral("bugtraq:append"); dirProperties += QStringLiteral("bugtraq:logregex"); dirComments += i18n("One of 'native', 'LF', 'CR', 'CRLF'."); dirComments += i18n("If present, make the file executable.
" "This property can not be set on a directory. " "A non-recursive attempt will fail, and a recursive attempt " "will set the property only on the file children of the folder."); /* TRANSLATORS: Do not translate "example" in the URL because this is according TRANSLATORS: to http://www.rfc-editor.org/rfc/rfc2606.txt a reserved URL.*/ dirComments += i18n("A newline separated list of module specifiers, each " "consisting of a relative directory path, optional revision " "flags, and a URL. For example:
" "foo http://example.com/repos/projectA
" "foo/bar -r 1234 http://example.com/repos/projectB"); dirComments += i18n("A newline separated list of file patterns to ignore."); dirComments += i18n("The mimetype of the file. Used to determine " "whether to merge the file and how to serve it from " "Apache. A mimetype beginning with 'text/' (or an absent " "mimetype) is treated as text. Anything else is treated as binary."); dirComments += i18n("Label text to show for the edit box where the user enters the issue number."); /* TRANSLATORS: Do not translate "example" in the URL because this is according TRANSLATORS: to http://www.rfc-editor.org/rfc/rfc2606.txt a reserved URL.*/ dirComments += i18n("URL pointing to the issue tracker. It must contain " "%BUGID% which gets replaced with the bug issue number. Example:
" "http://example.com/mantis/view.php?id=%BUGID%"); dirComments += i18n("String which is appended to a log message when an issue " "number is entered. The string must contain %BUGID% " "which gets replaced with the bug issue number."); dirComments += i18n("Set to 'yes' if a warning shall be shown when " "no issue is entered in the commit dialog. Possible values:
" "'true'/'yes' or 'false'/'no'."); dirComments += i18n("Set to 'false' if your bugtracking system has " "issues which are referenced not by numbers.
" "Possible values: 'true' or 'false'."); dirComments += i18n("Set to 'false' if you want the bugtracking ID " "to be inserted at the top of the log message. The " "default is 'true' which means the bugtracking " "ID is appended to the log message."); dirComments += i18n("Two regular expressions separated by a newline.
" "The first expression is used to find a string referring to an issue, the " "second expression is used to extract the bare bug ID from that string."); m_ui->m_NameEdit->setCompletionMode(KCompletion::CompletionPopupAuto); m_ui->m_NameEdit->setHistoryItems(fileProperties, true); m_ui->m_NameEdit->setToolTip(i18n("Select or enter new property")); - connect(m_ui->m_NameEdit, SIGNAL(activated(QString)), this, SLOT(updateToolTip(QString))); + connect(m_ui->m_NameEdit, QOverload::of(&KHistoryComboBox::activated), + this, &EditPropsDlg::updateToolTip); } EditPropsDlg::~EditPropsDlg() { delete m_ui; } void EditPropsDlg::updateToolTip(const QString &selection) { QString comment; if (m_isDir) { int i = dirProperties.indexOf(selection); if (i >= 0) { comment = dirComments.at(i); } } else { int i = fileProperties.indexOf(selection); if (i >= 0) { comment = fileComments.at(i); } } if (comment.isEmpty()) { comment = i18n("No help for this property available"); } m_ui->m_NameEdit->setToolTip(comment); } void EditPropsDlg::setDir(bool dir) { if (dir == m_isDir) { // Change not necessary return; } m_ui->m_NameEdit->setHistoryItems(dir ? dirProperties : fileProperties, true); m_isDir = dir; } QString EditPropsDlg::propName()const { return m_ui->m_NameEdit->currentText(); } QString EditPropsDlg::propValue()const { return m_ui->m_ValueEdit->toPlainText(); } void EditPropsDlg::setPropName(const QString &n) { m_ui->m_NameEdit->addToHistory(n); m_ui->m_NameEdit->setCurrentItem(n); updateToolTip(n); } void EditPropsDlg::setPropValue(const QString &v) { m_ui->m_ValueEdit->setText(v); } void EditPropsDlg::showHelp() { QPoint pos = m_ui->m_ValueEdit->pos(); pos.setX(pos.x() + m_ui->m_ValueEdit->width() / 2); pos.setY(pos.y() + m_ui->m_ValueEdit->height() / 4); QWhatsThis::showText(mapToGlobal(pos), m_ui->m_NameEdit->toolTip()); } diff --git a/src/svnfrontend/fronthelpers/watchedprocess.cpp b/src/svnfrontend/fronthelpers/watchedprocess.cpp index 761f6c99..e8204687 100644 --- a/src/svnfrontend/fronthelpers/watchedprocess.cpp +++ b/src/svnfrontend/fronthelpers/watchedprocess.cpp @@ -1,123 +1,129 @@ /*************************************************************************** * Copyright (C) 2005-2009 by Rajko Albrecht ral@alwins-world.de * * http://kdesvn.alwins-world.de/ * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "watchedprocess.h" #include #include #include class ProcessData { public: ProcessData() : _autoDelete(false) {} ~ProcessData() { QStringList::iterator it2; for (it2 = _tempFiles.begin(); it2 != _tempFiles.end(); ++it2) { QFile::remove(*it2); } for (it2 = _tempDirs.begin(); it2 != _tempDirs.end(); ++it2) { QDir(*it2).removeRecursively(); } } QStringList _tempFiles; QStringList _tempDirs; bool _autoDelete; }; WatchedProcess::WatchedProcess(QObject *parent) : KProcess(parent) + , m_Data(new ProcessData) { - m_Data = new ProcessData; - connect(this, SIGNAL(error(QProcess::ProcessError)), SLOT(slotError(QProcess::ProcessError))); - connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(slotFinished(int,QProcess::ExitStatus))); - connect(this, &QProcess::readyReadStandardError, this, &WatchedProcess::slotReadyReadStandardError); - connect(this, &QProcess::readyReadStandardOutput, this, &WatchedProcess::slotReadyReadStandardOutput); - connect(this, SIGNAL(started()), SLOT(slotStarted())); - connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), SLOT(slotStateChanged(QProcess::ProcessState))); + connect(this, &QProcess::errorOccurred, + this, &WatchedProcess::slotError); + connect(this, QOverload::of(&KProcess::finished), + this, &WatchedProcess::slotFinished); + connect(this, &QProcess::readyReadStandardError, + this, &WatchedProcess::slotReadyReadStandardError); + connect(this, &QProcess::readyReadStandardOutput, + this, &WatchedProcess::slotReadyReadStandardOutput); + connect(this, &KProcess::started, + this, &WatchedProcess::slotStarted); + connect(this, &KProcess::stateChanged, + this, &WatchedProcess::slotStateChanged); } WatchedProcess::~WatchedProcess() { if (state() == QProcess::NotRunning) { terminate(); if (!waitForFinished(1000)) { kill(); } } delete m_Data; } void WatchedProcess::setAutoDelete(bool autodel) { m_Data->_autoDelete = autodel; } bool WatchedProcess::autoDelete()const { return m_Data->_autoDelete; } void WatchedProcess::slotError(QProcess::ProcessError error_code) { emit error(error_code, this); } void WatchedProcess::slotFinished(int exitCode, QProcess::ExitStatus exitStatus) { emit finished(exitCode, exitStatus, this); if (m_Data->_autoDelete) { m_Data->_autoDelete = false; deleteLater(); } } void WatchedProcess::WatchedProcess::slotReadyReadStandardError() { emit dataStderrRead(readAllStandardError(), this); } void WatchedProcess::slotReadyReadStandardOutput() { emit dataStdoutRead(readAllStandardOutput(), this); } void WatchedProcess::slotStarted() { emit started(this); } void WatchedProcess::slotStateChanged(QProcess::ProcessState state) { emit stateChanged(state, this); } void WatchedProcess::appendTempFile(const QString &aFile) { m_Data->_tempFiles.append(aFile); } void WatchedProcess::appendTempDir(const QString &aDir) { m_Data->_tempDirs.append(aDir); } diff --git a/src/svnfrontend/graphtree/revgraphview.cpp b/src/svnfrontend/graphtree/revgraphview.cpp index 7db8837f..71357425 100644 --- a/src/svnfrontend/graphtree/revgraphview.cpp +++ b/src/svnfrontend/graphtree/revgraphview.cpp @@ -1,1006 +1,1006 @@ /*************************************************************************** * Copyright (C) 2006-2009 by Rajko Albrecht * * ral@alwins-world.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "revgraphview.h" #include "graphtreelabel.h" #include "pannerview.h" #include "graphtree_defines.h" #include "settings/kdesvnsettings.h" #include "../stopdlg.h" #include "svnqt/client.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LABEL_WIDTH 160 #define LABEL_HEIGHT 90 RevGraphView::RevGraphView(const svn::ClientP &_client, QWidget *parent) : QGraphicsView(parent) , m_Scene(nullptr) , m_Marker(nullptr) , m_Client(_client) , m_Selected(nullptr) , m_dotTmpFile(nullptr) , m_renderProcess(nullptr) , m_xMargin(0) , m_yMargin(0) , m_CompleteView(new PannerView(this)) , m_cvZoom(0) , m_LastAutoPosition(TopLeft) , m_isMoving(false) , m_noUpdateZoomerPos(false) { m_CompleteView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_CompleteView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_CompleteView->raise(); m_CompleteView->hide(); connect(m_CompleteView, &PannerView::zoomRectMoved, this, &RevGraphView::zoomRectMoved); connect(m_CompleteView, &PannerView::zoomRectMoveFinished, this, &RevGraphView::zoomRectMoveFinished); } RevGraphView::~RevGraphView() { setScene(nullptr); delete m_Scene; delete m_dotTmpFile; delete m_CompleteView; delete m_renderProcess; } void RevGraphView::showText(const QString &s) { clear(); m_Scene = new QGraphicsScene; m_Scene->addSimpleText(s); setScene(m_Scene); m_Scene->update(); m_CompleteView->hide(); } void RevGraphView::clear() { if (m_Selected) { m_Selected->setSelected(false); m_Selected = nullptr; } if (m_Marker) { m_Marker->hide(); delete m_Marker; m_Marker = nullptr; } setScene(nullptr); m_CompleteView->setScene(nullptr); delete m_Scene; m_Scene = nullptr; } void RevGraphView::beginInsert() { viewport()->setUpdatesEnabled(false); } void RevGraphView::endInsert() { if (m_Scene) { /* _cvZoom = 0; updateSizes(); */ m_Scene->update(); } viewport()->setUpdatesEnabled(true); } void RevGraphView::readDotOutput() { if (!m_renderProcess) { return; } m_dotOutput += QString::fromLocal8Bit(m_renderProcess->readAllStandardOutput()); } void RevGraphView::dotExit(int exitcode, QProcess::ExitStatus exitStatus) { if (!m_renderProcess) { return; } if (exitStatus != QProcess::NormalExit || exitcode != 0) { QString error = i18n("Could not run process \"%1\".\n\nProcess stopped with message:\n%2", m_renderProcess->program().join(" "), QString::fromLocal8Bit(m_renderProcess->readAllStandardError())); showText(error); delete m_renderProcess; m_renderProcess = nullptr; return; } // remove line breaks when lines to long QRegExp endslash("\\\\\\n"); m_dotOutput.remove(endslash); double scale = 1.0; double dotWidth = 1.0, dotHeight = 1.0; QTextStream dotStream(&m_dotOutput, QIODevice::ReadOnly); QString cmd; int lineno = 0; beginInsert(); clear(); /* mostly taken from kcachegrind */ double scaleX = scale * 60; double scaleY = scale * 70; QRectF startRect; while (!dotStream.atEnd()) { QString line = dotStream.readLine(); if (line.isNull()) { break; } lineno++; if (line.isEmpty()) { continue; } QTextStream lineStream(&line, QIODevice::ReadOnly); lineStream >> cmd; if (cmd == QLatin1String("stop")) { break; } if (cmd == QLatin1String("graph")) { lineStream >> scale >> dotWidth >> dotHeight; int w = qRound(scaleX * dotWidth); int h = qRound(scaleY * dotHeight); m_xMargin = 50; const QDesktopWidget *dw = QApplication::desktop(); if (w < dw->width()) { m_xMargin += (dw->width() - w) / 2; } m_yMargin = 50; if (h < dw->height()) { m_yMargin += (dw->height() - h) / 2; } m_Scene = new QGraphicsScene(0.0, 0.0, qreal(w + 2 * m_xMargin), qreal(h + 2 * m_yMargin)); m_Scene->setBackgroundBrush(Qt::white); continue; } if (m_dotTmpFile && (cmd != "node") && (cmd != "edge")) { qWarning() << "Ignoring unknown command '" << cmd << "' from dot (" << m_dotTmpFile->fileName() << ":" << lineno << ")" << endl; continue; } if (!m_Scene) { continue; } if (cmd == QLatin1String("node")) { QString nodeName, label; QString _x, _y, _w, _h; double x, y, width, height; lineStream >> nodeName >> _x >> _y >> _w >> _h; x = _x.toDouble(); y = _y.toDouble(); width = _w.toDouble(); height = _h.toDouble(); // better here 'cause dot may scramble utf8 labels so we regenerate it better // and do not read it in. label = getLabelstring(nodeName); double xx = (scaleX * x + m_xMargin); double yy = (scaleY * (dotHeight - y) + m_yMargin); double w = (scaleX * width); double h = (scaleY * height); QRectF r(xx - w / 2, yy - h / 2, w, h); GraphTreeLabel *t = new GraphTreeLabel(label, nodeName, r); m_Scene->addItem(t); if (isStart(nodeName)) { startRect = r; ensureVisible(startRect); } t->setBgColor(getBgColor(nodeName)); t->setZValue(1.0); t->show(); m_NodeList[nodeName] = t; t->setToolTip(toolTip(nodeName)); } else { QString node1Name, node2Name; QString _x, _y; double x, y; QPolygonF pa; int points, i; lineStream >> node1Name >> node2Name; lineStream >> points; pa.resize(points); for (i = 0; i < points; ++i) { if (lineStream.atEnd()) { break; } lineStream >> _x >> _y; x = _x.toDouble(); y = _y.toDouble(); double xx = (scaleX * x + m_xMargin); double yy = (scaleY * (dotHeight - y) + m_yMargin); #if 0 if (0) qDebug(" P %d: ( %f / %f ) => ( %d / %d)", i, x, y, xx, yy); #endif pa[i] = QPointF(xx, yy); } if (i < points) { qDebug("CallGraphView: Can't read %d spline points (%d)", points, lineno); continue; } GraphEdge *n = new GraphEdge(); QColor arrowColor = Qt::black; m_Scene->addItem(n); n->setPen(QPen(arrowColor, 1)); n->setControlPoints(pa); n->setZValue(0.5); n->show(); /* arrow dir * eg. it is vx and vy for computing, NO absolute points! */ QPointF arrowDir; int indexHead = -1; QMap::Iterator it; it = m_NodeList.find(node2Name); if (it != m_NodeList.end()) { it.value()->setSource(node1Name); } it = m_NodeList.find(node1Name); if (it != m_NodeList.end()) { GraphTreeLabel *tlab = it.value(); if (tlab) { QPointF toCenter = tlab->rect().center(); qreal dx0 = pa[0].x() - toCenter.x(); qreal dy0 = pa[0].y() - toCenter.y(); qreal dx1 = pa[points - 1].x() - toCenter.x(); qreal dy1 = pa[points - 1].y() - toCenter.y(); if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) { // start of spline is nearer to call target node indexHead = -1; while (arrowDir.isNull() && (indexHead < points - 2)) { indexHead++; arrowDir = pa[indexHead] - pa[indexHead + 1]; } } } } if (arrowDir.isNull()) { indexHead = points; // sometimes the last spline points from dot are the same... while (arrowDir.isNull() && (indexHead > 1)) { indexHead--; arrowDir = pa[indexHead] - pa[indexHead - 1]; } } if (!arrowDir.isNull()) { QPointF baseDir = arrowDir; arrowDir *= 10.0 / sqrt(double(arrowDir.x() * arrowDir.x() + arrowDir.y() * arrowDir.y())); baseDir /= (sqrt(baseDir.x() * baseDir.x() + baseDir.y() * baseDir.y())); QPointF t1(-baseDir.y() - baseDir.x(), baseDir.x() - baseDir.y()); QPointF t2(baseDir.y() - baseDir.x(), -baseDir.x() - baseDir.y()); QPolygonF a; t1 *= 3; t2 *= 3; a << pa[indexHead] + t1 << pa[indexHead] + arrowDir << pa[indexHead] + t2; GraphEdgeArrow *aItem = new GraphEdgeArrow(n, nullptr); m_Scene->addItem(aItem); aItem->setPolygon(a); aItem->setBrush(arrowColor); aItem->setZValue(1.5); aItem->show(); } } } if (!m_Scene) { QString s = i18n("Error running the graph layouting tool.\n"); s += i18n("Please check that 'dot' is installed (package GraphViz)."); showText(s); } else { setScene(m_Scene); m_CompleteView->setScene(m_Scene); if (startRect.isValid()) { ensureVisible(startRect); } } endInsert(); delete m_renderProcess; m_renderProcess = nullptr; } bool RevGraphView::isStart(const QString &nodeName)const { bool res = false; trevTree::ConstIterator it; it = m_Tree.find(nodeName); if (it == m_Tree.end()) { return res; } switch (it.value().Action) { case 'A': res = true; break; } return res; } char RevGraphView::getAction(const QString &nodeName)const { trevTree::ConstIterator it; it = m_Tree.find(nodeName); if (it == m_Tree.end()) { return (char)0; } return it.value().Action; } QColor RevGraphView::getBgColor(const QString &nodeName)const { trevTree::ConstIterator it; it = m_Tree.find(nodeName); QColor res = Qt::white; if (it == m_Tree.end()) { return res; } switch (it.value().Action) { case 'D': res = Kdesvnsettings::tree_delete_color(); break; case 'R': case 'M': res = Kdesvnsettings::tree_modify_color(); break; case 'A': res = Kdesvnsettings::tree_add_color(); break; case 'C': case 1: res = Kdesvnsettings::tree_copy_color(); break; case 2: res = Kdesvnsettings::tree_rename_color(); break; default: res = Kdesvnsettings::tree_modify_color(); break; } return res; } QString RevGraphView::getLabelstring(const QString &nodeName) { QMap::ConstIterator nIt; nIt = m_LabelMap.constFind(nodeName); if (nIt != m_LabelMap.constEnd()) { return nIt.value(); } trevTree::ConstIterator it1; it1 = m_Tree.constFind(nodeName); if (it1 == m_Tree.constEnd()) { return QString(); } QString res; QString revstring = svn::Revision(it1.value().rev).toString(); switch (it1.value().Action) { case 'D': res = i18n("Deleted at revision %1", revstring); break; case 'A': res = i18n("Added at revision %1 as %2", revstring, it1.value().name); break; case 'C': case 1: res = i18n("Copied to %1 at revision %2", it1.value().name, revstring); break; case 2: res = i18n("Renamed to %1 at revision %2", it1.value().name, revstring); break; case 'M': res = i18n("Modified at revision %1", revstring); break; case 'R': res = i18n("Replaced at revision %1", revstring); break; default: res = i18n("Revision %1", revstring); break; } m_LabelMap[nodeName] = res; return m_LabelMap[nodeName]; } void RevGraphView::dumpRevtree() { if (m_dotTmpFile) { m_dotTmpFile->close(); delete m_dotTmpFile; } clear(); m_dotOutput.clear(); m_dotTmpFile = new QTemporaryFile(QLatin1String("XXXXXX.dot")); m_dotTmpFile->setAutoRemove(true); m_dotTmpFile->open(); if (!m_dotTmpFile->open()) { showText(i18n("Could not open temporary file %1 for writing.", m_dotTmpFile->fileName())); return; } QTextStream stream(m_dotTmpFile); QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont); QFontMetrics _fm(f); int _fontsize = _fm.height(); if (_fontsize < 0) { _fontsize = 10; } stream << "digraph \"callgraph\" {\n"; stream << " bgcolor=\"transparent\";\n"; int dir = Kdesvnsettings::tree_direction(); stream << QString(" rankdir=\""); switch (dir) { case 3: stream << "TB"; break; case 2: stream << "RL"; break; case 1: stream << "BT"; break; case 0: default: stream << "LR"; break; } stream << "\";\n"; //stream << QString(" overlap=false;\n splines=true;\n"); RevGraphView::trevTree::ConstIterator it1; for (it1 = m_Tree.constBegin(); it1 != m_Tree.constEnd(); ++it1) { stream << " " << it1.key() << "[ " << "shape=box, " << "label=\"" << "Zeile 1 geht ab Zeile 2 geht ab"/*getLabelstring(it1.key())*/ << "\"," << "fontsize=" << _fontsize << ",fontname=\"" << f.family() << "\"," << "];\n"; for (int j = 0; j < it1.value().targets.count(); ++j) { stream << " " << it1.key().toLatin1() << " " << "->" << " " << it1.value().targets[j].key << " [fontsize=" << _fontsize << ",fontname=\"" << f.family() << "\",style=\"solid\"];\n"; } } stream << "}\n" << flush; - m_renderProcess = new KProcess(); + m_renderProcess = new KProcess; m_renderProcess->setEnv("LANG", "C"); *m_renderProcess << "dot"; *m_renderProcess << m_dotTmpFile->fileName() << "-Tplain"; - connect(m_renderProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(dotExit(int,QProcess::ExitStatus))); + connect(m_renderProcess, QOverload::of(&QProcess::finished), + this, &RevGraphView::dotExit); connect(m_renderProcess, &QProcess::readyReadStandardOutput, this, &RevGraphView::readDotOutput); m_renderProcess->setOutputChannelMode(KProcess::SeparateChannels); m_renderProcess->start(); } QString RevGraphView::toolTip(const QString &_nodename, bool full)const { QString res; trevTree::ConstIterator it = m_Tree.constFind(_nodename); if (it == m_Tree.constEnd()) { return res; } const QVector sp = it.value().Message.splitRef(QLatin1Char('\n')); QString sm; if (sp.isEmpty()) { sm = it.value().Message; } else { if (!full) { sm = sp[0].toString() + QLatin1String("..."); } else { for (int j = 0; j < sp.count(); ++j) { if (j > 0) { sm += QLatin1String("
"); } sm += sp[j].toString(); } } } if (!full && sm.length() > 50) { sm.truncate(47); sm += "..."; } static QLatin1String csep(""); static QLatin1String rend(""); static QLatin1String rstart(""); res = QLatin1String(""); if (!full) { res += QString(QLatin1String("%1")).arg(it.value().name); res += i18n("
Revision: %1
Author: %2
Date: %3
Log: %4", it.value().rev, it.value().Author, it.value().Date, sm); } else { res += QLatin1String("") + rstart + i18n("Revision%1%2%3", csep, it.value().rev, rend) + rstart + i18n("Author%1%2%3", csep, it.value().Author, rend) + rstart + i18n("Date%1%2%3", csep, it.value().Date, rend) + rstart + i18n("Log%1%2%3", csep, sm, rend) + QLatin1String("
") + it.value().name + QLatin1String("
"); } return res; } void RevGraphView::updateSizes(QSize s) { if (!m_Scene) { return; } if (s == QSize(0, 0)) { s = size(); } // the part of the canvas that should be visible qreal cWidth = m_Scene->width() - 2 * m_xMargin + 100; qreal cHeight = m_Scene->height() - 2 * m_yMargin + 100; // hide birds eye view if no overview needed if (((cWidth < s.width()) && cHeight < s.height()) || m_NodeList.isEmpty()) { m_CompleteView->hide(); return; } m_CompleteView->show(); // first, assume use of 1/3 of width/height (possible larger) double zoom = .33 * s.width() / cWidth; if (zoom * cHeight < .33 * s.height()) { zoom = .33 * s.height() / cHeight; } // fit to widget size if (cWidth * zoom > s.width()) { zoom = s.width() / (double)cWidth; } if (cHeight * zoom > s.height()) { zoom = s.height() / (double)cHeight; } // scale to never use full height/width zoom = zoom * 3 / 4; // at most a zoom of 1/3 if (zoom > .33) { zoom = .33; } if (zoom != m_cvZoom) { m_cvZoom = zoom; QMatrix wm; m_CompleteView->setMatrix(wm.scale(zoom, zoom)); // make it a little bigger to compensate for widget frame m_CompleteView->resize(int(cWidth * zoom) + 4, int(cHeight * zoom) + 4); // update ZoomRect in completeView scrollContentsBy(0, 0); } m_CompleteView->centerOn(m_Scene->width() / 2, m_Scene->height() / 2); updateZoomerPos(); } void RevGraphView::updateZoomerPos() { int cvW = m_CompleteView->width(); int cvH = m_CompleteView->height(); int x = width() - cvW - verticalScrollBar()->width() - 2; int y = height() - cvH - horizontalScrollBar()->height() - 2; QPoint oldZoomPos = m_CompleteView->pos(); QPoint newZoomPos = QPoint(0, 0); int tlCols = items(QRect(0, 0, cvW, cvH)).count(); int trCols = items(QRect(x, 0, cvW, cvH)).count(); int blCols = items(QRect(0, y, cvW, cvH)).count(); int brCols = items(QRect(x, y, cvW, cvH)).count(); int minCols = tlCols; ZoomPosition zp = m_LastAutoPosition; switch (zp) { case TopRight: minCols = trCols; break; case BottomLeft: minCols = blCols; break; case BottomRight: minCols = brCols; break; default: case TopLeft: minCols = tlCols; break; } if (minCols > tlCols) { minCols = tlCols; zp = TopLeft; } if (minCols > trCols) { minCols = trCols; zp = TopRight; } if (minCols > blCols) { minCols = blCols; zp = BottomLeft; } if (minCols > brCols) { minCols = brCols; zp = BottomRight; } m_LastAutoPosition = zp; switch (zp) { case TopRight: newZoomPos = QPoint(x, 0); break; case BottomLeft: newZoomPos = QPoint(0, y); break; case BottomRight: newZoomPos = QPoint(x, y); break; default: break; } if (newZoomPos != oldZoomPos) { m_CompleteView->move(newZoomPos); } } void RevGraphView::zoomRectMoved(qreal dx, qreal dy) { //if (leftMargin()>0) dx = 0; //if (topMargin()>0) dy = 0; m_noUpdateZoomerPos = true; QScrollBar *hBar = horizontalScrollBar(); QScrollBar *vBar = verticalScrollBar(); hBar->setValue(hBar->value() + int(dx)); vBar->setValue(vBar->value() + int(dy)); m_noUpdateZoomerPos = false; } void RevGraphView::zoomRectMoveFinished() { #if 0 if (_zoomPosition == Auto) #endif updateZoomerPos(); } void RevGraphView::resizeEvent(QResizeEvent *e) { QGraphicsView::resizeEvent(e); if (m_Scene) { updateSizes(e->size()); } } void RevGraphView::makeSelected(GraphTreeLabel *gtl) { if (m_Selected) { m_Selected->setSelected(false); } m_Selected = gtl; if (m_Marker) { m_Marker->hide(); delete m_Marker; m_Marker = nullptr; } if (gtl) { m_Marker = new GraphMark(gtl); m_Scene->addItem(m_Marker); m_Marker->setPos(gtl->pos()); m_Marker->setZValue(-1); } m_Scene->update(); m_CompleteView->update(); } GraphTreeLabel *RevGraphView::firstLabelAt(const QPoint &pos)const { QList its = items(pos); for (QList::size_type i = 0; i < its.size(); ++i) { if (its[i]->type() == GRAPHTREE_LABEL) { return static_cast(its[i]); } } return nullptr; } void RevGraphView::mouseDoubleClickEvent(QMouseEvent *e) { setFocus(); if (e->button() == Qt::LeftButton) { GraphTreeLabel *i = firstLabelAt(e->pos()); if (i == nullptr) { return; } makeSelected(i); emit dispDetails(toolTip((i)->nodename(), true)); } } void RevGraphView::mousePressEvent(QMouseEvent *e) { setFocus(); if (e->button() == Qt::LeftButton) { m_isMoving = true; m_lastPos = e->pos(); } } void RevGraphView::mouseReleaseEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton && m_isMoving) { QPointF topLeft = mapToScene(QPoint(0, 0)); QPointF bottomRight = mapToScene(QPoint(width(), height())); QRectF z(topLeft, bottomRight); m_CompleteView->setZoomRect(z); m_isMoving = false; updateZoomerPos(); } } void RevGraphView::scrollContentsBy(int dx, int dy) { // call QGraphicsView implementation QGraphicsView::scrollContentsBy(dx, dy); QPointF topLeft = mapToScene(QPoint(0, 0)); QPointF bottomRight = mapToScene(QPoint(width(), height())); m_CompleteView->setZoomRect(QRectF(topLeft, bottomRight)); if (!m_noUpdateZoomerPos && !m_isMoving) { updateZoomerPos(); } } void RevGraphView::mouseMoveEvent(QMouseEvent *e) { if (m_isMoving) { QPoint delta = e->pos() - m_lastPos; QScrollBar *hBar = horizontalScrollBar(); QScrollBar *vBar = verticalScrollBar(); hBar->setValue(hBar->value() - delta.x()); vBar->setValue(vBar->value() - delta.y()); m_lastPos = e->pos(); } } void RevGraphView::setNewDirection(int dir) { if (dir < 0) { dir = 3; } else if (dir > 3) { dir = 0; } Kdesvnsettings::setTree_direction(dir); dumpRevtree(); } void RevGraphView::contextMenuEvent(QContextMenuEvent *e) { if (!m_Scene) { return; } GraphTreeLabel *i = firstLabelAt(e->pos()); QAction *ac; QMenu popup; if (i) { if (!i->source().isEmpty() && getAction(i->nodename()) != 'D') { popup.addAction(i18n("Diff to previous"))->setData(301); } if (m_Selected && m_Selected != i && getAction(m_Selected->nodename()) != 'D' && getAction(i->nodename()) != 'D') { popup.addAction(i18n("Diff to selected item"))->setData(302); } if (getAction(i->nodename()) != 'D') { popup.addAction(i18n("Cat this version"))->setData(303); } if (m_Selected == i) { popup.addAction(i18n("Unselect item"))->setData(401); } else { popup.addAction(i18n("Select item"))->setData(402); } popup.addSeparator(); popup.addAction(i18n("Display details"))->setData(403); popup.addSeparator(); } popup.addAction(i18n("Rotate counter-clockwise"))->setData(101); popup.addAction(i18n("Rotate clockwise"))->setData(102); popup.addSeparator(); ac = popup.addAction(i18n("Diff in revision tree is recursive")); ac->setData(202); ac->setCheckable(true); ac->setChecked(Kdesvnsettings::tree_diff_rec()); popup.addAction(i18n("Save tree as PNG"))->setData(201); ac = popup.exec(e->globalPos()); int r = 0; if (ac) { r = ac->data().toInt(); } switch (r) { case 101: { int dir = Kdesvnsettings::tree_direction(); setNewDirection(++dir); } break; case 102: { int dir = Kdesvnsettings::tree_direction(); setNewDirection(--dir); } break; case 201: { QString fn = QFileDialog::getSaveFileName(this, i18n("Save tree as PNG"), QString(), i18n("Image (*.png)")); if (!fn.isEmpty()) { if (m_Marker) { m_Marker->hide(); } if (m_Selected) { m_Selected->setSelected(false); } QRect r = m_Scene->sceneRect().toRect(); QPixmap pix(r.width(), r.height()); pix.fill(); QPainter p(&pix); m_Scene->render(&p); pix.save(fn, "PNG"); if (m_Marker) { m_Marker->show(); } if (m_Selected) { m_Selected->setSelected(true); m_Scene->update(); m_CompleteView->updateCurrentRect(); } } } break; case 202: Kdesvnsettings::setTree_diff_rec(!Kdesvnsettings::tree_diff_rec()); break; case 301: if (i && i->type() == GRAPHTREE_LABEL && !i->source().isEmpty()) { makeDiffPrev(i); } break; case 302: if (i && m_Selected) { makeDiff(i->nodename(), m_Selected->nodename()); } break; case 303: if (i) { makeCat(i); } break; case 401: makeSelected(nullptr); break; case 402: makeSelected(i); break; case 403: if (i) { emit dispDetails(toolTip(i->nodename(), true)); } break; default: break; } } void RevGraphView::makeCat(GraphTreeLabel *_l) { if (!_l) { return; } QString n1 = _l->nodename(); trevTree::ConstIterator it = m_Tree.constFind(n1); if (it == m_Tree.constEnd()) { return; } svn::Revision tr(it.value().rev); QString tp = m_basePath + it.value().name; emit makeCat(tr, tp, it.value().name, tr, QApplication::activeModalWidget()); } void RevGraphView::makeDiffPrev(GraphTreeLabel *_l) { if (!_l) { return; } QString n1, n2; n1 = _l->nodename(); n2 = _l->source(); makeDiff(n1, n2); } void RevGraphView::makeDiff(const QString &n1, const QString &n2) { if (n1.isEmpty() || n2.isEmpty()) { return; } trevTree::ConstIterator it; it = m_Tree.constFind(n2); if (it == m_Tree.constEnd()) { return; } svn::Revision sr(it.value().rev); QString sp = m_basePath + it.value().name; it = m_Tree.constFind(n1); if (it == m_Tree.constEnd()) { return; } svn::Revision tr(it.value().rev); QString tp = m_basePath + it.value().name; if (Kdesvnsettings::tree_diff_rec()) { emit makeRecDiff(sp, sr, tp, tr, QApplication::activeModalWidget()); } else { emit makeNorecDiff(sp, sr, tp, tr, QApplication::activeModalWidget()); } } void RevGraphView::setBasePath(const QString &_path) { m_basePath = _path; } void RevGraphView::slotClientException(const QString &what) { KMessageBox::sorry(QApplication::activeModalWidget(), what, i18n("SVN Error")); }