diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2 (patch) | |
tree | d3bb9f5d25a2dc09ca81adecf39621d871534297 /kig/modes | |
download | tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.tar.gz tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeedu@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kig/modes')
33 files changed, 6532 insertions, 0 deletions
diff --git a/kig/modes/Makefile.am b/kig/modes/Makefile.am new file mode 100644 index 00000000..5f7518e5 --- /dev/null +++ b/kig/modes/Makefile.am @@ -0,0 +1,39 @@ +INCLUDES=$(all_includes) + +noinst_LTLIBRARIES=libmodes.la +libmodes_la_SOURCES= \ + base_mode.cc \ + construct_mode.cc \ + dragrectmode.cc \ + edittype.cc \ + edittypebase.ui \ + label.cc \ + linkslabel.cpp \ + macro.cc \ + macrowizard.cc \ + macrowizardbase.ui \ + mode.cc \ + moving.cc \ + normal.cc \ + popup.cc \ + textlabelwizard.cc \ + textlabelwizardbase.ui \ + typesdialog.cpp \ + typesdialogbase.ui +noinst_HEADERS=\ + base_mode.h \ + construct_mode.h \ + dragrectmode.h \ + edittype.h \ + label.h \ + linkslabel.h \ + macro.h \ + macrowizard.h \ + mode.h \ + moving.h \ + normal.h \ + popup.h \ + textlabelwizard.h \ + typesdialog.h + +METASOURCES=AUTO diff --git a/kig/modes/base_mode.cc b/kig/modes/base_mode.cc new file mode 100644 index 00000000..9e92274a --- /dev/null +++ b/kig/modes/base_mode.cc @@ -0,0 +1,160 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "base_mode.h" + +#include "popup.h" + +#include "../kig/kig_view.h" +#include "../kig/kig_part.h" +#include "../kig/kig_document.h" + +#include <qevent.h> +#include <kcursor.h> + +BaseMode::BaseMode( KigPart& d ) + : KigMode( d ) +{ +} + +BaseMode::~BaseMode() +{ +} + +void BaseMode::leftClicked( QMouseEvent* e, KigWidget* v ) +{ + // touch screens don't send a mouseMoved event before a click event, + // apparently, so we simulate it. + mouseMoved( e, v ); + + // get rid of text still showing... + v->updateCurPix(); + v->updateWidget(); + + mplc = e->pos(); + moco = mdoc.document().whatAmIOn( v->fromScreen( mplc ), *v ); + + if( moco.empty() ) + { + // clicked on an empty spot --> we show the rectangle for + // selecting stuff... + dragRect( mplc, *v ); + } + else + { + // the user clicked on some object.. --> this could either mean + // that he/she wants to select the object or that he wants to + // start moving it. We assume nothing here, we wait till he + // either moves some 4 pixels, or till he releases his mouse + // button in leftReleased() or mouseMoved()... + }; +} + +void BaseMode::leftMouseMoved( QMouseEvent* e, KigWidget* w ) +{ + if( !moco.empty() && ( mplc - e->pos() ).manhattanLength() > 3 ) + dragObject( moco, mplc, *w, + ( e->state() & (ShiftButton | ControlButton ) ) != 0 + ); +} + +void BaseMode::leftReleased( QMouseEvent* e, KigWidget* v ) +{ + if( (mplc - e->pos()).manhattanLength() > 4 ) return; + + ObjectHolder* o = 0; + bool keyCtrl = ( e->state() & ControlButton ) != 0; + bool keyShift = ( e->state() & ShiftButton ) != 0; + if ( ! moco.empty() ) + { + if ( keyShift ) + { + int id = ObjectChooserPopup::getObjectFromList( e->pos(), v, moco ); + if ( id >= 0 ) + o = moco[id]; + } + else + o = moco.front(); + } + leftClickedObject( o, e->pos(), *v, keyCtrl ); +} + +void BaseMode::midClicked( QMouseEvent* e, KigWidget* v ) +{ + // get rid of text still showing... + v->updateCurPix(); + v->updateWidget(); + + mplc = e->pos(); + moco = mdoc.document().whatAmIOn( v->fromScreen( e->pos() ), *v ); +} + +void BaseMode::midReleased( QMouseEvent* e, KigWidget* v ) +{ + if( (e->pos() - mplc).manhattanLength() > 4 ) return; + + midClicked( mplc, *v ); +} + +void BaseMode::rightClicked( QMouseEvent* e, KigWidget* w ) +{ + // get rid of text still showing... + w->updateCurPix(); + w->updateWidget(); + // set a normal cursor... + w->setCursor( KCursor::arrowCursor() ); + + mplc = e->pos(); + moco = mdoc.document().whatAmIOn( w->fromScreen( mplc ), *w ); + + rightClicked( moco, mplc, *w ); +} + +void BaseMode::mouseMoved( QMouseEvent* e, KigWidget* w ) +{ + std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( w->fromScreen( e->pos() ), *w ); + mouseMoved( os, e->pos(), *w, e->state() & Qt::ShiftButton ); +} + +void BaseMode::dragRect( const QPoint&, KigWidget& ) +{ +} + +void BaseMode::leftClickedObject( ObjectHolder*, const QPoint&, + KigWidget&, bool ) +{ +} + +void BaseMode::dragObject( const std::vector<ObjectHolder*>&, const QPoint&, + KigWidget&, bool ) +{ +} + +void BaseMode::enableActions() +{ + KigMode::enableActions(); +} + +std::vector<ObjectHolder*> BaseMode::oco() +{ + return moco; +} + +QPoint BaseMode::pointLocation() +{ + return mplc; +} diff --git a/kig/modes/base_mode.h b/kig/modes/base_mode.h new file mode 100644 index 00000000..2f89996f --- /dev/null +++ b/kig/modes/base_mode.h @@ -0,0 +1,64 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MODE_BASE_MODE_H +#define KIG_MODE_BASE_MODE_H + +#include "mode.h" + +#include <qpoint.h> +#include <vector> + +class KigWidget; +class KigDocument; +class ObjectHolder; + +class BaseMode + : public KigMode +{ + QPoint mplc; + std::vector<ObjectHolder*> moco; + + void leftClicked( QMouseEvent* e, KigWidget* v ); + void leftMouseMoved( QMouseEvent*, KigWidget* ); + void leftReleased( QMouseEvent* e, KigWidget* v ); + void midClicked( QMouseEvent* e, KigWidget* v ); + void midReleased( QMouseEvent* e, KigWidget* v ); + void rightClicked( QMouseEvent*, KigWidget* ); + void mouseMoved( QMouseEvent* e, KigWidget* v ); + +protected: + void enableActions(); + + std::vector<ObjectHolder*> oco(); + QPoint pointLocation(); +protected: + + virtual void dragRect( const QPoint& p, KigWidget& w ); + virtual void dragObject( const std::vector<ObjectHolder*>& os, const QPoint& pointClickedOn, KigWidget& w, bool ctrlOrShiftDown ); + virtual void leftClickedObject( ObjectHolder* o, const QPoint& p, + KigWidget& w, bool ctrlOrShiftDown ) = 0; + virtual void midClicked( const QPoint& p, KigWidget& w ) = 0; + virtual void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w ) = 0; + virtual void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed ) = 0; + +protected: + BaseMode( KigPart& ); + ~BaseMode(); +}; + +#endif diff --git a/kig/modes/construct_mode.cc b/kig/modes/construct_mode.cc new file mode 100644 index 00000000..9618aded --- /dev/null +++ b/kig/modes/construct_mode.cc @@ -0,0 +1,572 @@ +// Copyright (C) 2003 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "construct_mode.h" + +#include "../objects/object_factory.h" +#include "../objects/object_drawer.h" +#include "../objects/text_type.h" +#include "../objects/text_imp.h" +#include "../objects/bogus_imp.h" +#include "../objects/point_imp.h" +#include "../misc/argsparser.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/object_constructor.h" +#include "../misc/coordinate_system.h" +#include "../misc/kigpainter.h" +#include "../misc/calcpaths.h" + +#include "popup.h" + +#include <kcursor.h> +#include <kaction.h> + +#include <algorithm> +#include <functional> + +static void redefinePoint( ObjectTypeCalcer* mpt, const Coordinate& c, KigDocument& doc, const KigWidget& w ) +{ + ObjectFactory::instance()->redefinePoint( mpt, c, doc, w ); + mpt->calc( doc ); +} + +BaseConstructMode::BaseConstructMode( KigPart& d ) + : BaseMode( d ) +{ + mpt = ObjectFactory::instance()->fixedPointCalcer( Coordinate( 0, 0 ) ); + mpt->calc( d.document() ); + mcursor = ObjectFactory::instance()->cursorPointCalcer( Coordinate( 0, 0 ) ); + mcursor->calc( d.document() ); +// mcursorholder = new ObjectHolder( mcursor ); +} + +BaseConstructMode::~BaseConstructMode() +{ + delete mcursor; +// delete mcursorholder; +} + +void BaseConstructMode::leftReleased( QMouseEvent* e, KigWidget* v ) +{ + if( (pointLocation() - e->pos()).manhattanLength() > 4 ) return; + + ObjectHolder* o = 0; + bool keyCtrlOrShift = ( e->state() & ( ControlButton | ShiftButton) ) != 0; + std::vector<ObjectHolder*> moco = oco(); + if ( ! moco.empty() ) + { + std::vector<ObjectHolder*> goodargs; + if ( !moco.empty() ) + { + std::vector<ObjectHolder*>::const_iterator it; + std::vector<ObjectCalcer*> testargs = getCalcers( mparents ); + for ( std::vector<ObjectHolder*>::const_iterator i = moco.begin(); i != moco.end(); ++i ) + { + it = std::find( mparents.begin(), mparents.end(), *i ); + bool newdup = + ( it == mparents.end() ) || + isAlreadySelectedOK( testargs, it - mparents.begin() ); + if ( newdup ) + { + testargs.push_back( ( *i )->calcer() ); + if ( wantArgs( testargs, mdoc.document(), *v ) ) + goodargs.push_back( *i ); + testargs.pop_back(); + } + } + int id = ObjectChooserPopup::getObjectFromList( e->pos(), v, goodargs ); + if ( id >= 0 ) + o = goodargs[id]; + } + } + leftClickedObject( o, e->pos(), *v, keyCtrlOrShift ); + KigMode::leftReleased( e, v ); +} + +void BaseConstructMode::leftClickedObject( + ObjectHolder* o, const QPoint& p, KigWidget& w, bool ) +{ + std::vector<ObjectHolder*>::iterator it = std::find( mparents.begin(), mparents.end(), o ); + std::vector<ObjectCalcer*> nargs = getCalcers( mparents ); +// +// mp: duplicationchecked controls whether the arguments list is +// free of duplications or if a duplication is safe (asking this to +// the Constructor class through the "isAlreadySelectedOK" method). +// + bool duplicationchecked = + ( it == mparents.end() ) || + isAlreadySelectedOK( nargs, it - mparents.begin() ); + if ( o && duplicationchecked ) + { + nargs.push_back( o->calcer() ); + if ( wantArgs( nargs, mdoc.document(), w ) ) + { + selectObject( o, w ); + return; + } + } + + nargs = getCalcers( mparents ); + nargs.push_back( mpt.get() ); + if ( wantArgs( nargs, mdoc.document(), w ) ) + { + // add mpt to the document.. + ObjectHolder* n = new ObjectHolder( mpt.get() ); + mdoc.addObject( n ); + selectObject( n, w ); + // get a new mpt for our further use.. + mpt = ObjectFactory::instance()->sensiblePointCalcer( w.fromScreen( p ), mdoc.document(), w ); + mpt->calc( mdoc.document() ); + return; + } + + nargs = getCalcers( mparents ); + nargs.push_back( mcursor ); + + if ( wantArgs( nargs, mdoc.document(), w ) ) + { + // DON'T add mpt to the document.. + // the objectholder has been constructed once and for all + // when entering construction mode, and delete in the + // destructor. + ObjectHolder* n = new ObjectHolder( mcursor ); + selectObject( n, w ); + mcursor = ObjectFactory::instance()->cursorPointCalcer( w.fromScreen( p ) ); +// mcursor = ObjectFactory::instance()->sensiblePointCalcer( w.fromScreen( p ), mdoc.document(), w ); + mcursor->calc( mdoc.document() ); + delete n; + } +} + +void BaseConstructMode::midClicked( const QPoint& p, KigWidget& w ) +{ + std::vector<ObjectCalcer*> args = getCalcers( mparents ); + args.push_back( mpt.get() ); + if ( wantArgs( args, mdoc.document(), w ) ) + { + ObjectHolder* n = new ObjectHolder( mpt.get() ); + mdoc.addObject( n ); + + selectObject( n, w ); + + mpt = ObjectFactory::instance()->sensiblePointCalcer( w.fromScreen( p ), mdoc.document(), w ); + mpt->calc( mdoc.document() ); + } +} + +void BaseConstructMode::rightClicked( const std::vector<ObjectHolder*>&, const QPoint&, KigWidget& ) +{ + // TODO ? +} + +void BaseConstructMode::mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, + KigWidget& w, bool shiftpressed ) +{ + mdoc.emitStatusBarText( selectStatement( getCalcers( mparents ), w ) ); + + w.updateCurPix(); + KigPainter pter( w.screenInfo(), &w.curPix, mdoc.document() ); + + Coordinate ncoord = w.fromScreen( p ); + if ( shiftpressed ) + ncoord = mdoc.document().coordinateSystem().snapToGrid( ncoord, w ); + + redefinePoint( mpt.get(), ncoord, mdoc.document(), w ); + mcursor->move( ncoord, mdoc.document() ); + mcursor->calc( mdoc.document() ); + + std::vector<ObjectCalcer*> args = getCalcers( mparents ); + bool duplicationchecked = false; + std::vector<ObjectHolder*> goodargs; + if ( ! os.empty() ) + { + std::vector<ObjectHolder*>::const_iterator it; + std::vector<ObjectCalcer*> testargs = getCalcers( mparents ); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + { + it = std::find( mparents.begin(), mparents.end(), *i ); + bool newdup = + ( it == mparents.end() ) || + isAlreadySelectedOK( args, it - mparents.begin() ); + if ( newdup ) + { + testargs.push_back( ( *i )->calcer() ); + if ( wantArgs( testargs, mdoc.document(), w ) ) + goodargs.push_back( *i ); + testargs.pop_back(); + } + duplicationchecked |= newdup; + } + } + bool calcnow = ( goodargs.size() == 1 ) || ( ( goodargs.size() > 0 ) && ( goodargs.front()->imp()->inherits( PointImp::stype() ) ) ); + if ( calcnow ) + { + args.push_back( goodargs.front()->calcer() ); + } + + if ( !os.empty() && duplicationchecked && calcnow ) + { + handlePrelim( args, p, pter, w ); + + w.setCursor( KCursor::handCursor() ); + } + else + { + std::vector<ObjectCalcer*> args = getCalcers( mparents ); + args.push_back( mpt.get() ); + std::vector<ObjectCalcer*> argscursor = getCalcers( mparents ); + argscursor.push_back( mcursor ); + bool text = true; + if ( wantArgs( args, mdoc.document(), w ) ) + { + ObjectDrawer d; + d.draw( *mpt->imp(), pter, true ); + + handlePrelim( args, p, pter, w ); + + w.setCursor( KCursor::handCursor() ); + } + else if ( wantArgs( argscursor, mdoc.document(), w ) ) + { + ObjectDrawer d; +// d.draw( *mcursor->imp(), pter, true ); + + handlePrelim( argscursor, p, pter, w ); + + w.setCursor( KCursor::crossCursor() ); + } + else + { + w.setCursor( KCursor::arrowCursor() ); + text = false; + } + if ( !text && ( goodargs.size() > 1 ) ) + { + QString strwhich = i18n( "Which object?" ); + mdoc.emitStatusBarText( strwhich ); + + QPoint textloc = p; + textloc.setX( textloc.x() + 15 ); + pter.drawTextStd( textloc, strwhich ); + + w.setCursor( KCursor::handCursor() ); + } + } + w.updateWidget( pter.overlay() ); +} + +void BaseConstructMode::selectObject( ObjectHolder* o, KigWidget& w ) +{ + mparents.push_back( o ); + std::vector<ObjectCalcer*> args = getCalcers( mparents ); + + if ( wantArgs( args, mdoc.document(), w ) == ArgsParser::Complete ) + { + handleArgs( args, w ); + }; + + w.redrawScreen( mparents ); +} + +PointConstructMode::PointConstructMode( KigPart& d ) + : BaseMode( d ) +{ + // we add the data objects to the document cause + // ObjectFactory::redefinePoint does that too, and this way, we can + // depend on them already being known by the doc when we add the + // mpt.. + mpt = ObjectFactory::instance()->fixedPointCalcer( Coordinate() ); + mpt->calc( d.document() ); + + mdoc.emitStatusBarText( i18n( "Click the location where you want to place the new point, or the curve that you want to attach it to..." ) ); +} + +PointConstructMode::~PointConstructMode() +{ +} + +void PointConstructMode::leftClickedObject( + ObjectHolder*, const QPoint&, KigWidget& w, bool ) +{ + mdoc.addObject( new ObjectHolder( mpt.get() ) ); + w.redrawScreen( std::vector<ObjectHolder*>() ); + + mdoc.emitStatusBarText( QString::null ); + mdoc.doneMode( this ); +} + +void PointConstructMode::midClicked( const QPoint& p, KigWidget& w ) +{ + leftClickedObject( 0, p, w, true ); +} + +void PointConstructMode::rightClicked( const std::vector<ObjectHolder*>&, const QPoint&, + KigWidget& ) +{ + // TODO ? +} + +void PointConstructMode::mouseMoved( + const std::vector<ObjectHolder*>&, + const QPoint& p, + KigWidget& w, + bool shiftpressed ) +{ + w.updateCurPix(); + KigPainter pter( w.screenInfo(), &w.curPix, mdoc.document() ); + + Coordinate ncoord = w.fromScreen( p ); + if ( shiftpressed ) + ncoord = mdoc.document().coordinateSystem().snapToGrid( ncoord, w ); + + redefinePoint( mpt.get(), ncoord, mdoc.document(), w ); + + ObjectDrawer d; + d.draw( *mpt->imp(), pter, true ); + w.setCursor( KCursor::blankCursor() ); + + w.updateWidget( pter.overlay() ); +} + +void BaseConstructMode::enableActions() +{ + BaseMode::enableActions(); + + mdoc.aCancelConstruction->setEnabled( true ); +} + +void BaseConstructMode::cancelConstruction() +{ + finish(); +} + +void PointConstructMode::enableActions() +{ + BaseMode::enableActions(); + + mdoc.aCancelConstruction->setEnabled( true ); +} + +void PointConstructMode::cancelConstruction() +{ + mdoc.doneMode( this ); +} + +void BaseConstructMode::selectObjects( const std::vector<ObjectHolder*>& os, KigWidget& w ) +{ + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + { + std::vector<ObjectCalcer*> args = getCalcers( mparents ); + assert( wantArgs( args, mdoc.document(), w ) != ArgsParser::Complete ); + selectObject( *i, w ); + }; +} + +void ConstructMode::handlePrelim( const std::vector<ObjectCalcer*>& args, const QPoint& p, KigPainter& pter, KigWidget& w ) +{ + // set the text next to the arrow cursor like in modes/normal.cc + QPoint textloc = p; + textloc.setX( textloc.x() + 15 ); + + mctor->handlePrelim( pter, args, mdoc.document(), w ); + + QString o = mctor->useText( *args.back(), args, mdoc.document(), w ); + pter.drawTextStd( textloc, o ); +} + +int ConstructMode::isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os, + const int& pos ) +{ + return mctor->isAlreadySelectedOK( os, pos ); +} + +int ConstructMode::wantArgs( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) +{ + return mctor->wantArgs( os, d, w ); +} + +void BaseConstructMode::finish() +{ + mdoc.doneMode( this ); +} + +ConstructMode::ConstructMode( KigPart& d, const ObjectConstructor* ctor ) + : BaseConstructMode( d ), mctor( ctor ) +{ +} + +ConstructMode::~ConstructMode() +{ +} + +// does a test result have a frame by default ? +static const bool test_has_frame_dflt = true; + +void TestConstructMode::handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter& pter, KigWidget& w ) +{ + Args args; + std::transform( os.begin(), os.end(), std::back_inserter( args ), + std::mem_fun( &ObjectCalcer::imp ) ); + + // usetext + QString usetext = i18n( mtype->argsParser().usetext( args.back(), args ).c_str() ); + QPoint textloc = p; + textloc.setX( textloc.x() + 15 ); + pter.drawTextStd( textloc, usetext ); + + // test result + ObjectImp* data = mtype->calc( args, mdoc.document() ); + if ( ! data->valid() ) return; + assert( data->inherits( TestResultImp::stype() ) ); + QString outputtext = static_cast<TestResultImp*>( data )->data(); + TextImp ti( outputtext, w.fromScreen( p + QPoint( - 40, 30 ) ), test_has_frame_dflt ); + ti.draw( pter ); + + delete data; +} + +TestConstructMode::TestConstructMode( KigPart& d, const ArgsParserObjectType* type ) + : BaseConstructMode( d ), mtype( type ) +{ +} + +TestConstructMode::~TestConstructMode() +{ +} + +void ConstructMode::handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w ) +{ + mctor->handleArgs( args, mdoc, w ); + finish(); +} + +int TestConstructMode::isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, + const int& ) +{ + return false; +} + +int TestConstructMode::wantArgs( const std::vector<ObjectCalcer*>& os, KigDocument&, KigWidget& ) +{ + return mtype->argsParser().check( os ); +} + +void TestConstructMode::handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& ) +{ + mresult = new ObjectTypeCalcer( mtype, args ); + mresult->calc( mdoc.document() ); + mdoc.emitStatusBarText( i18n( "Now select the location for the result label." ) ); +} + +void TestConstructMode::leftClickedObject( ObjectHolder* o, const QPoint& p, + KigWidget& w, bool ctrlOrShiftDown ) +{ + if ( mresult ) { + QPoint qloc = p + QPoint( -40, 0 ); + Coordinate loc = w.fromScreen( qloc ); + + std::vector<ObjectCalcer*> parents; + parents.push_back( new ObjectConstCalcer( new IntImp( test_has_frame_dflt ) ) ); + parents.push_back( new ObjectConstCalcer( new PointImp( loc ) ) ); + parents.push_back( new ObjectConstCalcer( new StringImp( QString::fromLatin1( "%1" ) ) ) ); + assert( mresult->imp()->inherits( TestResultImp::stype() ) ); + parents.push_back( + new ObjectPropertyCalcer( + mresult.get(), mresult->imp()->propertiesInternalNames().findIndex( "test-result" ) ) ); + parents.back()->calc( mdoc.document() ); + + ObjectCalcer* ret = new ObjectTypeCalcer( TextType::instance(), parents ); + ret->calc( mdoc.document() ); + mdoc.addObject( new ObjectHolder( ret ) ); + + w.unsetCursor(); + mdoc.emitStatusBarText( QString::null ); + + finish(); + } + else + BaseConstructMode::leftClickedObject( o, p, w, ctrlOrShiftDown ); +} + +void TestConstructMode::midClicked( const QPoint& p, KigWidget& w ) +{ + if ( mresult ) { + // nothing to be done here, really + } + else + BaseConstructMode::midClicked( p, w ); +} + +void TestConstructMode::rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w ) +{ + if ( mresult ) { + // nothing to be done here, really + } + else + BaseConstructMode::rightClicked( oco, p, w ); +} + +void TestConstructMode::mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftPressed ) +{ + if ( mresult ) { + w.setCursor( KCursor::blankCursor() ); + + w.updateCurPix(); + KigPainter pter( w.screenInfo(), &w.curPix, mdoc.document() ); + + QPoint qloc = p + QPoint( -40, 0 ); + Coordinate loc = w.fromScreen( qloc ); + assert( dynamic_cast<const TestResultImp*>( mresult->imp() ) ); + TextImp ti( static_cast<const TestResultImp*>( mresult->imp() )->data(), loc, test_has_frame_dflt ); + ObjectDrawer d; + d.draw( ti, pter, false ); + + + w.updateWidget( pter.overlay() ); + } + else + BaseConstructMode::mouseMoved( os, p, w, shiftPressed ); +} + +QString ConstructMode::selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w ) +{ + return mctor->selectStatement( args, mdoc.document(), w ); +} + +QString TestConstructMode::selectStatement( const std::vector<ObjectCalcer*>& sel, const KigWidget& ) +{ + using namespace std; + Args args; + transform( sel.begin(), sel.end(), back_inserter( args ), mem_fun( &ObjectCalcer::imp ) ); + + std::string ret = mtype->argsParser().selectStatement( args ); + if ( ret.empty() ) return QString::null; + return i18n( ret.c_str() ); +} + +void PointConstructMode::redrawScreen( KigWidget* w ) +{ + w->redrawScreen( std::vector<ObjectHolder*>() ); +} + +void BaseConstructMode::redrawScreen( KigWidget* w ) +{ + w->redrawScreen( std::vector<ObjectHolder*>() ); +} diff --git a/kig/modes/construct_mode.h b/kig/modes/construct_mode.h new file mode 100644 index 00000000..fa1be86e --- /dev/null +++ b/kig/modes/construct_mode.h @@ -0,0 +1,154 @@ +// Copyright (C) 2003 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MODES_CONSTRUCT_MODE_H +#define KIG_MODES_CONSTRUCT_MODE_H + +#include "base_mode.h" + +#include "../objects/object_calcer.h" + +class ArgsParserObjectType; +class ObjectConstructor; +class ObjectCalcer; + +class PointConstructMode + : public BaseMode +{ + /** + * this is the point that we move around, for the user to add + * somewhere.. + */ + ObjectTypeCalcer::shared_ptr mpt; +public: + PointConstructMode( KigPart& d ); + ~PointConstructMode(); +protected: + void leftClickedObject( ObjectHolder* o, const QPoint& p, + KigWidget& w, bool ctrlOrShiftDown ); + void midClicked( const QPoint& p, KigWidget& w ); + void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w ); + void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed ); + + void enableActions(); + void cancelConstruction(); + + void redrawScreen( KigWidget* ); +}; + +class BaseConstructMode + : public BaseMode +{ + /** + * this is the point that we move around, in case the user wants to + * add a point somewhere.. + */ + ObjectTypeCalcer::shared_ptr mpt; + /** + * mp: this point always follows the cursor + * + * IMPORTANT: this Calcer must NEVER be added to the document, since + * its is used in constructors that need more input from the user + * to decide parameters of the constructed object that will be fixed + * afterwards (like the number of sides of a regular polygon) + */ + ObjectTypeCalcer* mcursor; + // we also allocate here the corresponding objectholder, since the + // only sensible place where to deallocate it is in the destructor + // of this class +// ObjectHolder* mcursorholder; + std::vector<ObjectHolder*> mparents; + + void leftReleased( QMouseEvent* e, KigWidget* v ); + +public: + void selectObject( ObjectHolder* o, KigWidget& w ); + void selectObjects( const std::vector<ObjectHolder*>& os, KigWidget& w ); + virtual ~BaseConstructMode(); +protected: + BaseConstructMode( KigPart& d ); +protected: + void leftClickedObject( ObjectHolder* o, const QPoint& p, + KigWidget& w, bool ctrlOrShiftDown ); + void midClicked( const QPoint& p, KigWidget& w ); + void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w ); + void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed ); + + void enableActions(); + void cancelConstruction(); + void finish(); + +protected: + virtual void handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter&, KigWidget& w ) = 0; + virtual QString selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w ) = 0; + virtual int isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& ) = 0; + virtual int wantArgs( const std::vector<ObjectCalcer*>&, KigDocument& d, KigWidget& w ) = 0; + virtual void handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w ) = 0; + + void redrawScreen( KigWidget* ); +}; + +class ConstructMode + : public BaseConstructMode +{ + const ObjectConstructor* mctor; +public: + ConstructMode( KigPart& d, const ObjectConstructor* ctor ); + ~ConstructMode(); + + void handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter&, KigWidget& w ); + QString selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w ); + int isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& ); + int wantArgs( const std::vector<ObjectCalcer*>&, KigDocument& d, KigWidget& w ); + void handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w ); +}; + +/** + * This class constructs a test object. It has special needs over + * ConstructMode because first the arguments need to be chosen, and + * then the location for the resulting TextImp needs to be chosen. It + * also needs special code for the drawPrelim and wantArgs code. + * + * Therefore, we inherit from BaseConstructMode, and override the + * event callbacks, so that this mode behaves like a + * BaseConstructMode, until handleArgs is called. After that, mresult + * is no longer 0, and then the mode behaves in its own way, allowing + * the user to choose a location for the new label object. + */ +class TestConstructMode + : public BaseConstructMode +{ + const ArgsParserObjectType* mtype; + ObjectCalcer::shared_ptr mresult; +public: + TestConstructMode( KigPart& d, const ArgsParserObjectType* type ); + ~TestConstructMode(); + + void handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter&, KigWidget& w ); + QString selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w ); + int isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& ); + int wantArgs( const std::vector<ObjectCalcer*>&, KigDocument& d, KigWidget& w ); + void handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w ); + + void leftClickedObject( ObjectHolder* o, const QPoint& p, + KigWidget& w, bool ctrlOrShiftDown ); + void midClicked( const QPoint& p, KigWidget& w ); + void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w ); + void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed ); +}; + +#endif diff --git a/kig/modes/dragrectmode.cc b/kig/modes/dragrectmode.cc new file mode 100644 index 00000000..a3c8c033 --- /dev/null +++ b/kig/modes/dragrectmode.cc @@ -0,0 +1,180 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "dragrectmode.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/kigpainter.h" + +#include <qevent.h> +#include <qglobal.h> +#include <kaction.h> + +DragRectMode::DragRectMode( const QPoint& start, KigPart& d, KigWidget& w ) + : KigMode( d ), mstart( start ), mnc( true ), mstartselected( true ), + mcancelled( false ) +{ + moved( start, w ); +} + +DragRectMode::DragRectMode( KigPart& d, KigWidget& w ) + : KigMode( d ), mnc( true ), mstartselected( false ), + mcancelled( false ) +{ + w.updateCurPix(); + w.updateWidget(); +} + +void DragRectMode::moved( const QPoint& p, KigWidget& w ) +{ + // update the rect... + w.updateCurPix(); + std::vector<QRect> overlay; + if ( mstartselected ) + { + KigPainter pt( w.screenInfo(), &w.curPix, mdoc.document() ); + pt.drawFilledRect( QRect( p, mstart ) ); + overlay = pt.overlay(); + }; + w.updateWidget( overlay ); +} + +void DragRectMode::released( const QPoint& p, KigWidget& w, bool nc ) +{ + if ( mstartselected ) + { + mrect = w.fromScreen( QRect( mstart, p ) ); + mret = mdoc.document().whatIsInHere( mrect, w ); + mnc = nc; + + mdoc.doneMode( this ); + }; +} + +void DragRectMode::enableActions() +{ + KigMode::enableActions(); + + mdoc.aCancelConstruction->setEnabled( true ); +} + +std::vector<ObjectHolder*> DragRectMode::ret() const +{ + return mret; +} + +bool DragRectMode::needClear() const +{ + return mnc; +} + +void DragRectMode::moved( QMouseEvent* e, KigWidget& w ) +{ + moved( e->pos(), w ); +} + +void DragRectMode::released( QMouseEvent* e, KigWidget& w ) +{ + released( e->pos(), w, ! ( e->state() & ( ControlButton | ShiftButton ) ) ); +} + +DragRectMode::~DragRectMode() +{ +} + +void DragRectMode::mouseMoved( QMouseEvent* e, KigWidget* w ) +{ + moved( e, *w ); +} + +void DragRectMode::leftMouseMoved( QMouseEvent* e, KigWidget* w ) +{ + moved( e, *w ); +} + +void DragRectMode::midMouseMoved( QMouseEvent* e, KigWidget* w ) +{ + moved( e, *w ); +} + +void DragRectMode::rightMouseMoved( QMouseEvent* e, KigWidget* w ) +{ + moved( e, *w ); +} + +void DragRectMode::leftReleased( QMouseEvent* e, KigWidget* w ) +{ + released( e, *w ); +} + +void DragRectMode::midReleased( QMouseEvent* e, KigWidget* w ) +{ + released( e, *w ); +} + +void DragRectMode::rightReleased( QMouseEvent* e, KigWidget* w ) +{ + released( e, *w ); +} + +Rect DragRectMode::rect() const +{ + return mrect; +} + +void DragRectMode::clicked( const QMouseEvent* e, KigWidget& w ) +{ + clicked( e->pos(), w ); +} + +void DragRectMode::leftClicked( QMouseEvent* e, KigWidget* w ) +{ + clicked( e, *w ); +} + +void DragRectMode::midClicked( QMouseEvent* e, KigWidget* w ) +{ + clicked( e, *w ); +} + +void DragRectMode::rightClicked( QMouseEvent* e, KigWidget* w ) +{ + clicked( e, *w ); +} + +void DragRectMode::clicked( const QPoint& p, KigWidget& ) +{ + if ( !mstartselected ) + { + mstartselected = true; + mstart = p; + }; +} + +bool DragRectMode::cancelled() const +{ + return mcancelled; +} + +void DragRectMode::cancelConstruction() +{ + mcancelled = true; + mdoc.doneMode( this ); +} + diff --git a/kig/modes/dragrectmode.h b/kig/modes/dragrectmode.h new file mode 100644 index 00000000..29f92139 --- /dev/null +++ b/kig/modes/dragrectmode.h @@ -0,0 +1,104 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + + +#ifndef KIG_MODES_DRAGRECTMODE_H +#define KIG_MODES_DRAGRECTMODE_H + +#include "mode.h" + +#include "../misc/rect.h" + +#include <qpoint.h> +#include <vector> + +class ObjectHolder; + +/** + * DragRectMode is a mode that provides a rect for selecting the + * objects inside it. Here's an example of how to use it + * \code + * DragRectMode d( e->pos(), document, widget ); + * mDoc.runMode( &d ); + * Objects sel = d.ret(); + * \endcode + */ +class DragRectMode + : public KigMode +{ + QPoint mstart; + std::vector<ObjectHolder*> mret; + Rect mrect; + bool mnc; + bool mstartselected; + bool mcancelled; +private: + void clicked( const QPoint& p, KigWidget& w ); + void clicked( const QMouseEvent* e, KigWidget& w ); + void released( const QPoint& p, KigWidget& w, bool nc ); + void released( QMouseEvent* e, KigWidget& w ); + void moved( const QPoint& p, KigWidget& w ); + void moved( QMouseEvent*, KigWidget& w ); + + void leftClicked( QMouseEvent*, KigWidget* ); + void leftMouseMoved( QMouseEvent*, KigWidget* ); + void leftReleased( QMouseEvent*, KigWidget* ); + void midClicked( QMouseEvent*, KigWidget* ); + void midMouseMoved( QMouseEvent*, KigWidget* ); + void midReleased( QMouseEvent*, KigWidget* ); + void rightClicked( QMouseEvent*, KigWidget* ); + void rightMouseMoved( QMouseEvent*, KigWidget* ); + void rightReleased( QMouseEvent*, KigWidget* ); + void mouseMoved( QMouseEvent*, KigWidget* ); + + void cancelConstruction(); + + void enableActions(); + +public: + DragRectMode( const QPoint& start, KigPart& d, KigWidget& w ); + DragRectMode( KigPart& d, KigWidget& w ); + ~DragRectMode(); + + /** + * this returns the selected objects.. + */ + std::vector<ObjectHolder*> ret() const; + + /** + * this returns the selected rect.. + */ + Rect rect() const; + + /** + * this returns false if the control or shift button were pressed + * when the mouse button was released, and true otherwise. This is + * because the user expects us to not clear the selection before + * adding the newly selected objects if (s)he pressed control or + * shift.. + */ + bool needClear() const; + + /** + * whether the user cancelled the rect mode.. If this returns true, + * all the other return data above will be in undefined state, so + * first check this function's result.. + */ + bool cancelled() const; +}; + +#endif diff --git a/kig/modes/edittype.cc b/kig/modes/edittype.cc new file mode 100644 index 00000000..8c6b538f --- /dev/null +++ b/kig/modes/edittype.cc @@ -0,0 +1,107 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2004 Dominique Devriese <devriese@kde.org> + Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it> + + 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +**/ + + +#include "edittype.h" +#include "edittype.moc" + +#include <kapplication.h> +#include <kicondialog.h> +#include <klineedit.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpushbutton.h> +#include <kstdguiitem.h> + +EditType::EditType( QWidget* parent, QString name, QString desc, QString icon ) + : EditTypeBase( parent, "edittype", true ), mname( name ), mdesc( desc ), micon( icon ) +{ + // improving GUI look'n'feel... + buttonHelp->setGuiItem( KStdGuiItem::help() ); + buttonOk->setGuiItem( KStdGuiItem::ok() ); + buttonCancel->setGuiItem( KStdGuiItem::cancel() ); + + editName->setText( mname ); + editDescription->setText( mdesc ); + typeIcon->setIcon( !micon.isEmpty() ? micon : "gear" ); +} + +EditType::~EditType() +{ +} + +void EditType::helpSlot() +{ + kapp->invokeHelp( QString::fromLatin1( "working-with-types" ), + QString::fromLatin1( "kig" ) ); +} + +void EditType::okSlot() +{ + QString tmp = editName->text(); + if ( tmp.isEmpty() ) + { + KMessageBox::information( this, i18n( "The name of the macro can not be empty." ) ); + return; + } + + bool namechanged = false; + bool descchanged = false; + bool iconchanged = false; + if ( tmp != mname ) + { + mname = tmp; + namechanged = true; + } + tmp = editDescription->text(); + if ( tmp != mdesc ) + { + mdesc = tmp; + descchanged = true; + } + tmp = typeIcon->icon(); + if ( tmp != micon ) + { + micon = tmp; + iconchanged = true; + } + done( namechanged || descchanged || iconchanged ); +} + +void EditType::cancelSlot() +{ + done( 0 ); +} + +const QString EditType::name() const +{ + return mname; +} + +const QString EditType::description() const +{ + return mdesc; +} + +const QString EditType::icon() const +{ + return micon; +} diff --git a/kig/modes/edittype.h b/kig/modes/edittype.h new file mode 100644 index 00000000..c6530df5 --- /dev/null +++ b/kig/modes/edittype.h @@ -0,0 +1,48 @@ +// This file is part of Kig, a KDE program for Interactive Geometry... +// Copyright (C) 2004 Dominique Devriese <devriese@kde.org> +// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MODES_EDITTYPE_H +#define KIG_MODES_EDITTYPE_H + +#include "edittypebase.h" + +/** + * Simply dialog that allow the user the editing of a macro type... + */ +class EditType : public EditTypeBase +{ + Q_OBJECT + + QString mname; + QString mdesc; + QString micon; +public: + EditType( QWidget* parent, QString name = QString::null, QString desc = QString::null, QString icon = QString::null ); + ~EditType(); + const QString name() const; + const QString description() const; + const QString icon() const; + +public slots: + void helpSlot(); + void okSlot(); + void cancelSlot(); +}; + +#endif diff --git a/kig/modes/edittypebase.ui b/kig/modes/edittypebase.ui new file mode 100644 index 00000000..0dc8129d --- /dev/null +++ b/kig/modes/edittypebase.ui @@ -0,0 +1,287 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>EditTypeBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>EditTypeBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>481</width> + <height>142</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Edit Type</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>label15</cstring> + </property> + <property name="text"> + <string>Here you can modify the name, the description and the icon of this macro type.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>label16</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>editName</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can edit the name of the current macro type.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>label17</cstring> + </property> + <property name="text"> + <string>Description:</string> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>editDescription</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can edit the description of the current macro type. This field is optional, so you can also leave this empty: if you do so, then your macro type will have no description.</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout23</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIconButton"> + <property name="name"> + <cstring>typeIcon</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="whatsThis" stdset="0"> + <string>Use this button to change the icon of the current macro type.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>Line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout24</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonHelp</cstring> + </property> + <property name="text"> + <string>&Help</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>buttonHelp</sender> + <signal>clicked()</signal> + <receiver>EditTypeBase</receiver> + <slot>helpSlot()</slot> + </connection> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>EditTypeBase</receiver> + <slot>okSlot()</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>EditTypeBase</receiver> + <slot>cancelSlot()</slot> + </connection> +</connections> +<slots> + <slot>helpSlot()</slot> + <slot>okSlot()</slot> + <slot>cancelSlot()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kicondialog.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kig/modes/label.cc b/kig/modes/label.cc new file mode 100644 index 00000000..cd726918 --- /dev/null +++ b/kig/modes/label.cc @@ -0,0 +1,589 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "label.h" +#include "normal.h" + +#include "textlabelwizard.h" +#include "linkslabel.h" + +#include "../kig/kig_commands.h" +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/common.h" +#include "../misc/kigpainter.h" +#include "../objects/bogus_imp.h" +#include "../objects/curve_imp.h" +#include "../objects/object_factory.h" +#include "../objects/point_imp.h" +#include "../objects/text_imp.h" +#include "../objects/text_type.h" + +#include <kcursor.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <klocale.h> +#include <qtextedit.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <qregexp.h> +#include <qpopupmenu.h> +#include <qcheckbox.h> + +#include <algorithm> +#include <functional> + +class TextLabelModeBase::Private +{ +public: + // point last clicked.. + QPoint plc; + // the currently selected coordinate + Coordinate mcoord; + // the possible parent object that defines the location of the label.. + ObjectCalcer* locationparent; + + // the text is only kept in the text input widget, not here + // QString mtext; + + // the property objects we'll be using as args, we keep a reference + // to them in the args object, and keep a pointer to them ( or 0 ) + // in the correct order in args ( separately, because we can't use + // the order of the parents of a ReferenceObject, and certainly + // can't give 0 as a parent.. + argvect args; + + // if we're ReallySelectingArgs, then this var points to the arg + // we're currently selecting... + int mwaaws; + + // last percent count... + uint lpc; + + TextLabelWizard* wiz; + + // What Are We Doing + wawdtype mwawd; +}; + +TextLabelModeBase::~TextLabelModeBase() +{ + delete d->wiz; + delete d; +} + +TextLabelModeBase::TextLabelModeBase( KigPart& doc ) + : KigMode( doc ), d( new Private ) +{ + d->locationparent = 0; + d->lpc = 0; + d->mwawd = SelectingLocation; + d->wiz = new TextLabelWizard( doc.widget(), this ); +} + +void TextLabelModeBase::leftClicked( QMouseEvent* e, KigWidget* ) +{ + d->plc = e->pos(); + switch( d->mwawd ) + { + case RequestingText: + case SelectingArgs: + d->wiz->raise(); + d->wiz->setActiveWindow(); + break; + default: + break; + }; +} + +void TextLabelModeBase::leftReleased( QMouseEvent* e, KigWidget* v ) +{ + switch( d->mwawd ) + { + case SelectingLocation: + { + if ( ( d->plc - e->pos() ).manhattanLength() > 4 ) return; + setCoordinate( v->fromScreen( d->plc ) ); + break; + } + case RequestingText: + case SelectingArgs: + d->wiz->raise(); + d->wiz->setActiveWindow(); + break; + case ReallySelectingArgs: + { + if ( ( d->plc - e->pos() ).manhattanLength() > 4 ) break; + std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( v->fromScreen( d->plc ), *v ); + if ( os.empty() ) break; + ObjectHolder* o = os[0]; + QPopupMenu* p = new QPopupMenu( v, "text_label_select_arg_popup" ); + p->insertItem( i18n( "Name" ), 0 ); + QCStringList l = o->imp()->properties(); + assert( l.size() == o->imp()->numberOfProperties() ); + for ( int i = 0; static_cast<uint>( i ) < l.size(); ++i ) + { + QString s = i18n( l[i] ); + const char* iconfile = o->imp()->iconForProperty( i ); + int t; + if ( iconfile && *iconfile ) + { + QPixmap pix = mdoc.instance()->iconLoader()->loadIcon( iconfile, KIcon::User ); + t = p->insertItem( QIconSet( pix ), s, i + 1 ); + } + else + { + t = p->insertItem( s, i + 1 ); + }; + assert( t == i + 1 ); + }; + int result = p->exec( v->mapToGlobal( d->plc ) ); + ObjectCalcer::shared_ptr argcalcer; + if ( result == -1 ) break; + else if ( result == 0 ) + { + argcalcer = o->nameCalcer(); + if ( !argcalcer ) + { + ObjectConstCalcer* c = new ObjectConstCalcer( new StringImp( i18n( "<unnamed object>" ) ) ); + o->setNameCalcer( c ); + argcalcer = c; + } + } + else + { + assert( static_cast<uint>( result ) < l.size() + 1 ); + argcalcer = new ObjectPropertyCalcer( o->calcer(), result - 1 ); + } + d->args[d->mwaaws] = argcalcer.get(); + argcalcer->calc( mdoc.document() ); + + updateLinksLabel(); + updateWiz(); + break; + } + default: + assert( false ); + break; + }; +} + +void TextLabelModeBase::killMode() +{ + mdoc.doneMode( this ); +} + +void TextLabelModeBase::cancelConstruction() +{ + killMode(); +} + +void TextLabelModeBase::enableActions() +{ + KigMode::enableActions(); + + mdoc.aCancelConstruction->setEnabled( true ); +} + +void TextLabelModeBase::mouseMoved( QMouseEvent* e, KigWidget* w ) +{ + if ( d->mwawd == ReallySelectingArgs ) + { + std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( w->fromScreen( e->pos() ), *w ); + if ( !os.empty() ) w->setCursor( KCursor::handCursor() ); + else w->setCursor( KCursor::arrowCursor() ); + } + else if ( d->mwawd == SelectingLocation ) + { + std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( w->fromScreen( e->pos() ), *w ); + bool attachable = false; + d->locationparent = 0; + for ( std::vector<ObjectHolder*>::iterator i = os.begin(); i != os.end(); ++i ) + { + if( (*i)->imp()->attachPoint().valid() || + (*i)->imp()->inherits( PointImp::stype() ) || + (*i)->imp()->inherits( CurveImp::stype() ) ) + { + attachable = true; + d->locationparent = (*i)->calcer(); + break; + }; + }; + w->updateCurPix(); + if ( attachable ) + { + w->setCursor( KCursor::handCursor() ); + QString s = d->locationparent->imp()->type()->attachToThisStatement(); + mdoc.emitStatusBarText( s ); + + KigPainter p( w->screenInfo(), &w->curPix, mdoc.document() ); + + // set the text next to the arrow cursor + QPoint point = e->pos(); + point.setX(point.x()+15); + + p.drawTextStd( point, s ); + w->updateWidget( p.overlay() ); + } + else + { + w->setCursor( KCursor::crossCursor() ); + mdoc.emitStatusBarText( 0 ); + w->updateWidget(); + }; + } +} + +void TextLabelModeBase::enterTextPageEntered() +{ +} + +void TextLabelModeBase::selectArgumentsPageEntered() +{ + updateLinksLabel(); +} + +void TextLabelModeBase::cancelPressed() +{ + cancelConstruction(); +} + +static uint percentCount( const QString& s ) +{ +// QRegExp re( QString::fromUtf8( "%[0-9]" ) ); + QRegExp re( QString::fromUtf8( "%[\\d]+" ) ); + int offset = 0; + uint percentcount = 0; + while ( ( offset = re.search( s, offset ) ) != -1 ) + { + ++percentcount; + offset += re.matchedLength(); + }; + return percentcount; +} + +void TextLabelModeBase::finishPressed() +{ + bool needframe = d->wiz->needFrameCheckBox->isChecked(); + QString s = d->wiz->labelTextInput->text(); + + assert( percentCount( s ) == d->args.size() ); + if ( d->wiz->currentPage() == d->wiz->enter_text_page ) + assert( d->args.size() == 0 ); + + bool finished = true; + for ( argvect::iterator i = d->args.begin(); i != d->args.end(); ++i ) + finished &= ( *i != 0 ); + + if ( ! finished ) + KMessageBox::sorry( mdoc.widget(), + i18n( "There are '%n' parts in the text that you have not selected a " + "value for. Please remove them or select enough arguments." ) ); + else + { + finish( d->mcoord, s, d->args, needframe, d->locationparent ); + killMode(); + }; +} + +void TextLabelModeBase::updateWiz() +{ + QString s = d->wiz->labelTextInput->text(); + uint percentcount = percentCount( s ); + if ( d->lpc > percentcount ) + { + d->args = argvect( d->args.begin(), d->args.begin() + percentcount ); + } + else if ( d->lpc < percentcount ) + { + d->args.resize( percentcount, 0 ); + }; + + if ( percentcount == 0 && ! s.isEmpty() ) + { + d->wiz->setNextEnabled( d->wiz->enter_text_page, false ); + d->wiz->setFinishEnabled( d->wiz->enter_text_page, true ); + d->wiz->setAppropriate( d->wiz->select_arguments_page, false ); + } + else + { + d->wiz->setAppropriate( d->wiz->select_arguments_page, !s.isEmpty() ); + d->wiz->setNextEnabled( d->wiz->enter_text_page, ! s.isEmpty() ); + d->wiz->setFinishEnabled( d->wiz->enter_text_page, false ); + bool finished = true; + for ( argvect::iterator i = d->args.begin(); i != d->args.end(); ++i ) + finished &= ( *i != 0 ); + assert( percentCount( s ) == d->args.size() ); + + d->wiz->setFinishEnabled( d->wiz->select_arguments_page, finished ); + }; + + d->lpc = percentcount; +} + +void TextLabelModeBase::labelTextChanged() +{ + updateWiz(); +} + +void TextLabelModeBase::updateLinksLabel() +{ + LinksLabel::LinksLabelEditBuf buf = d->wiz->myCustomWidget1->startEdit(); + QString s = d->wiz->labelTextInput->text(); +// QRegExp re( "%[0-9]" ); + QRegExp re( "%[\\d]+" ); + int prevpos = 0; + int pos = 0; + uint count = 0; + // we split up the string into text and "links" + while ( ( pos = re.search( s, pos ) ) != -1 ) + { + // prevpos is the first character after the last match, pos is the + // first char of the current match.. + if ( prevpos != pos ) + { + // there is a text part between the previous and the current + // "link"... + assert( prevpos < pos ); + // fetch the text part... + QString subs = s.mid( prevpos, pos - prevpos ); + // and add it... + d->wiz->myCustomWidget1->addText( subs, buf ); + }; + // we always need a link part... + QString linktext( "%1" ); + assert( count < d->args.size() ); + if ( d->args[count] ) + { + // if the user has already selected a property, then we show its + // value... + d->args[count]->imp()->fillInNextEscape( linktext, mdoc.document() ); + } + else + // otherwise, we show a stub... + linktext = i18n( "argument %1" ).arg( count + 1 ); + + d->wiz->myCustomWidget1->addLink( linktext, buf ); + // set pos and prevpos to the next char after the last match, so + // we don't enter infinite loops... +// pos += 2; + pos += re.matchedLength(); + prevpos = pos; + ++count; + }; + + if ( static_cast<uint>( prevpos ) != s.length() ) + d->wiz->myCustomWidget1->addText( s.mid( prevpos ), buf ); + + d->wiz->myCustomWidget1->applyEdit( buf ); + d->wiz->relayoutArgsPage(); + + d->wiz->resize( d->wiz->size() ); +} + +void TextLabelModeBase::linkClicked( int i ) +{ + mdoc.widget()->setActiveWindow(); + mdoc.widget()->raise(); + + assert( d->args.size() >= static_cast<uint>( i + 1 ) ); + + d->mwawd = ReallySelectingArgs; + d->mwaaws = i; + + mdoc.emitStatusBarText( i18n( "Selecting argument %1" ).arg( i + 1 ) ); +} + +void TextLabelModeBase::redrawScreen( KigWidget* w ) +{ + w->redrawScreen( std::vector<ObjectHolder*>() ); + w->updateScrollBars(); +} + +void TextLabelModeBase::setCoordinate( const Coordinate& coord ) +{ + d->mcoord = coord; + if ( d->mwawd == SelectingLocation ) + { + d->mwawd = RequestingText; + updateWiz(); + d->wiz->show(); + // shouldn't be necessary, but seems to be anyway.. :( + updateWiz(); + }; +} + +void TextLabelModeBase::setText( const QString& s ) +{ + d->wiz->labelTextInput->setText( s ); +} + +void TextLabelModeBase::setPropertyObjects( const argvect& props ) +{ + d->args = props; + for ( argvect::iterator i = d->args.begin(); i != d->args.end(); ++i ) + (*i)->calc( mdoc.document() ); +} + +TextLabelConstructionMode::TextLabelConstructionMode( KigPart& d ) + : TextLabelModeBase( d ) +{ +} + +TextLabelConstructionMode::~TextLabelConstructionMode() +{ +} + +void TextLabelConstructionMode::finish( + const Coordinate& coord, const QString& s, + const argvect& props, bool needframe, + ObjectCalcer* locationparent ) +{ + std::vector<ObjectCalcer*> args; + for ( argvect::const_iterator i = props.begin(); + i != props.end(); ++i ) + args.push_back( i->get() ); + + ObjectHolder* label = 0; + if ( locationparent ) + label = ObjectFactory::instance()->attachedLabel( s, locationparent, coord, needframe, args, mdoc.document() ); + else + label = ObjectFactory::instance()->label( s, coord, needframe, args, mdoc.document() ); + mdoc.addObject( label ); +} + +TextLabelRedefineMode::TextLabelRedefineMode( KigPart& d, ObjectTypeCalcer* label ) + : TextLabelModeBase( d ), mlabel( label ) +{ + assert( label->imp()->inherits( TextImp::stype() ) ); + std::vector<ObjectCalcer*> parents = label->parents(); + assert( parents.size() >= 3 ); + std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 ); + std::vector<ObjectCalcer*> rest( parents.begin() + 3, parents.end() ); + firstthree = TextType::instance()->argParser().parse( firstthree ); + + assert( firstthree[0]->imp()->inherits( IntImp::stype() ) ); + assert( firstthree[1]->imp()->inherits( PointImp::stype() ) ); + assert( firstthree[2]->imp()->inherits( StringImp::stype() ) ); + + bool frame = static_cast<const IntImp*>( firstthree[0]->imp() )->data() != 0; + Coordinate coord = static_cast<const PointImp*>( firstthree[1]->imp() )->coordinate(); + QString text = static_cast<const StringImp*>( firstthree[2]->imp() )->data(); + + // don't set it, let the user redefine it.. +// setCoordinate( coord ); + setText( text ); + setFrame( frame ); + + argvect v; + for ( uint i = 0; i < rest.size(); ++i ) + { + v.push_back( rest[i] ); + }; + assert( v.size() == rest.size() ); + + setPropertyObjects( v ); +} + +TextLabelRedefineMode::~TextLabelRedefineMode() +{ +} + +void TextLabelRedefineMode::finish( + const Coordinate& coord, const QString& s, + const argvect& props, bool needframe, + ObjectCalcer* locationparent ) +{ + std::vector<ObjectCalcer*> parents = mlabel->parents(); + assert( parents.size() >= 3 ); + std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 ); + std::vector<ObjectCalcer*> rest( parents.begin() + 3, parents.end() ); + firstthree = TextType::instance()->argParser().parse( firstthree ); + + KigCommand* kc = new KigCommand( mdoc, i18n( "Change Label" ) ); + MonitorDataObjects mon( firstthree ); + + assert( firstthree[0]->imp()->inherits( IntImp::stype() ) ); + assert( firstthree[1]->imp()->inherits( PointImp::stype() ) ); + assert( firstthree[2]->imp()->inherits( StringImp::stype() ) ); + + assert( dynamic_cast<ObjectConstCalcer*>( firstthree[0] ) ); + assert( dynamic_cast<ObjectConstCalcer*>( firstthree[2] ) ); + static_cast<ObjectConstCalcer*>( firstthree[0] )->setImp( new IntImp( needframe ? 1 : 0 ) ); + + // we don't do this, because + // 1 this isn't necessarily a DataObject, we also support it to be a + // user-known point, or an internal constrained point.. + // 2 we don't know that we don't want it to become a user-known + // point or an internal constrained point, instead of a + // DataObject.. + // static_cast<DataObject*>( firstthree[1] )->setImp( new PointImp( + // coord ) ); + + static_cast<ObjectConstCalcer*>( firstthree[2] )->setImp( new StringImp( s ) ); + mon.finish( kc ); + + std::vector<ObjectCalcer*> oldparents = mlabel->parents(); + std::vector<ObjectCalcer*> p; + for ( argvect::const_iterator i = props.begin(); + i != props.end(); ++i ) + p.push_back( i->get() ); + for ( std::vector<ObjectCalcer*>::iterator i = p.begin(); + i != p.end(); ++i ) + ( *i )->calc( mdoc.document() ); + + std::vector<ObjectCalcer*> np = firstthree; + /* + * take advantage of the method "getAttachPoint" that should + * do all the work; it is also used when creating a new label + */ + np[1] = ObjectFactory::instance()->getAttachPoint( locationparent, coord, mdoc.document() ); + +/* this is the old code, just in case... */ +// if ( locationparent && locationparent->imp()->inherits( CurveImp::stype() ) ) +// { +// double param = static_cast<const CurveImp*>( locationparent->imp() )->getParam( coord, mdoc.document() ); +// np[1] = ObjectFactory::instance()->constrainedPointCalcer( locationparent, param ); +// np[1]->calc( mdoc.document() ); +// } +// else if ( locationparent ) +// { +// assert( locationparent->imp()->inherits( PointImp::stype() ) ); +// np[1] = locationparent; +// } +// else +// np[1] = new ObjectConstCalcer( new PointImp( coord ) ); + + copy( p.begin(), p.end(), back_inserter( np ) ); + + kc->addTask( + new ChangeParentsAndTypeTask( + mlabel, np, TextType::instance() ) ); + + mdoc.history()->addCommand( kc ); +} + +void TextLabelModeBase::setFrame( bool f ) +{ + d->wiz->needFrameCheckBox->setChecked( f ); +} + +void TextLabelModeBase::setLocationParent( ObjectCalcer* o ) +{ + d->locationparent = o; +} diff --git a/kig/modes/label.h b/kig/modes/label.h new file mode 100644 index 00000000..4a3d09f7 --- /dev/null +++ b/kig/modes/label.h @@ -0,0 +1,129 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MODE_LABEL_H +#define KIG_MODE_LABEL_H + +#include "mode.h" + +#include "../objects/object_calcer.h" + +#include <vector> + +class TextLabelWizard; +class NormalMode; +class Coordinate; +class QString; +class ObjectPropertyCalcer; +class ObjectTypeCalcer; +class ObjectCalcer; + +/** + * this is the base class for TextLabelConstructionMode and + * TextLabelRedefineMode.. most of the work is done in this class, + * with some specific things delegated to the children.. Template + * method pattern, right ? :) + */ +class TextLabelModeBase + : public KigMode +{ + class Private; + Private* d; + +public: + // below is the interface towards TextLabelWizard... + void cancelPressed(); + void finishPressed(); + void enterTextPageEntered(); + void selectArgumentsPageEntered(); + void labelTextChanged(); + void linkClicked( int ); + void redrawScreen( KigWidget* w ); + +protected: + typedef std::vector<ObjectCalcer::shared_ptr> argvect; + // the protected interface for subclasses + TextLabelModeBase( KigPart& d ); + ~TextLabelModeBase(); + + void setCoordinate( const Coordinate& coord ); + void setText( const QString& s ); + void setLocationParent( ObjectCalcer* o ); + /** + * objects you pass here, should be newly created property objects, + * that have no children.. + */ + void setPropertyObjects( const argvect& props ); + void setFrame( bool f ); + + virtual void finish( const Coordinate& c, const QString& s, + const argvect& props, bool needframe, + ObjectCalcer* locationparent ) = 0; + +private: + // the KigMode interface.. + void leftClicked( QMouseEvent*, KigWidget* ); + void leftReleased( QMouseEvent*, KigWidget* ); + + void mouseMoved( QMouseEvent*, KigWidget* ); + + void enableActions(); + + void cancelConstruction(); + + void killMode(); + +private: + /** + * \internal + * What Are We Doing... + * the diff between SelectingArgs and ReallySelectingArgs is that + * the latter means the user is selecting an arg in the kig window, + * whereas the first only means that he's looking at the second + * page of the wizard... + */ + typedef enum { SelectingLocation, RequestingText, SelectingArgs, ReallySelectingArgs } wawdtype; + + void updateWiz(); + void updateLinksLabel(); +}; + +class TextLabelConstructionMode + : public TextLabelModeBase +{ +public: + TextLabelConstructionMode( KigPart& d ); + ~TextLabelConstructionMode(); + + void finish( const Coordinate& coord, const QString& s, + const argvect& props, bool needframe, + ObjectCalcer* locationparent ); +}; + +class TextLabelRedefineMode + : public TextLabelModeBase +{ + ObjectTypeCalcer* mlabel; + void finish( const Coordinate& coord, const QString& s, + const argvect& props, bool needframe, + ObjectCalcer* locationparent ); +public: + TextLabelRedefineMode( KigPart& d, ObjectTypeCalcer* label ); + ~TextLabelRedefineMode(); +}; + +#endif diff --git a/kig/modes/linkslabel.cpp b/kig/modes/linkslabel.cpp new file mode 100644 index 00000000..572c0bf8 --- /dev/null +++ b/kig/modes/linkslabel.cpp @@ -0,0 +1,134 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// 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 +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + + +#include "linkslabel.h" +#include "linkslabel.moc" + +#include <qlabel.h> +#include <kurllabel.h> +#include <qlayout.h> + +#include <vector> +#include <algorithm> +#include <functional> + +#include <assert.h> +using namespace std; + +class LinksLabel::Private +{ +public: + QHBoxLayout* layout; + std::vector<QLabel*> labels; + std::vector<KURLLabel*> urllabels; +}; + +LinksLabel::LinksLabel( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + p = new Private; + p->layout = new QHBoxLayout( this ); + + QLabel* l = new QLabel( QString::fromUtf8( "Dit is een " ), this ); + p->labels.push_back( l ); + p->layout->addWidget( l ); + + KURLLabel* u = new KURLLabel( QString::fromUtf8( "http://www.kde.org/" ), + QString::fromUtf8( "url"), this ); + p->urllabels.push_back( u ); + p->layout->addWidget( u ); + + l = new QLabel( QString::fromUtf8( " !" ), this ); + p->labels.push_back( l ); + p->layout->addWidget(l ); + + p->layout->activate(); +} + +LinksLabel::~LinksLabel() +{ + delete p; +} + +void LinksLabel::urlClicked() +{ + const QObject* o = sender(); + std::vector<KURLLabel*>::iterator i = std::find( p->urllabels.begin(), p->urllabels.end(), static_cast<const KURLLabel*>( o ) ); + assert( i != p->urllabels.end() ); + emit linkClicked( i - p->urllabels.begin() ); +} + +LinksLabel::LinksLabelEditBuf LinksLabel::startEdit() +{ + return LinksLabelEditBuf(); +} + +void LinksLabel::addText( const QString& s, LinksLabelEditBuf& buf ) +{ + buf.data.push_back( std::pair<bool, QString>( false, s ) ); +} + +void LinksLabel::addLink( const QString& s, LinksLabelEditBuf& buf ) +{ + buf.data.push_back( std::pair<bool, QString>( true, s ) ); +} + +namespace { + void deleteObj( QObject* o ) { delete o; } +} + +void LinksLabel::applyEdit( LinksLabelEditBuf& buf ) +{ + std::for_each( p->urllabels.begin(), p->urllabels.end(), deleteObj ); + std::for_each( p->labels.begin(), p->labels.end(), deleteObj ); + p->urllabels.clear(); + p->labels.clear(); + + delete p->layout; + p->layout = new QHBoxLayout( this ); + + for ( LinksLabelEditBuf::vec::iterator i = buf.data.begin(); i != buf.data.end(); ++i ) + { + if ( i->first ) + { + // we need a KURLLabel... + // the url is an unused stub... + KURLLabel* l = new KURLLabel( QString::fromUtf8( "http://edu.kde.org/kig" ), + i->second, this ); + p->urllabels.push_back( l ); + p->layout->addWidget( l ); + connect( l, SIGNAL( leftClickedURL() ), SLOT( urlClicked() ) ); + } + else + { + // we need a normal label... + QLabel* l = new QLabel( i->second, this ); + p->labels.push_back( l ); + p->layout->addWidget( l ); + }; + }; + + QSpacerItem* spacer = new QSpacerItem( 40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); + + p->layout->addItem( spacer ); + + p->layout->activate(); + + std::for_each( p->urllabels.begin(), p->urllabels.end(), mem_fun( &QWidget::show ) ); + std::for_each( p->labels.begin(), p->labels.end(), mem_fun( &QWidget::show ) ); +} diff --git a/kig/modes/linkslabel.h b/kig/modes/linkslabel.h new file mode 100644 index 00000000..ba64dbc2 --- /dev/null +++ b/kig/modes/linkslabel.h @@ -0,0 +1,85 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// 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 +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#ifndef KIG_lINKS_LABEL_H +#define KIG_lINKS_LABEL_H + +#include <qwidget.h> + +#include <vector> +#include <utility> + +/** + * this widget shows a line of text, with some links underlined, and + * emits a signal if one of the links is clicked... + */ +class LinksLabel : public QWidget +{ + Q_OBJECT + +public: + LinksLabel( QWidget* parent = 0, const char* name = 0 ); + ~LinksLabel(); + + class LinksLabelEditBuf + { + public: + friend class LinksLabel; + ~LinksLabelEditBuf() {} + private: + // declare these private so only LinksLabel can use them... + LinksLabelEditBuf() {} + typedef std::vector<std::pair<bool,QString> > vec; + vec data; + }; + + /** + * start editing, start recording changes in a LinksLabelEditBuf, + * but don't apply them until after endEdit(); + */ + LinksLabelEditBuf startEdit(); + /** + * add a piece of normal text.. + */ + void addText( const QString& s, LinksLabelEditBuf& buf ); + /** + * add a link... + */ + void addLink( const QString& s, LinksLabelEditBuf& buf ); + /** + * apply the changes... This clears the current contents and adds + * the new data... + */ + void applyEdit( LinksLabelEditBuf& buf ); + +signals: + /** + * the user clicked on a link. The index is the order in which it + * was added. E.g. this signal is emitted with arg 0 if the link + * you first added is clicked, argument 2 for the third link etc. + */ + void linkClicked( int i ); + +private slots: + void urlClicked(); + +private: + class Private; + Private* p; +}; + +#endif // KDE_URLS_LABEL_H diff --git a/kig/modes/macro.cc b/kig/modes/macro.cc new file mode 100644 index 00000000..879466dc --- /dev/null +++ b/kig/modes/macro.cc @@ -0,0 +1,245 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "macro.h" + +#include "macrowizard.h" +#include "dragrectmode.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/kigpainter.h" +#include "../misc/object_constructor.h" +#include "../misc/lists.h" +#include "../misc/guiaction.h" +#include "../objects/object_imp.h" + +#include <klineedit.h> +#include <kmessagebox.h> +#include <kcursor.h> +#include <klocale.h> + +#include <functional> +#include <algorithm> + +using namespace std; + +DefineMacroMode::DefineMacroMode( KigPart& d ) + : BaseMode( d ) +{ + mwizard = new MacroWizard( d.widget(), this ); + mwizard->show(); + updateNexts(); +} + +DefineMacroMode::~DefineMacroMode() +{ + delete mwizard; +} + +void DefineMacroMode::abandonMacro() +{ + mdoc.doneMode( this ); +} + +void DefineMacroMode::updateNexts() +{ + mwizard->setNextEnabled( mwizard->mpgiven, + !mgiven.empty() ); + mwizard->setNextEnabled( mwizard->mpfinal, + !mfinal.empty() ); + mwizard->setFinishEnabled( + mwizard->mpname, + !mwizard->KLineEdit2->text().isEmpty() + ); +} + +void DefineMacroMode::enableActions() +{ + KigMode::enableActions(); + // we don't enable any actions... +} + +void DefineMacroMode::givenPageEntered() +{ + std::vector<ObjectHolder*> given( mgiven.begin(), mgiven.end() ); + static_cast<KigView*>( mdoc.widget() )->realWidget()->redrawScreen( given ); + updateNexts(); +} + +void DefineMacroMode::finalPageEntered() +{ + std::vector<ObjectHolder*> final( mfinal.begin(), mfinal.end() ); + static_cast<KigView*>( mdoc.widget() )->realWidget()->redrawScreen( final ); + + updateNexts(); +} + +void DefineMacroMode::namePageEntered() +{ + ObjectCalcer* (ObjectHolder::*memfun)() = &ObjectHolder::calcer; + std::vector<ObjectCalcer*> given; + std::transform( mgiven.begin(), mgiven.end(), + std::back_inserter( given ), + std::mem_fun( memfun ) ); + std::vector<ObjectCalcer*> final; + std::transform( mfinal.begin(), mfinal.end(), + std::back_inserter( final ), + std::mem_fun( memfun ) ); + ObjectHierarchy hier( given, final ); + if ( hier.resultDoesNotDependOnGiven() ) + { + KMessageBox::sorry( mwizard, + i18n( "One of the result objects you selected " + "cannot be calculated from the given objects. " + "Kig cannot calculate this macro because of this. " + "Please press Back, and construct the objects " + "in the correct order..." ) ); + mwizard->back(); + } + else if( !hier.allGivenObjectsUsed() ) + { + KMessageBox::sorry( mwizard, + i18n( "One of the given objects is not used in the " + "calculation of the resultant objects. This " + "probably means you are expecting Kig to do " + "something impossible. Please check the " + "macro and try again." ) ); + mwizard->back(); + } + + static_cast<KigView*>( mdoc.widget() )->realWidget()->redrawScreen( std::vector<ObjectHolder*>() ); + + updateNexts(); +} + +void DefineMacroMode::finishPressed() +{ + ObjectCalcer* (ObjectHolder::*memfun)() = &ObjectHolder::calcer; + std::vector<ObjectCalcer*> given; + std::transform( mgiven.begin(), mgiven.end(), + std::back_inserter( given ), + std::mem_fun( memfun ) ); + std::vector<ObjectCalcer*> final; + std::transform( mfinal.begin(), mfinal.end(), + std::back_inserter( final ), + std::mem_fun( memfun ) ); + ObjectHierarchy hier( given, final ); + MacroConstructor* ctor = + new MacroConstructor( hier, + mwizard->KLineEdit2->text(), + mwizard->KLineEdit1->text() ); + ConstructibleAction* act = new ConstructibleAction( ctor, 0 ); + MacroList::instance()->add( new Macro( act, ctor ) ); + + abandonMacro(); +} + +void DefineMacroMode::cancelPressed() +{ + abandonMacro(); +} + +void DefineMacroMode::macroNameChanged() +{ + mwizard->setFinishEnabled( + mwizard->mpname, + !mwizard->KLineEdit2->text().isEmpty() + ); +} + +void DefineMacroMode::dragRect( const QPoint& p, KigWidget& w ) +{ + if ( mwizard->currentPage() == mwizard->mpname ) return; + std::vector<ObjectHolder*>* objs = mwizard->currentPage() == mwizard->mpgiven ? &mgiven : &mfinal; + DragRectMode dm( p, mdoc, w ); + mdoc.runMode( &dm ); + KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() ); + if ( ! dm.cancelled() ) + { + std::vector<ObjectHolder*> ret = dm.ret(); + if ( dm.needClear() ) + { + pter.drawObjects( objs->begin(), objs->end(), false ); + objs->clear(); + } + + std::copy( ret.begin(), ret.end(), std::back_inserter( *objs ) ); + pter.drawObjects( objs->begin(), objs->end(), true ); + }; + w.updateCurPix( pter.overlay() ); + w.updateWidget(); + + updateNexts(); +} + +void DefineMacroMode::leftClickedObject( ObjectHolder* o, const QPoint&, + KigWidget& w, bool ) +{ + if ( mwizard->currentPage() == mwizard->mpname ) return; + std::vector<ObjectHolder*>* objs = mwizard->currentPage() == mwizard->mpgiven ? &mgiven : &mfinal; + std::vector<ObjectHolder*>::iterator iter = std::find( objs->begin(), objs->end(), o ); + bool isselected = ( iter != objs->end() ); + if ( isselected ) objs->erase( iter ); + else objs->push_back( o ); + + KigPainter p( w.screenInfo(), &w.stillPix, mdoc.document() ); + p.drawObject( o, !isselected ); + w.updateCurPix( p.overlay() ); + w.updateWidget(); + + updateNexts(); +} + +void DefineMacroMode::mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& pt, KigWidget& w, bool ) +{ + w.updateCurPix(); + + if ( os.empty() ) + { + w.setCursor( KCursor::arrowCursor() ); + mdoc.emitStatusBarText( 0 ); + w.updateWidget(); + } + else + { + // the cursor is over an object, show object type next to cursor + // and set statusbar text + + w.setCursor( KCursor::handCursor() ); + QString selectstat = os.front()->selectStatement(); + + // statusbar text + mdoc.emitStatusBarText( selectstat ); + KigPainter p( w.screenInfo(), &w.curPix, mdoc.document() ); + + // set the text next to the arrow cursor + QPoint point = pt; + point.setX(point.x()+15); + + p.drawTextStd( point, selectstat ); + w.updateWidget( p.overlay() ); + } +} + +void DefineMacroMode::rightClicked( const std::vector<ObjectHolder*>&, const QPoint&, KigWidget& ) +{ +} + +void DefineMacroMode::midClicked( const QPoint&, KigWidget& ) +{ +} + diff --git a/kig/modes/macro.h b/kig/modes/macro.h new file mode 100644 index 00000000..4bf8c43e --- /dev/null +++ b/kig/modes/macro.h @@ -0,0 +1,68 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MODES_MACRO_H +#define KIG_MODES_MACRO_H + +#include "base_mode.h" + +#include <qobject.h> + +class MacroWizard; + +class DefineMacroMode + : public BaseMode +{ +public: + DefineMacroMode( KigPart& ); + ~DefineMacroMode(); + + void dragRect( const QPoint& p, KigWidget& w ); + void leftClickedObject( ObjectHolder* o, const QPoint& p, + KigWidget& w, bool ctrlOrShiftDown ); + void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w ); + void midClicked( const QPoint& p, KigWidget& w ); + void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed ); + + // called by MacroWizard class + void givenPageEntered(); + void finalPageEntered(); + void namePageEntered(); + void finishPressed(); + void cancelPressed(); + void macroNameChanged(); + +protected: + void enableActions(); + /** + * update the enabled state of the next buttons on the wizard... + */ + void updateNexts(); + /** + * quit this mode... + */ + void abandonMacro(); + + QPoint plc; + MacroWizard* mwizard; + + // we can't use a set for this because the order is important + std::vector<ObjectHolder*> mgiven; + std::vector<ObjectHolder*> mfinal; +}; + +#endif diff --git a/kig/modes/macrowizard.cc b/kig/modes/macrowizard.cc new file mode 100644 index 00000000..e6315caf --- /dev/null +++ b/kig/modes/macrowizard.cc @@ -0,0 +1,90 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "macrowizard.h" +#include "macrowizard.moc" + +#include "macro.h" + +#include <kdebug.h> +#include <klineedit.h> +#include <kapplication.h> + +MacroWizard::MacroWizard( QWidget* parent, DefineMacroMode* m ) + : MacroWizardBase( parent, "Define Macro Wizard", false ), mmode( m ) +{ + connect( KLineEdit2, SIGNAL( textChanged( const QString& ) ), + this, SLOT( nameTextChanged( const QString& ) ) ); + connect( this, SIGNAL( helpClicked() ), this, + SLOT( slotHelpClicked() ) ); +} + +MacroWizard::~MacroWizard() +{ +} + +void MacroWizard::back() +{ + if ( currentPage() == mpfinal ) + { + // currentPage() is not yet updated when we get here, so this + // means that the page about to be shown is actually mpgiven... + mmode->givenPageEntered(); + } + else if ( currentPage() == mpname ) + { + mmode->finalPageEntered(); + } + MacroWizardBase::back(); +} + +void MacroWizard::next() +{ + if ( currentPage() == mpgiven ) + { + // currentPage() is not yet updated when we get here, so this + // means that the page about to be shown is actually mpfinal... + mmode->finalPageEntered(); + } + else if ( currentPage() == mpfinal ) + { + mmode->namePageEntered(); + } + MacroWizardBase::next(); +} + +void MacroWizard::reject() +{ + MacroWizardBase::reject(); + mmode->cancelPressed(); +} + +void MacroWizard::nameTextChanged( const QString& ) +{ + mmode->macroNameChanged(); +} + +void MacroWizard::accept() +{ + mmode->finishPressed(); +} + +void MacroWizard::slotHelpClicked() +{ + kapp->invokeHelp( QString::fromLatin1( "defining-macros"), + QString::fromLatin1( "kig" ) ); +} diff --git a/kig/modes/macrowizard.h b/kig/modes/macrowizard.h new file mode 100644 index 00000000..dfce8b06 --- /dev/null +++ b/kig/modes/macrowizard.h @@ -0,0 +1,43 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef MACROWIZARD_H +#define MACROWIZARD_H + +#include "macrowizardbase.h" + +class DefineMacroMode; + +class MacroWizard : public MacroWizardBase +{ + Q_OBJECT +public: + MacroWizard( QWidget* parent, DefineMacroMode* m ); + ~MacroWizard(); + + void back(); + void next(); + void reject(); + void accept(); +private slots: + void nameTextChanged( const QString& ); + void slotHelpClicked(); +private: + DefineMacroMode* mmode; +}; + +#endif // MACROWIZARD_H diff --git a/kig/modes/macrowizardbase.ui b/kig/modes/macrowizardbase.ui new file mode 100644 index 00000000..d3929ad8 --- /dev/null +++ b/kig/modes/macrowizardbase.ui @@ -0,0 +1,188 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>MacroWizardBase</class> +<widget class="QWizard"> + <property name="name"> + <cstring>MacroWizardBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>4</x> + <y>0</y> + <width>344</width> + <height>172</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Define New Macro</string> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>mpgiven</cstring> + </property> + <attribute name="title"> + <string>Given Objects</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Select the "given" objects for your new macro and press "Next".</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>mpfinal</cstring> + </property> + <attribute name="title"> + <string>Final Object</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>Select the final object(s) for your new macro.</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>mpname</cstring> + </property> + <attribute name="title"> + <string>Name</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel1_2</cstring> + </property> + <property name="text"> + <string>Enter a name and description for your new type.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel2_2</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>KLineEdit2</cstring> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>KLineEdit2</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel2_2_2</cstring> + </property> + <property name="text"> + <string>Description:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>KLineEdit1</cstring> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>KLineEdit1</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/kig/modes/mode.cc b/kig/modes/mode.cc new file mode 100644 index 00000000..9d95b64d --- /dev/null +++ b/kig/modes/mode.cc @@ -0,0 +1,133 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + + 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +**/ + +#include "mode.h" + +#include "../kig/kig_part.h" + +#include <kaction.h> + +void KigMode::enableActions() +{ + mdoc.enableConstructActions( false ); + mdoc.aSelectAll->setEnabled( false ); + mdoc.aDeselectAll->setEnabled( false ); + mdoc.aInvertSelection->setEnabled( false ); + mdoc.aCancelConstruction->setEnabled( false ); + mdoc.aConfigureTypes->setEnabled( false ); + mdoc.aDeleteObjects->setEnabled( false ); + mdoc.aShowHidden->setEnabled( false ); + mdoc.aNewMacro->setEnabled( false ); + mdoc.action( "edit_undo" )->setEnabled( false ); + mdoc.action( "edit_redo" )->setEnabled( false ); +} + +KigMode::~KigMode() +{ +} + +KigMode::KigMode( KigPart& d ) + : mdoc( d ) +{ +} + +void KigMode::leftClicked( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::leftMouseMoved( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::leftReleased( QMouseEvent*, KigWidget* ) +{ + /* insist disabling the undo button to avoid crashes */ + mdoc.action( "edit_undo" )->setEnabled( false ); + mdoc.action( "edit_redo" )->setEnabled( false ); +} + +void KigMode::midClicked( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::midMouseMoved( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::midReleased( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::rightClicked( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::rightMouseMoved( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::rightReleased( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::mouseMoved( QMouseEvent*, KigWidget* ) +{ +} + +void KigMode::cancelConstruction() +{ +} + +void KigMode::deleteObjects() +{ +} + +void KigMode::showHidden() +{ +} + +void KigMode::newMacro() +{ +} + +void KigMode::editTypes() +{ +} + +void KigMode::redrawScreen( KigWidget* ) +{ +} + +StdConstructionMode* KigMode::toStdConstructionMode() +{ + return 0; +} + +void KigMode::selectAll() +{ +} + +void KigMode::deselectAll() +{ +} + +void KigMode::invertSelection() +{ +} diff --git a/kig/modes/mode.h b/kig/modes/mode.h new file mode 100644 index 00000000..6f476072 --- /dev/null +++ b/kig/modes/mode.h @@ -0,0 +1,91 @@ +/* + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + + 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +*/ + +#ifndef KIG_PART_MODE_H +#define KIG_PART_MODE_H + +#include <qnamespace.h> + +class KigDocument; +class KigPart; +class KigWidget; +class QMouseEvent; +class StdConstructionMode; + +/** + * this is an ABC of a class containing the current "Mode" of the Kig + * document... It tells us how to respond to a certain event. + */ +class KigMode + : public Qt +{ +public: + virtual ~KigMode(); + + virtual StdConstructionMode* toStdConstructionMode(); + + virtual void leftClicked( QMouseEvent*, KigWidget* ); + /** + * this means: mouse moved with left mouse button down (in case that + * wasn't clear...) + */ + virtual void leftMouseMoved( QMouseEvent*, KigWidget* ); + virtual void leftReleased( QMouseEvent*, KigWidget* ); + virtual void midClicked( QMouseEvent*, KigWidget* ); + virtual void midMouseMoved( QMouseEvent*, KigWidget* ); + virtual void midReleased( QMouseEvent*, KigWidget* ); + virtual void rightClicked( QMouseEvent*, KigWidget* ); + virtual void rightMouseMoved( QMouseEvent*, KigWidget* ); + virtual void rightReleased( QMouseEvent*, KigWidget* ); + /** + * mouse moved without any buttons down... + */ + virtual void mouseMoved( QMouseEvent*, KigWidget* ); + + /** + * actions: we enable the actions we want when our mode is made + * active. These actions are members of KigDocument, and call slots + * on KigDocument. These slots all call the correspondent mode() + * member. Modes reimplement the ones they need, and turn on the + * actions they support in enableActions(). + */ + virtual void enableActions(); + + virtual void cancelConstruction(); + virtual void deleteObjects(); + virtual void showHidden(); + virtual void newMacro(); + virtual void editTypes(); + virtual void selectAll(); + virtual void deselectAll(); + virtual void invertSelection(); + + /** + * Redraw the document on KigWidget \p w . It's up to the mode to + * refresh the screen... + */ + virtual void redrawScreen( KigWidget* w ); +protected: + KigPart& mdoc; + + KigMode( KigPart& d ); +}; + +#endif diff --git a/kig/modes/moving.cc b/kig/modes/moving.cc new file mode 100644 index 00000000..e628a7ce --- /dev/null +++ b/kig/modes/moving.cc @@ -0,0 +1,245 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "moving.h" + +#include "normal.h" + +#include "../objects/object_imp.h" +#include "../objects/object_factory.h" +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../kig/kig_commands.h" +#include "../misc/kigpainter.h" +#include "../misc/calcpaths.h" +#include "../misc/coordinate_system.h" + +#include <qevent.h> + +#include <functional> +#include <algorithm> +#include <map> + +void MovingModeBase::initScreen( const std::vector<ObjectCalcer*>& in ) +{ + mcalcable = in; + std::set<ObjectCalcer*> calcableset( mcalcable.begin(), mcalcable.end() ); + + // don't try to move objects that have been deleted from the + // document or internal objects that the user is not aware of.. + std::vector<ObjectHolder*> docobjs = mdoc.document().objects(); + for ( std::vector<ObjectHolder*>::iterator i = docobjs.begin(); + i != docobjs.end(); ++i ) + if ( calcableset.find( ( *i )->calcer() ) != calcableset.end() ) + mdrawable.push_back( *i ); + + std::set<ObjectHolder*> docobjsset( docobjs.begin(), docobjs.end() ); + std::set<ObjectHolder*> drawableset( mdrawable.begin(), mdrawable.end() ); + std::set<ObjectHolder*> notmovingobjs; + std::set_difference( docobjsset.begin(), docobjsset.end(), drawableset.begin(), drawableset.end(), + std::inserter( notmovingobjs, notmovingobjs.begin() ) ); + + mview.clearStillPix(); + KigPainter p( mview.screenInfo(), &mview.stillPix, mdoc.document() ); + p.drawGrid( mdoc.document().coordinateSystem(), mdoc.document().grid(), + mdoc.document().axes() ); + p.drawObjects( notmovingobjs.begin(), notmovingobjs.end(), false ); + mview.updateCurPix(); + + KigPainter p2( mview.screenInfo(), &mview.curPix, mdoc.document() ); + p2.drawObjects( drawableset.begin(), drawableset.end(), true ); +} + +void MovingModeBase::leftReleased( QMouseEvent*, KigWidget* v ) +{ + // clean up after ourselves: + for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin(); + i != mcalcable.end(); ++i ) + ( *i )->calc( mdoc.document() ); + stopMove(); + mdoc.setModified( true ); + + // refresh the screen: + v->redrawScreen( std::vector<ObjectHolder*>() ); + v->updateScrollBars(); + + mdoc.doneMode( this ); +} + +void MovingModeBase::mouseMoved( QMouseEvent* e, KigWidget* v ) +{ + v->updateCurPix(); + Coordinate c = v->fromScreen( e->pos() ); + + bool snaptogrid = e->state() & Qt::ShiftButton; + moveTo( c, snaptogrid ); + for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin(); + i != mcalcable.end(); ++i ) + ( *i )->calc( mdoc.document() ); + KigPainter p( v->screenInfo(), &v->curPix, mdoc.document() ); + // TODO: only draw the explicitly moving objects as selected, the + // other ones as deselected.. Needs some support from the + // subclasses.. + p.drawObjects( mdrawable, true ); + v->updateWidget( p.overlay() ); + v->updateScrollBars(); +} + +class MovingMode::Private +{ +public: + // explicitly moving objects: these are the objects that the user + // requested to move... + std::vector<ObjectCalcer*> emo; + // point where we started moving.. + Coordinate pwwsm; + MonitorDataObjects* mon; + // we keep a map from the emo objects to their reference location. + // This is the location that they claim to be at before moving + // starts, and we use it as a reference point to determine where + // they should move next.. + std::map<const ObjectCalcer*, Coordinate> refmap; +}; + +MovingMode::MovingMode( const std::vector<ObjectHolder*>& os, const Coordinate& c, + KigWidget& v, KigPart& doc ) + : MovingModeBase( doc, v ), d( new Private ) +{ + d->pwwsm = c; + std::vector<ObjectCalcer*> emo; + std::set<ObjectCalcer*> objs; + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + if ( (*i)->canMove() ) + { + emo.push_back( ( *i )->calcer() ); + d->refmap[( *i )->calcer()] = (*i)->moveReferencePoint(); + objs.insert( ( *i )->calcer() ); + std::vector<ObjectCalcer*> parents = ( *i )->calcer()->movableParents(); + objs.insert( parents.begin(), parents.end() ); + }; + + emo = calcPath( emo ); + for ( std::vector<ObjectCalcer*>::const_iterator i = emo.begin(); i != emo.end(); ++i ) + if ( !isChild( *i, d->emo ) ) + d->emo.push_back( *i ); + + d->mon = new MonitorDataObjects( std::vector<ObjectCalcer*>( objs.begin(),objs.end() ) ); + + std::set<ObjectCalcer*> tmp = objs; + for ( std::set<ObjectCalcer*>::const_iterator i = tmp.begin(); i != tmp.end(); ++i ) + { + std::set<ObjectCalcer*> children = getAllChildren(*i); + objs.insert( children.begin(), children.end() ); + } + + initScreen( calcPath( std::vector<ObjectCalcer*>( objs.begin(), objs.end() ) ) ); +} + +void MovingMode::stopMove() +{ + QString text = d->emo.size() == 1 ? + d->emo[0]->imp()->type()->moveAStatement() : + i18n( "Move %1 Objects" ).arg( d->emo.size() ); + KigCommand* mc = new KigCommand( mdoc, text ); + d->mon->finish( mc ); + mdoc.history()->addCommand( mc ); +} + +void MovingMode::moveTo( const Coordinate& o, bool snaptogrid ) +{ + for( std::vector<ObjectCalcer*>::iterator i = d->emo.begin(); i != d->emo.end(); ++i ) + { + assert( d->refmap.find( *i ) != d->refmap.end() ); + Coordinate nc = d->refmap[*i] + ( o - d->pwwsm ); + if ( snaptogrid ) nc = mdoc.document().coordinateSystem().snapToGrid( nc, mview ); + (*i)->move( nc, mdoc.document() ); + }; +} + +PointRedefineMode::PointRedefineMode( ObjectHolder* p, KigPart& d, KigWidget& v ) + : MovingModeBase( d, v ), mp( p ), mmon( 0 ) +{ + assert( dynamic_cast<ObjectTypeCalcer*>( p->calcer() ) ); + moldtype = static_cast<ObjectTypeCalcer*>( p->calcer() )->type(); + std::vector<ObjectCalcer*> oldparents = p->calcer()->parents(); + std::copy( oldparents.begin(), oldparents.end(), std::back_inserter( moldparents ) ); + + std::vector<ObjectCalcer*> parents = getAllParents( mp->calcer() ); + mmon = new MonitorDataObjects( parents ); + std::vector<ObjectCalcer*> moving = parents; + std::set<ObjectCalcer*> children = getAllChildren( mp->calcer() ); + std::copy( children.begin(), children.end(), std::back_inserter( moving ) ); + initScreen( moving ); +} + +void PointRedefineMode::moveTo( const Coordinate& o, bool snaptogrid ) +{ + Coordinate realo = + snaptogrid ? mdoc.document().coordinateSystem().snapToGrid( o, mview ) : o; + ObjectFactory::instance()->redefinePoint( + static_cast<ObjectTypeCalcer*>( mp->calcer() ), realo, mdoc.document(), mview ); +} + +PointRedefineMode::~PointRedefineMode() +{ +} + +MovingModeBase::MovingModeBase( KigPart& doc, KigWidget& v ) + : KigMode( doc ), mview( v ) +{ +} + +MovingModeBase::~MovingModeBase() +{ +} + +void MovingModeBase::leftMouseMoved( QMouseEvent* e, KigWidget* v ) +{ + mouseMoved( e, v ); +} + +MovingMode::~MovingMode() +{ + delete d->mon; + delete d; +} + +void PointRedefineMode::stopMove() +{ + assert( dynamic_cast<ObjectTypeCalcer*>( mp->calcer() ) ); + ObjectTypeCalcer* mpcalc = static_cast<ObjectTypeCalcer*>( mp->calcer() ); + + std::vector<ObjectCalcer*> newparents = mpcalc->parents(); + std::vector<ObjectCalcer::shared_ptr> newparentsref( + newparents.begin(), newparents.end() ); + const ObjectType* newtype = mpcalc->type(); + + std::vector<ObjectCalcer*> oldparents; + for( std::vector<ObjectCalcer::shared_ptr>::iterator i = moldparents.begin(); + i != moldparents.end(); ++i ) + oldparents.push_back( i->get() ); + mpcalc->setType( moldtype ); + mpcalc->setParents( oldparents ); + mp->calc( mdoc.document() ); + + KigCommand* command = new KigCommand( mdoc, i18n( "Redefine Point" ) ); + command->addTask( + new ChangeParentsAndTypeTask( mpcalc, newparents, newtype ) ); + mmon->finish( command ); + mdoc.history()->addCommand( command ); +} diff --git a/kig/modes/moving.h b/kig/modes/moving.h new file mode 100644 index 00000000..32828db3 --- /dev/null +++ b/kig/modes/moving.h @@ -0,0 +1,101 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef MOVING_H +#define MOVING_H + +#include "mode.h" + +#include "../misc/coordinate.h" +#include "../objects/object_calcer.h" + +class ObjectType; +class Coordinate; +class NormalPoint; +class KigWidget; +class KigDocument; +class MonitorDataObjects; + +/** + * "Template method" pattern ( see the Design patterns book ): + * This is a base class for two modes: normal MovingMode: used for + * moving a set of objects around, using Object::startMove, + * Object::moveTo and Object::stopMove, and another mode + * PointRedefineMode, used for redefining a NormalPoint... + */ +class MovingModeBase + : public KigMode +{ +protected: + KigWidget& mview; +private: + // all moving objects: these objects are all of the objects that + // need to be redrawn every time the cursor moves, and after calc is + // called. + std::vector<ObjectCalcer*> mcalcable; + std::vector<ObjectHolder*> mdrawable; +protected: + MovingModeBase( KigPart& doc, KigWidget& v ); + ~MovingModeBase(); + + /** + * Subclasses should call this in their constructor, when they know + * which objects will be moving around... They are expected to be in + * the right order for being calc()'ed... + */ + void initScreen( const std::vector<ObjectCalcer*>& amo ); + + // in these functions, subclasses should do the equivalent of + // Object::stopMove() and moveTo()... Note that no calc()'ing or + // drawing is to be done.. + virtual void stopMove() = 0; + virtual void moveTo( const Coordinate& o, bool snaptogrid ) = 0; + +public: + void leftReleased( QMouseEvent*, KigWidget* ); + void leftMouseMoved( QMouseEvent*, KigWidget* ); + void mouseMoved( QMouseEvent*, KigWidget* ); +}; + +class MovingMode + : public MovingModeBase +{ + class Private; + Private* d; + void stopMove(); + void moveTo( const Coordinate& o, bool snaptogrid ); +public: + MovingMode( const std::vector<ObjectHolder*>& objects, const Coordinate& c, + KigWidget&, KigPart& ); + ~MovingMode(); +}; + +class PointRedefineMode + : public MovingModeBase +{ + ObjectHolder* mp; + std::vector<ObjectCalcer::shared_ptr> moldparents; + const ObjectType* moldtype; + MonitorDataObjects* mmon; + void stopMove(); + void moveTo( const Coordinate& o, bool snaptogrid ); +public: + PointRedefineMode( ObjectHolder* p, KigPart& d, KigWidget& v ); + ~PointRedefineMode(); +}; + +#endif diff --git a/kig/modes/normal.cc b/kig/modes/normal.cc new file mode 100644 index 00000000..ecf5f5c1 --- /dev/null +++ b/kig/modes/normal.cc @@ -0,0 +1,306 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "normal.h" + +#include "../kig/kig_view.h" +#include "../kig/kig_part.h" +#include "../kig/kig_document.h" +#include "../kig/kig_commands.h" +#include "../objects/object_factory.h" +#include "../objects/object_imp.h" +#include "../objects/object_drawer.h" +#include "../misc/kigpainter.h" +#include "popup.h" +#include "moving.h" +#include "macro.h" +#include "dragrectmode.h" +#include "typesdialog.h" + +#include <kcursor.h> +#include <kaction.h> +#include <kcommand.h> +#include <klocale.h> + +#include <algorithm> +#include <functional> + +using namespace std; + +void NormalMode::enableActions() +{ + KigMode::enableActions(); + mdoc.enableConstructActions( true ); + mdoc.aSelectAll->setEnabled( true ); + mdoc.aDeselectAll->setEnabled( true ); + mdoc.aInvertSelection->setEnabled( true ); + mdoc.aDeleteObjects->setEnabled( true ); + mdoc.aShowHidden->setEnabled( true ); + mdoc.aNewMacro->setEnabled( true ); + mdoc.aConfigureTypes->setEnabled( true ); + mdoc.history()->updateActions(); +} + +void NormalMode::deleteObjects() +{ + std::vector<ObjectHolder*> sel( sos.begin(), sos.end() ); + mdoc.delObjects( sel ); + sos.clear(); +} + +void NormalMode::selectObject( ObjectHolder* o ) +{ + sos.insert( o ); +} + +void NormalMode::selectObjects( const std::vector<ObjectHolder*>& os ) +{ + // hehe, don't you love this c++ stuff ;) + std::for_each( os.begin(), os.end(), + std::bind1st( + std::mem_fun( &NormalMode::selectObject ), this ) ); +} + +void NormalMode::unselectObject( ObjectHolder* o ) +{ + sos.erase( o ); +} + +void NormalMode::clearSelection() +{ + sos.clear(); +} + +// KigDocumentPopup* NormalMode::popup( KigDocument* ) +// { +// return 0; +// } + +void NormalMode::showHidden() +{ + mdoc.showObjects( mdoc.document().objects() ); +} + +void NormalMode::newMacro() +{ + DefineMacroMode m( mdoc ); + mdoc.runMode( &m ); +} + +void NormalMode::redrawScreen( KigWidget* w ) +{ + // unselect removed objects.. + std::vector<ObjectHolder*> nsos; + const std::set<ObjectHolder*> docobjs = mdoc.document().objectsSet(); + std::set_intersection( docobjs.begin(), docobjs.end(), sos.begin(), sos.end(), + std::back_inserter( nsos ) ); + sos = std::set<ObjectHolder*>( nsos.begin(), nsos.end() ); + w->redrawScreen( nsos, true ); + w->updateScrollBars(); +} + +void NormalMode::editTypes() +{ + TypesDialog d( mdoc.widget(), mdoc ); + d.exec(); +} + +NormalMode::NormalMode( KigPart& d ) + : BaseMode( d ) +{ +} + +NormalMode::~NormalMode() +{ +} + +void NormalMode::dragRect( const QPoint& p, KigWidget& w ) +{ + DragRectMode d( p, mdoc, w ); + mdoc.runMode( &d ); + + KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() ); + + if ( ! d.cancelled() ) + { + std::vector<ObjectHolder*> sel = d.ret(); + + if ( d.needClear() ) + { + pter.drawObjects( sos.begin(), sos.end(), false ); + clearSelection(); + }; + + selectObjects( sel ); + pter.drawObjects( sel, true ); + }; + + w.updateCurPix( pter.overlay() ); + w.updateWidget(); +} + +void NormalMode::dragObject( const std::vector<ObjectHolder*>& oco, const QPoint& pco, + KigWidget& w, bool ctrlOrShiftDown ) +{ + // first determine what to move... + if( sos.find( oco.front() ) == sos.end() ) + { + // the user clicked on something that is currently not + // selected... --> we select it, taking the Ctrl- and + // Shift-buttons into account... + if ( !ctrlOrShiftDown ) clearSelection(); + selectObject(oco.front()); + } + + std::vector<ObjectHolder*> sosv( sos.begin(), sos.end() ); + MovingMode m( sosv, w.fromScreen( pco ), w, mdoc ); + mdoc.runMode( &m ); +} + +void NormalMode::leftClickedObject( ObjectHolder* o, const QPoint&, + KigWidget& w, bool ctrlOrShiftDown ) +{ + KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() ); + + if ( ! o ) + { + pter.drawObjects( sos.begin(), sos.end(), false ); + clearSelection(); + } + else if( sos.find( o ) == sos.end() ) + { + // clicked on an object that wasn't selected.... + if (!ctrlOrShiftDown) + { + pter.drawObjects( sos.begin(), sos.end(), false ); + clearSelection(); + }; + pter.drawObject( o, true ); + selectObject( o ); + } + else + { + // clicked on an object that was selected.... + pter.drawObject( o, false ); + unselectObject( o ); + }; + w.updateCurPix( pter.overlay() ); + w.updateWidget(); +} + +void NormalMode::midClicked( const QPoint& p, KigWidget& w ) +{ + ObjectHolder* pto = ObjectFactory::instance()->sensiblePoint( w.fromScreen( p ), mdoc.document(), w ); + pto->calc( mdoc.document() ); + mdoc.addObject( pto ); + + // refresh the screen... + // not necessary, done by addObjects, which calls NormalMode::redrawScreen.. +// w.redrawScreen(); +// w.updateScrollBars(); +} + +void NormalMode::rightClicked( const std::vector<ObjectHolder*>& os, + const QPoint& plc, + KigWidget& w ) +{ + // saving the current cursor position + QPoint pt = QCursor::pos(); + if( !os.empty() ) + { + ObjectHolder* o = 0; + int id = ObjectChooserPopup::getObjectFromList( pt, &w, os ); + if ( id >= 0 ) + o = os[id]; + else + return; + if( sos.find( o ) == sos.end() ) + { + clearSelection(); + selectObject( o ); + }; + // show a popup menu... + std::vector<ObjectHolder*> sosv( sos.begin(), sos.end() ); + NormalModePopupObjects p( mdoc, w, *this, sosv, plc ); + p.exec( pt ); + } + else + { + NormalModePopupObjects p( mdoc, w, *this, std::vector<ObjectHolder*>(), plc ); + p.exec( pt ); + }; +} + +void NormalMode::mouseMoved( const std::vector<ObjectHolder*>& os, + const QPoint& plc, + KigWidget& w, + bool ) +{ + w.updateCurPix(); + if( os.empty() ) + { + w.setCursor( KCursor::arrowCursor() ); + mdoc.emitStatusBarText( 0 ); + w.updateWidget(); + } + else + { + // the cursor is over an object, show object type next to cursor + // and set statusbar text + + w.setCursor( KCursor::handCursor() ); + + int id = ObjectChooserPopup::getObjectFromList( plc, &w, os, false ); + QString stat = id == 0 ? os.front()->selectStatement() : i18n( "Which object?" ); + + // statusbar text + mdoc.emitStatusBarText( stat ); + KigPainter p( w.screenInfo(), &w.curPix, mdoc.document() ); + + // set the text next to the arrow cursor + QPoint point = plc; + point.setX(point.x()+15); + + p.drawTextStd( point, stat ); + w.updateWidget( p.overlay() ); + }; +} + +void NormalMode::selectAll() +{ + const std::vector<ObjectHolder*> os = mdoc.document().objects(); + selectObjects( os ); + mdoc.redrawScreen(); +} + +void NormalMode::deselectAll() +{ + clearSelection(); + mdoc.redrawScreen(); +} + +void NormalMode::invertSelection() +{ + std::vector<ObjectHolder*> os = mdoc.document().objects(); + std::set<ObjectHolder*> oldsel = sos; + clearSelection(); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); + i != os.end(); ++i ) + if ( oldsel.find( *i ) == oldsel.end() ) + sos.insert( *i ); + mdoc.redrawScreen(); +} diff --git a/kig/modes/normal.h b/kig/modes/normal.h new file mode 100644 index 00000000..dd51c854 --- /dev/null +++ b/kig/modes/normal.h @@ -0,0 +1,74 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MODES_NORMAL_H +#define KIG_MODES_NORMAL_H + +#include "base_mode.h" + +#include <qpoint.h> +#include <set> + +class NormalMode + : public BaseMode +{ +public: + NormalMode( KigPart& ); + ~NormalMode(); +protected: + void dragRect( const QPoint& p, KigWidget& w ); + void dragObject( const std::vector<ObjectHolder*>& os, const QPoint& pointClickedOn, + KigWidget& w, bool ctrlOrShiftDown ); + void leftClickedObject( ObjectHolder* o, const QPoint& p, + KigWidget& w, bool ctrlOrShiftDown ); + void midClicked( const QPoint& p, KigWidget& w ); + void rightClicked( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w ); + void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, + bool shiftpressed ); + void selectAll(); + void deselectAll(); + void invertSelection(); + +protected: + /** + * Objcects were added.. + */ + void redrawScreen( KigWidget* ); + + void enableActions(); + + void deleteObjects(); + void showHidden(); + void newMacro(); + void editTypes(); + +public: + void selectObject( ObjectHolder* o ); + void selectObjects( const std::vector<ObjectHolder*>& os ); + void unselectObject( ObjectHolder* o ); + void clearSelection(); + +// KigObjectsPopup* popup( const Objects& os ); +// KigDocumentPopup* popup( KigDocument* ); +protected: + /** + * selected objects... + */ + std::set<ObjectHolder*> sos; +}; + +#endif diff --git a/kig/modes/popup.cc b/kig/modes/popup.cc new file mode 100644 index 00000000..b71d9896 --- /dev/null +++ b/kig/modes/popup.cc @@ -0,0 +1,1200 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + + 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +**/ + +#include "popup.h" +#include "popup.moc" + +#include "../kig/kig_part.h" +#include "../kig/kig_document.h" +#include "../kig/kig_view.h" +#include "../kig/kig_commands.h" +#include "../objects/object_imp.h" +#include "../objects/object_drawer.h" +#include "../objects/bogus_imp.h" +#include "../objects/point_imp.h" +#include "../objects/line_imp.h" +#include "../objects/other_type.h" +#include "../objects/object_factory.h" +#include "../objects/polygon_imp.h" +#include "../objects/text_imp.h" +#include "../misc/lists.h" +#include "../misc/argsparser.h" +#include "../misc/kigpainter.h" +#include "../misc/coordinate_system.h" +#include "../misc/object_constructor.h" +#include "construct_mode.h" +#include "normal.h" +#include "moving.h" + +#include <algorithm> +#include <functional> + +#include <qcursor.h> +#include <qdialog.h> +#include <qpen.h> +#include <qregexp.h> +#include <qvalidator.h> + +#include <kaction.h> +#include <kcolordialog.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +#if KDE_IS_VERSION( 3, 1, 90 ) +#include <kinputdialog.h> +#else +#include <klineeditdlg.h> +#endif + +#include <config.h> + +using namespace std; + +class NormalModePopupObjects; + +/** + * This class is an abstract class. Its role is to fill up the + * NormalModePopupObjects with useful actions.. + */ +class PopupActionProvider +{ +public: + virtual ~PopupActionProvider(); + /** + * add all your entries to menu menu in popup popup. Set nextfree + * to the next free index.. + */ + virtual void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ) = 0; + /** + * try to execute the id'th action you added to menu menu in popup + * popup ( first is 0 ). Return true if this action does indeed + * belong to you ( is not greater than the number of actions you + * added ). Else return false, and subtract the number of actions + * you added from id. This requires you to keep a record of how + * much actions you added ( unless it's a fixed number, of course + * ). + */ + virtual bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ) = 0; +}; + +class BuiltinObjectActionsProvider + : public PopupActionProvider +{ +public: + void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ); + bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ); +}; + +class NameObjectActionsProvider + : public PopupActionProvider +{ +public: + void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ); + bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ); +}; + +class BuiltinDocumentActionsProvider + : public PopupActionProvider +{ + int mnumberofcoordsystems; + bool misfullscreen; +public: + void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ); + bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ); +}; + +class ObjectConstructorActionsProvider + : public PopupActionProvider +{ + std::vector<ObjectConstructor*> mctors[NormalModePopupObjects::NumberOfMenus]; +public: + void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ); + bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ); +}; + +class PropertiesActionsProvider + : public PopupActionProvider +{ + // we don't really need NumberOfMenus vectors, but this is the + // easiest way to do it, and I'm too lazy to do it properly ;) + std::vector<int> mprops[NormalModePopupObjects::NumberOfMenus]; +public: + void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ); + bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ); +}; + +class ObjectTypeActionsProvider + : public PopupActionProvider +{ + int mnoa; +public: + void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ); + bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ); +}; + +#ifdef KIG_ENABLE_PYTHON_SCRIPTING +#include "../scripting/script-common.h" +#include "../scripting/script_mode.h" +#include "../scripting/python_type.h" + +class ScriptActionsProvider + : public PopupActionProvider +{ + int mns; +public: + void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ); + bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& m ); +}; +#endif + +NormalModePopupObjects::NormalModePopupObjects( KigPart& part, + KigWidget& view, + NormalMode& mode, + const std::vector<ObjectHolder*>& objs, + const QPoint& plc ) + : KPopupMenu( &view ), mplc( plc ), mpart( part ), mview( view ), mobjs( objs ), + mmode( mode ), monlylabels( false ) +{ + bool empty = objs.empty(); + bool single = objs.size() == 1; + connect( this, SIGNAL( activated( int ) ), this, SLOT( toplevelMenuSlot( int ) ) ); + + QString title; + if ( empty ) + title = i18n( "Kig Document" ); + else if ( single ) + { + if ( !objs[0]->name().isNull() ) + title = QString::fromLatin1( "%1 %2" ).arg( objs[0]->imp()->type()->translatedName() ).arg( objs[0]->name() ); + else + title = objs[0]->imp()->type()->translatedName(); + } + else + title = i18n( "%1 Objects" ).arg( objs.size() ); + insertTitle( title, 1 ); + + if ( !empty ) + { + monlylabels = true; + uint i = 0; + while ( i < objs.size() && monlylabels ) + { + monlylabels &= objs[i]->imp()->inherits( TextImp::stype() ); + ++i; + } + } + + if ( empty ) + { + // provides some diverse stuff like "unhide all", set coordinate + // system etc. + mproviders.push_back( new BuiltinDocumentActionsProvider() ); + }; + // construct an object using these objects and start constructing an + // object using these objects + mproviders.push_back( new ObjectConstructorActionsProvider() ); + if ( single ) + mproviders.push_back( new NameObjectActionsProvider() ); + if ( ! empty ) + { + // stuff like hide, show, delete, set size, set color.. + mproviders.push_back( new BuiltinObjectActionsProvider() ); + // show property as text label -> show menu + // and construct property's as objects -> construct menu + mproviders.push_back( new PropertiesActionsProvider() ); + // stuff like "redefine point" for a fixed or constrained point.. + mproviders.push_back( new ObjectTypeActionsProvider() ); + } +#ifdef KIG_ENABLE_PYTHON_SCRIPTING + // script action.. + mproviders.push_back( new ScriptActionsProvider() ); +#endif + + for ( uint i = 0; i < NumberOfMenus; ++i ) + mmenus[i] = new QPopupMenu( this ); + + connect( mmenus[TransformMenu], SIGNAL( activated( int ) ), + this, SLOT( transformMenuSlot( int ) ) ); + connect( mmenus[TestMenu], SIGNAL( activated( int ) ), + this, SLOT( testMenuSlot( int ) ) ); + connect( mmenus[ConstructMenu], SIGNAL( activated( int ) ), + this, SLOT( constructMenuSlot( int ) ) ); + connect( mmenus[StartMenu], SIGNAL( activated( int ) ), + this, SLOT( startMenuSlot( int ) ) ); + connect( mmenus[ShowMenu], SIGNAL( activated( int ) ), + this, SLOT( showMenuSlot( int ) ) ); + connect( mmenus[SetColorMenu], SIGNAL( activated( int ) ), + this, SLOT( setColorMenuSlot( int ) ) ); + connect( mmenus[SetSizeMenu], SIGNAL( activated( int ) ), + this, SLOT( setSizeMenuSlot( int ) ) ); + connect( mmenus[SetStyleMenu], SIGNAL( activated( int ) ), + this, SLOT( setStyleMenuSlot( int ) ) ); + connect( mmenus[SetCoordinateSystemMenu], SIGNAL( activated( int ) ), + this, SLOT( setCoordinateSystemMenuSlot( int ) ) ); + + for ( int i = 0; i <= NumberOfMenus; ++i ) + { + int nextfree = 10; + for ( uint j = 0; j < mproviders.size(); ++j ) + mproviders[j]->fillUpMenu( *this, i, nextfree ); + }; + static const QString menunames[NumberOfMenus] = + { + i18n( "&Transform" ), + i18n( "T&est" ), + i18n( "Const&ruct" ), + i18n( "&Start" ), + i18n( "Add Te&xt Label" ), + i18n( "Set Co&lor" ), + i18n( "Set &Pen Width" ), + i18n( "Set St&yle" ), + QString::null, + i18n( "Set Coordinate S&ystem" ) + }; + static const QString menuicons[NumberOfMenus] = + { + "centralsymmetry", + "test", + QString::null, + "launch", + "kig_text", + "color_fill", +// "colorize", + "sizer", + "paintbrush", + QString::null, + QString::null + }; + int index = 1; + for ( int i = 0; i < NumberOfMenus; ++i ) + { + if ( mmenus[i]->count() == 0 ) continue; + if ( menuicons[i].isNull() ) + insertItem( menunames[i], mmenus[i], i, index++ ); + else + { + KIconLoader* l = part.instance()->iconLoader(); + QPixmap icon = l->loadIcon( menuicons[i], KIcon::Small, 22, KIcon::DefaultState, 0L, true ); + insertItem( QIconSet( icon ), menunames[i], mmenus[i], i, index++ ); + } + }; +} + +void NormalModePopupObjects::testMenuSlot( int i ) +{ + activateAction( TestMenu, i ); +} + +void NormalModePopupObjects::transformMenuSlot( int i ) +{ + activateAction( TransformMenu, i ); +} + +void NormalModePopupObjects::constructMenuSlot( int i ) +{ + activateAction( ConstructMenu, i ); +} + +void NormalModePopupObjects::startMenuSlot( int i ) +{ + activateAction( StartMenu, i ); +} + +void NormalModePopupObjects::showMenuSlot( int i ) +{ + activateAction( ShowMenu, i ); +} + +void NormalModePopupObjects::toplevelMenuSlot( int i ) +{ + activateAction( ToplevelMenu, i ); +} + +void NormalModePopupObjects::activateAction( int menu, int action ) +{ + bool done = false; + // we need action - 10 cause we called fillUpMenu with nextfree set + // to 10 initially.. + action -= 10; + for ( uint i = 0; ! done && i < mproviders.size(); ++i ) + done = mproviders[i]->executeAction( menu, action, mobjs, *this, mpart, mview, mmode ); +} + +NormalModePopupObjects::~NormalModePopupObjects() +{ + delete_all ( mproviders.begin(), mproviders.end() ); +} + +static const QColor* colors[] = +{ + &Qt::blue, + &Qt::black, + &Qt::gray, + &Qt::red, + &Qt::green, + &Qt::cyan, + &Qt::yellow, + &Qt::darkRed +}; +static const int numberofcolors = sizeof( colors ) / sizeof( QColor* ); + +void BuiltinObjectActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ) +{ + if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + KIconLoader* l = popup.part().instance()->iconLoader(); + std::vector<ObjectHolder*> os = popup.objects(); + + /* + * mp: we want the "show" action to be visible only + * if we selected only one object (to be conservative) + * and if that object is currently hidden. + * conversely for one hidden object we don't want + * the "hide" action to be inserted. + * in any case we have a fixed 'id' associated + * with the two actions. + */ + + if ( os.size() > 1 || os.front()->shown() ) + { + popup.addAction( menu, i18n( "&Hide" ), nextfree ); + } + if ( os.size() == 1 && !os.front()->shown() ) + { + popup.addAction( menu, i18n( "&Show" ), nextfree+1 ); + } + nextfree += 2; + QPixmap p = l->loadIcon( "move", KIcon::Toolbar ); + popup.addAction( menu, p, i18n( "&Move" ), nextfree++ ); + p = l->loadIcon( "editdelete", KIcon::Toolbar ); + popup.addAction( menu, p, i18n( "&Delete" ), nextfree++ ); + } + else if ( menu == NormalModePopupObjects::SetColorMenu ) + { + QPixmap p( 50, 20 ); + for( const QColor** c = colors; c < colors + numberofcolors; ++c ) + { + p.fill( **c ); + popup.addAction( menu, p, nextfree++ ); + } + popup.addAction( menu, i18n( "&Custom Color" ), nextfree++ ); + } + else if ( menu == NormalModePopupObjects::SetSizeMenu && !popup.onlyLabels() ) + { + bool point = true; + bool samecolor = true; + std::vector<ObjectHolder*> os = popup.objects(); + QColor color = os.front()->drawer()->color(); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + { + if ( ! (*i)->imp()->inherits( PointImp::stype() ) ) + point = false; + if ( (*i)->drawer()->color() != color ) samecolor = false; + }; + if ( ! samecolor ) color = Qt::blue; + QPixmap p( point ? 20 : 50, 20 ); + for ( int i = 1; i < 8; ++i ) + { + p.fill( popup.eraseColor() ); + QPainter ptr( &p ); + ptr.setPen( QPen( color, 1 ) ); + ptr.setBrush( QBrush( color, Qt::SolidPattern ) ); + if ( point ) + { + int size = 2*i; + QRect r( ( 20 - size ) / 2, ( 20 - size ) / 2, size, size ); + ptr.drawEllipse( r ); + } + else + { + ptr.setPen( QPen( color, -1 + 2*i ) ); + ptr.drawLine( QPoint( 0, 10 ), QPoint( 50, 10 ) ); + }; + ptr.end(); + popup.addAction( menu, p, nextfree++ ); + }; + } + else if ( menu == NormalModePopupObjects::SetStyleMenu && !popup.onlyLabels() ) + { + bool samecolor = true; + int npoints = 0; + int nothers = 0; + std::vector<ObjectHolder*> os = popup.objects(); + QColor color = os.front()->drawer()->color(); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + { + if ( (*i)->imp()->inherits( PointImp::stype() ) ) + npoints++; + else + nothers++; + if ( (*i)->drawer()->color() != color ) samecolor = false; + }; + bool point = ( npoints > nothers ); + if ( ! samecolor ) color = Qt::blue; + if ( point ) + for ( int i = 0; i < 5; ++i ) + { + QPixmap p( 20, 20 ); + p.fill( popup.eraseColor() ); + ScreenInfo si( Rect( -1, -1, 2, 2 ), p.rect() ); + KigPainter ptr( si, &p, popup.part().document(), false ); + PointImp pt( Coordinate( 0, 0 ) ); + ObjectDrawer d( color, -1, true, Qt::SolidLine, i ); + d.draw( pt, ptr, false ); + popup.addAction( menu, p, nextfree++ ); + } + else + { + Qt::PenStyle penstyles[] = {Qt::SolidLine, Qt::DashLine, Qt::DashDotLine, Qt::DashDotDotLine, Qt::DotLine}; + for ( int i = 0; i < (int) ( sizeof( penstyles ) / sizeof( Qt::PenStyle ) ); ++i ) + { + QPixmap p( 50, 20 ); + p.fill( popup.eraseColor() ); + ScreenInfo si( Rect( -2.5, -1, 5, 2 ), p.rect() ); + KigPainter ptr( si, &p, popup.part().document(), false ); + LineImp line( Coordinate( -1, 0 ), Coordinate( 1, 0 ) ); + Qt::PenStyle ps = penstyles[i]; + ObjectDrawer d( color, -1, true, ps, 1 ); + d.draw( line, ptr, false ); + popup.addAction( menu, p, nextfree++ ); + }; + } + } +} + +void NameObjectActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ) +{ + if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + popup.addAction( menu, i18n( "Set &Name..." ), nextfree++ ); + } + else if ( menu == NormalModePopupObjects::ShowMenu ) + { + popup.addAction( menu, i18n( "&Name" ), nextfree++ ); + } +} + +static void addNameLabel( ObjectCalcer* object, ObjectCalcer* namecalcer, const Coordinate& loc, KigPart& doc ) +{ + std::vector<ObjectCalcer*> args; + args.push_back( namecalcer ); + const bool namelabelneedsframe = false; + ObjectCalcer* attachto = 0; + if ( object->imp()->inherits( PointImp::stype() ) || + object->imp()->attachPoint().valid() || + object->imp()->inherits( CurveImp::stype() ) ) + attachto = object; + ObjectHolder* label = ObjectFactory::instance()->attachedLabel( + QString::fromLatin1( "%1" ), attachto, loc, namelabelneedsframe, args, doc.document() ); + doc.addObject( label ); +} + +bool NameObjectActionsProvider::executeAction( + int menu, int& id, const std::vector<ObjectHolder*>& os, NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& ) +{ + if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + if ( id >= 1 ) + { + id -= 1; + return false; + } + assert( os.size() == 1 ); + QString name = os[0]->name(); + bool ok; + QRegExp re( ".*" ); + QRegExpValidator* rev = new QRegExpValidator( re, &doc ); + QString caption = i18n( "Set Object Name" ); + QString label = i18n( "Set Name of this Object:" ); +#if KDE_IS_VERSION( 3, 1, 90 ) + name = KInputDialog::getText( caption, label, name, &ok, &w, 0, rev ); +#else + name = KLineEditDlg::getText( caption, label, name, &ok, &w, rev ); +#endif + if ( ok ) + { + bool justadded = false; + ObjectCalcer* namecalcer = os[0]->nameCalcer(); + if ( !namecalcer ) + { + justadded = true; + ObjectConstCalcer* c = new ObjectConstCalcer( new StringImp( i18n( "<unnamed object>" ) ) ); + os[0]->setNameCalcer( c ); + namecalcer = c; + } + assert( dynamic_cast<ObjectConstCalcer*>( namecalcer ) ); + ObjectConstCalcer* cnamecalcer = static_cast<ObjectConstCalcer*>( os[0]->nameCalcer() ); + MonitorDataObjects mon( cnamecalcer ); + cnamecalcer->setImp( new StringImp( name ) ); + KigCommand* kc = new KigCommand( doc, i18n( "Set Object Name" ) ); + mon.finish( kc ); + doc.history()->addCommand( kc ); + + // if we just added the name, we add a label to show it to the user. + if ( justadded ) + addNameLabel( os[0]->calcer(), namecalcer, +// w.fromScreen( w.mapFromGlobal( popup.mapToGlobal( QPoint( 5, 0 ) ) ) ), + w.fromScreen( popup.plc() ), + doc ); + } + return true; + } + else if ( menu == NormalModePopupObjects::ShowMenu ) + { + if ( id >= 1 ) + { + id -= 1; + return false; + } + assert( os.size() == 1 ); + ObjectCalcer* namecalcer = os[0]->nameCalcer(); + if ( !namecalcer ) + { + ObjectConstCalcer* c = new ObjectConstCalcer( new StringImp( i18n( "<unnamed object>" ) ) ); + os[0]->setNameCalcer( c ); + namecalcer = c; + } + addNameLabel( os[0]->calcer(), namecalcer, +// w.fromScreen( w.mapFromGlobal( popup.mapToGlobal( QPoint( 5, 0 ) ) ) ), doc ); + w.fromScreen( popup.plc() ), doc ); + return true; + } + else + { + return false; + } +} + +bool BuiltinObjectActionsProvider::executeAction( + int menu, int& id, const std::vector<ObjectHolder*>& os, NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& mode ) +{ + if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + if ( id > 3 ) + { + id -= 4; + return false; + }; + switch( id ) + { + case 0: + // hide the objects.. + doc.hideObjects( os ); + break; + case 1: + // show the objects.. + doc.showObjects( os ); + break; + case 2: + { + // move + QCursor::setPos( popup.mapToGlobal( QPoint( 0, 0 ) ) ); + QPoint p = w.mapFromGlobal( QCursor::pos() ); + Coordinate c = w.fromScreen( p ); + MovingMode m( os, c, w, doc ); + doc.runMode( &m ); + // in this case, we return, cause we don't want objects to be + // unselected... ( or maybe we do ? ) + return true; + } + case 3: + // delete + doc.delObjects( os ); + break; + default: assert( false ); + }; + mode.clearSelection(); + return true; + } + else if ( menu == NormalModePopupObjects::SetColorMenu ) + { + if ( id >= numberofcolors + 1 ) + { + id -= numberofcolors + 1; + return false; + }; + QColor color; + if ( id < numberofcolors ) + color = *colors[id]; + else + { + if ( os.size() == 1 ) + color = os.front()->drawer()->color(); + int result = KColorDialog::getColor( color, &w ); + if ( result != KColorDialog::Accepted ) return true; + } + KigCommand* kc = new KigCommand( doc, i18n( "Change Object Color" ) ); + assert( color.isValid() ); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyColor( color ) ) ); + doc.history()->addCommand( kc ); + mode.clearSelection(); + return true; + } + else if ( menu == NormalModePopupObjects::SetSizeMenu ) + { + if ( id >= 7 ) + { + id -= 7; + return false; + }; + + KigCommand* kc = new KigCommand( doc, i18n( "Change Object Width" ) ); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyWidth( 1 + 2 * id ) ) ); + doc.history()->addCommand( kc ); + mode.clearSelection(); + return true; + } + else if ( menu == NormalModePopupObjects::SetStyleMenu ) + { + int npoints = 0; + int nothers = 0; + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + { + if ( (*i)->imp()->inherits( PointImp::stype() ) ) + npoints++; + else + nothers++; + }; + bool point = ( npoints > nothers ); + int max = point ? 5 : 5; + if ( id >= max ) + { + id -= max; + return false; + }; + + if ( point ) + { + KigCommand* kc = new KigCommand( doc, i18n( "Change Point Style" ) ); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + if ( (*i)->imp()->inherits( PointImp::stype() ) ) + kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyPointStyle( id ) ) ); + doc.history()->addCommand( kc ); + mode.clearSelection(); + return true; + } + else + { + Qt::PenStyle penstyles[] = {Qt::SolidLine, Qt::DashLine, Qt::DashDotLine, Qt::DashDotDotLine, Qt::DotLine}; + assert( id < (int)( sizeof( penstyles ) / sizeof( Qt::PenStyle ) ) ); + Qt::PenStyle p = penstyles[id]; + KigCommand* kc = new KigCommand( doc, i18n( "Change Object Style" ) ); + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + if ( ! (*i)->imp()->inherits( PointImp::stype() ) ) + kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyStyle( p ) ) ); + doc.history()->addCommand( kc ); + mode.clearSelection(); + } + return true; + } + else return false; +} + +void ObjectConstructorActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ) +{ + const KigDocument& d = popup.part().document(); + const KigWidget& v = popup.widget(); + typedef ObjectConstructorList::vectype vectype; + vectype vec = ObjectConstructorList::instance()->constructors(); + + for ( vectype::iterator i = vec.begin(); i != vec.end(); ++i ) + { + bool add = false; + if ( popup.objects().empty() ) + { + add = menu == NormalModePopupObjects::StartMenu && ! (*i)->isTransform() && ! (*i)->isTest(); + } + else + { + int ret = (*i)->wantArgs( getCalcers( popup.objects() ), d, v ); + if ( ret == ArgsParser::Invalid ) continue; + if ( (*i)->isTransform() && popup.objects().size() == 1 ) add = menu == NormalModePopupObjects::TransformMenu; + else if ( (*i)->isTest() ) add = menu == NormalModePopupObjects::TestMenu; + else if ( ( *i )->isIntersection() ) add = menu == NormalModePopupObjects::ToplevelMenu; + else if ( ret == ArgsParser::Complete ) add = menu == NormalModePopupObjects::ConstructMenu; + else add = menu == NormalModePopupObjects::StartMenu; + }; + if ( add ) + { + QCString iconfile = (*i)->iconFileName(); + if ( !iconfile.isEmpty() && !iconfile.isNull() ) + { + QPixmap icon = popup.part().instance()->iconLoader()->loadIcon( iconfile, KIcon::Toolbar, 22, KIcon::DefaultState, 0L, true ); + popup.addAction( menu, icon, (*i)->descriptiveName(), nextfree++ ); + } + else + popup.addAction( menu, (*i)->descriptiveName(), nextfree++ ); + mctors[menu].push_back( *i ); + } + }; +} + +bool ObjectConstructorActionsProvider::executeAction( + int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects&, + KigPart& doc, KigWidget& w, NormalMode& m ) +{ + if ( (uint) id >= mctors[menu].size() ) + { + id -= mctors[menu].size(); + return false; + } + + ObjectConstructor* ctor = mctors[menu][id]; + std::vector<ObjectCalcer*> osc = getCalcers( os ); + if ( ! os.empty() && ctor->wantArgs( osc, doc.document(), w ) == ArgsParser::Complete ) + { + ctor->handleArgs( osc, doc, w ); + m.clearSelection(); + } + else + { + BaseConstructMode* mode = ctor->constructMode( doc ); + mode->selectObjects( os, w ); + doc.runMode( mode ); + delete mode; + }; + return true; +} + +void NormalModePopupObjects::addAction( int menu, const QPixmap& pix, int id ) +{ + QPopupMenu* m = 0; + if ( menu == ToplevelMenu ) m = this; + else m = mmenus[menu]; + int ret = m->insertItem( pix, id ); + assert( ret == id ); + // pretend to use this var.. + (void) ret; +} + +void NormalModePopupObjects::setColorMenuSlot( int i ) +{ + activateAction( SetColorMenu, i ); +} + +void NormalModePopupObjects::setSizeMenuSlot( int i ) +{ + activateAction( SetSizeMenu, i ); +} + +void NormalModePopupObjects::setStyleMenuSlot( int i ) +{ + activateAction( SetStyleMenu, i ); +} + +void NormalModePopupObjects::setCoordinateSystemMenuSlot( int i ) +{ + activateAction( SetCoordinateSystemMenu, i ); +} + +void NormalModePopupObjects::addAction( int menu, const QPixmap& icon, const QString& name, int id ) +{ + QPopupMenu* m = 0; + if ( menu == ToplevelMenu ) m = this; + else m = mmenus[menu]; + int ret = m->insertItem( QIconSet( icon ), name, id ); + assert( ret == id ); + // pretend to use this var.. + (void)ret; +} + +void NormalModePopupObjects::addAction( int menu, const QString& name, int id ) +{ + QPopupMenu* m = 0; + if ( menu == ToplevelMenu ) m = this; + else m = mmenus[menu]; + int ret = m->insertItem( name, id ); + assert( ret == id ); + // pretend to use this var.. + (void)ret; +} + +PopupActionProvider::~PopupActionProvider() +{ +} + +void PropertiesActionsProvider::fillUpMenu( NormalModePopupObjects& popup, + int menu, int& nextfree ) +{ + if ( popup.objects().size() != 1 ) return; + ObjectHolder* o = popup.objects()[0]; + uint np = o->imp()->numberOfProperties(); + if ( menu != NormalModePopupObjects::ConstructMenu && + menu != NormalModePopupObjects::ShowMenu ) return; + for ( uint i = 0; i < np; ++i ) + { + ObjectImp* prop = o->imp()->property( i, popup.part().document() ); + const char* iconfile = o->imp()->iconForProperty( i ); + bool add = true; + if ( menu == NormalModePopupObjects::ConstructMenu ) + { + // we don't want imp's like DoubleImp, since we can't show them + // anyway.. + add &= ! prop->inherits( BogusImp::stype() ); + // we don't want to construct PointImp's coordinate property, + // since it would construct a point at the same place as its + // parent.. + add &= ! ( o->imp()->inherits( PointImp::stype() ) && + prop->inherits( PointImp::stype() ) ); + } + else if ( menu == NormalModePopupObjects::ShowMenu ) + add &= prop->canFillInNextEscape(); + if ( add ) + { + if ( iconfile && *iconfile ) + { + QPixmap pix = popup.part().instance()->iconLoader()->loadIcon( iconfile, KIcon::Toolbar, 22, KIcon::DefaultState, 0L, true ); + popup.addAction( menu, pix, i18n( o->imp()->properties()[i] ), nextfree++ ); + } + else + { + popup.addAction( menu, i18n( o->imp()->properties()[i] ), nextfree++ ); + }; + mprops[menu-1].push_back( i ); + }; + delete prop; + }; +} + +bool PropertiesActionsProvider::executeAction( + int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects& popup, + KigPart& doc, KigWidget& w, NormalMode& ) +{ + if ( menu != NormalModePopupObjects::ConstructMenu && + menu != NormalModePopupObjects::ShowMenu ) + return false; + if ( (uint) id >= mprops[menu - 1].size() ) + { + id -= mprops[menu - 1].size(); + return false; + } + int propid = mprops[menu-1][id]; + assert( os.size() == 1 ); + ObjectHolder* parent = os[0]; + if ( menu == NormalModePopupObjects::ShowMenu ) + { + std::vector<ObjectCalcer*> args; + args.push_back( new ObjectPropertyCalcer( parent->calcer(), propid ) ); + args.back()->calc( doc.document() ); +// TODO: recover the cursor position somehow... the following does not work +// in general... +// Coordinate c = w.fromScreen( w.mapFromGlobal( popup.mapToGlobal( QPoint( 5, 0 ) ) ) ); +// mp: it seems that we have no idea where to position the label, +// btw what's the meaning of (5,0)? let the +// attach method decide what to do... (passing an invalidCoord) +// /////// Coordinate c = Coordinate::invalidCoord(); + Coordinate c = w.fromScreen( popup.plc() ); + ObjectHolder* label = ObjectFactory::instance()->attachedLabel( + QString::fromLatin1( "%1" ), parent->calcer(), c, + false, args, doc.document() ); + doc.addObject( label ); + } + else + { + ObjectHolder* h = new ObjectHolder( + new ObjectPropertyCalcer( parent->calcer(), propid ) ); + h->calc( doc.document() ); + doc.addObject( h ); + }; + return true; +} + +void ObjectTypeActionsProvider::fillUpMenu( + NormalModePopupObjects& popup, int menu, int& nextfree ) +{ + if ( popup.objects().size() != 1 ) return; + if ( menu != NormalModePopupObjects::ToplevelMenu ) return; + ObjectHolder* to = popup.objects()[0]; + ObjectTypeCalcer* c = dynamic_cast<ObjectTypeCalcer*>( to->calcer() ); + if ( ! c ) return; + const ObjectType* t = c->type(); + + QStringList l = t->specialActions(); + mnoa = l.count(); + for ( int i = 0; i < mnoa; ++i ) + popup.addAction( menu, l[i], nextfree++ ); +} + +bool ObjectTypeActionsProvider::executeAction( + int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects&, + KigPart& doc, KigWidget& w, NormalMode& m ) +{ + if ( menu != NormalModePopupObjects::ToplevelMenu ) return false; + if ( id >= mnoa ) + { + id -= mnoa; + return false; + } + assert( os.size() == 1 ); + ObjectTypeCalcer* oc = dynamic_cast<ObjectTypeCalcer*>( os[0]->calcer() ); + assert( oc ); + + oc->type()->executeAction( id, *os[0], *oc, doc, w, m ); + return true; +} + +void BuiltinDocumentActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ) +{ + if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + popup.addAction( menu, i18n( "U&nhide All" ), nextfree++ ); + popup.part().action( "view_zoom_in" )->plug( &popup ); + popup.part().action( "view_zoom_out" )->plug( &popup ); + popup.part().action( "fullscreen" )->plug( &popup ); + nextfree += 3; + } + else if ( menu == NormalModePopupObjects::SetCoordinateSystemMenu ) + { + int idoffset = nextfree; + QStringList l = CoordinateSystemFactory::names(); + mnumberofcoordsystems = l.count(); + for ( uint i = 0; i < l.count(); ++i ) + popup.addAction( menu, l[i], nextfree++ ); + int current = popup.part().document().coordinateSystem().id(); + popup.setChecked( menu, idoffset + current, true ); + } +} + +bool BuiltinDocumentActionsProvider::executeAction( + int menu, int& id, const std::vector<ObjectHolder*>&, + NormalModePopupObjects&, + KigPart& doc, KigWidget&, NormalMode& m ) +{ + if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + kdDebug() << "id: " << id << endl; + if ( id == 0 ) + { + doc.showHidden(); + m.clearSelection(); + return true; + } + id -= 1; + return false; + } + else if ( menu == NormalModePopupObjects::SetCoordinateSystemMenu ) + { + if ( id >= mnumberofcoordsystems ) + { + id -= mnumberofcoordsystems; + return false; + }; + CoordinateSystem* sys = CoordinateSystemFactory::build( id ); + assert( sys ); + doc.history()->addCommand( KigCommand::changeCoordSystemCommand( doc, sys ) ); + m.clearSelection(); + return true; + } + else return false; +} + +void NormalModePopupObjects::setChecked( int menu, int n, bool checked ) +{ + mmenus[menu]->setItemChecked( n, checked ); +} + +#ifdef KIG_ENABLE_PYTHON_SCRIPTING +/** + * this is a local function that looks for a python script associated + * to a clicked object + */ +static ObjectTypeCalcer* getPythonExecuteTypeFromCalcer( ObjectCalcer* o ) +{ + ObjectTypeCalcer* oc = dynamic_cast<ObjectTypeCalcer *>( o ); + if ( !oc ) return 0; + const PythonExecuteType* pythonexec = dynamic_cast<const PythonExecuteType*>( oc->type() ); + if ( pythonexec ) return oc; + + return 0; +} + +void ScriptActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ) +{ + if ( menu == NormalModePopupObjects::StartMenu ) + { + KIconLoader* l = popup.part().instance()->iconLoader(); + QPixmap p = l->loadIcon( ScriptType::icon( ScriptType::Python ), KIcon::Toolbar, 22, KIcon::DefaultState, 0L, true ); + popup.addAction( menu, p, i18n( "Python Script" ), nextfree++ ); + mns++; + } + else if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + if ( !popup.objects().empty() && + getPythonExecuteTypeFromCalcer( popup.objects().front()->calcer() ) ) + { + popup.addAction( menu, i18n( "Edit Script..." ), nextfree ); + } + nextfree++; + } +} + +bool ScriptActionsProvider::executeAction( + int menu, int& id, const std::vector<ObjectHolder*>& os, + NormalModePopupObjects&, KigPart& doc, KigWidget& w, NormalMode& mode ) +{ + if ( menu == NormalModePopupObjects::StartMenu ) + { + if ( id == 0 ) + { + ScriptCreationMode m( doc ); + m.setScriptType( ScriptType::Python ); + if ( os.size() > 0 ) + { + mode.clearSelection(); + m.addArgs( os, w ); + m.goToCodePage(); + } + doc.runMode( &m ); + return true; + } + else + { + id -= mns; + } + } + else if ( menu == NormalModePopupObjects::ToplevelMenu ) + { + if ( id == 0 ) + { + ObjectTypeCalcer* oc = getPythonExecuteTypeFromCalcer( os.front()->calcer() ); + if ( oc ) + { + ScriptEditMode m( oc, doc ); + m.setScriptType( ScriptType::Python ); + doc.runMode( &m ); + } + return true; + } + else + { + id -= 1; + } + } + + return false; +} +#endif + +int ObjectChooserPopup::getObjectFromList( const QPoint& p, KigWidget* w, + const std::vector<ObjectHolder*>& objs, + bool givepopup ) +{ + int size = objs.size(); + + // no objects + if ( size == 0 ) + return -1; + + int id = -1; + + int numpoints = 0; + int numpolygons = 0; + int numothers = 0; + + for ( std::vector<ObjectHolder*>::const_iterator i = objs.begin(); + i != objs.end(); ++i ) + { + if ( (*i)->imp()->inherits( PointImp::stype() ) ) numpoints++; + else if ( (*i)->imp()->inherits( PolygonImp::stype() ) ) numpolygons++; + else numothers++; + } + + // simply cases: + // - only 1 point ( and eventually other objects ) + // - no points and an object which is not a polygon + // - only one object + // FIXME: we assume that our objects are sorted ( points, others, polygons )! + if ( ( numpoints == 1 ) || + ( ( numpoints == 0 ) && ( numothers == 1 ) ) || + ( size == 1 ) ) + id = 0; + else + { + if ( givepopup ) + { + ObjectChooserPopup* ppp = new ObjectChooserPopup( p, *w, objs ); + ppp->exec( QCursor::pos() ); + + id = ppp->mselected; + + delete ppp; + ppp = 0; + } + else + { + // we don't want to show a popup to the user, so let's give a + // value > 0 to indicate that it's not the first + id = 1; + } + } +// kdDebug() << "numpoints: " << numpoints << endl +// << "numothers: " << numothers << endl +// << "numpolygons: " << numpolygons << endl +// << "id: " << id << endl; + + return id; +} + +ObjectChooserPopup::ObjectChooserPopup( const QPoint& p, KigWidget& view, + const std::vector<ObjectHolder*>& objs ) + : KPopupMenu(), mplc( p ), mview( view ), mobjs( objs ), mselected( -1 ) +{ + for ( uint i = 0; i < mobjs.size(); i++ ) + { + insertItem( !mobjs[i]->name().isEmpty() + ? QString::fromLatin1( "%1 %2" ).arg( mobjs[i]->imp()->type()->translatedName() ).arg( mobjs[i]->name() ) + : mobjs[i]->imp()->type()->translatedName(), + i ); + } + + connect( this, SIGNAL( activated( int ) ), this, SLOT( actionActivatedSlot( int ) ) ); +} + +ObjectChooserPopup::~ObjectChooserPopup() +{ +} + +void ObjectChooserPopup::actionActivatedSlot( int which ) +{ + mselected = which; +} diff --git a/kig/modes/popup.h b/kig/modes/popup.h new file mode 100644 index 00000000..405bcee6 --- /dev/null +++ b/kig/modes/popup.h @@ -0,0 +1,153 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + + 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +**/ + +#ifndef KIG_MODES_POPUP_H +#define KIG_MODES_POPUP_H + +#include <kpopupmenu.h> + +#include <vector> + +class KigDocument; +class KigPart; +class KigWidget; +class NormalMode; +class PopupActionProvider; +class ObjectHolder; + +/** + * This is the popup menu that appears when you click on selected + * objects in NormalMode.. It's quite complex, since it has to fetch + * a lot of information from various places, and dispatch it again + * when the user selects something. + * Update: I'm also using it for when you clicked on an empty space in + * the document, because the difference between the two cases is not + * that important, and this class is generic enough to handle both + * cases.. When this is the case, mobjs is empty, some + * PopupActionProviders are disabled, and some others enabled.. + */ +class NormalModePopupObjects + : public KPopupMenu +{ + Q_OBJECT + +public: + NormalModePopupObjects( KigPart& part, KigWidget& view, + NormalMode& mode, + const std::vector<ObjectHolder*>& objs, const QPoint& p ); + ~NormalModePopupObjects(); + + // the different "menu's", the toplevel is considered as just + // another menu.. + enum { TransformMenu = 0, TestMenu, ConstructMenu, StartMenu, ShowMenu, + SetColorMenu, SetSizeMenu, SetStyleMenu, ToplevelMenu, + SetCoordinateSystemMenu, NumberOfMenus }; + + // used by the PopupActionProvider's to add actions to us.. + void addAction( int menu, const QString& name, int id ); + void addAction( int menu, const QPixmap& icon, const QString& name, int id ); + void addAction( int menu, const QPixmap& pix, int id ); + + /** + * set the checked state of the \p n 'th item in \p menu to \p checked .. + */ + void setChecked( int menu, int n, bool checked ); + + std::vector<ObjectHolder*> objects() const { return mobjs; } + KigPart& part() { return mpart; } + KigWidget& widget() { return mview; } + QPoint plc() { return mplc; } + + bool onlyLabels() const { return monlylabels; } + +protected: + void activateAction( int menu, int action ); + +private slots: + void transformMenuSlot( int ); + void testMenuSlot( int ); + void constructMenuSlot( int ); + void startMenuSlot( int ); + void showMenuSlot( int ); + void setColorMenuSlot( int ); + void setSizeMenuSlot( int ); + void setStyleMenuSlot( int ); + void toplevelMenuSlot( int ); + void setCoordinateSystemMenuSlot( int ); + +protected: + QPoint mplc; + KigPart& mpart; + KigWidget& mview; + std::vector<ObjectHolder*> mobjs; + NormalMode& mmode; + + std::vector<PopupActionProvider*> mproviders; + + QPopupMenu* mmenus[NumberOfMenus]; + +private: + bool monlylabels; +}; + +/** + * This class is useful to choose one object from a list of some, by + * querying the user via popup menu. + * + * You can't use this class directly, but these's a convenience method. + */ +class ObjectChooserPopup + : public KPopupMenu +{ + Q_OBJECT + +public: + /** + * Get the index of the choosen object from a list of objects. + * + * \param p is the point whene executre the popup + * \param w is the pointer to a KigWidget + * \param objs is the vector with the objects to chose from + * \param givepopup true means that we have to show a popup to the user + * + * \return the index of the chosen element ( starting from 0 ), or -1 + * if none was selected. + */ + static int getObjectFromList( const QPoint& p, KigWidget* w, + const std::vector<ObjectHolder*>& objs, + bool givepopup = true ); + +protected: + ObjectChooserPopup( const QPoint& p, KigWidget& view, + const std::vector<ObjectHolder*>& objs ); + ~ObjectChooserPopup(); + +protected slots: + void actionActivatedSlot( int ); + +protected: + QPoint mplc; + KigWidget& mview; + std::vector<ObjectHolder*> mobjs; + + int mselected; +}; + +#endif diff --git a/kig/modes/textlabelwizard.cc b/kig/modes/textlabelwizard.cc new file mode 100644 index 00000000..803ca819 --- /dev/null +++ b/kig/modes/textlabelwizard.cc @@ -0,0 +1,95 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "textlabelwizard.h" +#include "textlabelwizard.moc" + +#include "label.h" +#include "linkslabel.h" + +#include <qtextedit.h> +#include <kapplication.h> + +#include <qlayout.h> + +TextLabelWizard::TextLabelWizard( QWidget* parent, TextLabelModeBase* mode ) + : TextLabelWizardBase( parent, "TextLabelWizard", false ), mmode( mode ) +{ + connect( labelTextInput, SIGNAL( textChanged() ), + SLOT( textChanged() ) ); + connect( myCustomWidget1, SIGNAL( linkClicked( int ) ), + SLOT( linkClicked( int ) ) ); + connect( this, SIGNAL( helpClicked() ), + this, SLOT( slotHelpClicked() ) ); + labelTextInput->setFocus(); +} + +TextLabelWizard::~TextLabelWizard() +{ +} + +void TextLabelWizard::back() +{ + if ( currentPage() == select_arguments_page ) + { + mmode->enterTextPageEntered(); + } + TextLabelWizardBase::back(); +} + +void TextLabelWizard::next() +{ + if ( currentPage() == enter_text_page ) + { + mmode->selectArgumentsPageEntered(); + } + TextLabelWizardBase::next(); +} + +void TextLabelWizard::reject() +{ + TextLabelWizardBase::reject(); + mmode->cancelPressed(); +} + +void TextLabelWizard::accept() +{ + mmode->finishPressed(); +} + +void TextLabelWizard::textChanged() +{ + mmode->labelTextChanged(); +} + +void TextLabelWizard::linkClicked( int which ) +{ + mmode->linkClicked( which ); +} + +void TextLabelWizard::relayoutArgsPage() +{ + select_arguments_pageLayout->activate(); + repaint(); +} + +void TextLabelWizard::slotHelpClicked() +{ + kapp->invokeHelp( QString::fromLatin1( "text-labels" ), + QString::fromLatin1( "kig" ) ); +} + diff --git a/kig/modes/textlabelwizard.h b/kig/modes/textlabelwizard.h new file mode 100644 index 00000000..787e0803 --- /dev/null +++ b/kig/modes/textlabelwizard.h @@ -0,0 +1,46 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// 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. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MODES_TEXTLABELWIZARD_H +#define KIG_MODES_TEXTLABELWIZARD_H + +#include "textlabelwizardbase.h" + +class TextLabelModeBase; + +class TextLabelWizard : public TextLabelWizardBase +{ + Q_OBJECT +public: + TextLabelWizard( QWidget* parent, TextLabelModeBase* mode ); + ~TextLabelWizard(); + + void back(); + void next(); + void reject(); + void accept(); + + void relayoutArgsPage(); +private slots: + void textChanged(); + void linkClicked( int which ); + void slotHelpClicked(); +private: + TextLabelModeBase* mmode; +}; + +#endif // TEXTLABELWIZARD_H diff --git a/kig/modes/textlabelwizardbase.ui b/kig/modes/textlabelwizardbase.ui new file mode 100644 index 00000000..4e195b0d --- /dev/null +++ b/kig/modes/textlabelwizardbase.ui @@ -0,0 +1,113 @@ +<!DOCTYPE UI><UI version="3.1.2" stdsetdef="1"> +<class>TextLabelWizardBase</class> +<widget class="QWizard"> + <property name="name"> + <cstring>TextLabelWizardBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>488</width> + <height>300</height> + </rect> + </property> + <property name="caption"> + <string>Construct Label</string> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>enter_text_page</cstring> + </property> + <attribute name="title"> + <string>Enter Label Text</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>enterTextLabel</cstring> + </property> + <property name="text"> + <string>Enter the text for your label here and press "Next". +If you want to show variable parts, then put %1, %2, ... at the appropriate places (e.g. "This segment is %1 units long.").</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="QTextEdit"> + <property name="name"> + <cstring>labelTextInput</cstring> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>needFrameCheckBox</cstring> + </property> + <property name="text"> + <string>Show text in a frame</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>select_arguments_page</cstring> + </property> + <attribute name="title"> + <string>Select Arguments</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>selectArgsLabel</cstring> + </property> + <property name="text"> + <string>Now select the argument(s) you need. For every argument, click on it, select an object and a property in the Kig window, and click finish when you are done...</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="LinksLabel"> + <property name="name"> + <cstring>myCustomWidget1</cstring> + </property> + </widget> + </vbox> + </widget> +</widget> +<customwidgets> + <customwidget> + <class>LinksLabel</class> + <header location="local">linkslabel.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XPM.GZ" length="4462">789c9d97c76e24490e86effd1442f3d65870d2451a0ce6206f5adeb4cc620f8c34f2553225b5a4c1befb46927fe6a1d4c0ccac4287fa8a0c26834193f5dbb785b3fd9d856fbf7d799ec9ecba5ea8afe469e15bf3727ffffeeffffcf1e797af49b2d0ffc7d142f2f55f5fbe1ecc16ea85dde9a4ed81290045faa77ca49cf4ab67ba1e3953969173651ab9d4fdf1c8a27c3872ad7c3c72d3b32c2a67c3f3444636fbef23eb7e590267e68fcc4656395d8dacf6d938ef97eaef289781cddebdb2846fccff44b989ba58e3411f3dc75158e6df1d3889539517ca49bf54fe43398d1dec4f46567f685fd9c539f43fc025f80c1c3ce8d93f28e77185f8bf0c6cfae4c0b5f9c3c6e5c0542a4b5876fe13708df39d2bd7716372aa8c93c4e4723bb2f977aadc26ceec4bdb7310e6b0bfab9c2445ecd49f1370694cebca65d260ffa6711a41aef14d24e94cee6be3348e0ae5e9c8765f07ca3e8db17f0f9c825794eb3489351fe9bb7217e4969f29388bd51ee9fda5715a19730696b852fea95c6471647ca95cf64bcf43e0cef4657b647bfe6acf213d6bb32f9a9f5992b5a64f9a8f990b6cf9ecc15d6cf9acf6b2da55a8a75cb973dee4b2d1b38b5c05de02434e87e01aacfb351df5bebddea74b5c67f9c795711ea15e357e2ecde358fb87efc0a867df8cac728a074e62e527706afb59f3cf6583be5c28bb3c35f693812d1fbdc6dbe57966fec932d899ffa4f7e38adca17e34beaeca4b9c271a18f1d5fc739257b0d70d9c68be7bed7fcee7827ab91cd8e4740cf6b19d4ffb87ab07b9bf516e72d4a3ac821b9cef6e60d84f47367ded2fae1d9f7704f6163f79000ffde27660f387ed3c5dbf54dfeebb0bf6acbe6b706bfa5ef32f8f8b18f5bf0f463f20edb77956a4e68fbc80b3c4facd163847be6bfde72ec86dbeac82715fbc0286be683cf3bc081d44f7df80d344fb0b6b7de64581fb916765297263d6fccd9b7ee97e566e8b06cfdb1f59cf2bda2f8bbc2c11df0c5c41aefdb328ca22b1feb0012eedbce24736f91b18fb796d64eb87cb60817dcdafb07d906bfd14d22f659d8785ef97b2f6d7b2df6ef1d6fb2babaac6f92e8c25b27ecc1f239b7f3a5fca5a8678ea7c2d9bc0e6ef1238b3fca2c7814d5f4cbf9334b5f833384bed3c7a5f5514f4adbe2ec07962e7590457f06f6f649b977afe2a16f42f5e070bfc591e18f7a5f1a812a9e0df39d827da4fbd8c6ccfd7785569bf945f953371a9d5a3de67950bfa2d75c63eb2fb15bdcfaaf011e6c7263846bf8f4636f91618f3c7d3c0f047fb69550efab2074e12bd6fd27957553ec33c5b043bcc7f9d0795f818fdb501a3df8ae673e507ff69021eea37063bc45ffb73550736ff36c0a84f3e0317a86f8b5f139e6ffe1f821de6d9127898ff3be00a7c3ab2cd03e3d697560ff40016e47b3bb2e96bbd559d8f32bbff4b7065f193042c98873acf240af6adbf3c83c5f2954bb0c7bcd77c107d81d2fdebc63e33ff640aaecc9e1c8151df5c803dfaadc64b52dfa03ed64636ffb4ff4b2867f453ede7227586fcd3f9264ded91fffafe236d5da37fe83c91ceb7b9e5b7f6731ff92ed7f747d6fbf7e185cf58347e3e6932e47b3430fa893edf87d795c2fc3f003b67f5f902cec17abfde0dfa3c053b3c5ffb832fc2eb8fddcf233887fc195c801f46b6f3cdc02558fba72f7d2d1a7f7e321ee58fe0cad86bbff24dd3e2fe74fef836b0c6eb60d62fa6bf5e07b3419f853dd7dc70fb8bd5f1255fd90ed30f9f3c5ff30ddff21ddff384a7fcc08ffcc4cf61cdf8855ff9e79c7e1db4dff89d3f7891977899577895d7789d377893b7f83b6fcfe937bc13b477798ff7f9800ff928ac633ee11f7cca6761d7f99c7e1b3cb908da11c7413be1943376e153cc39175c72f549ff9e17c31744429e6a6aa8a58e2ee98aaee9866e7f617fc24b7417a4f734a1293dd0233dd133cd8285177aa5f9f3b63ca5377aa78f607b919668995682e62aadd17ab0b1419b9ff41f682b48bed336edd02eed05ed7d5ea3033a0cdf1ed1f127fd273ae123fa41a774a6b685cee982228a837e42e927fd47caf8985c38651eb40b2ac38e4a5842658a97fab33fd248cb87d2c9a55cc9b5dcc82d1fc99ddccb44a6f230af2f8ff224cf417f262ff22a3fe54ddee543166549966545567f617f4dd66523dc6b2c9bb225df655b7682f692ecca9eeccfe97772c09b722847722c27c1f3eb70f66bf9116c9fca999ccbc59cfe25bf4a143a5ef8992561324a78bd92522acf9ebc78efe7cf7b153276db37bef59dbff457fedadff85b7f27abfede4ffcd4cf9ff76faeff4fffefeff8c7f5fedfdfbffc0fa355c495</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>linkslabel.h</includehint> +</includehints> +</UI> diff --git a/kig/modes/typesdialog.cpp b/kig/modes/typesdialog.cpp new file mode 100644 index 00000000..67621c20 --- /dev/null +++ b/kig/modes/typesdialog.cpp @@ -0,0 +1,282 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + + 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +**/ + +#include "typesdialog.h" +#include "typesdialog.moc" + +#include "edittype.h" +#include "../kig/kig_part.h" +#include "../misc/guiaction.h" +#include "../misc/object_constructor.h" + +#include <kapplication.h> +#include <kdebug.h> +#include <kfiledialog.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpushbutton.h> +#include <kstdguiitem.h> + +#include <qfile.h> +#include <qpixmap.h> +#include <qstringlist.h> +#include <qtextstream.h> + +#include <algorithm> +#include <vector> + +class MacroListElement + : public QListViewItem +{ + Macro* macro; +public: + MacroListElement( KListView* lv, Macro* m ); + Macro* getMacro() const { return macro; } +}; + +MacroListElement::MacroListElement( KListView* lv, Macro* m ) + : QListViewItem( lv, QString::null, m->action->descriptiveName(), m->action->description() ), + macro( m ) +{ +} + +TypesDialog::TypesDialog( QWidget* parent, KigPart& part ) + : TypesDialogBase( parent, "types_dialog", true ), mpart( part ) +{ + // improving GUI look'n'feel... + buttonHelp->setGuiItem( KStdGuiItem::help() ); + buttonOk->setGuiItem( KStdGuiItem::ok() ); + buttonCancel->setGuiItem( KStdGuiItem::cancel() ); + il = part.instance()->iconLoader(); + buttonEdit->setIconSet( QIconSet( il->loadIcon( "edit", KIcon::Small ) ) ); + buttonRemove->setIconSet( QIconSet( il->loadIcon( "editdelete", KIcon::Small ) ) ); + buttonExport->setIconSet( QIconSet( il->loadIcon( "fileexport", KIcon::Small ) ) ); + buttonImport->setIconSet( QIconSet( il->loadIcon( "fileimport", KIcon::Small ) ) ); + + typeList->setColumnWidth( 0, 22 ); + typeList->setColumnWidth( 1, 140 ); + typeList->setColumnWidth( 2, 240 ); + + // loading macros... + loadAllMacros(); + + popup = new QPopupMenu( this ); + popup->insertItem( SmallIcon( "edit" ), i18n( "&Edit..." ), this, SLOT( editType() ) ); + popup->insertItem( SmallIcon( "editdelete" ), i18n( "&Delete" ), this, SLOT( deleteType() ) ); + popup->insertSeparator(); + popup->insertItem( SmallIcon( "fileexport" ), i18n( "E&xport..." ), this, SLOT( exportType() ) ); + + // saving types + part.saveTypes(); +} + +QListViewItem* TypesDialog::newListItem( Macro* m ) +{ + MacroListElement* e = new MacroListElement( typeList, m ); + QCString ifn = m->action->iconFileName(); + if ( !ifn.isNull() ) + { + QPixmap p = il->loadIcon( ifn, KIcon::Small ); + e->setPixmap( 0, p ); + } + return e; +} + +TypesDialog::~TypesDialog() +{ +} + +void TypesDialog::helpSlot() +{ + kapp->invokeHelp( QString::fromLatin1( "working-with-types" ), + QString::fromLatin1( "kig" ) ); +} + +void TypesDialog::okSlot() +{ + mpart.saveTypes(); + mpart.deleteTypes(); + mpart.loadTypes(); + accept(); +} + +void TypesDialog::deleteType() +{ + std::vector<QListViewItem*> items; + std::vector<Macro*> selectedTypes; + QListViewItemIterator it( typeList ); + while ( it.current() ) { + if ( ( it.current() )->isSelected() ) + { + items.push_back( it.current() ); + selectedTypes.push_back( static_cast<MacroListElement*>( it.current() )->getMacro() ); + } + ++it; + } + if (selectedTypes.empty()) return; + QStringList types; + for ( std::vector<Macro*>::iterator j = selectedTypes.begin(); + j != selectedTypes.end(); ++j ) + types << ( *j )->action->descriptiveName(); + if ( KMessageBox::warningContinueCancelList( this, + i18n( "Are you sure you want to delete this type?", + "Are you sure you want to delete these %n types?", selectedTypes.size() ), + types, i18n("Are You Sure?"), KStdGuiItem::cont(), + "deleteTypeWarning") == KMessageBox::Cancel ) + return; + for ( std::vector<QListViewItem*>::iterator i = items.begin(); i != items.end(); ++i) + { + int appel = typeList->itemIndex(*i); + assert (appel != -1); + delete *i; + }; + for ( std::vector<Macro*>::iterator j = selectedTypes.begin(); + j != selectedTypes.end(); ++j) + MacroList::instance()->remove( *j ); +} + +void TypesDialog::exportType() +{ + std::vector<Macro*> types; + QListViewItemIterator it( typeList ); + while ( it.current() ) { + if ( ( it.current() )->isSelected() ) + { + types.push_back( static_cast<MacroListElement*>( it.current() )->getMacro() ); + } + ++it; + } + if (types.empty()) return; + QString file_name = KFileDialog::getSaveFileName(":macro", i18n("*.kigt|Kig Types Files\n*|All Files"), this, i18n( "Export Types" ) ); + if ( file_name.isNull() ) + return; + QFile fi( file_name ); + if ( fi.exists() ) + if ( KMessageBox::warningContinueCancel( this, i18n( "The file \"%1\" already exists. " + "Do you wish to overwrite it?" ).arg( fi.name() ), + i18n( "Overwrite File?" ), i18n("Overwrite") ) == KMessageBox::Cancel ) + return; + MacroList::instance()->save( types, file_name ); +} + +void TypesDialog::importTypes() +{ + QStringList file_names = + KFileDialog::getOpenFileNames(":importTypes", i18n("*.kigt|Kig Types Files\n*|All Files"), this, i18n( "Import Types" )); + + std::vector<Macro*> macros; + + for ( QStringList::Iterator i = file_names.begin(); + i != file_names.end(); ++i) + { + std::vector<Macro*> nmacros; + bool ok = MacroList::instance()->load( *i, nmacros, mpart ); + if ( ! ok ) + continue; + std::copy( nmacros.begin(), nmacros.end(), std::back_inserter( macros ) ); + }; + MacroList::instance()->add( macros ); + + for ( uint i = 0; i < macros.size(); ++i ) + typeList->insertItem( newListItem( macros[i] ) ); +} + +QString TypesDialog::fetchIconFromListItem( QListViewItem* i ) +{ + QListViewItemIterator it( typeList ); + Macro* ai = static_cast<MacroListElement*>( i )->getMacro(); + while ( it.current() ) { + if ( ( it.current() )->isSelected() ) + { + Macro* ait = static_cast<MacroListElement*>( it.current() )->getMacro(); + if ( ai == ait ) + { + return ai->ctor->iconFileName( true ); + } + } + ++it; + } + return "gear"; +} + +void TypesDialog::editType() +{ + std::vector<QListViewItem*> items; + QListViewItemIterator it( typeList ); + while ( it.current() ) { + if ( ( it.current() )->isSelected() ) + items.push_back( it.current() ); + ++it; + } + if ( items.size() == 0 ) + return; + if ( items.size() > 1 ) + { + KMessageBox::sorry( this, + i18n( "There is more than one type selected. You can " + "only edit one type at a time. Please select " + "only the type you want to edit and try again." ), + i18n( "More Than One Type Selected" ) ); + return; + } + QListViewItem* i = items[0]; + EditType* d = new EditType( this, i->text( 1 ), i->text( 2 ), fetchIconFromListItem( i ) ); + if ( d->exec() ) + { + QString newname = d->name(); + QString newdesc = d->description(); + QString newicon = d->icon(); + + Macro* oldmacro = static_cast<MacroListElement*>( i )->getMacro(); +// mpart.unplugActionLists(); + oldmacro->ctor->setName( newname ); + oldmacro->ctor->setDescription( newdesc ); + QCString ncicon( newicon.utf8() ); + oldmacro->ctor->setIcon( ncicon ); +// mpart.plugActionLists(); + + typeList->clear(); + + loadAllMacros(); + } + delete d; +} + +void TypesDialog::contextMenuRequested( QListViewItem*, const QPoint& p, int ) +{ + popup->exec( p ); +} + +void TypesDialog::loadAllMacros() +{ + const vec& macros = MacroList::instance()->macros(); + for ( vec::const_reverse_iterator i = macros.rbegin(); i != macros.rend(); ++i ) + { + typeList->insertItem( newListItem( *i ) ); + } +} + +void TypesDialog::cancelSlot() +{ + mpart.deleteTypes(); + mpart.loadTypes(); + reject(); +} diff --git a/kig/modes/typesdialog.h b/kig/modes/typesdialog.h new file mode 100644 index 00000000..6f0e4702 --- /dev/null +++ b/kig/modes/typesdialog.h @@ -0,0 +1,70 @@ +/* + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + + 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +*/ + +#ifndef KIG_MODES_TYPESDIALOG_H +#define KIG_MODES_TYPESDIALOG_H + +#include "typesdialogbase.h" + +#include "../misc/lists.h" + +#include <qpopupmenu.h> + +#include <klistview.h> +#include <kiconloader.h> + +class KigPart; +class KigDocument; + +/** + * Manage the macro types... + */ +class TypesDialog : public TypesDialogBase +{ + Q_OBJECT + + // necessary because some MacroList functions need it.. + KigPart& mpart; + const KIconLoader* il; + QPopupMenu* popup; +public: + TypesDialog( QWidget* parent, KigPart& ); + ~TypesDialog(); + +public slots: + void helpSlot(); + void okSlot(); + void cancelSlot(); + +protected slots: + void deleteType(); + void exportType(); + void importTypes(); + void editType(); + void contextMenuRequested( QListViewItem* i, const QPoint& p, int c ); + +private: + QListViewItem* newListItem( Macro* m ); + QString fetchIconFromListItem( QListViewItem* i ); + void loadAllMacros(); + typedef MacroList::vectype vec; +}; + +#endif diff --git a/kig/modes/typesdialogbase.ui b/kig/modes/typesdialogbase.ui new file mode 100644 index 00000000..7cc7effb --- /dev/null +++ b/kig/modes/typesdialogbase.ui @@ -0,0 +1,337 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>TypesDialogBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>TypesDialogBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>456</width> + <height>249</height> + </rect> + </property> + <property name="caption"> + <string>Manage Types</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can manage types; you can remove them, and load and save them from and to files...</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView"> + <column> + <property name="text"> + <string>Icon</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Description</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>typeList</cstring> + </property> + <property name="selectionMode" stdset="0"> + <enum>Extended</enum> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Select types here...</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This is a list of the current macro types... You can select, edit, delete, export and import them...</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonEdit</cstring> + </property> + <property name="text"> + <string>Edit...</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Edit the selected type.</string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonRemove</cstring> + </property> + <property name="text"> + <string>Delete</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Delete all the selected types in the list.</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonExport</cstring> + </property> + <property name="text"> + <string>Export...</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Export all the selected types to a file.</string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonImport</cstring> + </property> + <property name="text"> + <string>Import...</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Import macros that are contained in one or more files.</string> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>Line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonHelp</cstring> + </property> + <property name="text"> + <string>&Help</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>buttonExport</sender> + <signal>clicked()</signal> + <receiver>TypesDialogBase</receiver> + <slot>exportType()</slot> + </connection> + <connection> + <sender>buttonHelp</sender> + <signal>clicked()</signal> + <receiver>TypesDialogBase</receiver> + <slot>helpSlot()</slot> + </connection> + <connection> + <sender>buttonImport</sender> + <signal>clicked()</signal> + <receiver>TypesDialogBase</receiver> + <slot>importTypes()</slot> + </connection> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>TypesDialogBase</receiver> + <slot>okSlot()</slot> + </connection> + <connection> + <sender>buttonRemove</sender> + <signal>clicked()</signal> + <receiver>TypesDialogBase</receiver> + <slot>deleteType()</slot> + </connection> + <connection> + <sender>buttonEdit</sender> + <signal>clicked()</signal> + <receiver>TypesDialogBase</receiver> + <slot>editType()</slot> + </connection> + <connection> + <sender>typeList</sender> + <signal>contextMenuRequested(QListViewItem*,const QPoint&,int)</signal> + <receiver>TypesDialogBase</receiver> + <slot>contextMenuRequested(QListViewItem*,const QPoint&,int)</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>TypesDialogBase</receiver> + <slot>cancelSlot()</slot> + </connection> +</connections> +<slots> + <slot access="protected">deleteType()</slot> + <slot access="protected">exportType()</slot> + <slot>helpSlot()</slot> + <slot access="protected">importTypes()</slot> + <slot>okSlot()</slot> + <slot access="protected">editType()</slot> + <slot access="protected">contextMenuRequested( QListViewItem* i, const QPoint& p, int c )</slot> + <slot>cancelSlot()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> |