Warning, file /sdk/cervisia/annotateview.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
0003  * Copyright (c) 2003-2008 André Wöbbeking <Woebbeking@kde.org>
0004  * Copyright (c) 2015 Martin Koller <kollix@aon.at>
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License as published by
0008  * the Free Software Foundation; either version 2 of the License, or
0009  * (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program; if not, write to the Free Software
0018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0019  */
0020 
0021 #include "annotateview.h"
0022 
0023 #include <QApplication>
0024 #include <QHeaderView>
0025 #include <kcolorscheme.h>
0026 #include <qpainter.h>
0027 
0028 #include "cervisiasettings.h"
0029 #include "loginfo.h"
0030 #include "tooltip.h"
0031 
0032 using namespace Cervisia;
0033 
0034 class AnnotateViewItem : public QTreeWidgetItem
0035 {
0036 public:
0037     enum { LineNumberColumn, AuthorColumn, ContentColumn };
0038 
0039     AnnotateViewItem(AnnotateView *parent, const LogInfo &logInfo, const QString &content, bool odd, int linenumber);
0040 
0041     int lineNumber() const
0042     {
0043         return m_lineNumber;
0044     }
0045 
0046     QVariant data(int column, int role) const override;
0047 
0048 private:
0049     LogInfo m_logInfo;
0050     QString m_content;
0051     bool m_odd;
0052     int m_lineNumber;
0053 
0054     friend class AnnotateView;
0055     friend class AnnotateViewDelegate;
0056 };
0057 
0058 AnnotateViewItem::AnnotateViewItem(AnnotateView *parent, const LogInfo &logInfo, const QString &content, bool odd, int linenumber)
0059     : QTreeWidgetItem(parent)
0060     , m_logInfo(logInfo)
0061     , m_content(content)
0062     , m_odd(odd)
0063     , m_lineNumber(linenumber)
0064 {
0065 }
0066 
0067 QVariant AnnotateViewItem::data(int column, int role) const
0068 {
0069     if (role == Qt::DisplayRole) {
0070         switch (column) {
0071         case LineNumberColumn:
0072             return QString::number(m_lineNumber);
0073         case AuthorColumn:
0074             if (m_logInfo.m_author.isNull())
0075                 return QString();
0076             else
0077                 return (m_logInfo.m_author + QChar(' ') + m_logInfo.m_revision);
0078         case ContentColumn:
0079             return m_content;
0080         default:;
0081         };
0082 
0083         return QString();
0084     }
0085 
0086     return QTreeWidgetItem::data(column, role);
0087 }
0088 
0089 //---------------------------------------------------------------------
0090 
0091 void AnnotateViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0092 {
0093     painter->save();
0094 
0095     auto item = static_cast<AnnotateViewItem *>(view->topLevelItem(index.row()));
0096 
0097     QColor backgroundColor;
0098     QColor foregroundColor;
0099 
0100     if (item->isSelected() || index.column() == AnnotateViewItem::LineNumberColumn) {
0101         backgroundColor = KColorScheme(QPalette::Active, KColorScheme::Selection).background().color();
0102         foregroundColor = KColorScheme(QPalette::Active, KColorScheme::Selection).foreground().color();
0103     } else {
0104         backgroundColor = item->m_odd ? KColorScheme(QPalette::Active, KColorScheme::View).background().color()
0105                                       : KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::AlternateBackground).color();
0106         foregroundColor = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
0107     }
0108 
0109     painter->setPen(foregroundColor);
0110     painter->fillRect(option.rect, backgroundColor);
0111 
0112     QString str = item->text(index.column());
0113     if (str.isEmpty()) {
0114         painter->restore();
0115         return;
0116     }
0117 
0118     Qt::Alignment align = (index.column() == AnnotateViewItem::LineNumberColumn) ? Qt::AlignRight : option.displayAlignment;
0119 
0120     if ((align & (Qt::AlignTop | Qt::AlignBottom)) == 0)
0121         align |= Qt::AlignVCenter;
0122 
0123     // only the content shall use the configured font, others use default
0124     // reason: usually you want fixed-width font in sourcecode, but line numbers and revision column look
0125     // nicer when they are not fixed-width
0126     if (index.column() == AnnotateViewItem::ContentColumn)
0127         painter->setFont(view->font());
0128     else
0129         painter->setFont(QApplication::font());
0130 
0131     painter->drawText(option.rect.x() + BORDER, option.rect.y(), option.rect.width() - 2 * BORDER, option.rect.height(), align, str);
0132 
0133     painter->restore();
0134 }
0135 
0136 QSize AnnotateViewDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
0137 {
0138     QStyleOptionViewItem opt(option);
0139 
0140     if (index.column() == AnnotateViewItem::ContentColumn)
0141         opt.font = view->font();
0142     else
0143         opt.font = QApplication::font();
0144 
0145     QSize s = QStyledItemDelegate::sizeHint(opt, index);
0146     s.setWidth(s.width() + 2 * BORDER);
0147 
0148     return s;
0149 }
0150 
0151 //---------------------------------------------------------------------
0152 
0153 AnnotateView::AnnotateView(QWidget *parent)
0154     : QTreeWidget(parent)
0155 {
0156     setItemDelegate(new AnnotateViewDelegate(this));
0157 
0158     setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
0159     setAllColumnsShowFocus(true);
0160     setRootIsDecorated(false);
0161     setAutoScroll(false);
0162     setSelectionMode(QAbstractItemView::SingleSelection); // to be able to show the found item
0163     header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0164     header()->setStretchLastSection(false);
0165     header()->hide();
0166     setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
0167     setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
0168 
0169     setColumnCount(3);
0170 
0171     auto toolTip = new ToolTip(viewport());
0172 
0173     connect(toolTip, SIGNAL(queryToolTip(QPoint, QRect &, QString &)), this, SLOT(slotQueryToolTip(QPoint, QRect &, QString &)));
0174 
0175     configChanged();
0176 
0177     connect(CervisiaSettings::self(), SIGNAL(configChanged()), this, SLOT(configChanged()));
0178 }
0179 
0180 void AnnotateView::addLine(const LogInfo &logInfo, const QString &content, bool odd)
0181 {
0182     new AnnotateViewItem(this, logInfo, content, odd, topLevelItemCount() + 1);
0183 }
0184 
0185 QSize AnnotateView::sizeHint() const
0186 {
0187     QFontMetrics fm(fontMetrics());
0188     return {100 * fm.width("0"), 10 * fm.lineSpacing()};
0189 }
0190 
0191 void AnnotateView::configChanged()
0192 {
0193     setFont(CervisiaSettings::annotateFont());
0194 }
0195 
0196 void AnnotateView::slotQueryToolTip(const QPoint &viewportPos, QRect &viewportRect, QString &text)
0197 {
0198     if (const AnnotateViewItem *item = static_cast<AnnotateViewItem *>(itemAt(viewportPos))) {
0199         const int column(indexAt(viewportPos).column());
0200         if ((column == AnnotateViewItem::AuthorColumn) && !item->m_logInfo.m_author.isNull()) {
0201             viewportRect = visualRect(indexAt(viewportPos));
0202             text = item->m_logInfo.createToolTipText(false);
0203         }
0204     }
0205 }
0206 
0207 void AnnotateView::findText(const QString &textToFind, bool up)
0208 {
0209     QTreeWidgetItem *item = currentItem();
0210     if (!item) {
0211         if (up)
0212             item = topLevelItem(topLevelItemCount() - 1); // last
0213         else
0214             item = topLevelItem(0); // first
0215     } else {
0216         if (up)
0217             item = itemAbove(item);
0218         else
0219             item = itemBelow(item);
0220     }
0221 
0222     for (; item && !item->text(AnnotateViewItem::ContentColumn).contains(textToFind, Qt::CaseInsensitive); item = up ? itemAbove(item) : itemBelow(item))
0223         ;
0224 
0225     setCurrentItem(item);
0226 
0227     if (item) {
0228         item->setSelected(true);
0229         scrollToItem(item);
0230     }
0231 }
0232 
0233 int AnnotateView::currentLine() const
0234 {
0235     QTreeWidgetItem *item = currentItem();
0236     if (!item)
0237         return -1;
0238 
0239     return static_cast<AnnotateViewItem *>(item)->lineNumber();
0240 }
0241 
0242 int AnnotateView::lastLine() const
0243 {
0244     auto item = static_cast<AnnotateViewItem *>(topLevelItem(topLevelItemCount() - 1));
0245     if (!item)
0246         return 0;
0247 
0248     return item->lineNumber();
0249 }
0250 
0251 void AnnotateView::gotoLine(int line)
0252 {
0253     for (auto item = static_cast<AnnotateViewItem *>(topLevelItem(0)); item; item = static_cast<AnnotateViewItem *>(itemBelow(item))) {
0254         if (item->lineNumber() == line) {
0255             setCurrentItem(item);
0256             item->setSelected(true);
0257             scrollToItem(item);
0258             return;
0259         }
0260     }
0261 }
0262 
0263 // Local Variables:
0264 // c-basic-offset: 4
0265 // End: