/* * Copyright (c) 2002-2003 Jesper K. Pedersen * * 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. **/ #ifdef TQT_ONLY #include "compat.h" #include "images.h" #else #include #include // #include #include #include #include "editorwindow.moc" #include #endif #include "editorwindow.h" #include "concwidget.h" #include #include #include #include #include #include #include "regexp.h" #include "userdefinedregexps.h" #include RegExpEditorWindow::RegExpEditorWindow( TQWidget *parent, const char *name) : TQWidget(parent, name, TQt::WPaintUnclipped) { _top = new ConcWidget(this, this); _layout = new TQHBoxLayout( this); _layout->addWidget(_top); _top->setToplevel(); _undrawSelection = false; _menu = 0; _insertInAction = false; _pasteInAction = false; _pasteData = 0; TQAccel* accel = new TQAccel( this ); accel->connectItem( accel->insertItem( CTRL+Key_C ), this, TQT_SLOT( slotCopy() ) ); accel->connectItem( accel->insertItem( CTRL+Key_X ), this, TQT_SLOT( slotCut() ) ); accel->connectItem( accel->insertItem( Key_Delete ), this, TQT_SLOT( slotCut() ) ); accel->connectItem( accel->insertItem( Key_BackSpace ), this, TQT_SLOT( slotCut() ) ); accel->connectItem( accel->insertItem( CTRL+Key_V ), this, TQT_SLOT( slotStartPasteAction() ) ); accel->connectItem( accel->insertItem( Key_Escape ), this, TQT_SLOT( slotEndActions() ) ); accel->connectItem( accel->insertItem( CTRL+Key_S ), this, TQT_SLOT( slotSave() ) ); connect( this, TQT_SIGNAL( change() ), this, TQT_SLOT( emitVerifyRegExp() ) ); } RegExp* RegExpEditorWindow::regExp() const { return _top->regExp(); } void RegExpEditorWindow::mousePressEvent ( TQMouseEvent* event ) { setFocus(); updateContent( 0 ); _start = event->pos(); _lastPoint = TQPoint(0,0); if ( pointSelected( event->globalPos() ) ) { _isDndOperation = true; } else { _isDndOperation = false; _selection = TQRect(); _top->updateSelection( false ); TQWidget::mousePressEvent( event ); } grabMouse(); } bool RegExpEditorWindow::pointSelected( TQPoint p ) const { TQRect rect = _top->selectionRect(); return rect.contains(p); } void RegExpEditorWindow::mouseMoveEvent ( TQMouseEvent* event ) { if ( _isDndOperation ) { if ( ( _start - event->pos() ).manhattanLength() > TQApplication::startDragDistance() ) { RegExp* regexp = _top->selection(); if ( !regexp ) return; TQDragObject *d = new RegExpWidgetDrag( regexp, this ); delete regexp; bool del = d->drag(); if ( del ) slotDeleteSelection(); else { clearSelection( true ); } releaseMouse(); emit change(); emit canSave( _top->hasAnyChildren() ); } } else { TQPainter p( this ); p.setRasterOp( TQt::NotROP ); p.setPen( TQt::DotLine ); // remove last selection rectangle if ( ! _lastPoint.isNull() && _undrawSelection ) { p.drawRect(TQRect(_start, _lastPoint)); } // Note this line must come after the old rect has been removed // and before the new one is draw otherwise the update event which this // line invokes, will remove a line, which later will be drawn instead of // removed during NotROP. _top->updateSelection( false ); emit scrolling( event->pos() ); p.drawRect(TQRect(_start, event->pos())); _undrawSelection = true; _lastPoint = event->pos(); _selection = TQRect(mapToGlobal(_start), mapToGlobal(_lastPoint)).normalize(); } } void RegExpEditorWindow::mouseReleaseEvent( TQMouseEvent *event) { releaseMouse(); TQWidget::mouseReleaseEvent( event); // remove last selection rectangle TQPainter p( this ); p.setRasterOp( TQt::NotROP ); p.setPen( TQt::DotLine ); if ( ! _lastPoint.isNull() ) { p.drawRect(TQRect(_start, _lastPoint)); } _top->validateSelection(); _top->updateAll(); emit anythingSelected( hasSelection() ); if ( hasSelection() ) { emit verifyRegExp(); } } bool RegExpEditorWindow::selectionOverlap( TQPoint pos, TQSize size ) const { TQRect child(pos, size); return (_selection.intersects(child) && ! child.contains(_selection)); } bool RegExpEditorWindow::hasSelection() const { return _top->hasSelection(); } void RegExpEditorWindow::clearSelection( bool update ) { _top->clearSelection(); if ( update ) _top->updateAll(); emit anythingSelected(false); } void RegExpEditorWindow::slotInsertRegExp( RegExpType type ) { _insertInAction = true; _insertTp = type; updateCursorUnderPoint(); setFocus(); } void RegExpEditorWindow::slotInsertRegExp( RegExp* regexp ) { if ( _pasteData ) delete _pasteData; _pasteData = regexp->clone(); _pasteInAction = true; updateCursorUnderPoint(); setFocus(); } void RegExpEditorWindow::slotDoSelect() { _pasteInAction = false; _insertInAction = false; // I need to update the cursor recursively, as a repaint may not have been issued yet // when this method is invoked. This means that when the repaint comes, the cursor may // move to an other widget. _top->updateCursorRecursively(); } void RegExpEditorWindow::slotDeleteSelection() { if ( ! hasSelection() ) { KMessageBox::information(this, i18n( "There is no selection."), i18n("Missing Selection") ); } else { _top->deleteSelection(); } updateContent( 0 ); } void RegExpEditorWindow::updateContent( TQWidget* focusChild) { TQPoint p(0,0); if ( focusChild ) p = focusChild->mapTo( this, TQPoint(0,0) ); _top->update(); emit contentChanged( p ); } TQSize RegExpEditorWindow::sizeHint() const { return _top->sizeHint(); } void RegExpEditorWindow::paintEvent( TQPaintEvent* event ) { TQWidget::paintEvent( event ); _undrawSelection = false; } void RegExpEditorWindow::slotCut() { cut( TQCursor::pos() ); emit change(); emit canSave( _top->hasAnyChildren() ); } void RegExpEditorWindow::cut( TQPoint pos ) { cutCopyAux( pos ); slotDeleteSelection(); } void RegExpEditorWindow::slotCopy() { copy( TQCursor::pos() ); } void RegExpEditorWindow::copy( TQPoint pos ) { cutCopyAux( pos ); clearSelection( true ); } void RegExpEditorWindow::cutCopyAux( TQPoint pos ) { if ( !hasSelection() ) { RegExpWidget* widget = _top->widgetUnderPoint( pos, true ); if ( !widget ) { KMessageBox::information(this, i18n("There is no widget under cursor."), i18n("Invalid Operation") ); return; } else { widget->updateSelection( true ); // HACK! } } RegExp* regexp = _top->selection(); RegExpWidgetDrag *clipboardData = new RegExpWidgetDrag( regexp, this ); delete regexp; TQClipboard* clipboard = tqApp->clipboard(); clipboard->setData( clipboardData ); emit anythingOnClipboard( true ); emit canSave( _top->hasAnyChildren() ); } void RegExpEditorWindow::slotStartPasteAction() { TQByteArray data = tqApp->clipboard()->data()->encodedData( "KRegExpEditor/widgetdrag" ); TQTextStream stream( data, IO_ReadOnly ); TQString str = stream.read(); RegExp* regexp = WidgetFactory::createRegExp( str ); if ( regexp ) slotInsertRegExp( regexp ); } void RegExpEditorWindow::slotEndActions() { emit doneEditing(); emit change(); emit canSave( _top->hasAnyChildren() ); } void RegExpEditorWindow::showRMBMenu( bool enableCutCopy ) { enum CHOICES { CUT, COPY, PASTE, SAVE, EDIT }; if ( !_menu ) { _menu = new TQPopupMenu( 0 ); _menu->insertItem(getIcon(TQString::fromLocal8Bit("edit-cut")), i18n("C&ut"), CUT); _menu->insertItem(getIcon(TQString::fromLocal8Bit("edit-copy")), i18n("&Copy"), COPY); _menu->insertItem(getIcon(TQString::fromLocal8Bit("edit-paste")), i18n("&Paste"), PASTE); _menu->insertSeparator(); _menu->insertItem(getIcon(TQString::fromLocal8Bit("edit")), i18n("&Edit"), EDIT); _menu->insertItem(getIcon(TQString::fromLocal8Bit("document-save")), i18n("&Save Regular Expression..."), SAVE); } _menu->setItemEnabled( CUT, enableCutCopy ); _menu->setItemEnabled( COPY, enableCutCopy ); if ( ! tqApp->clipboard()->data()->provides( "KRegExpEditor/widgetdrag" ) ) _menu->setItemEnabled( PASTE, false ); else _menu->setItemEnabled( PASTE, true ); _menu->setItemEnabled( SAVE, _top->hasAnyChildren() ); RegExpWidget* editWidget = _top->findWidgetToEdit( TQCursor::pos() ); _menu->setItemEnabled( EDIT, editWidget ); TQPoint pos = TQCursor::pos(); int choice = _menu->exec( pos ); switch ( choice ) { case COPY: copy( pos ); break; case CUT: cut( pos ); break; case PASTE: slotStartPasteAction(); break; case SAVE: slotSave(); break; case EDIT: editWidget->edit(); break; } emit change(); emit canSave( _top->hasAnyChildren() ); } void RegExpEditorWindow::applyRegExpToSelection( RegExpType tp ) { _top->applyRegExpToSelection( tp ); } void RegExpEditorWindow::slotSave() { TQString dir = WidgetWinItem::path(); TQString txt; #ifdef TQT_ONLY txt = TQInputDialog::getText( tr("Name for regexp"), tr("Enter name:") ); if ( txt.isNull() ) return; #else KLineEditDlg dlg(i18n("Enter name:"), TQString(), this); dlg.setCaption(i18n("Name for Regular Expression")); if (!dlg.exec()) return; txt = dlg.text(); #endif TQString fileName = dir + TQString::fromLocal8Bit("/") + txt + TQString::fromLocal8Bit(".regexp"); TQFileInfo finfo( fileName ); if ( finfo.exists() ) { int answer = KMessageBox::warningContinueCancel( this, i18n("

