kde-extraapps/kompare/komparepart/komparesplitter.cpp

493 lines
12 KiB
C++
Raw Normal View History

2014-11-19 18:58:05 +00:00
/**************************************************************************
** komparesplitter.cpp
** -------------------
** begin : Wed Jan 14 2004
** Copyright 2004-2005 Jeff Snyder <jeff-webcvsspam@caffeinated.me.uk>
** Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
***************************************************************************/
/**************************************************************************
**
** 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.
**
***************************************************************************/
// associated header
#include "komparesplitter.h"
// qt
#include <QtGui/QStyle>
#include <QtCore/QString>
#include <QtCore/QTimer>
#include <QtGui/QScrollBar>
#include <QtCore/QMap>
#include <QtGui/QSplitter>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QPixmap>
#include <QtGui/QKeyEvent>
#include <QtGui/QGridLayout>
#include <QtGui/QResizeEvent>
#include <QtCore/QChildEvent>
#include <QtCore/QEvent>
#include <QtGui/QWheelEvent>
// kde
#include <kdebug.h>
#include <kapplication.h>
#include <kglobalsettings.h>
// kompare
#include "komparelistview.h"
#include "viewsettings.h"
#include "kompareconnectwidget.h"
#include "diffmodel.h"
#include "difference.h"
using namespace Diff2;
KompareSplitter::KompareSplitter( ViewSettings *settings, QWidget *parent ) :
QSplitter( Qt::Horizontal, parent ),
m_settings( settings )
{
QFrame *scrollFrame = static_cast<QFrame *>(parent);
// Set up the scrollFrame
scrollFrame->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
scrollFrame->setLineWidth(scrollFrame->style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
QGridLayout *pairlayout = new QGridLayout(scrollFrame);
pairlayout->setSpacing(0);
pairlayout->setContentsMargins( 0, 0, 0, 0 );
m_vScroll = new QScrollBar( Qt::Vertical, scrollFrame );
pairlayout->addWidget( m_vScroll, 0, 1 );
m_hScroll = new QScrollBar( Qt::Horizontal, scrollFrame );
pairlayout->addWidget( m_hScroll, 1, 0 );
new KompareListViewFrame(true, m_settings, this, "source");
new KompareListViewFrame(false, m_settings, this, "destination");
pairlayout->addWidget( this, 0, 0 );
// set up our looks
setLineWidth( style()->pixelMetric( QStyle::PM_DefaultFrameWidth ) );
setHandleWidth(50);
setChildrenCollapsible( false );
setFrameStyle( QFrame::NoFrame );
setSizePolicy( QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored ));
setOpaqueResize( true );
setFocusPolicy( Qt::WheelFocus );
connect( this, SIGNAL(configChanged()), SLOT(slotConfigChanged()) );
connect( this, SIGNAL(configChanged()), SLOT(slotDelayedRepaintHandles()) );
connect( this, SIGNAL(configChanged()), SLOT(slotDelayedUpdateScrollBars()) );
// scrolling
connect( m_vScroll, SIGNAL(valueChanged(int)), SLOT(slotScrollToId(int)) );
connect( m_vScroll, SIGNAL(sliderMoved(int)), SLOT(slotScrollToId(int)) );
connect( m_hScroll, SIGNAL(valueChanged(int)), SIGNAL(setXOffset(int)) );
connect( m_hScroll, SIGNAL(sliderMoved(int)), SIGNAL(setXOffset(int)) );
m_scrollTimer=new QTimer(this);
m_restartTimer = false;
connect (m_scrollTimer, SIGNAL(timeout()), SLOT(timerTimeout()) );
// we need to receive childEvents now so that d->list is ready for when
// slotSetSelection(...) arrives
kapp->sendPostedEvents(this, QEvent::ChildAdded);
// init stuff
slotUpdateScrollBars();
}
KompareSplitter::~KompareSplitter()
{
}
QSplitterHandle* KompareSplitter::createHandle()
{
return new KompareConnectWidgetFrame(m_settings, this);
}
void KompareSplitter::slotDelayedRepaintHandles()
{
QTimer::singleShot(0, this, SLOT(slotRepaintHandles()));
}
void KompareSplitter::slotRepaintHandles()
{
const int end = count();
for ( int i = 1; i < end; ++i )
handle(i)->update();
}
void KompareSplitter::timerTimeout()
{
if ( m_restartTimer )
m_restartTimer = false;
else
m_scrollTimer->stop();
slotDelayedRepaintHandles();
emit scrollViewsToId( m_scrollTo );
slotRepaintHandles();
m_vScroll->setValue( m_scrollTo );
}
void KompareSplitter::slotScrollToId( int id )
{
m_scrollTo = id;
if( m_restartTimer )
return;
if( m_scrollTimer->isActive() )
{
m_restartTimer = true;
}
else
{
emit scrollViewsToId( id );
slotRepaintHandles();
m_vScroll->setValue( id );
m_scrollTimer->start( 30 );
}
}
void KompareSplitter::slotDelayedUpdateScrollBars()
{
QTimer::singleShot( 0, this, SLOT( slotUpdateScrollBars() ) );
}
void KompareSplitter::slotUpdateScrollBars()
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView* lv = listView(i);
int minHScroll = minHScrollId();
if (lv->contentsX() < minHScroll) {
lv->setXOffset(minHScroll);
}
}
int m_scrollDistance = m_settings->m_scrollNoOfLines * lineHeight();
int m_pageSize = pageSize();
if( needVScrollBar() )
{
m_vScroll->show();
m_vScroll->blockSignals( true );
m_vScroll->setRange( minVScrollId(),
maxVScrollId() );
m_vScroll->setValue( scrollId() );
m_vScroll->setSingleStep( m_scrollDistance );
m_vScroll->setPageStep( m_pageSize );
m_vScroll->blockSignals( false );
}
else
{
m_vScroll->hide();
}
if( needHScrollBar() )
{
m_hScroll->show();
m_hScroll->blockSignals( true );
m_hScroll->setRange( minHScrollId(), maxHScrollId() );
m_hScroll->setValue( maxContentsX() );
m_hScroll->setSingleStep( 10 );
m_hScroll->setPageStep( minVisibleWidth() - 10 );
m_hScroll->blockSignals( false );
}
else
{
m_hScroll->hide();
}
}
void KompareSplitter::slotDelayedUpdateVScrollValue()
{
QTimer::singleShot( 0, this, SLOT( slotUpdateVScrollValue() ) );
}
void KompareSplitter::slotUpdateVScrollValue()
{
m_vScroll->setValue( scrollId() );
}
void KompareSplitter::keyPressEvent( QKeyEvent* e )
{
//keyboard scrolling
switch ( e->key() ) {
case Qt::Key_Right:
case Qt::Key_L:
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
break;
case Qt::Key_Left:
case Qt::Key_H:
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
break;
case Qt::Key_Up:
case Qt::Key_K:
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
break;
case Qt::Key_Down:
case Qt::Key_J:
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
break;
case Qt::Key_PageDown:
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepAdd );
break;
case Qt::Key_PageUp:
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepSub );
break;
}
e->accept();
slotRepaintHandles();
}
void KompareSplitter::wheelEvent( QWheelEvent* e )
{
if ( e->orientation() == Qt::Vertical )
{
if ( e->modifiers() & Qt::ControlModifier ) {
if ( e->delta() < 0 ) // scroll down one page
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepAdd );
else // scroll up one page
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepSub );
} else {
if ( e->delta() < 0 ) // scroll down
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
else // scroll up
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
}
}
else
{
if ( e->modifiers() & Qt::ControlModifier ) {
if ( e->delta() < 0 ) // scroll right one page
m_hScroll->triggerAction( QAbstractSlider::SliderPageStepAdd );
else // scroll left one page
m_hScroll->triggerAction( QAbstractSlider::SliderPageStepSub );
} else {
if ( e->delta() < 0 ) // scroll to the right
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
else // scroll to the left
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
}
}
e->accept();
slotDelayedRepaintHandles();
}
/* FIXME: this should return/the scrollId() from the listview containing the
* /base/ of the diff. but there's bigger issues with that atm.
*/
int KompareSplitter::scrollId()
{
if(widget(0))
return listView(0)->scrollId();
return minVScrollId();
}
int KompareSplitter::lineHeight()
{
if(widget(0))
return listView(0)->fontMetrics().height();
return 1;
}
int KompareSplitter::pageSize()
{
if(widget(0)) {
KompareListView *view = listView(0);
return view->visibleHeight() - view->style()->pixelMetric( QStyle::PM_ScrollBarExtent );
}
return 1;
}
bool KompareSplitter::needVScrollBar()
{
int pagesize = pageSize();
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
if( view ->contentsHeight() > pagesize)
return true;
}
return false;
}
int KompareSplitter::minVScrollId()
{
int min = -1;
int mSId;
const int end = count();
for ( int i = 0; i < end; ++i ) {
mSId = listView(i)->minScrollId();
if (mSId < min || min == -1)
min = mSId;
}
return ( min == -1 ) ? 0 : min;
}
int KompareSplitter::maxVScrollId()
{
int max = 0;
int mSId;
const int end = count();
for ( int i = 0; i < end; ++i ) {
mSId = listView(i)->maxScrollId();
if ( mSId > max )
max = mSId;
}
return max;
}
bool KompareSplitter::needHScrollBar()
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
if ( view->contentsWidth() > view->visibleWidth() )
return true;
}
return false;
}
int KompareSplitter::minHScrollId()
{
// hardcode an offset to hide the tree controls
return 6;
}
int KompareSplitter::maxHScrollId()
{
int max = 0;
int mHSId;
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
mHSId = view->contentsWidth() - view->visibleWidth();
if ( mHSId > max )
max = mHSId;
}
return max;
}
int KompareSplitter::maxContentsX()
{
int max = 0;
int mCX;
const int end = count();
for ( int i = 0; i < end; ++i ) {
mCX = listView(i)->contentsX();
if ( mCX > max )
max = mCX;
}
return max;
}
int KompareSplitter::minVisibleWidth()
{
// Why the hell do we want to know this?
// ah yes, it is because we use it to set the "page size" for horiz. scrolling.
// despite the fact that *none* has a pgright and pgleft key :P
// But we do have mousewheels with horizontal scrolling functionality,
// pressing shift and scrolling then goes left and right one page at the time
int min = -1;
int vW;
const int end = count();
for ( int i = 0; i < end; ++i ) {
vW = listView(i)->visibleWidth();
if ( vW < min || min == -1 )
min = vW;
}
return ( min == -1 ) ? 0 : min;
}
KompareListView* KompareSplitter::listView( int index )
{
return static_cast<KompareListViewFrame*>(widget(index))->view();
}
KompareConnectWidget* KompareSplitter::connectWidget( int index )
{
return static_cast<KompareConnectWidgetFrame*>(handle(index))->wid();
}
void KompareSplitter::slotSetSelection( const DiffModel* model, const Difference* diff )
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
connectWidget(i)->slotSetSelection( model, diff );
listView(i)->slotSetSelection( model, diff );
static_cast<KompareListViewFrame*>(widget(i))->slotSetModel( model );
}
slotDelayedRepaintHandles();
slotDelayedUpdateScrollBars();
}
void KompareSplitter::slotSetSelection( const Difference* diff )
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
connectWidget(i)->slotSetSelection( diff );
listView(i)->slotSetSelection( diff );
}
slotDelayedRepaintHandles();
slotDelayedUpdateScrollBars();
}
void KompareSplitter::slotApplyDifference( bool apply )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->slotApplyDifference( apply );
slotDelayedRepaintHandles();
}
void KompareSplitter::slotApplyAllDifferences( bool apply )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->slotApplyAllDifferences( apply );
slotDelayedRepaintHandles();
slotScrollToId( m_scrollTo ); // FIXME!
}
void KompareSplitter::slotApplyDifference( const Difference* diff, bool apply )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->slotApplyDifference( diff, apply );
slotDelayedRepaintHandles();
}
void KompareSplitter::slotDifferenceClicked( const Difference* diff )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->setSelectedDifference( diff, false );
emit selectionChanged( diff );
}
void KompareSplitter::slotConfigChanged()
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
view->setFont( m_settings->m_font );
view->update();
}
}
#include "komparesplitter.moc"