/*************************************************************************** * Copyright (C) 2006-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 "blamedisplay_impl.h" #include "simple_logcb.h" #include "src/settings/tdesvnsettings.h" #include "src/svnqt/log_entry.hpp" #include "fronthelpers/cursorstack.h" #include "fronthelpers/widgetblockstack.h" #include "src/ksvnwidgets/encodingselector_impl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define COL_LINENR 0 #define COL_REV 1 #define COL_DATE 2 #define COL_AUT 3 #define COL_LINE 4 class LocalizedAnnotatedLine:public svn::AnnotateLine { public: LocalizedAnnotatedLine(const svn::AnnotateLine&al) :svn::AnnotateLine(al) { localeChanged(); } void localeChanged() { if (!codec_searched) { cc = TQTextCodec::codecForName(Kdesvnsettings::locale_for_blame()); codec_searched = true; } if (cc) { m_tLine=cc->toUnicode(line().data(),line().size()); m_tAuthor=cc->toUnicode(author().data(),author().size()); } else { m_tLine=TQString::FROMUTF8(line().data(),line().size()); m_tAuthor=TQString::FROMUTF8(author().data(),author().size()); } } const TQString& tAuthor()const{return m_tAuthor;} const TQString& tLine()const{return m_tLine;} static void reset_codec(){codec_searched = false; cc=0;} protected: TQString m_tAuthor,m_tLine; static bool codec_searched; static TQTextCodec * cc; }; TQTextCodec* LocalizedAnnotatedLine::cc = 0; bool LocalizedAnnotatedLine::codec_searched = false; class BlameDisplayItem:public KListViewItem { public: BlameDisplayItem(KListView*,const svn::AnnotateLine&,bool,BlameDisplay_impl*); BlameDisplayItem(KListView*,BlameDisplayItem*,const svn::AnnotateLine&,bool,BlameDisplay_impl*); virtual ~BlameDisplayItem(){} virtual int compare(TQListViewItem *i, int col, bool ascending)const; virtual void paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int tqalignment); virtual int rtti()const{return 1000;} virtual int width( const TQFontMetrics & fm, const TQListView * lv, int c ) const; apr_int64_t lineNumber(){return m_Content.lineNumber();} svn_revnum_t rev(){return m_Content.revision();} void localeChanged() { m_Content.localeChanged(); if (m_disp){ setText(COL_AUT,m_Content.tAuthor()); } TQString _line = m_Content.tLine(); _line.replace("\t"," "); setText(COL_LINE,TQString("%1").tqarg(_line)); } protected: LocalizedAnnotatedLine m_Content; bool m_disp; void display(); BlameDisplay_impl*cb; }; BlameDisplayItem::BlameDisplayItem(KListView*lv,const svn::AnnotateLine&al,bool disp,BlameDisplay_impl*_c) : KListViewItem(lv),m_Content(al),m_disp(disp),cb(_c) { display(); } BlameDisplayItem::BlameDisplayItem(KListView*lv,BlameDisplayItem*it,const svn::AnnotateLine&al,bool disp,BlameDisplay_impl*_c) : KListViewItem(lv,it),m_Content(al),m_disp(disp),cb(_c) { display(); } #define BORDER 4 int BlameDisplayItem::width (const TQFontMetrics & fm, const TQListView * lv, int c ) const { if (c == COL_LINE) { return KListViewItem::width(TQFontMetrics(KGlobalSettings::fixedFont()),lv,c)+2*BORDER; } return KListViewItem::width(fm,lv,c)+2*BORDER; } void BlameDisplayItem::display() { if (m_disp){ setText(COL_REV,TQString("%1").tqarg(m_Content.revision())); setText(COL_AUT,m_Content.tAuthor()); if (m_Content.date().isValid()) { setText(COL_DATE,KGlobal::locale()->formatDateTime(m_Content.date())); } } setText(COL_LINENR,TQString("%1").tqarg(m_Content.lineNumber()+1)); TQString _line = m_Content.tLine(); _line.replace("\t"," "); setText(COL_LINE,TQString("%1").tqarg(_line)); } int BlameDisplayItem::compare(TQListViewItem *item, int col, bool ascending)const { Q_UNUSED(ascending); BlameDisplayItem* k = static_cast(item); if (col == COL_REV) { return k->m_Content.revision()-m_Content.revision(); } if (col == COL_AUT) { if (Kdesvnsettings::locale_is_casesensitive()) { return m_Content.tAuthor().localeAwareCompare(k->m_Content.author()); } return m_Content.tAuthor().compare(k->m_Content.author()); } return k->m_Content.lineNumber()-m_Content.lineNumber(); } void BlameDisplayItem::paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int tqalignment) { if (tqalignment & (AlignTop || AlignBottom) == 0) tqalignment |= AlignVCenter; /* don't copy string */ const TQString & str = text(column);; if (column == COL_LINE) { p->setFont(KGlobalSettings::fixedFont()); } TQColorGroup _cg = cg; TQColor _bgColor; if (column==COL_LINENR || isSelected()) { _bgColor = KGlobalSettings::highlightColor(); p->setPen(KGlobalSettings::highlightedTextColor()); } else { if (Kdesvnsettings::self()->colored_blame()) { _bgColor = cb->rev2color(m_Content.revision()); } else { _bgColor = listView()->viewport()->tqcolorGroup().base(); } } p->fillRect(0, 0, width, height(), _bgColor); if (column==COL_AUT) { p->drawLine(width-1,0,width-1,height()); } if (str.isEmpty()) return; p->drawText(BORDER, 0, width - 2*BORDER, height(), tqalignment, str); } class BlameDisplayData { public: BlameDisplayData() { max=-1; min=INT_MAX-1; rev_count=0; up=false; m_cb=0;m_File=""; m_dlg = 0; } ~BlameDisplayData(){} svn_revnum_t max,min; TQMap m_shadingMap; TQMap m_logCache; TQColor m_lastCalcColor; unsigned int rev_count; bool up; SimpleLogCb*m_cb; TQString m_File; KDialogBase*m_dlg; TQString reposRoot; }; BlameDisplay_impl::BlameDisplay_impl(TQWidget*parent,const char*name) : BlameDisplay(parent,name) { m_Data = new BlameDisplayData(); connect(m_BlameList,TQT_SIGNAL(selectionChanged()),this,TQT_SLOT(slotSelectionChanged())); } BlameDisplay_impl::BlameDisplay_impl(const TQString&what,const svn::AnnotatedFile&blame,TQWidget*parent,const char*name) : BlameDisplay(parent,name) { m_Data = new BlameDisplayData(); connect(m_BlameList,TQT_SIGNAL(selectionChanged()),this,TQT_SLOT(slotSelectionChanged())); setContent(what,blame); } void BlameDisplay_impl::setCb(SimpleLogCb*_cb) { m_Data->m_cb = _cb; } void BlameDisplay_impl::setContent(const TQString&what,const svn::AnnotatedFile&blame) { m_Data->m_File = what; m_SearchWidget = new KListViewSearchLineWidget(m_BlameList,this); EncodingSelector_impl*m_Ls = new EncodingSelector_impl(Kdesvnsettings::locale_for_blame(),this); connect(m_Ls,TQT_SIGNAL(TextCodecChanged(const TQString&)), this,TQT_SLOT(slotTextCodecChanged(const TQString&))); BlameDisplayLayout->remove(m_BlameList); BlameDisplayLayout->addWidget(m_Ls); BlameDisplayLayout->addWidget(m_SearchWidget); BlameDisplayLayout->addWidget(m_BlameList); m_BlameList->setColumnAlignment(COL_REV,TQt::AlignRight); m_BlameList->setColumnAlignment(COL_LINENR,TQt::AlignRight); m_BlameList->clear(); if (m_Data->m_dlg) { m_Data->m_dlg->enableButton(KDialogBase::User2,false); } svn::AnnotatedFile::const_iterator bit; m_BlameList->setSorting(COL_LINENR,false); m_Data->max = -1; svn_revnum_t lastRev(-1); for (bit=blame.begin();bit!=blame.end();++bit) { bool disp = (*bit).revision()!=lastRev || bit==blame.begin() ; if ((*bit).revision()>m_Data->max) {m_Data->max=(*bit).revision();++(m_Data->rev_count);} if ((*bit).revision()min) m_Data->min=(*bit).revision(); new BlameDisplayItem(m_BlameList,(*bit),disp,this); if (disp) { lastRev = (*bit).revision(); } if (m_Data->m_shadingMap.find((*bit).revision())==m_Data->m_shadingMap.end()) { m_Data->m_shadingMap[(*bit).revision()]=TQColor(); } } if (Kdesvnsettings::self()->colored_blame()) { TQColor a(160,160,160); int offset = 10; int r=0; int g=0;int b=0; uint colinc=0; for (svn_revnum_t i = m_Data->min; i<= m_Data->max;++i) { if (m_Data->m_shadingMap.find(i)==m_Data->m_shadingMap.end()) { continue; } a.setRgb(a.red()+offset,a.green()+offset,a.blue()+offset); m_Data->m_shadingMap[i]=a; if ( a.red()>245||a.green()>245||a.blue()>245 ) { if (colinc==0) { ++colinc; } else if (r>=50||g>=50||b>=50) { if (++colinc>6) { colinc = 0; r=g=b=0; } else { r=g=b=-10; } } if (colinc & 0x1) { r+=10; } if (colinc & 0x2) { g+=10; } if (colinc & 0x4) { b+=10; } a.setRgb(160+r,160+g,160+b); } } } } const TQColor BlameDisplay_impl::rev2color(svn_revnum_t r )const { if (m_Data->m_shadingMap.find(r)!=m_Data->m_shadingMap.end() && m_Data->m_shadingMap[r].isValid()) { return m_Data->m_shadingMap[r]; } else { return m_BlameList->viewport()->tqcolorGroup().base(); } } BlameDisplay_impl::~BlameDisplay_impl() { delete m_Data; } void BlameDisplay_impl::slotGoLine() { bool ok = true; int line = KInputDialog::getInteger(i18n("Show line"),i18n("Show line number"), 1,1,m_BlameList->childCount(),1,&ok,this); if (!ok) { return; } TQListViewItem*item = m_BlameList->firstChild(); --line; while (item) { if (item->rtti()==1000) { BlameDisplayItem*bit = static_cast(item); if (bit->lineNumber()==line) { m_BlameList->ensureItemVisible(bit); m_BlameList->setSelected(bit,true); return; } } item = item->nextSibling(); } } void BlameDisplay_impl::slotContextMenuRequested(KListView*,TQListViewItem*item, const TQPoint&pos) { if (item==0||item->rtti()!=1000) return; BlameDisplayItem*bit = static_cast(item); TQPopupMenu popup; popup.insertItem(i18n("Log message for revision"),101); int r = popup.exec(pos); switch (r) { case 101: showCommit(bit); break; default: break; } } void BlameDisplay_impl::showCommit(BlameDisplayItem*bit) { if (!bit) return; WidgetBlockStack a(m_BlameList); TQString text; if (m_Data->m_logCache.find(bit->rev())!=m_Data->m_logCache.end()) { text = m_Data->m_logCache[bit->rev()].message; } else { CursorStack a(TQt::BusyCursor); svn::LogEntry t; if (m_Data->m_cb && m_Data->m_cb->getSingleLog(t,bit->rev(),m_Data->m_File,m_Data->max,m_Data->reposRoot)) { m_Data->m_logCache[bit->rev()] = t; text = m_Data->m_logCache[bit->rev()].message; } } KDialogBase* dlg = new KDialogBase( TQT_TQWIDGET(KApplication::activeModalWidget()), "simplelog",true,TQString(i18n("Logmessage for revision %1").tqarg(bit->rev())), KDialogBase::Close); TQWidget* Dialog1Layout = dlg->makeVBoxMainWidget(); KTextBrowser*ptr = new KTextBrowser(Dialog1Layout); ptr->setFont(KGlobalSettings::fixedFont()); ptr->setWordWrap(TQTextEdit::NoWrap); ptr->setText(text); dlg->resize(dlg->configDialogSize(*(Kdesvnsettings::self()->config()),"simplelog_display")); dlg->exec(); dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"simplelog_display",false); } void BlameDisplay_impl::slotShowCurrentCommit() { TQListViewItem*item = m_BlameList->selectedItem(); if (item==0||item->rtti()!=1000) return; BlameDisplayItem*bit = static_cast(item); showCommit(bit); } void BlameDisplay_impl::slotSelectionChanged() { if (!m_Data->m_dlg) return; TQListViewItem*item = m_BlameList->selectedItem(); if (item==0||item->rtti()!=1000) { m_Data->m_dlg->enableButton(KDialogBase::User2,false); } else { m_Data->m_dlg->enableButton(KDialogBase::User2,true); } } void BlameDisplay_impl::displayBlame(SimpleLogCb*_cb,const TQString&item,const svn::AnnotatedFile&blame,TQWidget*,const char*name) { int buttons = KDialogBase::Close|KDialogBase::User1|KDialogBase::User2; KDialogBase * dlg = new KDialogBase( TQT_TQWIDGET(KApplication::activeModalWidget()), name,true,TQString(i18n("Blame %1")).tqarg(item),buttons,KDialogBase::Close,false, KGuiItem(i18n("Goto line")),KGuiItem(i18n("Log message for revision"),"tdesvnlog")); TQWidget* Dialog1Layout = dlg->makeVBoxMainWidget(); BlameDisplay_impl*ptr = new BlameDisplay_impl(Dialog1Layout); dlg->resize(dlg->configDialogSize(*(Kdesvnsettings::self()->config()),"blame_dlg")); ptr->setContent(item,blame); ptr->setCb(_cb); ptr->m_Data->m_dlg = dlg; dlg->enableButton(KDialogBase::User2,false); connect(dlg,TQT_SIGNAL(user1Clicked()),ptr,TQT_SLOT(slotGoLine())); connect(dlg,TQT_SIGNAL(user2Clicked()),ptr,TQT_SLOT(slotShowCurrentCommit())); Dialog1Layout->adjustSize(); dlg->exec(); dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"blame_dlg",false); } void BlameDisplay_impl::slotItemDoubleClicked(TQListViewItem*item) { if (item==0||item->rtti()!=1000) return; BlameDisplayItem*bit = static_cast(item); showCommit(bit); } void BlameDisplay_impl::slotTextCodecChanged(const TQString&what) { if (Kdesvnsettings::locale_for_blame()!=what) { Kdesvnsettings::setLocale_for_blame(what); Kdesvnsettings::self()->writeConfig(); LocalizedAnnotatedLine::reset_codec(); TQListViewItemIterator it(m_BlameList); while ( it.current() ) { BlameDisplayItem*_it = static_cast(it.current()); _it->localeChanged(); ++it; } } } #include "blamedisplay_impl.moc"