/* ====================================================================
* Copyright (c) 2003-2006, Martin Hauner
* http://subcommander.tigris.org
*
* Subcommander is licensed as described in the file doc/COPYING, which
* you should have received as part of this distribution.
* ====================================================================
*/
// sc
#include "config.h"
#include "Diff3Widget.h"
#include "DiffInfoModel.h"
#include "SingleTextWidget.h"
#include "DoubleTextWidget.h"
#include "TextWidget.h"
#include "settings/FontSettings.h"
#include "sublib/Line.h"
#include "sublib/TextModel.h"
#include "sublib/SplitLayout.h"
#include "util/String.h"
// qt
#include <qapplication.h>
#include <qscrollbar.h>
#include <qpushbutton.h>
#include <qsplitter.h>
#include <qvbox.h>
#include <qlabel.h>
// sys
#include <assert.h>
#include <vector>
#include <iostream>
#include <stdio.h>
#include <algorithm>
Diff3Widget::Diff3Widget( FontSettings* fs, QWidget *parent, const char *name )
: super( parent, name ), _diffInfo(0)
{
setCaption( _q("Subcommander <diff3 - submerge>") );
setIconText( _q("Subcommander <icontext>") );
QFont font = fs->getEditorFont();
QApplication::setFont( font, false, "TextWidget" );
QApplication::setFont( font, false, "TextLineNrWidget" );
QApplication::setFont( font, false, "TextGlueWidget" );
setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding) );
//setFont( QFont("Courier New",10,QFont::Normal,false/*QFont::Unicode*/) );
QGridLayout* bl = new QGridLayout(this);
{
QWidget* vs = new QWidget(this);
VSplitLayout* vsl = new VSplitLayout(vs);
_splitMerge = vsl;
bl->addWidget(vs,0,0);
{
QWidget* hs = new QWidget(vs);
HSplitLayout* hsl = new HSplitLayout(hs);
_splitOrg = hsl;
vsl->addWidgetOne( hs, false );
{
_single = new SingleTextWidget(hs);
_single->setHScrollBarOff( SingleTextWidget::sboDisable );
_single->setAcceptDrops(true);
hsl->addWidgetOne( _single, true, 1 );
_double = new DoubleTextWidget(hs);
_double->setHScrollBarOff( SingleTextWidget::sboDisable );
_double->setAcceptDrops(true);
hsl->addWidgetTwo( _double, false, 2 );
}
_merged = new SingleTextWidget(vs);
_merged->enableSelection( true );
_merged->setEditable( true );
vsl->addWidgetTwo( _merged, true );
}
#if 0
// experimental vertical line display
QFontMetrics m( font() );
QVBox* f1 = new QVBox(this);
f1->setFrameStyle( QFrame::Panel | QFrame::Sunken );
f1->setMargin(1);
f1->setSpacing(1);
f1->setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed) );
bl->addWidget(f1,1,0);
{
TextWidget* tw1 = new TextWidget(f1);
tw1->setFixedHeight( m.height() );
TextWidget* tw2 = new TextWidget(f1);
tw2->setFixedHeight( m.height() );
}
#endif
}
// sync v scrollbars
connect(_single->getVScrollBar(), SIGNAL(valueChanged(int)), SLOT(vsbChange(int)) );
connect(_double->getVScrollBar(), SIGNAL(valueChanged(int)), SLOT(vsbChange(int)) );
// h scrollbars
connect( _single, SIGNAL(updatedScrollBars()), SLOT(hsbChange()) );
connect( _double, SIGNAL(updatedScrollBars()), SLOT(hsbChange()) );
// block selection
connect( _single->getText(), SIGNAL(blockChanged(int)), this, SLOT(blockChangeO(int)) );
connect( _double->getLeftText(), SIGNAL(blockChanged(int)), this, SLOT(blockChangeL(int)) );
connect( _double->getRightText(), SIGNAL(blockChanged(int)), this, SLOT(blockChangeR(int)) );
connect( _merged->getText(), SIGNAL(blockChanged(int)), this, SLOT(blockChangeM(int)) );
}
Diff3Widget::~Diff3Widget()
{
}
void Diff3Widget::setModel( TextModel* original, TextModel* modified, TextModel* latest )
{
_single->setModel( original );
_double->setModel( modified, latest );
}
void Diff3Widget::setModel( DiffInfoModel* info )
{
_double->setModel(info);
_diffInfo = info;
}
void Diff3Widget::setMergeModel( TextModel* merged )
{
_merged->setModel(merged);
}
void Diff3Widget::setLeftLabel( const sc::String& l )
{
_single->setLabel(l);
}
void Diff3Widget::setCenterLabel( const sc::String& l )
{
_double->setLeftLabel(l);
}
void Diff3Widget::setRightLabel( const sc::String& l )
{
_double->setRightLabel(l);
}
// todo move to "model"
// selected original block
void Diff3Widget::blockChangeO(int b)
{
setActiveDiffBlock(b);
TextModel* om = _single->getText()->getModel();
TextModel* mm = _double->getLeftText()->getModel();
TextModel* lm = _double->getRightText()->getModel();
TextModel* me = _merged->getText()->getModel();
//TextModel* om = _diffInfo->getModel( DiffInfoModel::dmOriginal );
//TextModel* mm = _diffInfo->getModel( DiffInfoModel::dmModified );
//TextModel* lm = _diffInfo->getModel( DiffInfoModel::dmLatest );
//TextModel* me = _diffInfo->getModel( DiffInfoModel::dmMerged );
_double->getLeftText()->clearBlockSelection();
_double->getRightText()->clearBlockSelection();
int line = me->replaceBlock(b,om);
_merged->setModel(me);
// TODO that is getting strange here...
// i think jumpToLine needs a better implementation, without
// the processEvents() it often jumps to the wrong position
// when a block get clicked. If it clicked a second time it
// jumps again. See also nextDiff() in MainWindow, which has
// the same problem.
//_merged->updateGeometry();
//qApp->processEvents();
DiffInfo& di = _diffInfo->getInfo(b);
di.setMergeType( msOriginal );
_merged->getText()->setBlockSelection(b);
_merged->update();
_merged->jumpToLine(line-2);
}
// selected left block
void Diff3Widget::blockChangeL(int b)
{
setActiveDiffBlock(b);
TextModel* om = _single->getText()->getModel();
TextModel* mm = _double->getLeftText()->getModel();
TextModel* lm = _double->getRightText()->getModel();
TextModel* me = _merged->getText()->getModel();
//TextModel* om = _diffInfo->getModel( DiffInfoModel::dmOriginal );
//TextModel* mm = _diffInfo->getModel( DiffInfoModel::dmModified );
//TextModel* lm = _diffInfo->getModel( DiffInfoModel::dmLatest );
//TextModel* me = _diffInfo->getModel( DiffInfoModel::dmMerged );
_single->getText()->clearBlockSelection();
_double->getRightText()->clearBlockSelection();
int line = me->replaceBlock(b,mm);
_merged->setModel(me);
//_merged->updateGeometry();
//qApp->processEvents();
DiffInfo& di = _diffInfo->getInfo(b);
di.setMergeType( msModified );
_merged->getText()->setBlockSelection(b);
_merged->update();
_merged->jumpToLine(line-2);
}
// select right block
void Diff3Widget::blockChangeR(int b)
{
setActiveDiffBlock(b);
TextModel* om = _single->getText()->getModel();
TextModel* mm = _double->getLeftText()->getModel();
TextModel* lm = _double->getRightText()->getModel();
TextModel* me = _merged->getText()->getModel();
//TextModel* om = _diffInfo->getModel( DiffInfoModel::dmOriginal );
//TextModel* mm = _diffInfo->getModel( DiffInfoModel::dmModified );
//TextModel* lm = _diffInfo->getModel( DiffInfoModel::dmLatest );
//TextModel* me = _diffInfo->getModel( DiffInfoModel::dmMerged );
_single->getText()->clearBlockSelection();
_double->getLeftText()->clearBlockSelection();
int line = me->replaceBlock(b,lm);
_merged->setModel(me);
//_merged->updateGeometry();
//qApp->processEvents();
DiffInfo& di = _diffInfo->getInfo(b);
di.setMergeType( msLatest );
_merged->getText()->setBlockSelection(b);
_merged->update();
_merged->jumpToLine(line-2);
}
// selected merge block
void Diff3Widget::blockChangeM(int b)
{
setActiveDiffBlock(b);
TextModel* om = _single->getText()->getModel();
TextModel* mm = _double->getLeftText()->getModel();
TextModel* lm = _double->getRightText()->getModel();
TextModel* me = _merged->getText()->getModel();
//TextModel* om = _diffInfo->getModel( DiffInfoModel::dmOriginal );
//TextModel* mm = _diffInfo->getModel( DiffInfoModel::dmModified );
//TextModel* lm = _diffInfo->getModel( DiffInfoModel::dmLatest );
//TextModel* me = _diffInfo->getModel( DiffInfoModel::dmMerged );
const DiffInfo& di = _diffInfo->getInfo(b);
switch( di.getMergeType() )
{
case msOriginal:
{
_single->getText()->setBlockSelection(b);
_double->getLeftText()->clearBlockSelection();
_double->getRightText()->clearBlockSelection();
break;
}
case msModified:
{
_single->getText()->clearBlockSelection();
_double->getLeftText()->setBlockSelection(b);
_double->getRightText()->clearBlockSelection();
break;
}
case msLatest:
{
_single->getText()->clearBlockSelection();
_double->getLeftText()->clearBlockSelection();
_double->getRightText()->setBlockSelection(b);
break;
}
case msNotMerged:
{
_single->getText()->setBlockSelection(b);
_double->getLeftText()->setBlockSelection(b);
_double->getRightText()->setBlockSelection(b);
break;
}
}
// TODO we need a way to get the line correction value
// from one place so we don't repeat it all the time....
jumpToLine( di.getBlockInfo().getStart()-2 );
}
void Diff3Widget::vsbChange(int y)
{
_single->getVScrollBar()->setValue(y);
_double->getVScrollBar()->setValue(y);
}
void Diff3Widget::hsbChange()
{
QScrollBar* sh = _single->getHScrollBar();
QScrollBar* dh = _double->getHScrollBar();
bool sd = ! _single->isVisible();
bool dd = ! _double->isVisible();
if( _single->getHScrollBarOff() == TextViewWidget::sboDisable )
{
sd |= ! sh->isEnabled();
dd |= ! dh->isEnabled();
}
else
{
sd |= ! sh->isVisible();
dd |= ! dh->isVisible();
}
if( sd && dd )
{
sh->hide();
dh->hide();
}
else
{
sh->show();
dh->show();
}
}
void Diff3Widget::jumpToLine( int line )
{
if( line < 0 )
{
line = 0;
}
_single->jumpToLine(line);
_double->jumpToLine(line);
//_merged->jumpToLine(line);
}
void Diff3Widget::jumpToBlock( int block )
{
_single->jumpToBlock(block);
_double->jumpToBlock(block);
_merged->jumpToBlock(block);
// set selection
_merged->getText()->setBlockSelection(block);
}
void Diff3Widget::setActiveDiffBlock( int block )
{
DiffInfo& bi = _diffInfo->getInfo(block);
_double->setActiveDiff( bi.getDiffNumber() );
_diffInfo->setActiveDiff( bi.getDiffNumber() );
emit diffChanged( bi.getDiffNumber() );
}
void Diff3Widget::setActiveDiff( int num )
{
_double->setActiveDiff(num);
}
void Diff3Widget::enableOriginal( bool enable, bool open )
{
_splitOrg->enableHandle(enable);
_splitOrg->jumpPos(open);
}
void Diff3Widget::enableMerged( bool enable, bool open )
{
_splitMerge->enableHandle(enable);
_splitMerge->jumpPos(open);
}
void Diff3Widget::wheelEvent( QWheelEvent* e )
{
if( ! _diffInfo )
{
e->ignore();
return;
}
//printf( "wheel delta: %d (%p)\n", e->delta(), e );
int b = 0;
if( e->delta() > 0 )
{
// forward -> to screen
if( _diffInfo->hasPrevDiff() )
{
b = _diffInfo->prevDiff();
}
}
else
{
// backward -> to user
if( _diffInfo->hasNextDiff() )
{
b = _diffInfo->nextDiff();
}
}
if( b == 0 )
{
e->ignore();
return;
}
jumpToBlock( b );
setActiveDiff( _diffInfo->getActiveDiff() );
emit diffChanged( _diffInfo->getActiveDiff() );
e->accept();
}
void Diff3Widget::connectOriginalDrop( const QObject* receiver, const char* member )
{
connect( _single->getText(), SIGNAL(fileDropped(const QString&)), receiver, member );
}
void Diff3Widget::connectModifiedDrop( const QObject* receiver, const char* member )
{
connect( _double->getLeftText(), SIGNAL(fileDropped(const QString&)), receiver, member );
}
void Diff3Widget::connectLatestDrop( const QObject* receiver, const char* member )
{
connect( _double->getRightText(), SIGNAL(fileDropped(const QString&)), receiver, member );
}
syntax highlighted by Code2HTML, v. 0.9.1