You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
508 lines
13 KiB
508 lines
13 KiB
/*
|
|
* Copyright (C) 1999-2002 Bernd Gehrmann
|
|
* bernd@mail.berlios.de
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
#include "diffview.h"
|
|
|
|
#include <tqpainter.h>
|
|
#include <tqscrollbar.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqregexp.h>
|
|
#include <tqstyle.h>
|
|
|
|
#include <kapplication.h>
|
|
#include <kconfig.h>
|
|
#include <kdebug.h>
|
|
#include <kglobalsettings.h>
|
|
#include <klocale.h>
|
|
|
|
|
|
class DiffViewItem
|
|
{
|
|
public:
|
|
TQString line;
|
|
DiffView::DiffType type;
|
|
bool inverted;
|
|
int no;
|
|
};
|
|
|
|
|
|
int DiffViewItemList::compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2)
|
|
{
|
|
return (static_cast<DiffViewItem*>(item1)->no
|
|
== static_cast<DiffViewItem*>(item2)->no)? 0 : 1;
|
|
}
|
|
|
|
|
|
const int DiffView::BORDER = 7;
|
|
|
|
|
|
DiffView::DiffView( KConfig& cfg, bool withlinenos, bool withmarker,
|
|
TQWidget *parent, const char *name )
|
|
: QtTableView(parent, name, WRepaintNoErase)
|
|
, partConfig(cfg)
|
|
{
|
|
setNumRows(0);
|
|
setNumCols( 1 + (withlinenos?1:0) + (withmarker?1:0) );
|
|
setTableFlags( Tbl_autoVScrollBar|Tbl_autoHScrollBar|
|
|
Tbl_smoothVScrolling );
|
|
setFrameStyle( TQFrame::WinPanel | TQFrame::Sunken );
|
|
setBackgroundMode( PaletteBase );
|
|
setWFlags( WResizeNoErase );
|
|
|
|
partConfig.setGroup("LookAndFeel");
|
|
setFont(partConfig.readFontEntry("DiffFont"));
|
|
TQFontMetrics fm(font());
|
|
setCellHeight(fm.lineSpacing());
|
|
setCellWidth(0);
|
|
textwidth = 0;
|
|
|
|
partConfig.setGroup("General");
|
|
m_tabWidth = partConfig.readNumEntry("TabWidth", 8);
|
|
|
|
items.setAutoDelete(true);
|
|
linenos = withlinenos;
|
|
marker = withmarker;
|
|
|
|
partConfig.setGroup("Colors");
|
|
TQColor defaultColor=TQColor(237, 190, 190);
|
|
diffChangeColor=partConfig.readColorEntry("DiffChange",&defaultColor);
|
|
defaultColor=TQColor(190, 190, 237);
|
|
diffInsertColor=partConfig.readColorEntry("DiffInsert",&defaultColor);
|
|
defaultColor=TQColor(190, 237, 190);
|
|
diffDeleteColor=partConfig.readColorEntry("DiffDelete",&defaultColor);
|
|
}
|
|
|
|
|
|
void DiffView::setFont(const TQFont &font)
|
|
{
|
|
QtTableView::setFont(font);
|
|
TQFontMetrics fm(font);
|
|
setCellHeight(fm.lineSpacing());
|
|
}
|
|
|
|
|
|
void DiffView::setPartner(DiffView *other)
|
|
{
|
|
partner = other;
|
|
if (partner)
|
|
{
|
|
connect( verticalScrollBar(), TQT_SIGNAL(valueChanged(int)),
|
|
TQT_SLOT(vertPositionChanged(int)) );
|
|
connect( verticalScrollBar(), TQT_SIGNAL(sliderMoved(int)),
|
|
TQT_SLOT(vertPositionChanged(int)) );
|
|
connect( horizontalScrollBar(), TQT_SIGNAL(valueChanged(int)),
|
|
TQT_SLOT(horzPositionChanged(int)) );
|
|
connect( horizontalScrollBar(), TQT_SIGNAL(sliderMoved(int)),
|
|
TQT_SLOT(horzPositionChanged(int)) );
|
|
}
|
|
}
|
|
|
|
|
|
void DiffView::vertPositionChanged(int val)
|
|
{
|
|
if (partner)
|
|
partner->setYOffset(QMIN(val,partner->maxYOffset()));
|
|
}
|
|
|
|
|
|
void DiffView::horzPositionChanged(int val)
|
|
{
|
|
if (partner)
|
|
partner->setXOffset(QMIN(val,partner->maxXOffset()));
|
|
}
|
|
|
|
|
|
// *offset methods are only for views withlineno
|
|
void DiffView::removeAtOffset(int offset)
|
|
{
|
|
items.remove(offset);
|
|
setNumRows(numRows()-1);
|
|
}
|
|
|
|
|
|
void DiffView::insertAtOffset(const TQString &line, DiffType type, int offset)
|
|
{
|
|
DiffViewItem *item = new DiffViewItem;
|
|
item->line = line;
|
|
item->type = type;
|
|
item->no = -1;
|
|
item->inverted = false;
|
|
items.insert(offset, item);
|
|
setNumRows(numRows()+1);
|
|
}
|
|
|
|
|
|
void DiffView::setCenterOffset(int offset)
|
|
{
|
|
if (!rowIsVisible(offset))
|
|
{
|
|
int visiblerows = viewHeight()/cellHeight(0);
|
|
setTopCell( QMAX(0, offset - visiblerows/2) );
|
|
}
|
|
}
|
|
|
|
|
|
void DiffView::addLine(const TQString &line, DiffType type, int no)
|
|
{
|
|
TQFont f(font());
|
|
f.setBold(true);
|
|
TQFontMetrics fmbold(f);
|
|
TQFontMetrics fm(font());
|
|
|
|
|
|
// calculate textwidth based on 'line' where tabs are expanded
|
|
//
|
|
// *Please note*
|
|
// For some fonts, e.g. "Clean", is fm.maxWidth() greater than
|
|
// fmbold.maxWidth().
|
|
TQString copy(line);
|
|
const int numTabs = copy.contains('\t', false);
|
|
copy.replace( TQRegExp("\t"), "");
|
|
|
|
const int tabSize = m_tabWidth * QMAX(fm.maxWidth(), fmbold.maxWidth());
|
|
const int copyWidth = QMAX(fm.width(copy), fmbold.width(copy));
|
|
textwidth = QMAX(textwidth, copyWidth + numTabs * tabSize);
|
|
|
|
DiffViewItem *item = new DiffViewItem;
|
|
item->line = line;
|
|
item->type = type;
|
|
item->no = no;
|
|
item->inverted = false;
|
|
items.append(item);
|
|
setNumRows(numRows()+1);
|
|
}
|
|
|
|
|
|
TQString DiffView::stringAtOffset(int offset)
|
|
{
|
|
if (offset >= (int)items.count())
|
|
{
|
|
kdDebug(8050) << "Internal error: lineAtOffset" << endl;
|
|
}
|
|
return items.at(offset)->line;
|
|
}
|
|
|
|
|
|
int DiffView::count()
|
|
{
|
|
return items.count();
|
|
}
|
|
|
|
|
|
int DiffView::findLine(int lineno)
|
|
{
|
|
int offset;
|
|
DiffViewItem tmp;
|
|
tmp.no = lineno;
|
|
if ( (offset = items.find(&tmp)) == -1)
|
|
{
|
|
kdDebug(8050) << "Internal Error: Line " << lineno << " not found" << endl;
|
|
return -1;
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
|
|
void DiffView::setInverted(int lineno, bool inverted)
|
|
{
|
|
int offset;
|
|
if ( (offset = findLine(lineno)) != -1)
|
|
items.at(offset)->inverted = inverted;
|
|
}
|
|
|
|
|
|
void DiffView::setCenterLine(int lineno)
|
|
{
|
|
int offset;
|
|
if ( (offset = findLine(lineno)) != -1)
|
|
setCenterOffset(offset);
|
|
}
|
|
|
|
|
|
TQString DiffView::stringAtLine(int lineno)
|
|
{
|
|
int pos;
|
|
if ( (pos = findLine(lineno)) != -1 )
|
|
return items.at(pos)->line;
|
|
else
|
|
return TQString();
|
|
}
|
|
|
|
|
|
TQByteArray DiffView::compressedContent()
|
|
{
|
|
TQByteArray res(items.count());
|
|
|
|
TQPtrListIterator<DiffViewItem> it(items);
|
|
int i=0;
|
|
for (; it.current(); ++it)
|
|
{
|
|
switch (it.current()->type)
|
|
{
|
|
case Change: res[i] = 'C'; break;
|
|
case Insert: res[i] = 'I'; break;
|
|
case Delete: res[i] = 'D'; break;
|
|
case Neutral: res[i] = 'N'; break;
|
|
case Unchanged:res[i] = 'U'; break;
|
|
default: res[i] = ' ';
|
|
}
|
|
++i;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
int DiffView::cellWidth(int col)
|
|
{
|
|
if (col == 0 && linenos)
|
|
{
|
|
TQFontMetrics fm(font());
|
|
return fm.width("10000");
|
|
}
|
|
else if (marker && (col == 0 || col == 1))
|
|
{
|
|
TQFontMetrics fm( fontMetrics() );
|
|
return QMAX(QMAX( fm.width(i18n("Delete")),
|
|
fm.width(i18n("Insert"))),
|
|
fm.width(i18n("Change")))+2*BORDER;
|
|
}
|
|
else
|
|
{
|
|
int rest = (linenos || marker)? cellWidth(0) : 0;
|
|
if (linenos && marker)
|
|
rest += cellWidth(1);
|
|
return QMAX(textwidth, viewWidth()-rest);
|
|
}
|
|
}
|
|
|
|
|
|
TQSize DiffView::sizeHint() const
|
|
{
|
|
TQFontMetrics fm(font());
|
|
return TQSize( 4*fm.width("0123456789"), fm.lineSpacing()*8 );
|
|
}
|
|
|
|
|
|
void DiffView::paintCell(TQPainter *p, int row, int col)
|
|
{
|
|
TQFontMetrics fm(font());
|
|
p->setTabStops(m_tabWidth * fm.maxWidth());
|
|
|
|
DiffViewItem *item = items.at(row);
|
|
|
|
int width = cellWidth(col);
|
|
int height = cellHeight();
|
|
|
|
TQColor backgroundColor;
|
|
bool inverted;
|
|
int align;
|
|
int innerborder;
|
|
TQString str;
|
|
|
|
TQFont oldFont(p->font());
|
|
if (item->type==Separator)
|
|
{
|
|
backgroundColor = KGlobalSettings::highlightColor();
|
|
p->setPen(KGlobalSettings::highlightedTextColor());
|
|
inverted = false;
|
|
align = AlignLeft;
|
|
innerborder = 0;
|
|
if (col == (linenos?1:0) + (marker?1:0))
|
|
str = item->line;
|
|
TQFont f(oldFont);
|
|
f.setBold(true);
|
|
p->setFont(f);
|
|
}
|
|
else if (col == 0 && linenos)
|
|
{
|
|
backgroundColor = KGlobalSettings::highlightColor();
|
|
p->setPen(KGlobalSettings::highlightedTextColor());
|
|
inverted = false;
|
|
align = AlignLeft;
|
|
innerborder = 0;
|
|
if (item->no == -1)
|
|
str = "+++++";
|
|
else
|
|
str.setNum(item->no);
|
|
}
|
|
else if (marker && (col == 0 || col == 1))
|
|
{
|
|
backgroundColor = KGlobalSettings::alternateBackgroundColor();
|
|
p->setPen(KGlobalSettings::textColor());
|
|
inverted = false;
|
|
align = AlignRight;
|
|
innerborder = BORDER;
|
|
str = (item->type==Change)? i18n("Change")
|
|
: (item->type==Insert)? i18n("Insert")
|
|
: (item->type==Delete)? i18n("Delete") : TQString::null;
|
|
}
|
|
else
|
|
{
|
|
backgroundColor =
|
|
(item->type==Change)? diffChangeColor
|
|
: (item->type==Insert)? diffInsertColor
|
|
: (item->type==Delete)? diffDeleteColor
|
|
: (item->type==Neutral)? KGlobalSettings::alternateBackgroundColor() : KGlobalSettings::baseColor();
|
|
p->setPen(KGlobalSettings::textColor());
|
|
inverted = item->inverted;
|
|
align = AlignLeft;
|
|
innerborder = 0;
|
|
str = item->line;
|
|
}
|
|
|
|
if (inverted)
|
|
{
|
|
p->setPen(backgroundColor);
|
|
backgroundColor = KGlobalSettings::textColor();
|
|
TQFont f(oldFont);
|
|
f.setBold(true);
|
|
p->setFont(f);
|
|
}
|
|
|
|
p->fillRect(0, 0, width, height, backgroundColor);
|
|
p->drawText(innerborder, 0, width-2*innerborder, height, align|ExpandTabs, str);
|
|
p->setFont(oldFont);
|
|
}
|
|
|
|
|
|
void DiffView::wheelEvent(TQWheelEvent *e)
|
|
{
|
|
TQApplication::sendEvent(verticalScrollBar(), e);
|
|
}
|
|
|
|
|
|
DiffZoomWidget::DiffZoomWidget(KConfig& cfg, TQWidget *parent, const char *name)
|
|
: TQFrame(parent, name)
|
|
{
|
|
setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Minimum ) );
|
|
|
|
cfg.setGroup("Colors");
|
|
TQColor defaultColor=TQColor(237, 190, 190);
|
|
diffChangeColor=cfg.readColorEntry("DiffChange",&defaultColor);
|
|
defaultColor=TQColor(190, 190, 237);
|
|
diffInsertColor=cfg.readColorEntry("DiffInsert",&defaultColor);
|
|
defaultColor=TQColor(190, 237, 190);
|
|
diffDeleteColor=cfg.readColorEntry("DiffDelete",&defaultColor);
|
|
}
|
|
|
|
|
|
DiffZoomWidget::~DiffZoomWidget()
|
|
{}
|
|
|
|
|
|
void DiffZoomWidget::setDiffView(DiffView *view)
|
|
{
|
|
diffview = view;
|
|
TQScrollBar *sb = const_cast<TQScrollBar*>(diffview->scrollBar());
|
|
sb->installEventFilter(this);
|
|
}
|
|
|
|
|
|
TQSize DiffZoomWidget::sizeHint() const
|
|
{
|
|
return TQSize(25, style().pixelMetric(TQStyle::PM_ScrollBarExtent, this));
|
|
}
|
|
|
|
|
|
bool DiffZoomWidget::eventFilter(TQObject *o, TQEvent *e)
|
|
{
|
|
if (e->type() == TQEvent::Show
|
|
|| e->type() == TQEvent::Hide
|
|
|| e->type() == TQEvent::Resize)
|
|
repaint();
|
|
|
|
return TQFrame::eventFilter(o, e);
|
|
}
|
|
|
|
|
|
void DiffZoomWidget::paintEvent(TQPaintEvent *)
|
|
{
|
|
const TQScrollBar* scrollBar = diffview->scrollBar();
|
|
if (!scrollBar)
|
|
return;
|
|
|
|
// only y and height are important
|
|
const TQRect scrollBarGroove(scrollBar->isVisible()
|
|
? style().querySubControlMetrics(TQStyle::CC_ScrollBar,
|
|
scrollBar,
|
|
TQStyle::SC_ScrollBarGroove)
|
|
: rect());
|
|
|
|
// draw rectangles at the positions of the differences
|
|
|
|
const TQByteArray& lineTypes(diffview->compressedContent());
|
|
|
|
TQPixmap pixbuf(width(), scrollBarGroove.height());
|
|
pixbuf.fill(KGlobalSettings::baseColor());
|
|
|
|
TQPainter p(&pixbuf, this);
|
|
if (const unsigned int numberOfLines = lineTypes.size())
|
|
{
|
|
const double scale(((double) scrollBarGroove.height()) / numberOfLines);
|
|
for (unsigned int index(0); index < numberOfLines;)
|
|
{
|
|
const char lineType(lineTypes[index]);
|
|
|
|
// don't use qRound() to avoid painting outside of the pixmap
|
|
// (yPos1 must be lesser than scrollBarGroove.height())
|
|
const int yPos1(static_cast<int>(index * scale));
|
|
|
|
// search next line with different lineType
|
|
for (++index; index < numberOfLines && lineType == lineTypes[index]; ++index)
|
|
;
|
|
|
|
TQColor color;
|
|
switch (lineType)
|
|
{
|
|
case 'C':
|
|
color = diffChangeColor;
|
|
break;
|
|
case 'I':
|
|
color = diffInsertColor;
|
|
break;
|
|
case 'D':
|
|
color = diffDeleteColor;
|
|
break;
|
|
case ' ':
|
|
case 'N':
|
|
color = KGlobalSettings::alternateBackgroundColor();
|
|
break;
|
|
}
|
|
|
|
if (color.isValid())
|
|
{
|
|
const int yPos2(qRound(index * scale));
|
|
const int areaHeight((yPos2 != yPos1) ? yPos2 - yPos1 : 1);
|
|
|
|
p.fillRect(0, yPos1, pixbuf.width(), areaHeight, TQBrush(color));
|
|
}
|
|
}
|
|
}
|
|
p.flush();
|
|
bitBlt(this, 0, scrollBarGroove.y(), &pixbuf);
|
|
}
|
|
|
|
#include "diffview.moc"
|
|
|
|
|
|
// Local Variables:
|
|
// c-basic-offset: 4
|
|
// End:
|