diff options
Diffstat (limited to 'kregexpeditor/concwidget.cpp')
-rw-r--r-- | kregexpeditor/concwidget.cpp | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/kregexpeditor/concwidget.cpp b/kregexpeditor/concwidget.cpp new file mode 100644 index 0000000..f67c49b --- /dev/null +++ b/kregexpeditor/concwidget.cpp @@ -0,0 +1,400 @@ +/* + * 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 <qpainter.h> + +ConcWidget::ConcWidget(RegExpEditorWindow* editorWindow, QWidget *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, + QWidget *parent, const char *name) + :MultiContainerWidget(editorWindow, parent, name == 0 ? "concwidget" : name) +{ + init(); + DragAccepter *accepter = new DragAccepter(editorWindow, this); + _children.append(accepter); + child->reparent(this, QPoint(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, QPoint(0,0), false); + } + _children.prepend( new DragAccepter(editorWindow, this) ); +} + +ConcWidget::ConcWidget( ConcRegExp* regexp, RegExpEditorWindow* editorWindow, + QWidget* 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; +} + + +QSize ConcWidget::sizeHint() const +{ + int childrenWidth = 0; + int childrenHeight = 0; + QPtrListIterator<RegExpWidget> it(_children); + + for ( ; *it; ++it) { + QSize thisChildSize = (*it)->sizeHint(); + childrenWidth += thisChildSize.width(); + childrenHeight = QMAX(childrenHeight, thisChildSize.height()); + } + + return QSize(childrenWidth, childrenHeight); +} + +void ConcWidget::paintEvent( QPaintEvent *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 { + QSize myReqSize = sizeHint(); + QSize mySize(QMAX(myReqSize.width(), size().width()), + QMAX(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; + } + + QPainter 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); + + QSize childSize = child->sizeHint(); + QSize curChildSize = child->size(); + + //----------------------------- first place the accepter + int x = offset; + int w = accepter->sizeHint().width(); + if ( i == 1 ) w+= extra; + int h = QMAX( 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, QBrush( 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, QBrush( 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 ( QMouseEvent* event ) +{ + if ( event->button() == 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 +{ + QPtrListIterator<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; + + QPtrListIterator<RegExpWidget> it(_children); + ++it; // Skip past the first DragAccepter + for ( ; *it; it +=2 ) { + if ( (*it)->isSelected() ) { + _maxSelectedHeight = QMAX( _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 + + QPtrListIterator<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, QPoint(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; + QPtrListIterator<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; + + QPtrListIterator<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, QPoint(0,0), false); + _children.insert( i+1, newChildA ); + RegExpWidget* newChildB = other->_children.take(j-1); + newChildB->reparent( this, QPoint(0,0), false); + _children.insert( i+1, newChildB ); + newChildA->show(); + newChildB->show(); + } + delete other; + return; + } + } + qFatal("accepter not found"); +} + +bool ConcWidget::validateSelection() const +{ + bool cont = true; + QPtrListIterator<RegExpWidget> it(_children); + ++it; // skip past the DragAccepter. + for ( ; *it && cont; it += 2 ) { + cont = (*it)->validateSelection(); + } + return cont; +} |