summaryrefslogtreecommitdiffstats
path: root/src/svnfrontend/svnlogdlgimp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/svnfrontend/svnlogdlgimp.cpp')
-rw-r--r--src/svnfrontend/svnlogdlgimp.cpp661
1 files changed, 661 insertions, 0 deletions
diff --git a/src/svnfrontend/svnlogdlgimp.cpp b/src/svnfrontend/svnlogdlgimp.cpp
new file mode 100644
index 0000000..9919ab7
--- /dev/null
+++ b/src/svnfrontend/svnlogdlgimp.cpp
@@ -0,0 +1,661 @@
+/***************************************************************************
+ * Copyright (C) 2005-2007 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 "svnlogdlgimp.h"
+#include "src/settings/kdesvnsettings.h"
+#include "src/svnqt/log_entry.hpp"
+#include "helpers/sub2qt.h"
+#include "svnactions.h"
+#include "src/svnfrontend/fronthelpers/revisionbuttonimpl.h"
+
+#include <klistview.h>
+#include <ktextbrowser.h>
+#include <kpushbutton.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kapp.h>
+#include <kconfigbase.h>
+#include <kconfig.h>
+#include <ktabwidget.h>
+#include <kdebug.h>
+
+#include <qdatetime.h>
+#include <qheader.h>
+#include <qsplitter.h>
+#include <qtextstream.h>
+#include <qpopupmenu.h>
+
+#include <list>
+
+
+const char* SvnLogDlgImp::groupName = "log_dialog_size";
+
+class LogListViewItem:public KListViewItem
+{
+public:
+ LogListViewItem (KListView *parent,const svn::LogEntry&);
+ virtual int compare( QListViewItem* i, int col, bool ascending ) const;
+
+ static const int COL_MARKER,COL_REV,COL_AUTHOR,COL_DATE,COL_MSG;
+ const QString&message()const;
+ svn_revnum_t rev()const{return _revision;}
+ void showChangedEntries(KListView*);
+ unsigned int numChangedEntries(){return changedPaths.count();}
+ void setChangedEntries(const svn::LogEntry&);
+ void setRealName(const QString&_n){_realName=_n;}
+ const QString&realName()const{return _realName;}
+
+ bool copiedFrom(QString&_n,long&rev)const;
+ static bool isParent(const QString&_par,const QString&tar);
+
+protected:
+ svn_revnum_t _revision;
+ QDateTime fullDate;
+ QString _message,_realName;
+ QValueList<svn::LogChangePathEntry> changedPaths;
+};
+
+const int LogListViewItem::COL_MARKER = 0;
+const int LogListViewItem::COL_REV = 2;
+const int LogListViewItem::COL_AUTHOR = 1;
+const int LogListViewItem::COL_DATE = 3;
+const int LogListViewItem::COL_MSG = 4;
+
+class LogChangePathItem:public KListViewItem
+{
+public:
+ LogChangePathItem(KListView*parent,const svn::LogChangePathEntry&);
+ virtual ~LogChangePathItem(){}
+
+ QChar action() const{return _action;}
+ const QString& path() const{return _path;}
+ const QString& source() const{return _source;}
+ svn_revnum_t revision() const{ return _revision;}
+
+protected:
+ QString _path,_source;
+ QChar _action;
+ svn_revnum_t _revision;
+};
+
+LogListViewItem::LogListViewItem(KListView*_parent,const svn::LogEntry&_entry)
+ : KListViewItem(_parent),_realName(QString::null)
+{
+ setMultiLinesEnabled(false);
+ _revision=_entry.revision;
+ fullDate=svn::DateTime(_entry.date);
+ setText(COL_REV,QString("%1").arg(_revision));
+ setText(COL_AUTHOR,_entry.author);
+ setText(COL_DATE,helpers::sub2qt::apr_time2qtString(_entry.date));
+ _message = _entry.message;
+ QStringList sp = QStringList::split("\n",_message);
+ if (sp.count()==0) {
+ setText(COL_MSG,_message);
+ } else {
+ setText(COL_MSG,sp[0]);
+ }
+ changedPaths = _entry.changedPaths;
+ //setText(COL_MSG,_entry.message.c_str());
+}
+
+const QString&LogListViewItem::message()const
+{
+ return _message;
+}
+
+int LogListViewItem::compare( QListViewItem* item, int col, bool ) const
+{
+ LogListViewItem* k = static_cast<LogListViewItem*>( item );
+ if (col==COL_REV) {
+ return _revision-k->_revision;
+ }
+ if (col==COL_DATE) {
+ return k->fullDate.secsTo(fullDate);
+ }
+ return text(col).localeAwareCompare(k->text(col));
+}
+
+void LogListViewItem::showChangedEntries(KListView*where)
+{
+ if (!where)return;
+ where->clear();
+ if (changedPaths.count()==0) {
+ return;
+ }
+ for (unsigned i = 0; i < changedPaths.count();++i) {
+ new LogChangePathItem(where,changedPaths[i]);
+ }
+}
+
+LogChangePathItem::LogChangePathItem(KListView*parent,const svn::LogChangePathEntry&e)
+ :KListViewItem(parent)
+{
+ _action = QChar(e.action);
+ setText(0,_action);
+ _path = e.path;
+ setText(1,e.path);
+ _revision = e.copyFromRevision;
+ _source = e.copyFromPath;
+ if (e.copyFromRevision>-1)
+ {
+ setText(2,i18n("%1 at revision %2").arg(e.copyFromPath).arg(e.copyFromRevision));
+ }
+}
+
+void LogListViewItem::setChangedEntries(const svn::LogEntry&_entry)
+{
+ changedPaths = _entry.changedPaths;
+}
+
+bool LogListViewItem::copiedFrom(QString&_n,long&_rev)const
+{
+ for (unsigned i = 0; i < changedPaths.count();++i) {
+ if (changedPaths[i].action=='A' &&
+ !changedPaths[i].copyFromPath.isEmpty() &&
+ isParent(changedPaths[i].path,_realName)) {
+ kdDebug()<<_realName<< " - " << changedPaths[i].path << endl;
+ QString tmpPath = _realName;
+ QString r = _realName.mid(changedPaths[i].path.length());
+ _n=changedPaths[i].copyFromPath;
+ _n+=r;
+ _rev = changedPaths[i].copyFromRevision;
+ kdDebug()<<"Found switch from "<< changedPaths[i].copyFromPath << " rev "<<changedPaths[i].copyFromRevision<<endl;
+ kdDebug()<<"Found switch from "<< _n << " rev "<<_rev<<endl;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LogListViewItem::isParent(const QString&_par,const QString&tar)
+{
+ if (_par==tar) return true;
+ QString par = _par+(_par.endsWith("/")?"":"/");
+ return tar.startsWith(par);
+}
+
+SvnLogDlgImp::SvnLogDlgImp(SvnActions*ac,QWidget *parent, const char *name,bool modal)
+ :SvnLogDialogData(parent, name,modal),_name("")
+{
+ m_LogView->setSorting(LogListViewItem::COL_REV);
+ m_LogView->setSortOrder(Qt::Descending);
+ resize(dialogSize());
+ m_ControlKeyDown = false;
+ m_first = 0;
+ m_second = 0;
+
+ if (Kdesvnsettings::self()->log_always_list_changed_files()) {
+ buttonListFiles->hide();
+ } else {
+ m_ChangedList->hide();
+ }
+ m_Actions = ac;
+ KConfigGroup cs(Kdesvnsettings::self()->config(), groupName);
+ QString t1 = cs.readEntry("logsplitter",QString::null);
+ if (!t1.isEmpty()) {
+ QTextStream st2(&t1,IO_ReadOnly);
+ st2 >> *m_centralSplitter;
+ }
+ t1 = cs.readEntry("right_logsplitter",QString::null);
+ if (!t1.isEmpty()) {
+ if (cs.readBoolEntry("laststate",false)==m_ChangedList->isHidden()) {
+ QTextStream st2(&t1,IO_ReadOnly);
+ st2 >> *m_rightSplitter;
+ }
+ }
+}
+
+SvnLogDlgImp::~SvnLogDlgImp()
+{
+ QString t1,t2;
+ QTextStream st1(&t1,IO_WriteOnly);
+ st1 << *m_rightSplitter;
+ QTextStream st2(&t2,IO_WriteOnly);
+ st2 << *m_centralSplitter;
+ KConfigGroup cs(Kdesvnsettings::self()->config(), groupName);
+ cs.writeEntry("right_logsplitter",t1);
+ cs.writeEntry("logsplitter",t2);
+ cs.writeEntry("laststate",m_ChangedList->isHidden());
+}
+
+void SvnLogDlgImp::dispLog(const svn::SharedPointer<svn::LogEntriesMap>&_log,const QString & what,const QString&root,const svn::Revision&peg,const QString&pegUrl)
+{
+ m_peg = peg;
+ m_PegUrl = pegUrl;
+ m_first = m_second = 0;
+ m_startRevButton->setNoWorking(m_PegUrl.isUrl());
+ m_endRevButton->setNoWorking(m_PegUrl.isUrl());
+ if (!m_PegUrl.isUrl() || Kdesvnsettings::remote_special_properties()) {
+ QString s = m_Actions->searchProperty(_bugurl,"bugtraq:url",pegUrl,peg,true);
+ if (!s.isEmpty() ){
+ QString reg;
+ s = m_Actions->searchProperty(reg,"bugtraq:logregex",pegUrl,peg,true);
+ if (!s.isNull() && !reg.isEmpty()) {
+ QStringList s1 = QStringList::split("\n",reg);
+ if (s1.size()>0) {
+ _r1.setPattern(s1[0]);
+ if (s1.size()>1) {
+ _r2.setPattern(s1[1]);
+ }
+ }
+ }
+ }
+ }
+ _base = root;
+ m_first = m_second = 0;
+ m_Entries = _log;
+ kdDebug()<<"What: "<<what << endl;
+ if (!what.isEmpty()){
+ setCaption(i18n("SVN Log of %1").arg(what));
+ } else {
+ setCaption(i18n("SVN Log"));
+ }
+ _name = what;
+ dispLog(_log);
+}
+
+void SvnLogDlgImp::dispLog(const svn::SharedPointer<svn::LogEntriesMap>&_log)
+{
+ m_LogView->clear();
+ m_LogView->header()->setLabel(0, " ");
+ m_LogView->setColumnWidth(0,10);
+ if (!_log) {
+ return;
+ }
+ svn::LogEntriesMap::const_iterator lit;
+ LogListViewItem * item;
+ QMap<long int,QString> namesMap;
+ QMap<long int,LogListViewItem*> itemMap;
+ long min,max;
+ min = max = -1;
+ for (lit=_log->begin();lit!=_log->end();++lit) {
+ item = new LogListViewItem(m_LogView,(*lit));
+ if ((*lit).revision>max) max = (*lit).revision;
+ if ((*lit).revision<min || min == -1) min = (*lit).revision;
+ itemMap[(*lit).revision]=item;
+ }
+ if (itemMap.count()==0) {
+ return;
+ }
+ m_startRevButton->setRevision(max);
+ m_endRevButton->setRevision(min);
+ m_LogView->setSelected(m_LogView->firstChild(),true);
+ QString bef = _name;
+ long rev;
+ // YES! I'd checked it: this is much faster than getting list of keys
+ // and iterating over that list!
+ for (long c=max;c>-1;--c) {
+ if (!itemMap.contains(c)) {
+ continue;
+ }
+ if (itemMap[c]->realName().isEmpty()) {
+ itemMap[c]->setRealName(bef);
+ }
+ itemMap[c]->copiedFrom(bef,rev);
+ }
+}
+
+QString SvnLogDlgImp::genReplace(const QString&r1match)
+{
+ static QString anf("<a href=\"");
+ static QString mid("\">");
+ static QString end("</a>");
+ QString res("");
+ if (_r2.pattern().length()<1) {
+ res = _bugurl;
+ res.replace("%BUGID%",_r1.cap(1));
+ res = anf+res+mid+r1match+end;
+ return res;
+ }
+ int pos=0;
+ int count=0;
+ int oldpos;
+
+ kdDebug()<<"Search second pattern: "<<_r2.pattern()<<" in "<<r1match<<endl;
+
+ while (pos > -1) {
+ oldpos = pos+count;
+ pos = r1match.find(_r2,pos+count);
+ if (pos==-1) {
+ break;
+ }
+ count = _r2.matchedLength();
+ res+=r1match.mid(oldpos,pos-oldpos);
+ QString sub = r1match.mid(pos,count);
+ QString _url = _bugurl;
+ _url.replace("%BUGID%",sub);
+ res+=anf+_url+mid+sub+end;
+ }
+ res+=r1match.mid(oldpos);
+ return res;
+}
+
+void SvnLogDlgImp::replaceBugids(QString&msg)
+{
+ msg = QStyleSheet::convertFromPlainText(msg);
+ if (!_r1.isValid() || _r1.pattern().length()<1 || _bugurl.isEmpty()) {
+ return;
+ }
+ kdDebug()<<"Try match "<< _r1.pattern() << endl;
+ int pos = 0;
+ int count = 0;
+
+ pos = _r1.search(msg,pos+count);
+ count = _r1.matchedLength();
+
+ while (pos>-1) {
+ kdDebug()<<"Found at "<<pos << " length "<<count << " with " << _r1.pattern()<< endl;
+ QString s1 = msg.mid(pos,count);
+ kdDebug()<<"Sub: "<<s1 << endl;
+ kdDebug()<<_r1.cap(1) << endl;
+ QString rep = genReplace(s1);
+ kdDebug()<<"Replace with "<<rep << endl;
+ msg = msg.replace(pos,count,rep);
+
+ pos = _r1.search(msg,pos+rep.length());
+ count = _r1.matchedLength();
+ }
+}
+
+/*!
+ \fn SvnLogDlgImp::slotItemClicked(QListViewItem*)
+ */
+void SvnLogDlgImp::slotSelectionChanged(QListViewItem*_it)
+{
+ if (!_it) {
+ m_DispPrevButton->setEnabled(false);
+ buttonListFiles->setEnabled(false);
+ buttonBlame->setEnabled(false);
+ m_ChangedList->clear();
+ return;
+ }
+ LogListViewItem* k = static_cast<LogListViewItem*>( _it );
+ if (k->numChangedEntries()==0) {
+ buttonListFiles->setEnabled(true);
+ if (m_ChangedList->isVisible()){
+ m_ChangedList->hide();
+ }
+ } else {
+ buttonListFiles->setEnabled(false);
+ if (!m_ChangedList->isVisible()){
+ m_ChangedList->show();
+ }
+ }
+ QString msg = k->message();
+ replaceBugids(msg);
+ m_LogDisplay->setText(msg);
+
+ k->showChangedEntries(m_ChangedList);
+ buttonBlame->setEnabled(true);
+
+ k = static_cast<LogListViewItem*>(_it->nextSibling());
+ if (!k) {
+ m_DispPrevButton->setEnabled(false);
+ } else {
+ m_DispPrevButton->setEnabled(true);
+ }
+}
+
+
+/*!
+ \fn SvnLogDlgImp::slotDispPrevious()
+ */
+void SvnLogDlgImp::slotDispPrevious()
+{
+ LogListViewItem* k = static_cast<LogListViewItem*>(m_LogView->selectedItem());
+ if (!k) {
+ m_DispPrevButton->setEnabled(false);
+ return;
+ }
+ LogListViewItem* p = static_cast<LogListViewItem*>(k->nextSibling());
+ if (!p) {
+ m_DispPrevButton->setEnabled(false);
+ return;
+ }
+ QString s,e;
+ s = _base+k->realName();
+ e = _base+p->realName();
+ emit makeDiff(e,p->rev(),s,k->rev(),this);
+}
+
+
+/*!
+ \fn SvnLogDlgImp::saveSize()
+ */
+void SvnLogDlgImp::saveSize()
+{
+ int scnum = QApplication::desktop()->screenNumber(parentWidget());
+ QRect desk = QApplication::desktop()->screenGeometry(scnum);
+ KConfigGroupSaver cs(Kdesvnsettings::self()->config(), groupName);
+ QSize sizeToSave = size();
+ Kdesvnsettings::self()->config()->writeEntry( QString::fromLatin1("Width %1").arg( desk.width()),
+ QString::number( sizeToSave.width()), true, false);
+ Kdesvnsettings::self()->config()->writeEntry( QString::fromLatin1("Height %1").arg( desk.height()),
+ QString::number( sizeToSave.height()), true, false);
+}
+
+QSize SvnLogDlgImp::dialogSize()
+{
+ int w, h;
+ int scnum = QApplication::desktop()->screenNumber(parentWidget());
+ QRect desk = QApplication::desktop()->screenGeometry(scnum);
+ w = sizeHint().width();
+ h = sizeHint().height();
+ KConfigGroupSaver cs(Kdesvnsettings::self()->config(), groupName);
+ w = Kdesvnsettings::self()->config()->readNumEntry( QString::fromLatin1("Width %1").arg( desk.width()), w );
+ h = Kdesvnsettings::self()->config()->readNumEntry( QString::fromLatin1("Height %1").arg( desk.height()), h );
+ return( QSize( w, h ) );
+}
+
+void SvnLogDlgImp::slotItemClicked(int button,QListViewItem*item,const QPoint &,int)
+{
+ if (!item) {
+ m_ChangedList->clear();
+ return;
+ }
+ LogListViewItem*which = static_cast<LogListViewItem*>(item);
+ /* left mouse */
+ if (button == 1&&!m_ControlKeyDown) {
+ if (m_first) m_first->setText(0,"");
+ if (m_first == which) {
+ m_first = 0;
+ } else {
+ m_first = which;
+ m_first->setText(0,"1");
+ }
+ if (m_first==m_second) {
+ m_second = 0;
+ }
+ m_startRevButton->setRevision(which->rev());
+
+ /* other mouse or ctrl hold*/
+ } else {
+ if (m_second) m_second->setText(0,"");
+ if (m_second == which) {
+ m_second = 0;
+ } else {
+ m_second = which;
+ m_second->setText(0,"2");
+ }
+ if (m_first==m_second) {
+ m_first = 0;
+ }
+ m_endRevButton->setRevision(which->rev());
+ }
+ m_DispSpecDiff->setEnabled(m_first!=0 && m_second!=0);
+}
+
+void SvnLogDlgImp::slotRevisionSelected()
+{
+ m_goButton->setFocus();
+ //m_DispSpecDiff->setEnabled( m_first && m_second && m_first != m_second);
+}
+
+void SvnLogDlgImp::slotDispSelected()
+{
+ if (!m_first || !m_second) return;
+ emit makeDiff(_base+m_first->realName(),m_first->rev(),_base+m_second->realName(),m_second->rev(),this);
+}
+
+bool SvnLogDlgImp::getSingleLog(svn::LogEntry&t,const svn::Revision&r,const QString&what,const svn::Revision&peg,QString&root)
+{
+ root = _base;
+ if (m_Entries->find(r.revnum()) == m_Entries->end())
+ {
+ return m_Actions->getSingleLog(t,r,what,peg,root);
+ }
+ t=(*m_Entries)[r.revnum()];
+ return true;
+}
+
+void SvnLogDlgImp::slotGetLogs()
+{
+ kdDebug()<<"Displog: "<<m_peg.toString()<<endl;
+ svn::SharedPointer<svn::LogEntriesMap> lm = m_Actions->getLog(m_startRevButton->revision(),
+ m_endRevButton->revision(),m_peg,
+ _base+"/"+_name,Kdesvnsettings::self()->log_always_list_changed_files(),0,this);
+ if (lm) {
+ dispLog(lm);
+ }
+}
+
+void SvnLogDlgImp::slotListEntries()
+{
+ LogListViewItem * it = static_cast<LogListViewItem*>(m_LogView->selectedItem());
+ if (!it||it->numChangedEntries()>0||!m_Actions) {
+ buttonListFiles->setEnabled(false);
+ return;
+ }
+ svn::SharedPointer<svn::LogEntriesMap>_log = m_Actions->getLog(it->rev(),it->rev(),it->rev(),_name,true,0);
+ if (!_log) {
+ return;
+ }
+ if (_log->count()>0) {
+ it->setChangedEntries((*_log)[it->rev()]);
+ it->showChangedEntries(m_ChangedList);
+ if (!m_ChangedList->isVisible()) m_ChangedList->show();
+ }
+ buttonListFiles->setEnabled(false);
+}
+
+void SvnLogDlgImp::keyPressEvent (QKeyEvent * e)
+{
+ if (!e) return;
+ if (e->text().isEmpty()&&e->key()==Key_Control) {
+ m_ControlKeyDown = true;
+ }
+ SvnLogDialogData::keyPressEvent(e);
+}
+
+void SvnLogDlgImp::keyReleaseEvent (QKeyEvent * e)
+{
+ if (!e) return;
+ if (e->text().isEmpty()&&e->key()==Qt::Key_Control) {
+ m_ControlKeyDown = false;
+ }
+ SvnLogDialogData::keyReleaseEvent(e);
+}
+
+void SvnLogDlgImp::slotBlameItem()
+{
+ LogListViewItem* k = static_cast<LogListViewItem*>(m_LogView->selectedItem());
+ if (!k) {
+ buttonBlame->setEnabled(false);
+ return;
+ }
+ svn::Revision start(svn::Revision::START);
+ m_Actions->makeBlame(start,k->rev(),_base+k->realName(),kapp->activeModalWidget(),k->rev(),this);
+}
+
+void SvnLogDlgImp::slotEntriesSelectionChanged()
+{
+}
+
+void SvnLogDlgImp::slotSingleContext(QListViewItem*_item, const QPoint & e, int)
+{
+ if (!_item)
+ {
+ return;
+ }
+
+ LogChangePathItem* item = static_cast<LogChangePathItem*>(_item);
+ LogListViewItem* k = static_cast<LogListViewItem*>(m_LogView->selectedItem());
+ if (!k) {
+ kdDebug()<<"????"<<endl;
+ return;
+ }
+ QPopupMenu popup;
+ QString name = item->path();
+ QString action = item->action();
+ QString source =item->revision()>-1?item->source():item->path();
+ svn_revnum_t prev = item->revision()>0?item->revision():k->rev()-1;
+ if (action != "D") {
+ popup.insertItem(i18n("Annotate"),101);
+ if (action != "A" || item->revision()>-1) {
+ popup.insertItem(i18n("Diff previous"),102);
+ }
+ popup.insertItem(i18n("Cat this version"),103);
+ }
+ int r = popup.exec(e);
+ svn::Revision start(svn::Revision::START);
+ switch (r)
+ {
+ case 101:
+ {
+ m_Actions->makeBlame(start,k->rev(),_base+name,kapp->activeModalWidget(),k->rev(),this);
+ break;
+ }
+ case 102:
+ {
+ emit makeDiff(_base+source,prev,_base+name,k->rev(),this);
+ break;
+ }
+ case 103:
+ {
+ emit makeCat(k->rev(),_base+source,source,k->rev(),kapp->activeModalWidget());
+ }
+ default:
+ break;
+ }
+}
+
+void SvnLogDlgImp::slotSingleDoubleClicked(QListViewItem*_item)
+{
+ if (!_item)
+ {
+ return;
+ }
+
+ LogChangePathItem* item = static_cast<LogChangePathItem*>(_item);
+ LogListViewItem* k = static_cast<LogListViewItem*>(m_LogView->selectedItem());
+ if (!k) {
+ kdDebug()<<"????"<<endl;
+ return;
+ }
+ QString name = item->path();
+ QString action = item->action();
+ QString source =item->revision()>-1?item->source():item->path();
+ //svn_revnum_t prev = item->revision()>0?item->revision():k->rev()-1;
+ svn::Revision start(svn::Revision::START);
+ if (action != "D") {
+ m_Actions->makeBlame(start,k->rev(),_base+name,kapp->activeModalWidget(),k->rev(),this);
+ }
+}
+
+#include "svnlogdlgimp.moc"