Emit signal on selection change, ensure currentIndex is first item in selectedItems()
[quassel.git] / src / qtui / topiclabel.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005/06 by the Quassel Project                          *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "topiclabel.h"
22
23
24 #include <QDebug>
25
26 #include <QApplication>
27 #include <QDesktopServices>
28 #include <QPainter>
29 // #include <QHBoxLayout>
30 #include <QFont>
31 #include <QFontMetrics>
32
33 #include "qtui.h"
34 #include "qtuistyle.h"
35 #include "message.h"
36
37 TopicLabel::TopicLabel(QWidget *parent)
38   : QFrame(parent),
39     offset(0),
40     dragStartX(0),
41     textWidth(0),
42     dragMode(false)
43 {
44   setToolTip(tr("Drag to scroll the topic!"));
45   setCursor(Qt::OpenHandCursor);
46 }
47
48 void TopicLabel::paintEvent(QPaintEvent *event) {
49   Q_UNUSED(event);
50
51   textPartOffset.clear();
52
53   QPainter painter(this);
54   painter.setBackgroundMode(Qt::OpaqueMode);
55
56   // FIXME use QTextLayout instead
57
58   QRect drawRect = rect().adjusted(offset, 0, 0, 0);
59   QRect brect;
60   QString textPart;
61   foreach(QTextLayout::FormatRange fr, formatList) {
62     textPart = plainText.mid(fr.start, fr.length);
63     textPartOffset << drawRect.left();
64     painter.setFont(fr.format.font());
65     painter.setPen(QPen(fr.format.foreground(), 0));
66     painter.setBackground(fr.format.background());
67     painter.drawText(drawRect, Qt::AlignLeft|Qt::AlignVCenter, textPart, &brect);
68     drawRect.setLeft(brect.right());
69   }
70   textWidth = brect.right();
71 }
72
73 void TopicLabel::setText(const QString &text) {
74   if(_text == text)
75     return;
76
77   _text = text;
78   offset = 0;
79   update();
80
81   UiStyle::StyledString styledContents = QtUi::style()->styleString("%D0" + QtUi::style()->mircToInternal(text));
82   plainText = styledContents.plainText;
83   formatList = QtUi::style()->toTextLayoutList(styledContents.formatList, plainText.length());
84   int height = 1;
85   foreach(QTextLayout::FormatRange fr, formatList) {
86     height = qMax(height, QFontMetrics(fr.format.font()).height());
87   }
88
89   // ensure the label is editable (height != 1) if there is no text to show
90   if(text.isEmpty())
91     height = QFontMetrics(qApp->font()).height();
92
93   // setFixedHeight(height);
94   // show topic in tooltip
95 }
96
97
98 void TopicLabel::mouseMoveEvent(QMouseEvent *event) {
99   if(!dragMode)
100     return;
101
102   event->accept();
103   int newOffset = event->pos().x() - dragStartX;
104   if(newOffset > 0)
105     offset = 0;
106   else if(width() + 1 < textWidth || offset < newOffset)
107     offset = newOffset;
108
109   update();
110 }
111
112 void TopicLabel::mousePressEvent(QMouseEvent *event) {
113   event->accept();
114   dragMode = true;
115   dragStartX = event->pos().x() - offset;
116   setCursor(Qt::ClosedHandCursor);
117 }
118
119 void TopicLabel::mouseReleaseEvent(QMouseEvent *event) {
120   event->accept();
121   dragMode = false;
122   if(qAbs(offset) < 30) {
123     offset = 0;
124     update();
125   }
126   setCursor(Qt::OpenHandCursor);
127 }
128
129 void TopicLabel::mouseDoubleClickEvent(QMouseEvent *event) {
130   event->accept();
131   if(textPartOffset.isEmpty())
132     return;
133
134   // find the text part that contains the url. We don't expect color codes in urls so we expect only full parts (yet?)
135   int textPart = 0;
136   int x = event->pos().x() + offset;
137   while(textPart + 1 < textPartOffset.count()) {
138     if(textPartOffset[textPart + 1] < x)
139       textPart++;
140     else
141       break;
142   }
143   int textOffset = textPartOffset[textPart];
144
145   // we've Identified the needed text part \o/
146   QString text = plainText.mid(formatList[textPart].start, formatList[textPart].length);
147
148   // now we have to find the the left and right word delimiters of the clicked word
149   QFontMetrics fontMetric(formatList[textPart].format.font());
150
151   int start = 0;
152   int spacePos = text.indexOf(" ");
153   x -= offset; // offset needs to go here as it's already in the textOffset
154   while(spacePos != -1) {
155     if(fontMetric.width(text.left(spacePos + 1)) + textOffset < x) {
156       start = spacePos + 1;
157       spacePos = text.indexOf(" ", start + 1);
158     } else {
159       break;
160     }
161   }
162
163   int end = text.indexOf(" ", start);
164   int len = -1;
165   if(end != -1) {
166     len = end - start;
167   }
168   QString word = text.mid(start, len);
169   QRegExp regex("^(h|f)t{1,2}ps?:\\/\\/");
170   if(regex.indexIn(word) != -1) {
171     QDesktopServices::openUrl(QUrl(word));
172   }
173 }