2 Author: Marco Costalba (C) 2005-2007
4 Copyright: See COPYING file that comes with this distribution
7 #include <QContextMenuEvent>
11 #include <QWheelEvent>
13 #include "smartbrowse.h"
23 SmartLabel::SmartLabel(const QString
& text
, QWidget
* par
) : QLabel(text
, par
) {
24 this->setStyleSheet("SmartLabel { border: 1px solid LightGray;"
25 "padding: 0px 2px 2px 2px; }");
28 void SmartLabel::paintEvent(QPaintEvent
* event
) {
29 // our QPainter must be destroyed before QLabel's paintEvent is called
31 QPainter
painter(this);
32 QColor backgroundColor
= Qt::white
;
34 // give label a semi-transparent background
35 backgroundColor
.setAlpha(200);
36 painter
.fillRect(this->rect(), backgroundColor
);
39 // let QLabel do the rest
40 QLabel::paintEvent(event
);
43 void SmartLabel::contextMenuEvent(QContextMenuEvent
* e
) {
45 if (text().count("href=") != 2)
48 QMenu
* menu
= new QMenu(this);
49 menu
->addAction("Switch links", this, SLOT(switchLinks()));
50 menu
->exec(e
->globalPos());
54 void SmartLabel::switchLinks() {
57 QString
link1(t
.section("<a href=", 1). section("</a>", 0, 0));
58 QString
link2(t
.section("<a href=", 2). section("</a>", 0, 0));
59 t
.replace(link1
, "%1").replace(link2
, "%2");
60 setText(t
.arg(link2
, link1
));
64 SmartBrowse::SmartBrowse(RevsView
* par
) : QObject(par
) {
68 lablesEnabled
= QGit::testFlag(QGit::SMART_LBL_F
);
70 QString
txt("<p><img src=\":/icons/resources/%1\"> %2 %3</p>");
71 QString
link("<a href=\"%1\">%2</a>");
72 QString
linkUp(link
.arg(QString::number(GO_UP
), "Up"));
73 QString
linkDown(link
.arg(QString::number(GO_DOWN
), "Down"));
74 QString
linkLog(link
.arg(QString::number(GO_LOG
), "Log"));
75 QString
linkDiff(link
.arg(QString::number(GO_DIFF
), "Diff"));
77 QTextEdit
* log
= static_cast<QTextEdit
*>(rv
->tab()->textBrowserDesc
);
78 QTextEdit
* diff
= static_cast<QTextEdit
*>(rv
->tab()->textEditDiff
);
80 logTopLbl
= new SmartLabel(txt
.arg("go-up.svg", linkUp
, ""), log
);
81 logBottomLbl
= new SmartLabel(txt
.arg("go-down.svg", linkDiff
, linkDown
), log
);
82 diffTopLbl
= new SmartLabel(txt
.arg("go-up.svg", linkLog
, linkUp
), diff
);
83 diffBottomLbl
= new SmartLabel(txt
.arg("go-down.svg", linkUp
, linkDown
), diff
);
85 diffTopLbl
->setFont(qApp
->font()); // override parent's font to
86 diffBottomLbl
->setFont(qApp
->font()); // avoid QGit::TYPE_WRITER_FONT
90 log
->installEventFilter(this);
91 diff
->installEventFilter(this);
93 QScrollBar
* vsbLog
= log
->verticalScrollBar();
94 QScrollBar
* vsbDiff
= diff
->verticalScrollBar();
96 vsbLog
->installEventFilter(this);
97 vsbDiff
->installEventFilter(this);
99 log
->horizontalScrollBar()->installEventFilter(this);
100 diff
->horizontalScrollBar()->installEventFilter(this);
102 connect(vsbLog
, SIGNAL(valueChanged(int)),
103 this, SLOT(updateVisibility()));
105 connect(vsbDiff
, SIGNAL(valueChanged(int)),
106 this, SLOT(updateVisibility()));
108 connect(logTopLbl
, SIGNAL(linkActivated(const QString
&)),
109 this, SLOT(linkActivated(const QString
&)));
111 connect(logBottomLbl
, SIGNAL(linkActivated(const QString
&)),
112 this, SLOT(linkActivated(const QString
&)));
114 connect(diffTopLbl
, SIGNAL(linkActivated(const QString
&)),
115 this, SLOT(linkActivated(const QString
&)));
117 connect(diffBottomLbl
, SIGNAL(linkActivated(const QString
&)),
118 this, SLOT(linkActivated(const QString
&)));
121 void SmartBrowse::setVisible(bool b
) {
123 b
= b
&& lablesEnabled
;
124 logTopLbl
->setVisible(b
);
125 logBottomLbl
->setVisible(b
);
126 diffTopLbl
->setVisible(b
);
127 diffBottomLbl
->setVisible(b
);
130 QTextEdit
* SmartBrowse::curTextEdit(bool* isDiff
) {
132 QTextEdit
* log
= static_cast<QTextEdit
*>(rv
->tab()->textBrowserDesc
);
133 QTextEdit
* diff
= static_cast<QTextEdit
*>(rv
->tab()->textEditDiff
);
136 *isDiff
= diff
->isVisible();
138 if (!diff
->isVisible() && !log
->isVisible())
141 return (diff
->isVisible() ? diff
: log
);
144 int SmartBrowse::visibilityFlags(bool* isDiff
) {
148 QTextEdit
* te
= curTextEdit(isDiff
);
152 QScrollBar
* vsb
= te
->verticalScrollBar();
154 bool v
= lablesEnabled
&& te
->isEnabled();
155 bool top
= v
&& (!vsb
->isVisible() || (vsb
->value() - vsb
->minimum() < MIN
));
156 bool btm
= v
&& (!vsb
->isVisible() || (vsb
->maximum() - vsb
->value() < MIN
));
158 return AT_TOP
* top
+ AT_BTM
* btm
;
161 void SmartBrowse::updateVisibility() {
164 int flags
= visibilityFlags(&isDiff
);
167 diffTopLbl
->setVisible(flags
& AT_TOP
);
168 diffBottomLbl
->setVisible(flags
& AT_BTM
);
170 logTopLbl
->setVisible(flags
& AT_TOP
);
171 logBottomLbl
->setVisible(flags
& AT_BTM
);
175 void SmartBrowse::flagChanged(uint flag
) {
177 if (flag
== QGit::SMART_LBL_F
&& curTextEdit()) {
178 lablesEnabled
= QGit::testFlag(QGit::SMART_LBL_F
);
179 setVisible(curTextEdit()->isEnabled());
182 if (flag
== QGit::LOG_DIFF_TAB_F
)
183 rv
->setTabLogDiffVisible(QGit::testFlag(QGit::LOG_DIFF_TAB_F
));
186 void SmartBrowse::linkActivated(const QString
& text
) {
188 int key
= text
.toInt();
192 rv
->toggleDiffView();
195 rv
->tab()->listViewLog
->on_keyUp();
198 rv
->tab()->listViewLog
->on_keyDown();
201 dbp("ASSERT in SmartBrowse::linkActivated, key %1 not known", text
);
205 bool SmartBrowse::eventFilter(QObject
*obj
, QEvent
*event
) {
208 return QObject::eventFilter(obj
, event
);
210 QTextEdit
* te
= dynamic_cast<QTextEdit
*>(obj
);
211 QScrollBar
* sb
= dynamic_cast<QScrollBar
*>(obj
);
213 QEvent::Type t
= event
->type();
214 if (te
&& t
== QEvent::Resize
)
217 if (sb
&& (t
== QEvent::Show
|| t
== QEvent::Hide
))
220 if (te
&& t
== QEvent::EnabledChange
) {
221 setVisible(te
->isEnabled());
224 if (sb
&& t
== QEvent::Wheel
&& sb
->orientation() == Qt::Vertical
) {
226 QWheelEvent
* we
= static_cast<QWheelEvent
*>(event
);
227 if (wheelRolled(we
->angleDelta().y(), visibilityFlags()))
228 return true; // filter event out
230 return QObject::eventFilter(obj
, event
);
233 void SmartBrowse::updatePosition() {
235 QTextEdit
* te
= curTextEdit();
239 QScrollBar
* vb
= te
->verticalScrollBar();
240 QScrollBar
* hb
= te
->horizontalScrollBar();
242 int w
= te
->width() - vb
->width() * vb
->isVisible();
243 int h
= te
->height() - hb
->height() * hb
->isVisible();
245 logTopLbl
->move(w
- logTopLbl
->width() - 10, 10);
246 diffTopLbl
->move(w
- diffTopLbl
->width() - 10, 10);
247 logBottomLbl
->move(w
- logBottomLbl
->width() - 10, h
- logBottomLbl
->height() - 10);
248 diffBottomLbl
->move(w
- diffBottomLbl
->width() - 10, h
- diffBottomLbl
->height() - 10);
252 // we are called also when user toggle view manually,
253 // so reset wheel counters to be sure we don't have alias
254 scrollTimer
.restart();
258 bool SmartBrowse::wheelRolled(int delta
, int flags
) {
260 bool justSwitched
= (switchTimer
.isValid() && switchTimer
.elapsed() < 400);
262 switchTimer
.restart();
264 bool scrolling
= (scrollTimer
.isValid() && scrollTimer
.elapsed() < 400);
265 bool directionChanged
= (wheelCnt
* delta
< 0);
267 // we are called before the scroll bar is updated, so we need
268 // to take in account roll direction to avoid false positives
269 bool scrollingOut
= ( ((flags
& AT_TOP
) && (delta
> 0))
270 ||((flags
& AT_BTM
) && (delta
< 0)));
272 // a scroll action have to start when in range
273 // but can continue also when goes out of range
274 if (!scrollingOut
|| scrolling
)
275 scrollTimer
.restart();
277 if (!scrollingOut
|| justSwitched
)
278 return justSwitched
; // filter wheels events just after a switch
280 // we want a quick rolling action to be considered valid
281 bool tooSlow
= (timeoutTimer
.isValid() && timeoutTimer
.elapsed() > 300);
282 timeoutTimer
.restart();
284 if (directionChanged
|| scrolling
|| tooSlow
)
287 // ok, we would be ready to switch, but we want to add some inertia
288 wheelCnt
+= (delta
> 0 ? 1 : -1);
289 if (wheelCnt
* wheelCnt
< 9)
294 l
= logTopLbl
->isVisible() ? logTopLbl
: diffTopLbl
;
296 l
= logBottomLbl
->isVisible() ? logBottomLbl
: diffBottomLbl
;
299 switchTimer
.restart();
300 linkActivated(l
->text().section("href=", 1).section("\"", 1, 1));