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.
tdeutils/kregexpeditor/concwidget.cpp

401 lines
12 KiB

/*
* Copyright (c) 2002-2003 Jesper K. Pedersen <blackie@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#include "concregexp.h"
#include "concwidget.h"
#include "dragaccepter.h"
#include <tqpainter.h>
ConcWidget::ConcWidget(RegExpEditorWindow* editorWindow, TQWidget *parent,
const char *name)
:MultiContainerWidget(editorWindow, parent, name == 0 ? "concwidget" : name)
{
init();
DragAccepter *accepter = new DragAccepter(editorWindow, this);
accepter->show();
_children.append(accepter);
}
ConcWidget::ConcWidget(RegExpEditorWindow* editorWindow, RegExpWidget *child,
TQWidget *parent, const char *name)
:MultiContainerWidget(editorWindow, parent, name == 0 ? "concwidget" : name)
{
init();
DragAccepter *accepter = new DragAccepter(editorWindow, this);
_children.append(accepter);
child->reparent(this, TQPoint(0,0), false);
addNewChild(accepter, child);
}
ConcWidget::ConcWidget( RegExpEditorWindow* editorWindow, ConcWidget* origConc,
unsigned int start, unsigned int end)
:MultiContainerWidget(editorWindow, 0, "Splitted ConcWidget")
{
init();
_children.prepend( new DragAccepter(editorWindow, this) );
for (unsigned int i = end; i >= start; i--) {
RegExpWidget* child = origConc->_children.take( i );
_children.prepend( child );
child->reparent( this, TQPoint(0,0), false);
}
_children.prepend( new DragAccepter(editorWindow, this) );
}
ConcWidget::ConcWidget( ConcRegExp* regexp, RegExpEditorWindow* editorWindow,
TQWidget* parent, const char* name )
:MultiContainerWidget( editorWindow, parent, name == 0 ? "concwidget" : name )
{
init();
DragAccepter *accepter = new DragAccepter(editorWindow, this);
_children.append(accepter);
RegExpList list = regexp->children();
for ( RegExpListIt it(list); *it; ++it ) {
RegExpWidget* child = WidgetFactory::createWidget( *it, editorWindow, this );
append( child );
}
}
void ConcWidget::init()
{
_maxSelectedHeight = 0;
}
TQSize ConcWidget::sizeHint() const
{
int childrenWidth = 0;
int childrenHeight = 0;
TQPtrListIterator<RegExpWidget> it(_children);
for ( ; *it; ++it) {
TQSize thisChildSize = (*it)->sizeHint();
childrenWidth += thisChildSize.width();
childrenHeight = TQMAX(childrenHeight, thisChildSize.height());
}
return TQSize(childrenWidth, childrenHeight);
}
void ConcWidget::paintEvent( TQPaintEvent *e)
{
Q_ASSERT( dynamic_cast<DragAccepter*>(_children.at(0)) );
// if this fails, then I should check the location of the show()
Q_ASSERT( _children.count() == 1 ||
( _children.count() >=3 &&
dynamic_cast<DragAccepter*>(_children.at(_children.count()-1)) ) );
if ( _children.count() == 1) {
// There is only an accepter, lets give it all the space.
_children.at(0)->setGeometry( 0, 0, size().width(), size().height() );
}
else {
TQSize myReqSize = sizeHint();
TQSize mySize(TQMAX(myReqSize.width(), size().width()),
TQMAX(myReqSize.height(), size().height()));
// If the widget needs less space than it can get then this space should
// be given to the leftmost and rightmost accepter. So lets calculate
// this extra space.
int extra = 0;
if (size().width() > myReqSize.width()) {
extra = (size().width() - myReqSize.width())/2;
}
TQPainter painter( this );
drawPossibleSelection( painter, mySize );
int lastHeight = 0;
int offset = 0;
for (unsigned int i = 1; i < _children.count(); i += 2 ) {
DragAccepter* accepter = dynamic_cast<DragAccepter*>(_children.at(i-1));
if (!accepter)
continue;
RegExpWidget* child = _children.at(i);
TQSize childSize = child->sizeHint();
TQSize curChildSize = child->size();
//----------------------------- first place the accepter
int x = offset;
int w = accepter->sizeHint().width();
if ( i == 1 ) w+= extra;
int h = TQMAX( lastHeight, childSize.height() );
int y = (mySize.height() - h)/2;
accepter->setGeometry( x, y, w, h );
offset += w;
lastHeight = childSize.height();
//------------------------------ Draw Accepter selection
if ( accepter->isSelected() ) {
y = (mySize.height()-_maxSelectedHeight)/2;
h = _maxSelectedHeight;
painter.fillRect( x, y, w, h, TQBrush( gray ) );
}
//-------------------------------------- place the child
x = offset;
h = childSize.height();
w = childSize.width();
y = (mySize.height() - h)/2;
child->setGeometry( x, y, w, h );
if ( childSize != curChildSize ) {
// I resized the child, so give it a chance to relect thus.
child->update();
}
offset += w;
//------------------------------ Draw Accepter selection
if ( child->isSelected() ) {
y = (mySize.height()-_maxSelectedHeight)/2;
h = _maxSelectedHeight;
painter.fillRect( x, y, w, h, TQBrush( gray ) );
}
}
//---------------------- Finally place the last accepter.
DragAccepter* accepter =
dynamic_cast<DragAccepter*>(_children.at(_children.count()-1));
// dynamic_cast is ASSERTed at top
int x = offset;
int h = lastHeight;
int w = accepter->sizeHint().width() + extra;
int y = (mySize.height()-h)/2;
accepter->setGeometry( x, y, w, h );
}
MultiContainerWidget::paintEvent( e );
}
void ConcWidget::mousePressEvent ( TQMouseEvent* event )
{
if ( event->button() == TQt::RightButton ) {
_editorWindow->showRMBMenu( _editorWindow->hasSelection() );
}
else {
RegExpWidget::mousePressEvent( event );
}
}
void ConcWidget::sizeAccepter( DragAccepter* accepter, int height, int totHeight )
{
if (accepter->height() != height ) {
accepter->resize( accepter->width(), height );
}
if (accepter->y() != (totHeight - height)/2) {
accepter->move( accepter->x(), (totHeight - height)/2 );
}
}
RegExp* ConcWidget::regExp() const
{
TQPtrListIterator<RegExpWidget> it( _children );
++it; // start with the second element.
if ( _children.count() == 3 ) {
// Exactly one child (and two drag accepters)
return (*it)->regExp();
}
else {
ConcRegExp *regexp = new ConcRegExp( isSelected() );
for ( ; *it; it+=2 ) {
regexp->addRegExp( (*it)->regExp() );
}
return regexp;
}
}
bool ConcWidget::updateSelection(bool parentSelected)
{
bool isSel = _isSelected;
bool changed = MultiContainerWidget::updateSelection( parentSelected );
_maxSelectedHeight = 0;
TQPtrListIterator<RegExpWidget> it(_children);
++it; // Skip past the first DragAccepter
for ( ; *it; it +=2 ) {
if ( (*it)->isSelected() ) {
_maxSelectedHeight = TQMAX( _maxSelectedHeight, (*it)->sizeHint().height() );
}
}
changed = changed || isSel != _isSelected;
if ( changed ) {
repaint();
}
return changed;
}
void ConcWidget::getSelectionIndexes( int* start, int* end )
{
*start = -1;
*end = -1;
// Start with element at index 1, and skip every second element, as we
// know they are dragAccepters.
for ( unsigned int index = 1; index< _children.count(); index += 2 ) {
RegExpWidget* child = _children.at(index);
if ( child->isSelected() ) {
// The child is selected at topmost level.
if ( *start == -1 ) {
*start = index;
}
}
else if ( *start != -1 ) {
// Found the end of the selection.
*end = index -2;
break;
}
}
if ( *start != -1 && *end == -1 )
*end = _children.count() -2;
}
void ConcWidget::applyRegExpToSelection( RegExpType type )
{
int start, end;
getSelectionIndexes( &start, &end );
if ( start == -1 ) {
// No item selected at top level
TQPtrListIterator<RegExpWidget> it(_children);
++it; // Skip past the first DragAccepter
for ( ; *it ; it += 2 ) {
if ( (*it)->hasSelection() ) {
(*it)->applyRegExpToSelection( type );
break;
}
}
}
else {
// Apply RegExp to selection.
RegExpWidget* newElm = WidgetFactory::createWidget( _editorWindow, this, type );
if ( newElm ) {
ConcWidget* subSequence = new ConcWidget(_editorWindow, this, start, end);
newElm->setConcChild( subSequence );
subSequence->resize(0,0); // see note (1)
subSequence->reparent( newElm, TQPoint(0,0), false);
_children.insert( start, newElm );
newElm->show();
}
}
}
bool ConcWidget::isSelected() const
{
// A ConcWidget should be considered selected when all its elements has been selected
// otherwise empty ConcWidgets may be left behind when for example selection is deleted.
bool allSelected = true;
TQPtrListIterator<RegExpWidget> it(_children);
++it; // Skip past first DragAccepter.
for ( ; *it && allSelected; it += 2 ) {
allSelected = allSelected && (*it)->isSelected();
}
return allSelected;
}
RegExp* ConcWidget::selection() const
{
if ( isSelected() )
return regExp();
bool foundAny = false;
bool foundMoreThanOne = false;
RegExp* regexp = 0;
TQPtrListIterator<RegExpWidget> it(_children);
++it; // Skip past the first DragAccepter
for ( ; (*it) ; it += 2 ) {
if ( (*it)->hasSelection() ) {
if (!foundAny) {
regexp = (*it)->selection();
foundAny = true;
}
else if ( !foundMoreThanOne ) {
ConcRegExp* reg = new ConcRegExp( isSelected() );
reg->addRegExp( regexp );
reg->addRegExp( (*it)->selection() );
regexp = reg;
foundMoreThanOne = true;
}
else {
dynamic_cast<ConcRegExp*>(regexp)->addRegExp( (*it)->selection() );
}
}
}
Q_ASSERT( foundAny );
return regexp;
}
void ConcWidget::addNewConcChild(DragAccepter *accepter, ConcWidget *other)
{
for ( unsigned int i=0; i<_children.count(); i+= 2 ) {
RegExpWidget *ch = _children.at( i );
if ( ch == accepter ) {
// Move all the element from the `child' ConcWidget to this one.
// Do not copy the first one as this is a dragAccepter, and we place the widgets
// after this drag accepter.
// We must take them in pairs to avoid breaking the invariant for paintEvent,
// namely that every second element is a dragAccepter
for ( unsigned int j = other->_children.count()-1; j > 0 ; j-=2 ) {
RegExpWidget* newChildA = other->_children.take(j);
newChildA->reparent( this, TQPoint(0,0), false);
_children.insert( i+1, newChildA );
RegExpWidget* newChildB = other->_children.take(j-1);
newChildB->reparent( this, TQPoint(0,0), false);
_children.insert( i+1, newChildB );
newChildA->show();
newChildB->show();
}
delete other;
return;
}
}
tqFatal("accepter not found");
}
bool ConcWidget::validateSelection() const
{
bool cont = true;
TQPtrListIterator<RegExpWidget> it(_children);
++it; // skip past the DragAccepter.
for ( ; *it && cont; it += 2 ) {
cont = (*it)->validateSelection();
}
return cont;
}