/*************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char* SvnLogDlgImp::groupName = "log_dialog_size"; class LogListViewItem:public KListViewItem { public: LogListViewItem (KListView *tqparent,const svn::LogEntry&); virtual int compare( TQListViewItem* i, int col, bool ascending ) const; static const int COL_MARKER,COL_REV,COL_AUTHOR,COL_DATE,COL_MSG; const TQString&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 TQString&_n){_realName=_n;} const TQString&realName()const{return _realName;} bool copiedFrom(TQString&_n,long&rev)const; static bool isParent(const TQString&_par,const TQString&tar); protected: svn_revnum_t _revision; TQDateTime fullDate; TQString _message,_realName; TQValueList 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*tqparent,const svn::LogChangePathEntry&); virtual ~LogChangePathItem(){} TQChar action() const{return _action;} const TQString& path() const{return _path;} const TQString& source() const{return _source;} svn_revnum_t revision() const{ return _revision;} protected: TQString _path,_source; TQChar _action; svn_revnum_t _revision; }; LogListViewItem::LogListViewItem(KListView*_tqparent,const svn::LogEntry&_entry) : KListViewItem(_tqparent),_realName(TQString()) { setMultiLinesEnabled(false); _revision=_entry.revision; fullDate=svn::DateTime(_entry.date); setText(COL_REV,TQString("%1").tqarg(_revision)); setText(COL_AUTHOR,_entry.author); setText(COL_DATE,helpers::sub2qt::apr_time2qtString(_entry.date)); _message = _entry.message; TQStringList sp = TQStringList::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 TQString&LogListViewItem::message()const { return _message; } int LogListViewItem::compare( TQListViewItem* item, int col, bool ) const { LogListViewItem* k = static_cast( 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*tqparent,const svn::LogChangePathEntry&e) :KListViewItem(tqparent) { _action = TQChar(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").tqarg(e.copyFromPath).tqarg(e.copyFromRevision)); } } void LogListViewItem::setChangedEntries(const svn::LogEntry&_entry) { changedPaths = _entry.changedPaths; } bool LogListViewItem::copiedFrom(TQString&_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; TQString tmpPath = _realName; TQString 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 "<setSorting(LogListViewItem::COL_REV); m_LogView->setSortOrder(TQt::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); TQString t1 = cs.readEntry("logsplitter",TQString()); if (!t1.isEmpty()) { TQTextStream st2(&t1,IO_ReadOnly); st2 >> *m_centralSplitter; } t1 = cs.readEntry("right_logsplitter",TQString()); if (!t1.isEmpty()) { if (cs.readBoolEntry("laststate",false)==m_ChangedList->isHidden()) { TQTextStream st2(&t1,IO_ReadOnly); st2 >> *m_rightSplitter; } } } SvnLogDlgImp::~SvnLogDlgImp() { TQString t1,t2; TQTextStream st1(&t1,IO_WriteOnly); st1 << *m_rightSplitter; TQTextStream 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&_log,const TQString & what,const TQString&root,const svn::Revision&peg,const TQString&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()) { TQString s = m_Actions->searchProperty(_bugurl,"bugtraq:url",pegUrl,peg,true); if (!s.isEmpty() ){ TQString reg; s = m_Actions->searchProperty(reg,"bugtraq:logregex",pegUrl,peg,true); if (!s.isNull() && !reg.isEmpty()) { TQStringList s1 = TQStringList::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: "<&_log) { m_LogView->clear(); m_LogView->header()->setLabel(0, " "); m_LogView->setColumnWidth(0,10); if (!_log) { return; } svn::LogEntriesMap::const_iterator lit; LogListViewItem * item; TQMap namesMap; TQMap 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).revisionsetRevision(max); m_endRevButton->setRevision(min); m_LogView->setSelected(m_LogView->firstChild(),true); TQString 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); } } TQString SvnLogDlgImp::genReplace(const TQString&r1match) { static TQString anf(""); static TQString end(""); TQString 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: "< -1) { oldpos = pos+count; pos = r1match.find(_r2,pos+count); if (pos==-1) { break; } count = _r2.matchedLength(); res+=r1match.mid(oldpos,pos-oldpos); TQString sub = r1match.mid(pos,count); TQString _url = _bugurl; _url.replace("%BUGID%",sub); res+=anf+_url+mid+sub+end; } res+=r1match.mid(oldpos); return res; } void SvnLogDlgImp::replaceBugids(TQString&msg) { msg = TQStyleSheet::convertFromPlainText(msg); if (!_r1.isValid() || _r1.pattern().length()<1 || _bugurl.isEmpty()) { return; } kdDebug()<<"Try match "<< TQString(_r1.pattern()) << endl; int pos = 0; int count = 0; pos = _r1.search(msg,pos+count); count = _r1.matchedLength(); while (pos>-1) { kdDebug()<<"Found at "<setEnabled(false); buttonListFiles->setEnabled(false); buttonBlame->setEnabled(false); m_ChangedList->clear(); return; } LogListViewItem* k = static_cast( _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(); } } TQString msg = k->message(); replaceBugids(msg); m_LogDisplay->setText(msg); k->showChangedEntries(m_ChangedList); buttonBlame->setEnabled(true); k = static_cast(_it->nextSibling()); if (!k) { m_DispPrevButton->setEnabled(false); } else { m_DispPrevButton->setEnabled(true); } } /*! \fn SvnLogDlgImp::slotDispPrevious() */ void SvnLogDlgImp::slotDispPrevious() { LogListViewItem* k = static_cast(m_LogView->selectedItem()); if (!k) { m_DispPrevButton->setEnabled(false); return; } LogListViewItem* p = static_cast(k->nextSibling()); if (!p) { m_DispPrevButton->setEnabled(false); return; } TQString 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 = TQApplication::desktop()->screenNumber(parentWidget()); TQRect desk = TQApplication::desktop()->screenGeometry(scnum); KConfigGroupSaver cs(Kdesvnsettings::self()->config(), groupName); TQSize sizeToSave = size(); Kdesvnsettings::self()->config()->writeEntry( TQString::tqfromLatin1("Width %1").tqarg( desk.width()), TQString::number( sizeToSave.width()), true, false); Kdesvnsettings::self()->config()->writeEntry( TQString::tqfromLatin1("Height %1").tqarg( desk.height()), TQString::number( sizeToSave.height()), true, false); } TQSize SvnLogDlgImp::dialogSize() { int w, h; int scnum = TQApplication::desktop()->screenNumber(parentWidget()); TQRect desk = TQApplication::desktop()->screenGeometry(scnum); w = tqsizeHint().width(); h = tqsizeHint().height(); KConfigGroupSaver cs(Kdesvnsettings::self()->config(), groupName); w = Kdesvnsettings::self()->config()->readNumEntry( TQString::tqfromLatin1("Width %1").tqarg( desk.width()), w ); h = Kdesvnsettings::self()->config()->readNumEntry( TQString::tqfromLatin1("Height %1").tqarg( desk.height()), h ); return( TQSize( w, h ) ); } void SvnLogDlgImp::slotItemClicked(int button,TQListViewItem*item,const TQPoint &,int) { if (!item) { m_ChangedList->clear(); return; } LogListViewItem*which = static_cast(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 TQString&what,const svn::Revision&peg,TQString&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: "< 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(m_LogView->selectedItem()); if (!it||it->numChangedEntries()>0||!m_Actions) { buttonListFiles->setEnabled(false); return; } svn::SharedPointer_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 (TQKeyEvent * e) { if (!e) return; if (e->text().isEmpty()&&e->key()==Key_Control) { m_ControlKeyDown = true; } SvnLogDialogData::keyPressEvent(e); } void SvnLogDlgImp::keyReleaseEvent (TQKeyEvent * e) { if (!e) return; if (e->text().isEmpty()&&e->key()==TQt::Key_Control) { m_ControlKeyDown = false; } SvnLogDialogData::keyReleaseEvent(e); } void SvnLogDlgImp::slotBlameItem() { LogListViewItem* k = static_cast(m_LogView->selectedItem()); if (!k) { buttonBlame->setEnabled(false); return; } svn::Revision start(svn::Revision::START); m_Actions->makeBlame(start,k->rev(),_base+k->realName(),TQT_TQWIDGET(kapp->activeModalWidget()),k->rev(),this); } void SvnLogDlgImp::slotEntriesSelectionChanged() { } void SvnLogDlgImp::slotSingleContext(TQListViewItem*_item, const TQPoint & e, int) { if (!_item) { return; } LogChangePathItem* item = static_cast(_item); LogListViewItem* k = static_cast(m_LogView->selectedItem()); if (!k) { kdDebug()<<"????"<path(); TQString action = item->action(); TQString 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,TQT_TQWIDGET(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(),TQT_TQWIDGET(kapp->activeModalWidget())); } default: break; } } void SvnLogDlgImp::slotSingleDoubleClicked(TQListViewItem*_item) { if (!_item) { return; } LogChangePathItem* item = static_cast(_item); LogListViewItem* k = static_cast(m_LogView->selectedItem()); if (!k) { kdDebug()<<"????"<path(); TQString action = item->action(); TQString 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,TQT_TQWIDGET(kapp->activeModalWidget()),k->rev(),this); } } #include "svnlogdlgimp.moc"