1 /*
2     This file is part of Kig, a KDE program for Interactive Geometry...
3     SPDX-FileCopyrightText: 2002 Dominique Devriese <devriese@kde.org>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "popup.h"
9 
10 #include "../../kig/kig_part.h"
11 #include "../../kig/kig_document.h"
12 #include "../../kig/kig_view.h"
13 #include "../../kig/kig_commands.h"
14 #include "../../objects/object_imp.h"
15 #include "../../objects/object_drawer.h"
16 #include "../../objects/bogus_imp.h"
17 #include "../../objects/point_imp.h"
18 #include "../../objects/line_imp.h"
19 #include "../../objects/other_type.h"
20 #include "../../objects/object_factory.h"
21 #include "../../objects/polygon_imp.h"
22 #include "../../objects/text_imp.h"
23 #include "../../objects/text_type.h"
24 #include "../../misc/lists.h"
25 #include "../../misc/argsparser.h"
26 #include "../../misc/kigpainter.h"
27 #include "../../misc/coordinate_system.h"
28 #include "../../misc/object_constructor.h"
29 #include "../construct_mode.h"
30 #include "../normal.h"
31 #include "../moving.h"
32 
33 #include "builtindocumentactionsprovider.h"
34 #include "builtinobjectactionsprovider.h"
35 #include "nameobjectactionsprovider.h"
36 #include "objectconstructoractionsprovider.h"
37 #include "objecttypeactionsprovider.h"
38 #include "propertiesactionsprovider.h"
39 
40 #include <KIconEngine>
41 
42 #include <config-kig.h>
43 
44 #ifdef KIG_ENABLE_PYTHON_SCRIPTING
45 #include "scriptactionsprovider.h"
46 #endif
47 
48 #define MAXMENUITEMS 20
49 /*
50  * mp: if a submenus requires more than MAXMENUITEMS items then a new
51  * submenu titled " more..." is added
52  */
53 
54 using namespace std;
55 
NormalModePopupObjects(KigPart & part,KigWidget & view,NormalMode & mode,const std::vector<ObjectHolder * > & objs,const QPoint & plc)56 NormalModePopupObjects::NormalModePopupObjects( KigPart& part,
57                                                 KigWidget& view,
58                                                 NormalMode& mode,
59                                                 const std::vector<ObjectHolder*>& objs,
60                                                 const QPoint& plc )
61   : QMenu( &view ), mplc( plc ), mpart( part ), mview( view ), mobjs( objs ),
62     mmode( mode ), monlylabels( false )
63 {
64   bool empty = objs.empty();
65   bool single = objs.size() == 1;
66 
67   QString title;
68   if ( empty )
69     title = i18n( "Kig Document" );
70   else if ( single )
71   {
72     if ( !objs[0]->name().isNull() )
73       title = QStringLiteral( "%1 %2" ).arg( objs[0]->imp()->type()->translatedName() ).arg( objs[0]->name() );
74     else
75       title = objs[0]->imp()->type()->translatedName();
76   }
77   else
78     title = i18np( "%1 Object", "%1 Objects", objs.size() );
79   addSection( title );
80 
81   if ( !empty )
82   {
83     monlylabels = true;
84     uint i = 0;
85     while ( i < objs.size() && monlylabels )
86     {
87       monlylabels &= objs[i]->imp()->inherits( TextImp::stype() );
88       ++i;
89     }
90   }
91 
92   if ( empty )
93   {
94     // provides some diverse stuff like "unhide all", set coordinate
95     // system etc.
96     mproviders.push_back( new BuiltinDocumentActionsProvider() );
97   };
98   // construct an object using these objects and start constructing an
99   // object using these objects
100   mproviders.push_back( new ObjectConstructorActionsProvider() );
101   if ( single )
102     mproviders.push_back( new NameObjectActionsProvider() );
103   if ( ! empty )
104   {
105     // stuff like hide, show, delete, set size, set color..
106     mproviders.push_back( new BuiltinObjectActionsProvider() );
107     // show property as text label -> show menu
108     // and construct property's as objects -> construct menu
109     mproviders.push_back( new PropertiesActionsProvider() );
110     // stuff like "redefine point" for a fixed or constrained point..
111     mproviders.push_back( new ObjectTypeActionsProvider() );
112   }
113 #ifdef KIG_ENABLE_PYTHON_SCRIPTING
114   // script action..
115   mproviders.push_back( new ScriptActionsProvider() );
116 #endif
117 
118   static const QString menunames[NumberOfMenus] =
119     {
120       i18n( "&Transform" ),
121       i18n( "T&est" ),
122       i18n( "Const&ruct" ),
123       i18n( "&Start" ),
124       i18n( "Add Te&xt Label" ),
125       i18n( "Set Co&lor" ),
126       i18n( "Set &Pen Width" ),
127       i18n( "Set St&yle" ),
128       QString(),
129       i18n( "Set Coordinate S&ystem" )
130     };
131   static const QString menuicons[NumberOfMenus] =
132     {
133       "centralsymmetry",
134       "test",
135       QString(),
136       "system-run",
137       "kig_text", // <- draw-text... hope I manage to rename it in time
138       "format-fill-color",
139 //      "colorize",
140       "sizer",
141       "draw-brush",
142       QString(),
143       QString()
144     };
145 
146   // creating the menus and setting their title and icon
147   KIconLoader* l = part.iconLoader();
148   for ( uint i = 0; i < NumberOfMenus; ++i )
149   {
150     if ( i == ToplevelMenu ) continue;
151     mmenus[i] = mmenuslast[i] = new QMenu( this );
152     if ( !menunames[i].isEmpty() )
153       mmenus[i]->setTitle( menunames[i] );
154     if ( !menuicons[i].isEmpty() )
155     {
156       mmenus[i]->setIcon( QIcon( new KIconEngine( menuicons[i], l ) ) );
157     }
158   }
159   mmenus[ToplevelMenu] = mmenuslast[ToplevelMenu] = this;
160   /*
161    * mp: previously ToplevelMenu was treated like a submenu (of itself).
162    * unfortunately this had as side effect a duplicated triggering of its
163    * actions with unpredictable consequences.  In this way the addAction
164    * in addInternalAction directly adds the action at toplevel.
165    */
166 
167   connect( this, &QMenu::triggered,
168            this, &NormalModePopupObjects::toplevelMenuSlot );
169 
170   for ( int i = 0; i < NumberOfMenus; ++i )
171   {
172     int nextfree = 10;
173     for ( uint j = 0; j < mproviders.size(); ++j )
174       mproviders[j]->fillUpMenu( *this, i, nextfree );
175   };
176   QAction* firstrealaction = actions()[1];
177   for ( int i = 0; i < NumberOfMenus; ++i )
178   {
179     if ( i == ToplevelMenu ) continue;
180     if ( mmenus[i]->actions().count() == 0 ) continue;
181     //addMenu( mmenus[i] );
182     insertMenu( firstrealaction, mmenus[i] );
183   };
184   // addActions( mmenus[ToplevelMenu]->actions() );
185 }
186 
toplevelMenuSlot(QAction * act)187 void NormalModePopupObjects::toplevelMenuSlot( QAction* act )
188 {
189 //  activateAction( ToplevelMenu, i );
190   int data = act->data().toInt();
191   int id = data & 0xFF;
192   int menu = data >> 8;
193 qDebug() << "menu: " << menu << " - id: " << id;
194   activateAction( menu, id );
195 }
196 
activateAction(int menu,int action)197 void NormalModePopupObjects::activateAction( int menu, int action )
198 {
199   bool done = false;
200   // we need action - 10 cause we called fillUpMenu with nextfree set
201   // to 10 initially..
202   action -= 10;
203 qDebug() << "MENU: " << menu << " - ACTION: " << action;
204   for ( uint i = 0; ! done && i < mproviders.size(); ++i )
205     done = mproviders[i]->executeAction( menu, action, mobjs, *this, mpart, mview, mmode );
206 }
207 
~NormalModePopupObjects()208 NormalModePopupObjects::~NormalModePopupObjects()
209 {
210   delete_all ( mproviders.begin(), mproviders.end() );
211 }
212 
addInternalAction(int menu,const QIcon & pix,int id)213 QAction* NormalModePopupObjects::addInternalAction( int menu, const QIcon& pix, int id )
214 {
215   return addInternalAction( menu, pix, QLatin1String(""), id );
216 }
217 
addInternalAction(int menu,const QIcon & icon,const QString & name,int id)218 QAction* NormalModePopupObjects::addInternalAction( int menu, const QIcon& icon, const QString& name, int id )
219 {
220   if ( mmenuslast[menu]->actions().size() >= MAXMENUITEMS )
221     mmenuslast[menu] = mmenuslast[menu]->addMenu( i18nc( "More menu items", "More..." ) );
222   QAction* newaction = mmenuslast[menu]->addAction( icon, name );
223   newaction->setData( QVariant::fromValue( ( menu << 8 ) | id ) );
224   return newaction;
225 }
226 
addInternalAction(int menu,const QString & name,int id)227 QAction* NormalModePopupObjects::addInternalAction( int menu, const QString& name, int id )
228 {
229   if ( mmenuslast[menu]->actions().size() >= MAXMENUITEMS )
230     mmenuslast[menu] = mmenuslast[menu]->addMenu( i18nc( "More menu items", "More..." ) );
231   QAction* newaction = mmenuslast[menu]->addAction( name );
232   newaction->setData( QVariant::fromValue( ( menu << 8 ) | id ) );
233   return newaction;
234 }
235 
addInternalAction(int menu,QAction * act)236 QAction* NormalModePopupObjects::addInternalAction( int menu, QAction* act )
237 {
238   if ( mmenuslast[menu]->actions().size() >= MAXMENUITEMS )
239     mmenuslast[menu] = mmenuslast[menu]->addMenu( i18nc( "More menu items", "More..." ) );
240   mmenuslast[menu]->addAction( act );
241   return act;
242 }
243