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 }