Overwrite named regular expression %1

").arg(txt), TQString(), i18n("Overwrite")); if ( answer != KMessageBox::Continue ) return; } TQFile file( fileName ); if ( ! file.open(IO_WriteOnly) ) { KMessageBox::sorry( this, i18n("Could not open file for writing: %1").arg(fileName) ); return; } // Convert to XML. RegExp* regexp = _top->regExp(); TQString xml = regexp->toXmlString(); delete regexp; TQTextStream stream(&file); stream << xml; file.close(); emit savedRegexp(); } void RegExpEditorWindow::slotSetRegExp( RegExp* regexp ) { // I have no clue why the following line is necesarry, but if it is not here // then the editor area is messed up when calling slotSetRegExp before starting the eventloop. tqApp->processEvents(); delete _top; RegExpWidget* widget = WidgetFactory::createWidget( regexp, this, this ); if ( ! (_top = dynamic_cast( widget ) ) ) { // It was not a ConcWidget _top = new ConcWidget( this, widget, this ); } _top->setToplevel(); _top->show(); _layout->addWidget( _top ); clearSelection( true ); // HACK? emit canSave( _top->hasAnyChildren() ); } void RegExpEditorWindow::updateCursorUnderPoint() { RegExpWidget* widget = _top->widgetUnderPoint( TQCursor::pos(), false ); if ( widget ) widget->updateCursorShape(); } void RegExpEditorWindow::emitVerifyRegExp() { emit verifyRegExp(); } TQIconSet RegExpEditorWindow::getIcon( const TQString& name ) { #ifdef TQT_ONLY TQPixmap pix; pix.convertFromImage( qembed_findImage( name ) ); return pix; #else return SmallIconSet( name ); #endif }