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