1 /****************************************************************************
2 **
3 ** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
4 **
5 ** This file is part of the Edyuk project <http://edyuk.org>
6 **
7 ** This file may be used under the terms of the GNU General Public License
8 ** version 3 as published by the Free Software Foundation and appearing in the
9 ** file GPL.txt included in the packaging of this file.
10 **
11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 **
14 ****************************************************************************/
15 
16 #include "qlinemarkpanel.h"
17 
18 /*!
19 	\file qlinemarkpanel.cpp
20 	\brief Implementation of the QLineMarkPanel class.
21 */
22 
23 #include "qeditor.h"
24 
25 #include "qdocument.h"
26 #include "qdocumentline.h"
27 
28 #include "qlanguagedefinition.h"
29 #include "qlinemarksinfocenter.h"
30 
31 /*!
32 	\ingroup widgets
33 	@{
34 */
35 
36 /*!
37 	\class QLineMarkPanel
38 	\brief A specific panel in charge of drawing line marks of an editor
39 */
40 
QCE_AUTO_REGISTER(QLineMarkPanel)41 QCE_AUTO_REGISTER(QLineMarkPanel)
42 
43 /*!
44 	\brief Constructor
45 */
46 QLineMarkPanel::QLineMarkPanel(QWidget *p)
47  : QPanel(p)
48 {
49 	setObjectName("lineMarkPanel");
50 	minMarksPerLine=1;
51 	maxMarksPerLine=1;
52 	setFixedWidth(minMarksPerLine*16+2);
53 }
54 
55 /*!
56 	\brief Empty destructor
57 */
~QLineMarkPanel()58 QLineMarkPanel::~QLineMarkPanel()
59 {
60 
61 }
62 
63 /*!
64 
65 */
type() const66 QString QLineMarkPanel::type() const
67 {
68 	return "Line marks";
69 }
70 
setToolTipForTouchedMark(QString text)71 void QLineMarkPanel::setToolTipForTouchedMark(QString text){
72     markToolTip=text;
73 }
74 
75 /*!
76 	\internal
77 */
event(QEvent * e)78 bool QLineMarkPanel::event(QEvent *e) {
79      if (e->type() == QEvent::ToolTip) {
80         QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
81         int linen=editor()->document()->lineNumber(editor()->verticalOffset()+helpEvent->y());
82         markToolTip="";
83         if (linen>-1 && linen<editor()->document()->lines()) {
84             QDocumentLine line = editor()->document()->line(linen);
85 			QList<int> lm = line.marks();
86 			int count = 1;
87 			int bestMark = -1;
88 			QLineMarksInfoCenter *mic = QLineMarksInfoCenter::instance();
89 			foreach ( int id, lm )
90 			{
91 			    if (mic->markType(id).icon.isNull())
92                     continue;
93                 if (helpEvent->x()>count && helpEvent->x()<count+16)
94                     bestMark = id; //no break do to overdraw
95 				if (count < 16*(maxMarksPerLine-1)) {
96                     count += 16;
97                     if (bestMark!=-1) break;
98 				}
99 			}
100 			if (bestMark!=-1)
101                 emit toolTipRequested(linen,bestMark);
102         }
103         if (markToolTip.isEmpty()) QToolTip::hideText();
104         else QToolTip::showText(helpEvent->globalPos(), markToolTip);
105 		e->setAccepted(true);
106     }
107     return QWidget::event(e);
108 }
paint(QPainter * p,QEditor * e)109 bool QLineMarkPanel::paint(QPainter *p, QEditor *e)
110 {
111 	if ( !e || !e->document() )
112 		return true;
113 
114 	m_rects.clear();
115 	m_lines.clear();
116 	QDocument *d = e->document();
117 
118 	int realMarksPerLine = d->maxMarksPerLine();
119 	int marksPerLine = realMarksPerLine;
120 	if (marksPerLine<minMarksPerLine) marksPerLine=minMarksPerLine;
121 	if (marksPerLine>maxMarksPerLine) marksPerLine=maxMarksPerLine;
122 	setFixedWidth(marksPerLine ? marksPerLine * 16 + 2 : 18);
123 
124     int n;
125     qreal posY,
126         as = QFontMetricsF(d->font()).ascent(),
127 		ls = d->getLineSpacing(),
128 		pageBottom = e->viewport()->height(),
129 		contentsY = e->verticalOffset();
130 
131 	QLineMarksInfoCenter *mic = QLineMarksInfoCenter::instance();
132 
133 	n = d->lineNumber(contentsY);
134 	posY = 2 + d->y(n) - contentsY;
135 
136 	//qDebug("first = %i; last = %i", first, last);
137 	//qDebug("beg pos : %i", posY);
138 	//qDebug("<session>");
139 	for ( ; ; ++n )
140 	{
141 		//qDebug("n = %i; pos = %i", n, posY);
142 		QDocumentLine line = d->line(n);
143 
144 		if ( line.isNull() || ((posY - as) > pageBottom) )
145 			break;
146 
147 		if ( line.isHidden() )
148 			continue;
149 
150 		m_lines << n;
151         m_rects << QRectF(0, posY, width(), ls);
152 
153 		if ( realMarksPerLine )
154 		{
155 			int count = 1;
156 			QList<int> lm = line.marks();
157 
158 			foreach ( int id, lm )
159 			{
160 				const QIcon & icon = mic->markType(id).icon;
161 
162 				if ( icon.isNull() )
163 					continue;
164 
165                 int size = qMin(16., ls-4); // (maxWidth, maxHeight) assuming square icons
166 
167 
168                 qreal x = count,
169                     y = posY + ( (ls - size) /2  );
170 #ifdef Q_OS_MAC
171                 QPixmap pix=icon.pixmap(2*size); // oversampling on mac !!!!
172 #else
173                 QPixmap pix=icon.pixmap(size);
174 #endif
175 
176                 p->drawPixmap(QRectF(x, y, size,size),pix,pix.rect());
177 
178 				if (count < 16*(maxMarksPerLine-1))
179                     count += 16;
180 			}
181 		}
182 
183 		posY += ls * line.lineSpan();
184 	}
185 	//qDebug("</session>");
186 
187 	return true;
188 }
189 
190 /*!
191 	\internal
192 */
mousePressEvent(QMouseEvent * e)193 void QLineMarkPanel::mousePressEvent(QMouseEvent *e)
194 {
195 // 	if ( !editor() || !editor()->document() || !editor()->marker() )
196 // 	{
197 // 		return QPanel::mousePressEvent(e);
198 // 	}
199 //
200 	QPanel::mousePressEvent(e);
201  	e->accept();
202 }
203 
204 /*!
205 	\internal
206 */
mouseReleaseEvent(QMouseEvent * e)207 void QLineMarkPanel::mouseReleaseEvent(QMouseEvent *e)
208 {
209 	if ( !editor() || !editor()->document() || !editor()->languageDefinition() || e->button()!= Qt::LeftButton)
210 	{
211 		QPanel::mouseReleaseEvent(e);
212 		return;
213 	}
214 
215 	int line=editor()->document()->lineNumber(editor()->verticalOffset()+e->y());
216 	if (editor()->document()->line(line).isValid())
217 		emit lineClicked(line);
218 
219 	//QMessageBox::warning(0, 0, "clik.");
220 
221 	QDocumentLine l;
222 	QLanguageDefinition *d = editor()->languageDefinition();
223 	const int id = QLineMarksInfoCenter::instance()->markTypeId(d->defaultLineMark());
224 	if ( id < 0 )
225 		return;
226 
227 	e->accept();
228 
229 
230 	for ( int i = 0; i < m_rects.count(); ++i )
231 	{
232 		if ( m_rects.at(i).contains(e->pos()) )
233 		{
234 			l = editor()->document()->line(m_lines.at(i));
235 			l.toggleMark(id);
236 			//m->toggleDefaultMark(l, -1);
237 
238 			break;
239 		}
240 	}
241 
242 	QPanel::mouseReleaseEvent(e);
243 }
244 
245 /*!
246 	\internal
247 */
contextMenuEvent(QContextMenuEvent * e)248 void QLineMarkPanel::contextMenuEvent(QContextMenuEvent *e)
249 {
250 	if ( !editor() || !editor()->document() )
251 	{
252 		e->ignore();
253 		return;
254 	}
255 
256 	int line=editor()->document()->lineNumber(editor()->verticalOffset()+e->y());
257 	if (editor()->document()->line(line).isValid())
258 		emit contextMenuRequested(line, e->globalPos());
259 
260 	/*
261 	QTextBlock b;
262 	QMarker *m = editor()->marker();
263 	QTextDocument *d = editor()->document();
264 
265 	e->accept();
266 
267 	QHash<int, QRect>::iterator i;
268 
269 	for ( i = rects.begin(); i != rects.end(); i++ )
270 	{
271 		b = d->findBlock(i.key());
272 
273 		if ( i->contains( e->pos() ) )
274 			return m->menu(b, e->globalPos());
275 	}
276 	*/
277 }
278 
279 /*! @} */
280