Mercurial > hg > easyhg-kdiff3
comparison kdiff3/src/difftextwindow.cpp @ 8:86d21651c8db
KDiff3 version 0.9.70
author | joachim99 |
---|---|
date | Mon, 06 Oct 2003 18:50:45 +0000 |
parents | |
children | 1ed6a356f3f6 |
comparison
equal
deleted
inserted
replaced
7:ff98a43bbfea | 8:86d21651c8db |
---|---|
1 /*************************************************************************** | |
2 difftextwindow.cpp - description | |
3 ------------------- | |
4 begin : Mon Apr 8 2002 | |
5 copyright : (C) 2002 by Joachim Eibl | |
6 email : joachim.eibl@gmx.de | |
7 ***************************************************************************/ | |
8 | |
9 /*************************************************************************** | |
10 * * | |
11 * This program is free software; you can redistribute it and/or modify * | |
12 * it under the terms of the GNU General Public License as published by * | |
13 * the Free Software Foundation; either version 2 of the License, or * | |
14 * (at your option) any later version. * | |
15 * * | |
16 ***************************************************************************/ | |
17 | |
18 /*************************************************************************** | |
19 * $Log$ | |
20 * Revision 1.1 2003/10/06 18:38:48 joachim99 | |
21 * KDiff3 version 0.9.70 | |
22 * * | |
23 ***************************************************************************/ | |
24 | |
25 #include <iostream> | |
26 #include "diff.h" | |
27 #include "merger.h" | |
28 #include <qpainter.h> | |
29 #include <assert.h> | |
30 #include <qpixmap.h> | |
31 #include <qstatusbar.h> | |
32 #include <qapplication.h> | |
33 #include <qtooltip.h> | |
34 #include <qfont.h> | |
35 #include <optiondialog.h> | |
36 #include <math.h> | |
37 #include <qdragobject.h> | |
38 | |
39 #define leftInfoWidth (4+m_lineNumberWidth) // Nr of information columns on left side | |
40 | |
41 //using namespace std; | |
42 | |
43 DiffTextWindow::DiffTextWindow( | |
44 QWidget* pParent, | |
45 QStatusBar* pStatusBar, | |
46 OptionDialog* pOptionDialog | |
47 ) | |
48 : QWidget(pParent, 0, WRepaintNoErase) | |
49 { | |
50 setFocusPolicy( QWidget::ClickFocus ); | |
51 setAcceptDrops( true ); | |
52 | |
53 m_pOptionDialog = pOptionDialog; | |
54 init( 0, 0, 0, 0, 0, false ); | |
55 | |
56 setBackgroundMode( PaletteBase ); | |
57 setMinimumSize(QSize(20,20)); | |
58 | |
59 m_pStatusBar = pStatusBar; | |
60 m_bPaintingAllowed = true; | |
61 } | |
62 | |
63 | |
64 void DiffTextWindow::init( | |
65 const QString& filename, | |
66 LineData* pLineData, | |
67 int size, | |
68 const Diff3LineVector* pDiff3LineVector, | |
69 int winIdx, | |
70 bool bTriple | |
71 ) | |
72 { | |
73 m_filename = filename; | |
74 m_pLineData = pLineData; | |
75 m_size = size; | |
76 m_pDiff3LineVector = pDiff3LineVector; | |
77 m_winIdx = winIdx; | |
78 | |
79 m_firstLine = 0; | |
80 m_oldFirstLine = -1; | |
81 m_firstColumn = 0; | |
82 m_oldFirstColumn = -1; | |
83 m_bTriple = bTriple; | |
84 m_scrollDeltaX=0; | |
85 m_scrollDeltaY=0; | |
86 m_bMyUpdate = false; | |
87 m_fastSelectorLine1 = 0; | |
88 m_fastSelectorNofLines = 0; | |
89 m_lineNumberWidth = 0; | |
90 selection.reset(); | |
91 selection.oldFirstLine = -1; // reset is not enough here. | |
92 selection.oldLastLine = -1; | |
93 selection.lastLine = -1; | |
94 | |
95 QToolTip::remove(this); | |
96 QToolTip::add( this, QRect( 0,0, 1024, fontMetrics().height() ), m_filename ); | |
97 update(); | |
98 } | |
99 | |
100 void DiffTextWindow::setPaintingAllowed( bool bAllowPainting ) | |
101 { | |
102 if (m_bPaintingAllowed != bAllowPainting) | |
103 { | |
104 m_bPaintingAllowed = bAllowPainting; | |
105 if ( m_bPaintingAllowed ) update(); | |
106 } | |
107 } | |
108 | |
109 void DiffTextWindow::dragEnterEvent( QDragEnterEvent* e ) | |
110 { | |
111 e->accept( QUriDrag::canDecode(e) || QTextDrag::canDecode(e) ); | |
112 // Note that the corresponding drop is handled in KDiff3App::eventFilter(). | |
113 } | |
114 | |
115 void DiffTextWindow::setFirstLine(int firstLine) | |
116 { | |
117 m_firstLine = max2(0,firstLine); | |
118 myUpdate(0); // Immediately | |
119 } | |
120 | |
121 void DiffTextWindow::setFirstColumn(int firstCol) | |
122 { | |
123 m_firstColumn = max2(0,firstCol); | |
124 myUpdate(0); // Immediately | |
125 } | |
126 | |
127 int DiffTextWindow::getNofColumns() | |
128 { | |
129 int nofColumns = 0; | |
130 for( int i = 0; i< m_size; ++i ) | |
131 { | |
132 if ( m_pLineData[i].width() > nofColumns ) | |
133 nofColumns = m_pLineData[i].width(); | |
134 } | |
135 return nofColumns; | |
136 } | |
137 | |
138 int DiffTextWindow::getNofLines() | |
139 { | |
140 return m_pDiff3LineVector->size(); | |
141 } | |
142 | |
143 /** Returns a line number where the linerange [line, line+nofLines] can | |
144 be displayed best. If it fits into the currently visible range then | |
145 the returned value is the current firstLine. | |
146 */ | |
147 int getBestFirstLine( int line, int nofLines, int firstLine, int visibleLines ) | |
148 { | |
149 int newFirstLine = firstLine; | |
150 if ( line < firstLine || line + nofLines + 2 > firstLine + visibleLines ) | |
151 { | |
152 if ( nofLines > visibleLines || nofLines <= ( 2*visibleLines / 3 - 1) ) | |
153 newFirstLine = line - visibleLines/3; | |
154 else | |
155 newFirstLine = line - (visibleLines - nofLines); | |
156 } | |
157 | |
158 return newFirstLine; | |
159 } | |
160 | |
161 | |
162 void DiffTextWindow::setFastSelectorRange( int line1, int nofLines ) | |
163 { | |
164 m_fastSelectorLine1 = line1; | |
165 m_fastSelectorNofLines = nofLines; | |
166 | |
167 if ( isVisible() ) | |
168 { | |
169 int newFirstLine = getBestFirstLine( line1, nofLines, m_firstLine, getNofVisibleLines() ); | |
170 if ( newFirstLine != m_firstLine ) | |
171 { | |
172 scroll( 0, newFirstLine - m_firstLine ); | |
173 } | |
174 | |
175 update(); | |
176 } | |
177 } | |
178 | |
179 | |
180 static void showStatusLine(int line, int winIdx, const QString& filename, const Diff3LineVector& d3lv, QStatusBar* sb) | |
181 { | |
182 int l=0; | |
183 const Diff3Line* pD3l = d3lv[line]; | |
184 if(line >= 0 && line<(int)d3lv.size() && pD3l != 0 ) | |
185 { | |
186 if ( winIdx==1 ) l = pD3l->lineA; | |
187 else if ( winIdx==2 ) l = pD3l->lineB; | |
188 else if ( winIdx==3 ) l = pD3l->lineC; | |
189 else assert(false); | |
190 | |
191 QString s; | |
192 if ( l!=-1 ) | |
193 s.sprintf("File %s: Line %d", filename.ascii(), l+1 ); | |
194 else | |
195 s.sprintf("File %s: Line not available", filename.ascii() ); | |
196 if (sb!=0) sb->message(s); | |
197 } | |
198 } | |
199 | |
200 | |
201 void DiffTextWindow::mousePressEvent ( QMouseEvent* e ) | |
202 { | |
203 if ( e->button() == LeftButton ) | |
204 { | |
205 int line; | |
206 int pos; | |
207 convertToLinePos( e->x(), e->y(), line, pos ); | |
208 if ( pos < m_firstColumn ) | |
209 { | |
210 emit setFastSelectorLine( line ); | |
211 selection.firstLine = -1; // Disable current selection | |
212 } | |
213 else | |
214 { // Selection | |
215 resetSelection(); | |
216 selection.start( line, pos ); | |
217 selection.end( line, pos ); | |
218 | |
219 showStatusLine( line, m_winIdx, m_filename, *m_pDiff3LineVector, m_pStatusBar ); | |
220 } | |
221 } | |
222 } | |
223 | |
224 bool isCTokenChar( char c ) | |
225 { | |
226 return (c=='_') || | |
227 ( c>='A' && c<='Z' ) || ( c>='a' && c<='z' ) || | |
228 (c>='0' && c<='9'); | |
229 } | |
230 | |
231 /// Calculate where a token starts and ends, given the x-position on screen. | |
232 void calcTokenPos( const char* p, int size, int posOnScreen, int& pos1, int& pos2 ) | |
233 { | |
234 // Cursor conversions that consider g_tabSize | |
235 int pos = convertToPosInText( p, size, max2( 0, posOnScreen ) ); | |
236 if ( pos>=size ) | |
237 { | |
238 pos1=size; | |
239 pos2=size; | |
240 return; | |
241 } | |
242 | |
243 pos1 = pos; | |
244 pos2 = pos+1; | |
245 | |
246 if( isCTokenChar( p[pos1] ) ) | |
247 { | |
248 while( pos1>=0 && isCTokenChar( p[pos1] ) ) | |
249 --pos1; | |
250 ++pos1; | |
251 | |
252 while( pos2<size && isCTokenChar( p[pos2] ) ) | |
253 ++pos2; | |
254 } | |
255 } | |
256 | |
257 void DiffTextWindow::mouseDoubleClickEvent( QMouseEvent* e ) | |
258 { | |
259 if ( e->button() == LeftButton ) | |
260 { | |
261 int line; | |
262 int pos; | |
263 convertToLinePos( e->x(), e->y(), line, pos ); | |
264 | |
265 // Get the string data of the current line | |
266 QCString s = getString( line ); | |
267 | |
268 if ( ! s.isEmpty() ) | |
269 { | |
270 int pos1, pos2; | |
271 calcTokenPos( s, s.length(), pos, pos1, pos2 ); | |
272 | |
273 resetSelection(); | |
274 selection.start( line, convertToPosOnScreen( s, pos1 ) ); | |
275 selection.end( line, convertToPosOnScreen( s, pos2 ) ); | |
276 update(); | |
277 // emit selectionEnd() happens in the mouseReleaseEvent. | |
278 showStatusLine( line, m_winIdx, m_filename, *m_pDiff3LineVector, m_pStatusBar ); | |
279 } | |
280 } | |
281 } | |
282 | |
283 void DiffTextWindow::mouseReleaseEvent ( QMouseEvent * /*e*/ ) | |
284 { | |
285 //if ( e->button() == LeftButton ) | |
286 { | |
287 killTimers(); | |
288 if (selection.firstLine != -1 ) | |
289 { | |
290 emit selectionEnd(); | |
291 } | |
292 } | |
293 m_scrollDeltaX=0; | |
294 m_scrollDeltaY=0; | |
295 } | |
296 | |
297 void DiffTextWindow::mouseMoveEvent ( QMouseEvent * e ) | |
298 { | |
299 int line; | |
300 int pos; | |
301 convertToLinePos( e->x(), e->y(), line, pos ); | |
302 if (selection.firstLine != -1 ) | |
303 { | |
304 selection.end( line, pos ); | |
305 myUpdate(0); | |
306 | |
307 showStatusLine( line, m_winIdx, m_filename, *m_pDiff3LineVector, m_pStatusBar ); | |
308 | |
309 // Scroll because mouse moved out of the window | |
310 const QFontMetrics& fm = fontMetrics(); | |
311 int fontHeight = fm.height(); | |
312 int fontWidth = fm.width('W'); | |
313 int topLineYOffset = fontHeight + 3; | |
314 int deltaX=0; | |
315 int deltaY=0; | |
316 if ( e->x() < leftInfoWidth*fontWidth ) deltaX=-1; | |
317 if ( e->x() > width() ) deltaX=+1; | |
318 if ( e->y() < topLineYOffset ) deltaY=-1; | |
319 if ( e->y() > height() ) deltaY=+1; | |
320 m_scrollDeltaX = deltaX; | |
321 m_scrollDeltaY = deltaY; | |
322 if ( deltaX != 0 || deltaY!= 0) | |
323 { | |
324 emit scroll( deltaX, deltaY ); | |
325 } | |
326 } | |
327 } | |
328 | |
329 | |
330 void DiffTextWindow::myUpdate(int afterMilliSecs) | |
331 { | |
332 killTimers(); | |
333 m_bMyUpdate = true; | |
334 startTimer( afterMilliSecs ); | |
335 } | |
336 | |
337 void DiffTextWindow::timerEvent(QTimerEvent*) | |
338 { | |
339 killTimers(); | |
340 | |
341 if ( m_bMyUpdate ) | |
342 { | |
343 paintEvent( 0 ); | |
344 m_bMyUpdate = false; | |
345 } | |
346 | |
347 if ( m_scrollDeltaX != 0 || m_scrollDeltaY != 0 ) | |
348 { | |
349 selection.end( selection.lastLine + m_scrollDeltaY, selection.lastPos + m_scrollDeltaX ); | |
350 emit scroll( m_scrollDeltaX, m_scrollDeltaY ); | |
351 killTimers(); | |
352 startTimer(50); | |
353 } | |
354 } | |
355 | |
356 void DiffTextWindow::resetSelection() | |
357 { | |
358 selection.reset(); | |
359 update(); | |
360 } | |
361 | |
362 void DiffTextWindow::convertToLinePos( int x, int y, int& line, int& pos ) | |
363 { | |
364 const QFontMetrics& fm = fontMetrics(); | |
365 int fontHeight = fm.height(); | |
366 int fontWidth = fm.width('W'); | |
367 int xOffset = (leftInfoWidth-m_firstColumn)*fontWidth; | |
368 | |
369 int topLineYOffset = fontHeight + 3; | |
370 | |
371 int yOffset = topLineYOffset - m_firstLine * fontHeight; | |
372 | |
373 line = ( y - yOffset ) / fontHeight; | |
374 pos = ( x - xOffset ) / fontWidth; | |
375 } | |
376 | |
377 int Selection::firstPosInLine(int l) | |
378 { | |
379 assert( firstLine != -1 ); | |
380 | |
381 int l1 = firstLine; | |
382 int l2 = lastLine; | |
383 int p1 = firstPos; | |
384 int p2 = lastPos; | |
385 if ( l1>l2 ){ std::swap(l1,l2); std::swap(p1,p2); } | |
386 if ( l1==l2 && p1>p2 ){ std::swap(p1,p2); } | |
387 | |
388 if ( l==l1 ) | |
389 return p1; | |
390 return 0; | |
391 } | |
392 | |
393 int Selection::lastPosInLine(int l) | |
394 { | |
395 assert( firstLine != -1 ); | |
396 | |
397 int l1 = firstLine; | |
398 int l2 = lastLine; | |
399 int p1 = firstPos; | |
400 int p2 = lastPos; | |
401 | |
402 if ( l1>l2 ){ std::swap(l1,l2); std::swap(p1,p2); } | |
403 if ( l1==l2 && p1>p2 ){ std::swap(p1,p2); } | |
404 | |
405 if ( l==l2 ) | |
406 return p2; | |
407 return INT_MAX; | |
408 } | |
409 | |
410 bool Selection::within( int l, int p ) | |
411 { | |
412 if ( firstLine == -1 ) return false; | |
413 int l1 = firstLine; | |
414 int l2 = lastLine; | |
415 int p1 = firstPos; | |
416 int p2 = lastPos; | |
417 if ( l1>l2 ){ std::swap(l1,l2); std::swap(p1,p2); } | |
418 if ( l1==l2 && p1>p2 ){ std::swap(p1,p2); } | |
419 if( l1 <= l && l <= l2 ) | |
420 { | |
421 if ( l1==l2 ) | |
422 return p>=p1 && p<p2; | |
423 if ( l==l1 ) | |
424 return p>=p1; | |
425 if ( l==l2 ) | |
426 return p<p2; | |
427 return true; | |
428 } | |
429 return false; | |
430 } | |
431 | |
432 bool Selection::lineWithin( int l ) | |
433 { | |
434 if ( firstLine == -1 ) return false; | |
435 int l1 = firstLine; | |
436 int l2 = lastLine; | |
437 | |
438 if ( l1>l2 ){ std::swap(l1,l2); } | |
439 | |
440 return ( l1 <= l && l <= l2 ); | |
441 } | |
442 | |
443 void DiffTextWindow::writeLine( | |
444 QPainter& p, | |
445 const LineData* pld, | |
446 const DiffList* pLineDiff1, | |
447 const DiffList* pLineDiff2, | |
448 int line, | |
449 int whatChanged, | |
450 int whatChanged2, | |
451 int srcLineNr | |
452 ) | |
453 { | |
454 QFont normalFont = font(); | |
455 QFont diffFont = normalFont; | |
456 diffFont.setItalic( m_pOptionDialog->m_bItalicForDeltas ); | |
457 const QFontMetrics& fm = fontMetrics(); | |
458 int fontHeight = fm.height(); | |
459 int fontAscent = fm.ascent(); | |
460 int fontDescent = fm.descent(); | |
461 int fontWidth = fm.width('W'); | |
462 int topLineYOffset = fontHeight + 3; | |
463 | |
464 int xOffset = (leftInfoWidth - m_firstColumn)*fontWidth; | |
465 int yOffset = (line-m_firstLine) * fontHeight + topLineYOffset; | |
466 | |
467 QRect lineRect( 0, yOffset, width(), fontHeight ); | |
468 if ( ! m_invalidRect.intersects( lineRect ) ) | |
469 return; | |
470 | |
471 int fastSelectorLine2 = m_fastSelectorLine1+m_fastSelectorNofLines - 1; | |
472 bool bFastSelectionRange = (line>=m_fastSelectorLine1 && line<= fastSelectorLine2 ); | |
473 QColor bgColor = m_pOptionDialog->m_bgColor; | |
474 QColor diffBgColor = m_pOptionDialog->m_diffBgColor; | |
475 | |
476 if ( bFastSelectionRange ) | |
477 { | |
478 bgColor = m_pOptionDialog->m_currentRangeBgColor; | |
479 diffBgColor = m_pOptionDialog->m_currentRangeDiffBgColor; | |
480 } | |
481 | |
482 // QRect winRect = rect(); //p.window(); | |
483 if ( yOffset+fontHeight<0 || height() + fontHeight < yOffset ) | |
484 return; | |
485 | |
486 int changed = whatChanged; | |
487 if ( pLineDiff1 != 0 ) changed |= 1; | |
488 if ( pLineDiff2 != 0 ) changed |= 2; | |
489 | |
490 QColor c = m_pOptionDialog->m_fgColor; | |
491 if ( changed == 2 ) { | |
492 c = m_cDiff2; | |
493 } else if ( changed == 1 ) { | |
494 c = m_cDiff1; | |
495 } else if ( changed == 3 ) { | |
496 c = m_cDiffBoth; | |
497 } | |
498 | |
499 p.fillRect( leftInfoWidth*fontWidth, yOffset, width(), fontHeight, bgColor ); | |
500 | |
501 if (pld!=0) | |
502 { | |
503 // First calculate the "changed" information for each character. | |
504 int i=0; | |
505 std::vector<UINT8> charChanged( pld->size ); | |
506 if ( pLineDiff1!=0 || pLineDiff2 != 0 ) | |
507 { | |
508 Merger merger( pLineDiff1, pLineDiff2 ); | |
509 while( ! merger.isEndReached() && i<pld->size ) | |
510 { | |
511 if ( i < pld->size ) | |
512 { | |
513 charChanged[i] = merger.whatChanged(); | |
514 ++i; | |
515 } | |
516 merger.next(); | |
517 } | |
518 } | |
519 | |
520 QCString s=" "; | |
521 // Convert tabs | |
522 int outPos = 0; | |
523 for( i=0; i<pld->size; ++i ) | |
524 { | |
525 int spaces = 1; | |
526 | |
527 if ( pld->pLine[i]=='\t' ) | |
528 { | |
529 spaces = tabber( outPos, g_tabSize ); | |
530 s[0] = ' '; | |
531 } | |
532 else | |
533 { | |
534 s[0] = pld->pLine[i]; | |
535 } | |
536 | |
537 QColor c = m_pOptionDialog->m_fgColor; | |
538 int cchanged = charChanged[i] | whatChanged; | |
539 | |
540 if ( cchanged == 2 ) { | |
541 c = m_cDiff2; | |
542 } else if ( cchanged == 1 ) { | |
543 c = m_cDiff1; | |
544 } else if ( cchanged == 3 ) { | |
545 c = m_cDiffBoth; | |
546 } | |
547 | |
548 QRect outRect( xOffset + fontWidth*outPos, yOffset, fontWidth*spaces, fontHeight ); | |
549 if ( m_invalidRect.intersects( outRect ) ) | |
550 { | |
551 if( !selection.within( line, outPos ) ) | |
552 { | |
553 if( c!=m_pOptionDialog->m_fgColor ) | |
554 { | |
555 QColor lightc = diffBgColor; | |
556 p.fillRect( xOffset + fontWidth*outPos, yOffset, | |
557 fontWidth*spaces, fontHeight, lightc ); | |
558 p.setFont(diffFont); | |
559 } | |
560 | |
561 p.setPen( c ); | |
562 if ( s[0]==' ' && c!=m_pOptionDialog->m_fgColor && charChanged[i]!=0 ) | |
563 { | |
564 if ( m_pOptionDialog->m_bShowWhiteSpace ) | |
565 { | |
566 p.fillRect( xOffset + fontWidth*outPos, yOffset+fontAscent, | |
567 fontWidth*spaces-1, fontDescent+1, c ); | |
568 } | |
569 } | |
570 else | |
571 { | |
572 p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, QString::fromUtf8(s) ); | |
573 } | |
574 p.setFont(normalFont); | |
575 } | |
576 else | |
577 { | |
578 | |
579 p.fillRect( xOffset + fontWidth*outPos, yOffset, | |
580 fontWidth*(spaces), fontHeight, colorGroup().highlight() ); | |
581 | |
582 p.setPen( colorGroup().highlightedText() ); | |
583 p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, QString::fromUtf8(s) ); | |
584 | |
585 selection.bSelectionContainsData = true; | |
586 } | |
587 } | |
588 | |
589 outPos += spaces; | |
590 } | |
591 | |
592 if( selection.lineWithin( line ) && selection.lineWithin( line+1 ) ) | |
593 { | |
594 p.fillRect( xOffset + fontWidth*outPos, yOffset, | |
595 width(), fontHeight, colorGroup().highlight() ); | |
596 } | |
597 } | |
598 | |
599 p.fillRect( 0, yOffset, leftInfoWidth*fontWidth, fontHeight, m_pOptionDialog->m_bgColor ); | |
600 | |
601 xOffset = (m_lineNumberWidth+2)*fontWidth; | |
602 int xLeft = m_lineNumberWidth*fontWidth; | |
603 p.setPen( m_pOptionDialog->m_fgColor ); | |
604 if ( pld!=0 ) | |
605 { | |
606 if ( m_pOptionDialog->m_bShowLineNumbers ) | |
607 { | |
608 QString num; | |
609 num.sprintf( "%0*d", m_lineNumberWidth, srcLineNr); | |
610 p.drawText( 0, yOffset + fontAscent, num ); | |
611 //p.drawLine( xLeft -1, yOffset, xLeft -1, yOffset+fontHeight-1 ); | |
612 } | |
613 p.drawLine( xOffset +1, yOffset, xOffset +1, yOffset+fontHeight-1 ); | |
614 } | |
615 if ( c!=m_pOptionDialog->m_fgColor && whatChanged2==0 )//&& whatChanged==0 ) | |
616 { | |
617 p.setBrushOrigin(0,0); | |
618 p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, QBrush(c,Dense5Pattern) ); | |
619 } | |
620 else | |
621 { | |
622 p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, c==m_pOptionDialog->m_fgColor ? bgColor : c ); | |
623 } | |
624 | |
625 if ( bFastSelectionRange ) | |
626 { | |
627 p.fillRect( xOffset + fontWidth-1, yOffset, 3, fontHeight, m_pOptionDialog->m_fgColor ); | |
628 /* p.drawLine( xOffset + fontWidth-1, yOffset, xOffset + fontWidth-1, yOffset+fontHeight-1 ); | |
629 if ( line == m_fastSelectorLine1 ) | |
630 { | |
631 p.drawLine( xOffset + fontWidth-1, yOffset, xOffset + fontWidth+2, yOffset ); | |
632 } | |
633 if ( line == fastSelectorLine2 ) | |
634 { | |
635 p.drawLine( xOffset + fontWidth-1, yOffset+fontHeight-1, xOffset + fontWidth+2, yOffset+fontHeight-1 ); | |
636 }*/ | |
637 } | |
638 } | |
639 | |
640 void DiffTextWindow::paintEvent( QPaintEvent* e ) | |
641 { | |
642 if ( m_pDiff3LineVector==0 || ! m_bPaintingAllowed ) return; | |
643 | |
644 m_lineNumberWidth = m_pOptionDialog->m_bShowLineNumbers ? (int)log10((double)m_size)+1 : 0; | |
645 | |
646 if (e!=0) | |
647 { | |
648 m_invalidRect |= e->rect(); | |
649 } | |
650 | |
651 if ( m_winIdx==1 ) | |
652 { | |
653 m_cThis = m_pOptionDialog->m_colorA; | |
654 m_cDiff1 = m_pOptionDialog->m_colorB; | |
655 m_cDiff2 = m_pOptionDialog->m_colorC; | |
656 } | |
657 if ( m_winIdx==2 ) | |
658 { | |
659 m_cThis = m_pOptionDialog->m_colorB; | |
660 m_cDiff1 = m_pOptionDialog->m_colorC; | |
661 m_cDiff2 = m_pOptionDialog->m_colorA; | |
662 } | |
663 if ( m_winIdx==3 ) | |
664 { | |
665 m_cThis = m_pOptionDialog->m_colorC; | |
666 m_cDiff1 = m_pOptionDialog->m_colorA; | |
667 m_cDiff2 = m_pOptionDialog->m_colorB; | |
668 } | |
669 m_cDiffBoth = m_pOptionDialog->m_colorForConflict; // Conflict color | |
670 | |
671 if (font() != m_pOptionDialog->m_font ) | |
672 { | |
673 setFont(m_pOptionDialog->m_font); | |
674 } | |
675 | |
676 bool bOldSelectionContainsData = selection.bSelectionContainsData; | |
677 selection.bSelectionContainsData = false; | |
678 | |
679 int fontHeight = fontMetrics().height(); | |
680 int fontAscent = fontMetrics().ascent(); | |
681 // int fontDescent = fontMetrics().descent(); | |
682 int fontWidth = fontMetrics().width('W'); | |
683 | |
684 int topLineYOffset = fontHeight + 3; | |
685 int xOffset = leftInfoWidth * fontWidth; | |
686 | |
687 int firstLineToDraw = 0; | |
688 int lastLineToDraw = (height() - topLineYOffset ) / fontHeight; | |
689 if ( abs(m_oldFirstLine - m_firstLine)>=lastLineToDraw ) | |
690 { | |
691 m_oldFirstLine = -1; | |
692 m_invalidRect |= QRect( 0, topLineYOffset, width(), height() ); | |
693 } | |
694 | |
695 if ( m_oldFirstLine != -1 && m_oldFirstLine != m_firstLine ) | |
696 { | |
697 int deltaY = fontHeight * ( m_oldFirstLine - m_firstLine ); | |
698 if ( deltaY > 0 ) | |
699 { // Move down | |
700 bitBlt( this, 0, deltaY + topLineYOffset /*dy*/, this, 0, topLineYOffset /*sy*/, width(), height()- (deltaY + topLineYOffset), CopyROP, true); | |
701 lastLineToDraw = firstLineToDraw + ( m_oldFirstLine - m_firstLine); | |
702 m_invalidRect |= QRect( 0, topLineYOffset, width(), deltaY ); | |
703 } | |
704 else | |
705 { // Move up | |
706 bitBlt( this, 0, topLineYOffset /*dy*/, this, 0, -deltaY+topLineYOffset /*sy*/, width(), height()-(-deltaY+topLineYOffset), CopyROP, true); | |
707 firstLineToDraw = lastLineToDraw + ( m_oldFirstLine - m_firstLine); | |
708 m_invalidRect |= QRect( 0, height()+deltaY, width(), -deltaY ); | |
709 } | |
710 } | |
711 | |
712 if ( m_oldFirstColumn != -1 && m_oldFirstColumn != m_firstColumn ) | |
713 { | |
714 int deltaX = fontWidth * ( m_oldFirstColumn - m_firstColumn ); | |
715 if ( deltaX > 0 ) | |
716 { // Move right, scroll left | |
717 bitBlt( this, deltaX+xOffset, topLineYOffset, this, xOffset, topLineYOffset, width(), height(), CopyROP, true); | |
718 m_invalidRect |= | |
719 QRect( xOffset, topLineYOffset, deltaX, height() - topLineYOffset ); | |
720 } | |
721 else | |
722 { // Move left, scroll right | |
723 bitBlt( this, xOffset, topLineYOffset, this, xOffset-deltaX, topLineYOffset, width()-(xOffset-deltaX), height()-topLineYOffset, CopyROP, true); | |
724 m_invalidRect |= | |
725 QRect( width() + deltaX, topLineYOffset, -deltaX, height() - topLineYOffset ); | |
726 } | |
727 } | |
728 | |
729 if ( selection.oldLastLine != -1 ) | |
730 { | |
731 int lastLine; | |
732 int firstLine; | |
733 if ( selection.oldFirstLine != -1 ) | |
734 { | |
735 firstLine = min3( selection.oldFirstLine, selection.lastLine, selection.oldLastLine ); | |
736 lastLine = max3( selection.oldFirstLine, selection.lastLine, selection.oldLastLine ); | |
737 } | |
738 else | |
739 { | |
740 firstLine = min2( selection.lastLine, selection.oldLastLine ); | |
741 lastLine = max2( selection.lastLine, selection.oldLastLine ); | |
742 } | |
743 int y1 = topLineYOffset + ( firstLine - m_firstLine ) * fontHeight; | |
744 int y2 = min2( height(), | |
745 topLineYOffset + ( lastLine - m_firstLine +1 ) * fontHeight ); | |
746 | |
747 if ( y1<height() && y2>topLineYOffset ) | |
748 { | |
749 m_invalidRect |= QRect( 0, y1, width(), y2-y1 ); | |
750 } | |
751 } | |
752 | |
753 if ( m_invalidRect.isEmpty() ) | |
754 return; | |
755 | |
756 QPainter painter(this); | |
757 //QPainter& p=painter; | |
758 QPixmap pixmap( m_invalidRect.size() ); | |
759 QPainter p( &pixmap ); | |
760 p.translate( -m_invalidRect.x(), -m_invalidRect.y() ); | |
761 | |
762 p.fillRect( m_invalidRect, m_pOptionDialog->m_bgColor ); | |
763 | |
764 firstLineToDraw += m_firstLine; | |
765 lastLineToDraw += m_firstLine; | |
766 | |
767 p.setFont( font() ); | |
768 | |
769 p.setPen( m_cThis ); | |
770 if( m_invalidRect.intersects( QRect(0,0,width(), topLineYOffset ) ) | |
771 || m_firstLine != m_oldFirstLine ) | |
772 { | |
773 int l=-1; | |
774 for ( int i = m_firstLine; i<(int)m_pDiff3LineVector->size(); ++i ) | |
775 { | |
776 const Diff3Line* d3l = (*m_pDiff3LineVector)[i]; | |
777 if ( m_winIdx==1 ) l=d3l->lineA; | |
778 else if ( m_winIdx==2 ) l=d3l->lineB; | |
779 else if ( m_winIdx==3 ) l=d3l->lineC; | |
780 else assert(false); | |
781 if (l!=-1) break; | |
782 } | |
783 | |
784 const char* winId = ( m_winIdx==1 ? (m_bTriple?"A (Base)":"A") : | |
785 ( m_winIdx==2 ? "B" : "C" ) ); | |
786 | |
787 QString s; | |
788 if ( l!=-1 ) | |
789 s.sprintf(" %s : %s : Topline %d", winId, m_filename.ascii(), l+1 ); | |
790 else | |
791 s.sprintf(" %s : %s: End", winId, m_filename.ascii() ); | |
792 | |
793 if (hasFocus()) | |
794 { | |
795 painter.fillRect( 0, 0, width(), topLineYOffset, m_cThis ); | |
796 painter.setPen( m_pOptionDialog->m_bgColor ); | |
797 painter.drawText( 0, fontAscent+1, s ); | |
798 } | |
799 else | |
800 { | |
801 painter.fillRect( 0, 0, width(), topLineYOffset, m_pOptionDialog->m_bgColor ); | |
802 painter.setPen( m_cThis ); | |
803 painter.drawLine( 0, fontHeight + 2, width(), fontHeight + 2 ); | |
804 painter.drawText( 0, fontAscent+1, s ); | |
805 } | |
806 } | |
807 | |
808 int lastVisibleLine = min2( m_firstLine + getNofVisibleLines()+2, (int)m_pDiff3LineVector->size() ); | |
809 | |
810 for ( int line = m_firstLine; line<lastVisibleLine; ++line ) | |
811 { | |
812 const Diff3Line* d3l = (*m_pDiff3LineVector)[line]; | |
813 DiffList* pFineDiff1; | |
814 DiffList* pFineDiff2; | |
815 int changed=0; | |
816 int changed2=0; | |
817 int lineIdx; | |
818 | |
819 getLineInfo( *d3l, lineIdx, pFineDiff1, pFineDiff2, changed, changed2 ); | |
820 | |
821 writeLine( | |
822 p, // QPainter | |
823 lineIdx == -1 ? 0 : &m_pLineData[lineIdx], // Text in this line | |
824 pFineDiff1, | |
825 pFineDiff2, | |
826 line, // Line on the screen | |
827 changed, | |
828 changed2, | |
829 lineIdx+1 | |
830 ); | |
831 } | |
832 | |
833 // p.drawLine( m_invalidRect.x(), m_invalidRect.y(), m_invalidRect.right(), m_invalidRect.bottom() ); | |
834 p.end(); | |
835 | |
836 painter.setClipRect ( 0, topLineYOffset, width(), height()-topLineYOffset ); | |
837 | |
838 painter.drawPixmap( m_invalidRect.x(), m_invalidRect.y(), pixmap ); | |
839 | |
840 m_oldFirstLine = m_firstLine; | |
841 m_oldFirstColumn = m_firstColumn; | |
842 m_invalidRect = QRect(0,0,0,0); | |
843 selection.oldLastLine = -1; | |
844 if ( selection.oldFirstLine !=-1 ) | |
845 selection.oldFirstLine = -1; | |
846 if( !bOldSelectionContainsData && selection.bSelectionContainsData ) | |
847 emit newSelection(); | |
848 | |
849 } | |
850 | |
851 QCString DiffTextWindow::getString( int line ) | |
852 { | |
853 const Diff3Line* d3l = (*m_pDiff3LineVector)[line]; | |
854 DiffList* pFineDiff1; | |
855 DiffList* pFineDiff2; | |
856 int changed=0; | |
857 int changed2=0; | |
858 int lineIdx; | |
859 getLineInfo( *d3l, lineIdx, pFineDiff1, pFineDiff2, changed, changed2 ); | |
860 | |
861 if (lineIdx==-1) return QCString(); | |
862 else | |
863 { | |
864 LineData* ld = &m_pLineData[lineIdx]; | |
865 return QCString( ld->pLine, ld->size + 1 ); | |
866 } | |
867 return QCString(); | |
868 } | |
869 | |
870 | |
871 void DiffTextWindow::getLineInfo( | |
872 const Diff3Line& d, | |
873 int& lineIdx, | |
874 DiffList*& pFineDiff1, DiffList*& pFineDiff2, // return values | |
875 int& changed, int& changed2 | |
876 ) | |
877 { | |
878 changed=0; | |
879 changed2=0; | |
880 bool bAEqB = d.bAEqB || ( d.bWhiteLineA && d.bWhiteLineB ); | |
881 bool bAEqC = d.bAEqC || ( d.bWhiteLineA && d.bWhiteLineC ); | |
882 bool bBEqC = d.bBEqC || ( d.bWhiteLineB && d.bWhiteLineC ); | |
883 if ( m_winIdx == 1 ) { | |
884 lineIdx=d.lineA; | |
885 pFineDiff1=d.pFineAB; | |
886 pFineDiff2=d.pFineCA; | |
887 changed |= ((d.lineB==-1)!=(lineIdx==-1) ? 1 : 0) + | |
888 ((d.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 2 : 0); | |
889 changed2 |= ( bAEqB ? 0 : 1 ) + (bAEqC || !m_bTriple ? 0 : 2); | |
890 } | |
891 else if ( m_winIdx == 2 ) { | |
892 lineIdx=d.lineB; | |
893 pFineDiff1=d.pFineBC; | |
894 pFineDiff2=d.pFineAB; | |
895 changed |= ((d.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 1 : 0) + | |
896 ((d.lineA==-1)!=(lineIdx==-1) ? 2 : 0); | |
897 changed2 |= ( bBEqC || !m_bTriple ? 0 : 1 ) + (bAEqB ? 0 : 2); | |
898 } | |
899 else if ( m_winIdx == 3 ) { | |
900 lineIdx=d.lineC; | |
901 pFineDiff1=d.pFineCA; | |
902 pFineDiff2=d.pFineBC; | |
903 changed |= ((d.lineA==-1)!=(lineIdx==-1) ? 1 : 0) + | |
904 ((d.lineB==-1)!=(lineIdx==-1) ? 2 : 0); | |
905 changed2 |= ( bAEqC ? 0 : 1 ) + (bBEqC ? 0 : 2); | |
906 } | |
907 else assert(false); | |
908 } | |
909 | |
910 | |
911 | |
912 void DiffTextWindow::resizeEvent( QResizeEvent* e ) | |
913 { | |
914 QSize s = e->size(); | |
915 QFontMetrics fm = fontMetrics(); | |
916 int visibleLines = s.height()/fm.height()-2; | |
917 int visibleColumns = s.width()/fm.width('W')-leftInfoWidth; | |
918 emit resizeSignal( visibleColumns, visibleLines ); | |
919 QWidget::resizeEvent(e); | |
920 } | |
921 | |
922 int DiffTextWindow::getNofVisibleLines() | |
923 { | |
924 QFontMetrics fm = fontMetrics(); | |
925 int fmh = fm.height(); | |
926 int h = height(); | |
927 return h/fmh -2;//height()/fm.height()-2; | |
928 } | |
929 | |
930 int DiffTextWindow::getNofVisibleColumns() | |
931 { | |
932 QFontMetrics fm = fontMetrics(); | |
933 return width()/fm.width('W')-leftInfoWidth; | |
934 } | |
935 | |
936 QString DiffTextWindow::getSelection() | |
937 { | |
938 QString selectionString; | |
939 | |
940 int line=0; | |
941 int lineIdx=0; | |
942 | |
943 int it; | |
944 for( it=0; it<(int)m_pDiff3LineVector->size(); ++it ) | |
945 { | |
946 const Diff3Line* d = (*m_pDiff3LineVector)[it]; | |
947 if ( m_winIdx == 1 ) { lineIdx=d->lineA; } | |
948 else if ( m_winIdx == 2 ) { lineIdx=d->lineB; } | |
949 else if ( m_winIdx == 3 ) { lineIdx=d->lineC; } | |
950 else assert(false); | |
951 | |
952 if( lineIdx != -1 ) | |
953 { | |
954 const char* pLine = m_pLineData[lineIdx].pLine; | |
955 int size = m_pLineData[lineIdx].size; | |
956 | |
957 // Consider tabs | |
958 int outPos = 0; | |
959 for( int i=0; i<size; ++i ) | |
960 { | |
961 int spaces = 1; | |
962 if ( pLine[i]=='\t' ) | |
963 { | |
964 | |
965 spaces = tabber( outPos, g_tabSize ); | |
966 } | |
967 | |
968 if( selection.within( line, outPos ) ) | |
969 { | |
970 selectionString += pLine[i]; | |
971 } | |
972 | |
973 outPos += spaces; | |
974 } | |
975 | |
976 if( selection.within( line, outPos ) ) | |
977 { | |
978 #ifdef _WIN32 | |
979 selectionString += '\r'; | |
980 #endif | |
981 selectionString += '\n'; | |
982 } | |
983 } | |
984 | |
985 | |
986 | |
987 ++line; | |
988 } | |
989 | |
990 return selectionString; | |
991 } | |
992 | |
993 bool DiffTextWindow::findString( const QCString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive ) | |
994 { | |
995 int it = d3vLine; | |
996 int endIt = bDirDown ? (int)m_pDiff3LineVector->size() : -1; | |
997 int step = bDirDown ? 1 : -1; | |
998 int startPos = posInLine; | |
999 | |
1000 for( ; it!=endIt; it+=step ) | |
1001 { | |
1002 QCString line = getString( it ); | |
1003 if ( !line.isEmpty() ) | |
1004 { | |
1005 int pos = line.find( s, startPos, bCaseSensitive ); | |
1006 if ( pos != -1 ) | |
1007 { | |
1008 d3vLine = it; | |
1009 posInLine = pos; | |
1010 return true; | |
1011 } | |
1012 | |
1013 startPos = 0; | |
1014 } | |
1015 } | |
1016 return false; | |
1017 } | |
1018 | |
1019 void DiffTextWindow::setSelection( int firstLine, int startPos, int lastLine, int endPos ) | |
1020 { | |
1021 selection.reset(); | |
1022 selection.start( firstLine, convertToPosOnScreen( getString(firstLine), startPos ) ); | |
1023 selection.end( lastLine, convertToPosOnScreen( getString(lastLine), endPos ) ); | |
1024 update(); | |
1025 } |