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/editorwindow.cpp

454 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.
**/
#ifdef TQT_ONLY
#include "compat.h"
#include "images.h"
#else
#include <tdelocale.h>
#include <tdemessagebox.h>
// #include <tdefiledialog.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include "editorwindow.moc"
#include <klineeditdlg.h>
#endif
#include "editorwindow.h"
#include "concwidget.h"
#include <tqlayout.h>
#include <tqpainter.h>
#include <tqaccel.h>
#include <tqcursor.h>
#include <tqclipboard.h>
#include <tqpopupmenu.h>
#include "regexp.h"
#include "userdefinedregexps.h"
#include <tqfileinfo.h>
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, TQ_SLOT( slotCopy() ) );
accel->connectItem( accel->insertItem( CTRL+Key_X ), this, TQ_SLOT( slotCut() ) );
accel->connectItem( accel->insertItem( Key_Delete ), this, TQ_SLOT( slotCut() ) );
accel->connectItem( accel->insertItem( Key_BackSpace ), this, TQ_SLOT( slotCut() ) );
accel->connectItem( accel->insertItem( CTRL+Key_V ), this, TQ_SLOT( slotStartPasteAction() ) );
accel->connectItem( accel->insertItem( Key_Escape ), this, TQ_SLOT( slotEndActions() ) );
accel->connectItem( accel->insertItem( CTRL+Key_S ), this, TQ_SLOT( slotSave() ) );
connect( this, TQ_SIGNAL( change() ), this, TQ_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("<p>Overwrite named regular expression <b>%1</b></p>").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<ConcWidget*>( 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
}