1 /***************************************************************************
2                           imagemapeditor.cpp  -  description
3                             -------------------
4     begin                : Wed Apr 4 2001
5     copyright            : (C) 2001 by Jan Schäfer
6     email                : j_schaef@informatik.uni-kl.de
7 ***************************************************************************/
8 
9 /***************************************************************************
10 *                                                                         *
11 *   This program is free software; you can redistribute it and/or modify  *
12 *   it under the terms of the GNU General Public License as published by  *
13 *   the Free Software Foundation; either version 2 of the License, or     *
14 *   (at your option) any later version.                                   *
15 *                                                                         *
16 ***************************************************************************/
17 
18 #include "kimagemapeditor.h"
19 
20 #include <iostream>
21 #include <assert.h>
22 
23 // Qt
24 #include <QAction>
25 #include <QApplication>
26 #include <QComboBox>
27 #include <QDialogButtonBox>
28 #include <QFile>
29 #include <QFileDialog>
30 #include <QFileInfo>
31 #include <QFontDatabase>
32 #include <QIcon>
33 #include <QInputDialog>
34 #include <QLayout>
35 #include <QLinkedList>
36 #include <QListWidget>
37 #include <QMenu>
38 #include <QMimeDatabase>
39 #include <QMimeType>
40 #include <QPainter>
41 #include <QPixmap>
42 #include <QPushButton>
43 #include <QScrollArea>
44 #include <QSplitter>
45 #include <QStandardPaths>
46 #include <QTabWidget>
47 #include <QTextEdit>
48 #include <QTextStream>
49 #include <QToolTip>
50 #include <QUndoStack>
51 #include <QVBoxLayout>
52 
53 // KDE Frameworks
54 #include <KPluginMetaData>
55 #include <KActionCollection>
56 #include <KConfigGroup>
57 #include <KIO/Job>
58 #include <KLocalizedString>
59 #include <KMessageBox>
60 #include <KPluginFactory>
61 #include <KSharedConfig>
62 #include <KUndoActions>
63 #include <KXMLGUIFactory>
64 #include <KXmlGuiWindow>
65 
66 // local
67 #include "kimagemapeditor_debug.h"
68 #include "drawzone.h"
69 #include "kimedialogs.h"
70 #include "kimecommands.h"
71 #include "areacreator.h"
72 #include "arealistview.h"
73 #include "imageslistview.h"
74 #include "mapslistview.h"
75 #include "kimecommon.h"
76 #include "imagemapchoosedialog.h"
77 #include "kimagemapeditor_version.h"
78 
79 K_PLUGIN_FACTORY_WITH_JSON(KImageMapEditorFactory, "kimagemapeditorpart.json", registerPlugin<KImageMapEditor>();)
80 
KImageMapEditor(QWidget * parentWidget,QObject * parent,const KPluginMetaData & metaData,const QVariantList &)81 KImageMapEditor::KImageMapEditor(QWidget *parentWidget, QObject *parent,
82                                  const KPluginMetaData &metaData,
83                                  const QVariantList & )
84   : KParts::ReadWritePart(parent)
85 {
86   setMetaData(metaData);
87 
88 //  KDockMainWindow* mainWidget;
89 
90   mainWindow = dynamic_cast<KXmlGuiWindow*>(parent) ;
91   QSplitter * splitter = nullptr;
92   tabWidget = nullptr;
93 
94   if (mainWindow) {
95 //    qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: We got a KDockMainWindow !";
96 
97 //    K3DockWidget* parentDock = mainDock->getMainDockWidget();
98     areaDock = new QDockWidget(i18n("Areas"),mainWindow);
99     mapsDock = new QDockWidget(i18n("Maps"),mainWindow);
100     imagesDock = new QDockWidget(i18n("Images"),mainWindow);
101 
102     // Needed to save their state
103     areaDock->setObjectName("areaDock");
104     mapsDock->setObjectName("mapsDock");
105     imagesDock->setObjectName("imagesDock");
106 
107     mainWindow->addDockWidget( Qt::LeftDockWidgetArea, areaDock);
108     mainWindow->addDockWidget( Qt::LeftDockWidgetArea, mapsDock);
109     mainWindow->addDockWidget( Qt::LeftDockWidgetArea, imagesDock);
110 
111     areaListView = new AreaListView(areaDock);
112     mapsListView = new MapsListView(mapsDock);
113     imagesListView = new ImagesListView(imagesDock);
114 
115     areaDock->setWidget(areaListView);
116     mapsDock->setWidget(mapsListView);
117     imagesDock->setWidget(imagesListView);
118 
119   }
120   else
121   {
122     areaDock = nullptr;
123     mapsDock = nullptr;
124     imagesDock = nullptr;
125     splitter = new QSplitter(parentWidget);
126     tabWidget = new QTabWidget(splitter);
127     areaListView = new AreaListView(tabWidget);
128     mapsListView = new MapsListView(tabWidget);
129     imagesListView = new ImagesListView(tabWidget);
130 
131     tabWidget->addTab(areaListView,i18n("Areas"));
132     tabWidget->addTab(mapsListView,i18n("Maps"));
133     tabWidget->addTab(imagesListView,i18n("Images"));
134   }
135 
136 
137   connect( areaListView->listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged()));
138   connect( areaListView->listView,
139            SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
140            this,
141            SLOT(showTagEditor(QTreeWidgetItem*)));
142   connect( areaListView->listView,
143            SIGNAL(customContextMenuRequested(QPoint)),
144            this,
145            SLOT(slotShowPopupMenu(QPoint)));
146 
147   connect( mapsListView, SIGNAL(mapSelected(QString)),
148            this, SLOT(setMap(QString)));
149 
150   connect( mapsListView, SIGNAL(mapRenamed(QString)),
151            this, SLOT(setMapName(QString)));
152 
153   connect( mapsListView->listView(),
154            SIGNAL(customContextMenuRequested(QPoint)),
155            this,
156            SLOT(slotShowMapPopupMenu(QPoint)));
157 
158   connect( imagesListView, &ImagesListView::imageSelected,
159            this, QOverload<const QUrl &>::of(&KImageMapEditor::setPicture));
160 
161   connect( imagesListView,
162            SIGNAL(customContextMenuRequested(QPoint)),
163            this,
164            SLOT(slotShowImagePopupMenu(QPoint)));
165 
166   if (splitter) {
167     drawZone = new DrawZone(splitter,this);
168     splitter->setStretchFactor(splitter->indexOf(tabWidget), 0);
169     splitter->setStretchFactor(splitter->indexOf(drawZone), 1);
170     setWidget(splitter);
171   } else {
172     QScrollArea *sa = new QScrollArea(mainWindow);
173     drawZone = new DrawZone(nullptr,this);
174     mainWindow->setCentralWidget(sa);
175     sa->setWidget(drawZone);
176     setWidget(mainWindow);
177     //    sa->setWidgetResizable(true);
178   }
179 
180 
181   areas = new AreaList();
182   currentSelected= new AreaSelection();
183   _currentToolType=KImageMapEditor::Selection;
184   copyArea = nullptr;
185   defaultArea = nullptr;
186   currentMapElement = nullptr;
187 
188   setupActions();
189   setupStatusBar();
190 
191   setXMLFile("kimagemapeditorpartui.rc");
192 
193   setPicture(getBackgroundImage());
194 
195   init();
196   readConfig();
197 }
198 
~KImageMapEditor()199 KImageMapEditor::~KImageMapEditor() {
200   writeConfig();
201 
202   delete areas;
203 
204   delete currentSelected;
205   delete copyArea;
206   delete defaultArea;
207 
208   // Delete our DockWidgets
209   if (areaDock) {
210     areaDock->hide();
211     mapsDock->hide();
212     imagesDock->hide();
213 
214     delete areaDock;
215     delete mapsDock;
216     delete imagesDock;
217   }
218 
219 }
220 
componentName() const221 QString KImageMapEditor::componentName() const
222 {
223     // the part ui.rc file is in the program folder, not a separate one
224     // TODO: change the component name to "kimagemapeditorpart" by removing this method and
225     // adapting the folder where the file is placed.
226     // Needs a way to also move any potential custom user ui.rc files
227     // from kimagemapeditor/ to kimagemapeditorpart/
228     return QStringLiteral("kimagemapeditor");
229 }
230 
MapTag()231 MapTag::MapTag() {
232   modified = false;
233   name.clear();
234 }
235 
init()236 void KImageMapEditor::init()
237 {
238   _htmlContent.clear();
239   _imageUrl.clear();
240   //  closeUrl();
241   HtmlElement* el = new HtmlElement("<html>\n");
242   _htmlContent.append(el);
243   el = new HtmlElement("<head>\n");
244   _htmlContent.append(el);
245   el = new HtmlElement("</head>\n");
246   _htmlContent.append(el);
247   el = new HtmlElement("<body>\n");
248   _htmlContent.append(el);
249 
250   addMap(i18n("unnamed"));
251 
252   el = new HtmlElement("</body>\n");
253   _htmlContent.append(el);
254   el = new HtmlElement("</html>\n");
255   _htmlContent.append(el);
256 
257   setImageActionsEnabled(false);
258 }
259 
setReadWrite(bool)260 void KImageMapEditor::setReadWrite(bool)
261 {
262 
263   // For now it does not matter if it is readwrite or readonly
264   // it is always readwrite, because Quanta only supports ReadOnlyParts
265   // at this moment and in that case it should be readwrite, too.
266   ReadWritePart::setReadWrite(true);
267   /*
268     if (rw)
269       ;
270     else
271     {
272      actionCollection()->remove(arrowAction);
273      actionCollection()->remove(circleAction);
274      actionCollection()->remove(rectangleAction);
275      actionCollection()->remove(polygonAction);
276      actionCollection()->remove(freehandAction);
277      actionCollection()->remove(addPointAction);
278      actionCollection()->remove(removePointAction);
279 
280      actionCollection()->remove(cutAction);
281      actionCollection()->remove(deleteAction);
282      actionCollection()->remove(copyAction);
283      actionCollection()->remove(pasteAction);
284 
285      actionCollection()->remove(mapNewAction);
286      actionCollection()->remove(mapDeleteAction);
287      actionCollection()->remove(mapNameAction);
288      actionCollection()->remove(mapDefaultAreaAction);
289 
290      actionCollection()->remove(areaPropertiesAction);
291 
292      actionCollection()->remove(moveLeftAction);
293      actionCollection()->remove(moveRightAction);
294      actionCollection()->remove(moveUpAction);
295      actionCollection()->remove(moveDownAction);
296 
297      actionCollection()->remove(increaseWidthAction);
298      actionCollection()->remove(decreaseWidthAction);
299      actionCollection()->remove(increaseHeightAction);
300      actionCollection()->remove(decreaseHeightAction);
301 
302      actionCollection()->remove(toFrontAction);
303      actionCollection()->remove(toBackAction);
304      actionCollection()->remove(forwardOneAction);
305      actionCollection()->remove(backOneAction);
306 
307      actionCollection()->remove(imageRemoveAction);
308      actionCollection()->remove(imageAddAction);
309      actionCollection()->remove(imageUsemapAction);
310 
311     }
312   */
313 
314 }
315 
setModified(bool modified)316 void KImageMapEditor::setModified(bool modified)
317 {
318     // get a handle on our Save action and make sure it is valid
319     QAction *save = actionCollection()->action(KStandardAction::name(KStandardAction::Save));
320     if (!save)
321         return;
322 
323     // if so, we either enable or disable it based on the current
324     // state
325     if (modified)
326         save->setEnabled(true);
327     else
328         save->setEnabled(false);
329 
330     // in any event, we want our parent to do it's thing
331     ReadWritePart::setModified(modified);
332 }
333 
334 
config()335 KConfig *KImageMapEditor::config()
336 {
337     /* TODO KF5
338     KSharedConfigPtr tmp = KimeFactory::componentData().config();
339     return tmp.data();
340     */
341     return new KConfig();
342 }
343 
readConfig(const KConfigGroup & config)344 void KImageMapEditor::readConfig(const KConfigGroup &config) {
345   KConfigGroup data = config.parent().group( "Data" );
346   recentFilesAction->loadEntries( data );
347 }
348 
writeConfig(KConfigGroup & config)349 void KImageMapEditor::writeConfig(KConfigGroup& config) {
350   config.writeEntry("highlightareas",highlightAreasAction->isChecked());
351   config.writeEntry("showalt",showAltAction->isChecked());
352   KConfigGroup data = config.parent().group( "Data" );
353   recentFilesAction->saveEntries( data );
354   saveLastURL(config);
355 
356 }
357 
readConfig()358 void KImageMapEditor::readConfig() {
359   readConfig(config()->group("General Options" ) );
360   slotConfigChanged();
361 }
362 
writeConfig()363 void KImageMapEditor::writeConfig() {
364   KConfigGroup cg( config(), "General Options");
365   writeConfig( cg );
366   config()->sync();
367 }
368 
369 
saveProperties(KConfigGroup & config)370 void KImageMapEditor::saveProperties(KConfigGroup &config)
371 {
372   saveLastURL(config);
373 }
374 
readProperties(const KConfigGroup & config)375 void KImageMapEditor::readProperties(const KConfigGroup& config)
376 {
377   openLastURL(config);
378 }
379 
slotConfigChanged()380 void KImageMapEditor::slotConfigChanged()
381 {
382   KConfigGroup group = config()->group("Appearance");
383   int newHeight=group.readEntry("maximum-preview-height",50);
384   group = config()->group("General Options");
385   _commandHistory->setUndoLimit(group.readEntry("undo-level",100));
386 #if 0
387   _commandHistory->setRedoLimit(group.readEntry("redo-level",100));
388 #endif
389   Area::highlightArea = group.readEntry("highlightareas",true);
390   highlightAreasAction->setChecked(Area::highlightArea);
391   Area::showAlt = group.readEntry("showalt",true);
392   showAltAction->setChecked(Area::showAlt);
393 
394   // if the image preview size changed update all images
395   if (maxAreaPreviewHeight!=newHeight) {
396     maxAreaPreviewHeight=newHeight;
397     areaListView->listView->setIconSize(QSize(newHeight,newHeight));
398   }
399 
400   updateAllAreas();
401   drawZone->repaint();
402 }
403 
openLastURL(const KConfigGroup & config)404 void KImageMapEditor::openLastURL(const KConfigGroup & config) {
405   QUrl lastURL ( config.readPathEntry("lastopenurl", QString()) );
406   QString lastMap = config.readEntry("lastactivemap");
407   QString lastImage = config.readPathEntry("lastactiveimage", QString());
408 
409 
410 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "loading from group : " << config.group();
411 
412 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "loading entry lastopenurl : " << lastURL.path();
413 //  KMessageBox::information(0L, config.group()+" "+lastURL.path());
414   if (!lastURL.isEmpty()) {
415     openUrl(lastURL);
416     if (!lastMap.isEmpty())
417       mapsListView->selectMap(lastMap);
418     if (!lastImage.isEmpty())
419       setPicture(QUrl::fromLocalFile(lastImage));
420 //    qCDebug(KIMAGEMAPEDITOR_LOG) << "opening HTML file with map " << lastMap << " and image " << lastImage;
421 //    if (! openHTMLFile(lastURL, lastMap, lastImage) )
422 //      closeUrl();
423       //openUrl(lastURL);
424       //    else
425       //closeUrl();
426   }
427 }
428 
saveLastURL(KConfigGroup & config)429 void KImageMapEditor::saveLastURL(KConfigGroup & config) {
430   qCDebug(KIMAGEMAPEDITOR_LOG) << "saveLastURL: " << url().path();
431   config.writePathEntry("lastopenurl",url().path());
432   config.writeEntry("lastactivemap",mapName());
433   config.writePathEntry("lastactiveimage",_imageUrl.path());
434 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "writing entry lastopenurl : " << url().path();
435 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "writing entry lastactivemap : " << mapName();
436 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "writing entry lastactiveimage : " << _imageUrl.path();
437   //KMessageBox::information(0L, QString("Group: %1 Saving ... %2").arg(config.group()).arg(url().path()));
438 }
439 
setupActions()440 void KImageMapEditor::setupActions()
441 {
442 	// File Open
443   QAction *temp =
444     KStandardAction::open(this, SLOT(fileOpen()),
445 			  actionCollection());
446   temp->setWhatsThis(i18n("<h3>Open File</h3>Click this to <em>open</em> a new picture or HTML file."));
447   temp->setToolTip(i18n("Open new picture or HTML file"));
448 
449   // File Open Recent
450   recentFilesAction = KStandardAction::openRecent(this, SLOT(openURL(QUrl)),
451                                       actionCollection());
452 	// File Save
453   temp =KStandardAction::save(this, SLOT(fileSave()), actionCollection());
454 	temp->setWhatsThis(i18n("<h3>Save File</h3>Click this to <em>save</em> the changes to the HTML file."));
455 	temp->setToolTip(i18n("Save HTML file"));
456 
457 
458 	// File Save As
459   (void)KStandardAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
460 
461 	// File Close
462   temp=KStandardAction::close(this, SLOT(fileClose()), actionCollection());
463 	temp->setWhatsThis(i18n("<h3>Close File</h3>Click this to <em>close</em> the currently open HTML file."));
464 	temp->setToolTip(i18n("Close HTML file"));
465 
466   // Edit Copy
467   copyAction=KStandardAction::copy(this, SLOT(slotCopy()), actionCollection());
468   copyAction->setWhatsThis(i18n("<h3>Copy</h3>"
469                           "Click this to <em>copy</em> the selected area."));
470   copyAction->setEnabled(false);
471 
472   // Edit Cut
473   cutAction=KStandardAction::cut(this, SLOT(slotCut()), actionCollection());
474   cutAction->setWhatsThis(i18n("<h3>Cut</h3>"
475                           "Click this to <em>cut</em> the selected area."));
476   cutAction->setEnabled(false);
477 
478   // Edit Paste
479   pasteAction=KStandardAction::paste(this, SLOT(slotPaste()), actionCollection());
480   pasteAction->setWhatsThis(i18n("<h3>Paste</h3>"
481                           "Click this to <em>paste</em> the copied area."));
482   pasteAction->setEnabled(false);
483 
484 
485   // Edit Delete
486   deleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")),
487       i18n("&Delete"), this);
488   actionCollection()->addAction("edit_delete", deleteAction );
489   connect(deleteAction, SIGNAL(triggered(bool)), SLOT (slotDelete()));
490   actionCollection()->setDefaultShortcut(deleteAction, QKeySequence(Qt::Key_Delete));
491   deleteAction->setWhatsThis(i18n("<h3>Delete</h3>"
492                           "Click this to <em>delete</em> the selected area."));
493   deleteAction->setEnabled(false);
494 
495   // Edit Undo/Redo
496   _commandHistory = new QUndoStack(this);
497   KUndoActions::createUndoAction(_commandHistory, actionCollection());
498   KUndoActions::createRedoAction(_commandHistory, actionCollection());
499 
500   // Edit Properties
501     areaPropertiesAction  = new QAction(i18n("Pr&operties"), this);
502     actionCollection()->addAction("edit_properties", areaPropertiesAction );
503   connect(areaPropertiesAction, SIGNAL(triggered(bool)), SLOT(showTagEditor()));
504   areaPropertiesAction->setEnabled(false);
505 
506   // View Zoom In
507   zoomInAction=KStandardAction::zoomIn(this, SLOT(slotZoomIn()), actionCollection());
508   // View Zoom Out
509   zoomOutAction=KStandardAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection());
510 
511   // View Zoom
512   zoomAction  = new KSelectAction(i18n("Zoom"), this);
513   actionCollection()->addAction("view_zoom", zoomAction );
514   connect(zoomAction, &KSelectAction::indexTriggered, this, &KImageMapEditor::slotZoom);
515   zoomAction->setWhatsThis(i18n("<h3>Zoom</h3>"
516                           "Choose the desired zoom level."));
517   zoomAction->setItems(QStringList()
518     << i18n("25%")
519     << i18n("50%")
520     << i18n("100%")
521     << i18n("150%")
522     << i18n("200%")
523     << i18n("250%")
524     << i18n("300%")
525     << i18n("500%")
526     << i18n("750%")
527     << i18n("1000%"));
528 
529   zoomAction->setCurrentItem(2);
530 
531   highlightAreasAction = actionCollection()->add<KToggleAction>("view_highlightareas");
532   highlightAreasAction->setText(i18n("Highlight Areas"));
533 
534   connect(highlightAreasAction, SIGNAL(toggled(bool)),
535 	  this, SLOT(slotHighlightAreas(bool)));
536 
537   showAltAction =   actionCollection()->add<KToggleAction>("view_showalt");
538   showAltAction->setText(i18n("Show Alt Tag"));
539   connect(showAltAction, SIGNAL(toggled(bool)),this, SLOT (slotShowAltTag(bool)));
540 
541     mapNameAction  = new QAction(i18n("Map &Name..."), this);
542     actionCollection()->addAction("map_name", mapNameAction );
543   connect(mapNameAction, SIGNAL(triggered(bool)), SLOT(mapEditName()));
544 
545     mapNewAction  = new QAction(i18n("Ne&w Map..."), this);
546     actionCollection()->addAction("map_new", mapNewAction );
547   connect(mapNewAction, SIGNAL(triggered(bool)), SLOT(mapNew()));
548   mapNewAction->setToolTip(i18n("Create a new map"));
549 
550     mapDeleteAction  = new QAction(i18n("D&elete Map"), this);
551     actionCollection()->addAction("map_delete", mapDeleteAction );
552   connect(mapDeleteAction, SIGNAL(triggered(bool)), SLOT(mapDelete()));
553   mapDeleteAction->setToolTip(i18n("Delete the current active map"));
554 
555     mapDefaultAreaAction  = new QAction(i18n("Edit &Default Area..."), this);
556     actionCollection()->addAction("map_defaultarea", mapDefaultAreaAction );
557   connect(mapDefaultAreaAction, SIGNAL(triggered(bool)), SLOT(mapDefaultArea()));
558   mapDefaultAreaAction->setToolTip(i18n("Edit the default area of the current active map"));
559 
560     temp  = new QAction(i18n("&Preview"), this);
561     actionCollection()->addAction("map_preview", temp );
562   connect(temp, SIGNAL(triggered(bool)), SLOT(mapPreview()));
563   temp->setToolTip(i18n("Show a preview"));
564 
565   // IMAGE
566   i18n("&Image");
567 
568   imageAddAction  = new QAction(i18n("Add Image..."), this);
569   actionCollection()->addAction("image_add", imageAddAction );
570   connect(imageAddAction, SIGNAL(triggered(bool)), SLOT(imageAdd()));
571   imageAddAction->setToolTip(i18n("Add a new image"));
572 
573     imageRemoveAction  = new QAction(i18n("Remove Image"), this);
574     actionCollection()->addAction("image_remove", imageRemoveAction );
575   connect(imageRemoveAction, SIGNAL(triggered(bool)), SLOT(imageRemove()));
576   imageRemoveAction->setToolTip(i18n("Remove the current visible image"));
577 
578     imageUsemapAction  = new QAction(i18n("Edit Usemap..."), this);
579     actionCollection()->addAction("image_usemap", imageUsemapAction );
580   connect(imageUsemapAction, SIGNAL(triggered(bool)), SLOT(imageUsemap()));
581   imageUsemapAction->setToolTip(i18n("Edit the usemap tag of the current visible image"));
582 
583     temp  = new QAction(i18n("Show &HTML"), this);
584     actionCollection()->addAction("map_showhtml", temp );
585   connect(temp, SIGNAL(triggered(bool)), SLOT(mapShowHTML()));
586 
587 
588   QActionGroup *drawingGroup = new QActionGroup(this);
589   // Selection Tool
590   arrowAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("arrow")), i18n("&Selection"), this);
591   actionCollection()->setDefaultShortcut(arrowAction, QKeySequence("s"));
592   actionCollection()->addAction("tool_arrow", arrowAction);
593   connect(arrowAction, SIGNAL(triggered(bool)), SLOT (slotDrawArrow()));
594   arrowAction->setWhatsThis(i18n("<h3>Selection</h3>"
595                           "Click this to select areas."));
596   drawingGroup->addAction(arrowAction);
597   arrowAction->setChecked(true);
598 
599   // Circle
600   circleAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("circle")), i18n("&Circle"), this);
601   actionCollection()->setDefaultShortcut(circleAction, QKeySequence("c"));
602 
603   actionCollection()->addAction("tool_circle", circleAction);
604   connect(circleAction, SIGNAL(triggered(bool)), this, SLOT(slotDrawCircle()));
605   circleAction->setWhatsThis(i18n("<h3>Circle</h3>"
606                           "Click this to start drawing a circle."));
607   drawingGroup->addAction(circleAction);
608 
609   // Rectangle
610     rectangleAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("rectangle")), i18n("&Rectangle"), this);
611   actionCollection()->setDefaultShortcut(rectangleAction, QKeySequence("r"));
612     actionCollection()->addAction("tool_rectangle", rectangleAction);
613   connect(rectangleAction, SIGNAL(triggered(bool)), this, SLOT(slotDrawRectangle()));
614   rectangleAction->setWhatsThis(i18n("<h3>Rectangle</h3>"
615                           "Click this to start drawing a rectangle."));
616   drawingGroup->addAction(rectangleAction);
617 
618   // Polygon
619     polygonAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("polygon")), i18n("&Polygon"), this);
620   actionCollection()->setDefaultShortcut(polygonAction, QKeySequence("p"));
621     actionCollection()->addAction("tool_polygon", polygonAction);
622   connect(polygonAction, SIGNAL(triggered(bool)), SLOT(slotDrawPolygon()));
623   polygonAction->setWhatsThis(i18n("<h3>Polygon</h3>"
624                           "Click this to start drawing a polygon."));
625   drawingGroup->addAction(polygonAction);
626 
627   // Freehand
628     freehandAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("freehand")), i18n("&Freehand Polygon"), this);
629   actionCollection()->setDefaultShortcut(freehandAction, QKeySequence("f"));
630     actionCollection()->addAction("tool_freehand", freehandAction);
631   connect(freehandAction, SIGNAL(triggered(bool)), SLOT(slotDrawFreehand()));
632   freehandAction->setWhatsThis(i18n("<h3>Freehandpolygon</h3>"
633                           "Click this to start drawing a freehand polygon."));
634   drawingGroup->addAction(freehandAction);
635 
636   // Add Point
637     addPointAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("addpoint")), i18n("&Add Point"), this);
638   actionCollection()->setDefaultShortcut(addPointAction, QKeySequence("a"));
639     actionCollection()->addAction("tool_addpoint", addPointAction);
640   connect(addPointAction, SIGNAL(triggered(bool)), SLOT(slotDrawAddPoint()));
641   addPointAction->setWhatsThis(i18n("<h3>Add Point</h3>"
642                           "Click this to add points to a polygon."));
643   drawingGroup->addAction(addPointAction);
644 
645   // Remove Point
646   removePointAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("removepoint")), i18n("&Remove Point"), this);
647   actionCollection()->setDefaultShortcut(removePointAction, QKeySequence("e"));
648   actionCollection()->addAction("tool_removepoint", removePointAction);
649   connect(removePointAction, SIGNAL(triggered(bool)),
650           SLOT(slotDrawRemovePoint()));
651   removePointAction->setWhatsThis(i18n("<h3>Remove Point</h3>"
652                           "Click this to remove points from a polygon."));
653   drawingGroup->addAction(removePointAction);
654 
655     QAction *action  = new QAction(i18n("Cancel Drawing"), this);
656     actionCollection()->addAction("canceldrawing", action );
657   connect(action, SIGNAL(triggered(bool)), SLOT(slotCancelDrawing()));
658   actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Escape));
659 
660   moveLeftAction  = new QAction(i18n("Move Left"), this);
661   actionCollection()->addAction("moveleft", moveLeftAction );
662   connect(moveLeftAction, SIGNAL(triggered(bool)),
663          SLOT(slotMoveLeft()));
664   actionCollection()->setDefaultShortcut(moveLeftAction, QKeySequence(Qt::Key_Left));
665 
666     moveRightAction  = new QAction(i18n("Move Right"), this);
667     actionCollection()->addAction("moveright", moveRightAction );
668   connect(moveRightAction, SIGNAL(triggered(bool)), SLOT(slotMoveRight()));
669   actionCollection()->setDefaultShortcut(moveRightAction, QKeySequence(Qt::Key_Right));
670 
671     moveUpAction  = new QAction(i18n("Move Up"), this);
672     actionCollection()->addAction("moveup", moveUpAction );
673   connect(moveUpAction, SIGNAL(triggered(bool)), SLOT(slotMoveUp()));
674   actionCollection()->setDefaultShortcut(moveUpAction, QKeySequence(Qt::Key_Up));
675 
676     moveDownAction  = new QAction(i18n("Move Down"), this);
677     actionCollection()->addAction("movedown", moveDownAction );
678   connect(moveDownAction, SIGNAL(triggered(bool)), SLOT(slotMoveDown()));
679   actionCollection()->setDefaultShortcut(moveDownAction, QKeySequence(Qt::Key_Down));
680 
681     increaseWidthAction  = new QAction(i18n("Increase Width"), this);
682     actionCollection()->addAction("increasewidth", increaseWidthAction );
683   connect(increaseWidthAction, SIGNAL(triggered(bool)), SLOT(slotIncreaseWidth()));
684   actionCollection()->setDefaultShortcut(increaseWidthAction, QKeySequence(Qt::Key_Right + Qt::SHIFT));
685 
686     decreaseWidthAction  = new QAction(i18n("Decrease Width"), this);
687     actionCollection()->addAction("decreasewidth", decreaseWidthAction );
688   connect(decreaseWidthAction, SIGNAL(triggered(bool)), SLOT(slotDecreaseWidth()));
689   actionCollection()->setDefaultShortcut(decreaseWidthAction, QKeySequence(Qt::Key_Left + Qt::SHIFT));
690 
691     increaseHeightAction  = new QAction(i18n("Increase Height"), this);
692     actionCollection()->addAction("increaseheight", increaseHeightAction );
693   connect(increaseHeightAction, SIGNAL(triggered(bool)), SLOT(slotIncreaseHeight()));
694   actionCollection()->setDefaultShortcut(increaseHeightAction, QKeySequence(Qt::Key_Up + Qt::SHIFT));
695 
696     decreaseHeightAction  = new QAction(i18n("Decrease Height"), this);
697     actionCollection()->addAction("decreaseheight", decreaseHeightAction );
698   connect(decreaseHeightAction, SIGNAL(triggered(bool)), SLOT(slotDecreaseHeight()));
699   actionCollection()->setDefaultShortcut(decreaseHeightAction, QKeySequence(Qt::Key_Down + Qt::SHIFT));
700 
701     toFrontAction  = new QAction(i18n("Bring to Front"), this);
702     actionCollection()->addAction("tofront", toFrontAction );
703   connect(toFrontAction, SIGNAL(triggered(bool)), SLOT(slotToFront()));
704 
705     toBackAction  = new QAction(i18n("Send to Back"), this);
706     actionCollection()->addAction("toback", toBackAction );
707   connect(toBackAction, SIGNAL(triggered(bool)), SLOT(slotToBack()));
708 
709     forwardOneAction  = new QAction(QIcon::fromTheme(QStringLiteral("raise")), i18n("Bring Forward One"), this);
710     actionCollection()->addAction("forwardone", forwardOneAction );
711   connect(forwardOneAction, SIGNAL(triggered(bool)), SLOT(slotForwardOne()));
712     backOneAction  = new QAction(QIcon::fromTheme(QStringLiteral("lower")), i18n("Send Back One"), this);
713     actionCollection()->addAction("backone", backOneAction );
714   connect(backOneAction, SIGNAL(triggered(bool)), SLOT(slotBackOne()));
715 
716   areaListView->upBtn->addAction(forwardOneAction);
717   areaListView->downBtn->addAction(backOneAction);
718 
719   connect( areaListView->upBtn, SIGNAL(pressed()), forwardOneAction, SLOT(trigger()));
720   connect( areaListView->downBtn, SIGNAL(pressed()), backOneAction, SLOT(trigger()));
721 
722     action  = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure KImageMapEditor..."), this);
723     actionCollection()->addAction("configure_kimagemapeditor", action );
724   connect(action, SIGNAL(triggered(bool)), SLOT(slotShowPreferences()));
725 
726   qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: 1";
727 
728   if (areaDock) {
729 
730     QAction* a =  areaDock->toggleViewAction();
731     a->setText(i18n("Show Area List"));
732     actionCollection()->addAction("configure_show_arealist",
733 				  a);
734 
735     a = mapsDock->toggleViewAction();
736     a->setText(i18n("Show Map List"));
737     actionCollection()->addAction("configure_show_maplist", a );
738 
739     a = imagesDock->toggleViewAction();
740     a->setText(i18n("Show Image List"));
741     actionCollection()->addAction("configure_show_imagelist", a );
742   }
743 
744   qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: 2";
745   updateActionAccess();
746   qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: 3";
747 }
748 
setupStatusBar()749 void KImageMapEditor::setupStatusBar()
750 {
751 
752 //  We can't do this with a KPart !
753 //	widget()->statusBar()->insertItem(i18n(" Cursor")+" : x: 0 ,y: 0",STATUS_CURSOR);
754 //	widget()->statusBar()->insertItem(i18n(" Selection")+" : - ",STATUS_SELECTION);
755   emit setStatusBarText( i18n(" Selection: -  Cursor: x: 0, y: 0 "));
756 }
757 
slotShowPreferences()758 void KImageMapEditor::slotShowPreferences()
759 {
760   PreferencesDialog *dialog = new PreferencesDialog(widget(),config());
761   connect(dialog, SIGNAL(preferencesChanged()), this, SLOT(slotConfigChanged()));
762   dialog->exec();
763   delete dialog;
764 }
765 
766 
showPopupMenu(const QPoint & pos,const QString & name)767 void KImageMapEditor::showPopupMenu(const QPoint & pos, const QString & name)
768 {
769   QMenu* pop = static_cast<QMenu *>(factory()->container(name, this));
770 
771   if (!pop) {
772       qCWarning(KIMAGEMAPEDITOR_LOG) << QString("KImageMapEditorPart: Missing XML definition for %1\n").arg(name);
773       return;
774   }
775 
776   pop->popup(pos);
777 }
778 
slotShowMainPopupMenu(const QPoint & pos)779 void KImageMapEditor::slotShowMainPopupMenu(const QPoint & pos)
780 {
781   showPopupMenu(pos,"popup_main");
782 }
783 
slotShowMapPopupMenu(const QPoint & pos)784 void KImageMapEditor::slotShowMapPopupMenu(const QPoint & pos)
785 {
786   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotShowMapPopupMenu";
787   QTreeWidgetItem* item = mapsListView->listView()->itemAt(pos);
788 
789   if (isReadWrite()) {
790     mapDeleteAction->setEnabled(item);
791     mapNameAction->setEnabled(item);
792     mapDefaultAreaAction->setEnabled(item);
793   }
794 
795   if (item)
796      mapsListView->selectMap(item);
797 
798   showPopupMenu(mapsListView->listView()->viewport()->mapToGlobal(pos),"popup_map");
799 }
800 
slotShowImagePopupMenu(const QPoint & pos)801 void KImageMapEditor::slotShowImagePopupMenu(const QPoint & pos)
802 {
803   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotShowImagePopupMenu";
804   QTreeWidgetItem* item = imagesListView->itemAt(pos);
805 
806   imageRemoveAction->setEnabled(item);
807   imageUsemapAction->setEnabled(item);
808 
809   if (item)
810      imagesListView->setCurrentItem(item);
811 
812   showPopupMenu(imagesListView->viewport()->mapToGlobal(pos),"popup_image");
813 }
814 
slotShowPopupMenu(const QPoint & p)815 void KImageMapEditor::slotShowPopupMenu(const QPoint & p)
816 {
817   QTreeWidgetItem* item = areaListView->listView->itemAt(p);
818 
819   if (!item)
820     return;
821 
822   if (!item->isSelected())
823   {
824     deselectAll();
825     select(item);
826   }
827 
828   slotShowMainPopupMenu(areaListView->listView->viewport()->mapToGlobal(p));
829 }
830 
updateStatusBar()831 void KImageMapEditor::updateStatusBar()
832 {
833   emit setStatusBarText(selectionStatusText+"  "+cursorStatusText);
834 }
835 
slotChangeStatusCoords(int x,int y)836 void KImageMapEditor::slotChangeStatusCoords(int x,int y)
837 {
838 //	statusBar()->changeItem(QString(" Cursor : x: %1 ,y: %2 ").arg(x).arg(y),STATUS_CURSOR);
839   cursorStatusText = i18n(" Cursor: x: %1, y: %2 ", x, y);
840   updateStatusBar();
841 }
842 
slotUpdateSelectionCoords()843 void KImageMapEditor::slotUpdateSelectionCoords() {
844   if (selected()->count()>0) {
845     QRect r=selected()->rect();
846 //		statusBar()->changeItem(
847     selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ", r.left(), r.top(), r.width(), r.height());
848 
849 //		  ,STATUS_SELECTION);
850     qApp->processEvents();
851   } else
852     selectionStatusText = i18n(" Selection: - ");
853     //statusBar()->changeItem(" Selection : - ",STATUS_SELECTION);
854 
855   updateStatusBar();
856 }
857 
slotUpdateSelectionCoords(const QRect & r)858 void KImageMapEditor::slotUpdateSelectionCoords( const QRect & r )
859 {
860   selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ", r.left(), r.top(), r.width(), r.height());
861   updateStatusBar();
862   qApp->processEvents();
863 }
864 
drawToCenter(QPainter * p,const QString & str,int y,int width)865 void KImageMapEditor::drawToCenter(QPainter* p, const QString & str, int y, int width) {
866   int xmid = width / 2;
867 
868   QFontMetrics fm = p->fontMetrics();
869   QRect strBounds = fm.boundingRect(str);
870 
871   p->drawText(xmid-(strBounds.width()/2),y,str);
872 }
873 
874 
getBackgroundImage()875 QImage KImageMapEditor::getBackgroundImage() {
876 
877   // Lazy initialisation
878   if ( _backgroundImage.isNull() ) {
879 
880 
881 //  QString filename = QString("dropimage_")+KGlobal::locale()->language()+".png";
882 //  QString path = QString(); //KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/"+filename ) + "kimagemapeditor/"+filename;
883 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "getBackgroundPic : loaded image : " << path;
884 
885 //  if ( ! QFileInfo(path).exists() ) {
886     int width = 400;
887     int height = 400;
888     int border = 20;
889     int fontSize = 58;
890 
891     QPixmap pix(width,height);
892     pix.fill(QColor(74,76,74));
893     QPainter p(&pix);
894 
895     //    QFont font = QFontDatabase().font("Luxi Sans","Bold",fontSize);
896     QFont font;
897     font.setBold(true);
898     font.setPixelSize(fontSize);
899     p.setFont( font );
900     p.setCompositionMode(QPainter::CompositionMode_Source);
901     p.setPen(QPen(QColor(112,114,112),1));
902 
903     // The translated string must be divided into
904     // parts with about the same size that fit to the image
905     QString str = i18n("Drop an image or HTML file");
906     const QStringList strList = str.split(' ');
907 
908     // Get the string parts
909     QString tmp;
910     QStringList outputStrList;
911     QFontMetrics fm = p.fontMetrics();
912 
913     for ( QStringList::ConstIterator it = strList.begin(); it != strList.end(); ++it ) {
914       QString tmp2 = tmp + *it;
915 
916         if (fm.boundingRect(tmp2).width() > width-border) {
917            outputStrList.append(tmp);
918            tmp = *it + ' ';
919         }
920         else
921           tmp = tmp2 + ' ';
922     }
923 
924     // Last one was forgotten so add it.
925     outputStrList.append(tmp);
926 
927     // Try to adjust the text vertically centered
928     int step = myround(float(height) / (outputStrList.size()+1));
929     int y = step;
930 
931     for ( QStringList::Iterator it = outputStrList.begin(); it != outputStrList.end(); ++it ) {
932         drawToCenter(&p, *it, y, pix.width());
933         y += step;
934     }
935 
936     p.end();
937 
938     _backgroundImage = pix.toImage();
939   }
940 
941 
942   return _backgroundImage;
943 
944 /*
945         QFontDatabase fdb;
946     QStringList families = fdb.families();
947     for ( QStringList::Iterator f = families.begin(); f != families.end(); ++f ) {
948         QString family = *f;
949         qDebug( family );
950         QStringList styles = fdb.styles( family );
951         for ( QStringList::Iterator s = styles.begin(); s != styles.end(); ++s ) {
952             QString style = *s;
953             QString dstyle = "\t" + style + " (";
954             QValueList<int> smoothies = fdb.smoothSizes( family, style );
955             for ( QValueList<int>::Iterator points = smoothies.begin();
956                   points != smoothies.end(); ++points ) {
957                 dstyle += QString::number( *points ) + " ";
958             }
959             dstyle = dstyle.left( dstyle.length() - 1 ) + ")";
960             qDebug( dstyle );
961         }
962     }
963 
964 
965     path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "kimagemapeditor/" ) +filename;
966     qCDebug(KIMAGEMAPEDITOR_LOG) << "getBackgroundPic : save new image to : " << path;
967     pix.save(path,"PNG",100);
968   }
969 
970   if ( ! QFileInfo(path).exists() ) {
971       qCCritical(KIMAGEMAPEDITOR_LOG) << "Couldn't find needed " << filename << " file in "
972                    "the data directory of KImageMapEditor.\n"
973                    "Perhaps you have forgotten to do a make install !";
974       exit(1);
975   }
976 */
977 }
978 
979 
addArea(Area * area)980 void KImageMapEditor::addArea(Area* area) {
981   if (!area) return;
982 
983   // Perhaps we've got a selection of areas
984   // so test it and add all areas of the selection
985   // nested selections are possible but doesn't exist
986   AreaSelection *selection = nullptr;
987   if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
988   {
989     AreaListIterator it = selection->getAreaListIterator();
990     while (it.hasNext()) {
991       Area* a = it.next();
992       areas->prepend(a);
993       a->setListViewItem(new QTreeWidgetItem(
994           areaListView->listView,
995           QStringList(a->attribute("href"))));
996       a->listViewItem()->setIcon(1,QIcon(makeListViewPix(*a)));
997     }
998   }
999   else
1000   {
1001     areas->prepend(area);
1002     area->setListViewItem(new QTreeWidgetItem(
1003       areaListView->listView,
1004       QStringList(area->attribute("href"))));
1005     area->listViewItem()->setIcon(1,QIcon(makeListViewPix(*area)));
1006   }
1007 
1008   setModified(true);
1009 
1010 }
1011 
addAreaAndEdit(Area * s)1012 void KImageMapEditor::addAreaAndEdit(Area* s)
1013 {
1014   areas->prepend(s);
1015   s->setListViewItem(new QTreeWidgetItem(
1016     areaListView->listView,
1017     QStringList(s->attribute("href"))));
1018   s->listViewItem()->setIcon(1,QIcon(makeListViewPix(*s)));
1019   deselectAll();
1020   select(s);
1021   if (!showTagEditor(selected())) {
1022     // If the user has pressed cancel
1023     // he undos the creation
1024     commandHistory()->undo();
1025   }
1026 }
1027 
deleteArea(Area * area)1028 void KImageMapEditor::deleteArea( Area * area )
1029 {
1030   if (!area) return;
1031 
1032   // only for repaint reasons
1033   QRect redrawRect = area->selectionRect();
1034 
1035   // Perhaps we've got a selection of areas
1036   // so test it and delete the whole selection
1037   // nested selections are possible but doesn't exist
1038   AreaSelection *selection = nullptr;
1039     if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
1040   {
1041     AreaListIterator it = selection->getAreaListIterator();
1042     while (it.hasNext()) {
1043       Area* a = it.next();
1044       currentSelected->remove(a);
1045       areas->removeAll( a );
1046       a->deleteListViewItem();
1047     }
1048   }
1049   else
1050   {
1051     deselect( area );
1052     areas->removeAll( area );
1053     area->deleteListViewItem();
1054   }
1055 
1056   drawZone->repaintRect(redrawRect);
1057 
1058 
1059   // Only to disable cut and copy actions
1060   if (areas->count()==0)
1061     deselectAll();
1062 
1063   setModified(true);
1064 }
1065 
deleteSelected()1066 void KImageMapEditor::deleteSelected() {
1067 
1068   AreaListIterator it = currentSelected->getAreaListIterator();
1069   while (it.hasNext()) {
1070     Area *a = it.next();
1071     currentSelected->remove( a );
1072     areas->removeAll( a );
1073     delete a->listViewItem();
1074   }
1075 
1076 
1077   drawZone->repaintArea( *currentSelected );
1078   // Only to disable cut and copy actions
1079   if (areas->count()==0)
1080     deselectAll();
1081 
1082   setModified(true);
1083 }
1084 
deleteAllAreas()1085 void KImageMapEditor::deleteAllAreas()
1086 {
1087   Area* a;
1088   foreach (a,*areas) {
1089     deselect( a );
1090     areas->removeAll( a );
1091     a->deleteListViewItem();
1092     if (!areas->isEmpty())
1093       a = areas->first(); // because the current is deleted
1094   }
1095 
1096   drawZone->repaint();
1097 
1098 }
1099 
updateAllAreas()1100 void KImageMapEditor::updateAllAreas()
1101 {
1102 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::updateAllAreas";
1103   Area* a;
1104   foreach(a,*areas) {
1105     a->listViewItem()->setIcon(1,QIcon(makeListViewPix(*a)));
1106   }
1107   drawZone->repaint();
1108 }
1109 
updateSelection() const1110 void KImageMapEditor::updateSelection() const {
1111   //FIXME: areaListView->listView->triggerUpdate();
1112 }
1113 
selected() const1114 AreaSelection* KImageMapEditor::selected() const {
1115   return currentSelected;
1116 }
1117 
select(Area * a)1118 void KImageMapEditor::select(Area* a)
1119 {
1120   if (!a) return;
1121 
1122   currentSelected->add(a);
1123   updateActionAccess();
1124   slotUpdateSelectionCoords();
1125 //	drawZone->repaintArea( *a);
1126 
1127 }
1128 
selectWithoutUpdate(Area * a)1129 void KImageMapEditor::selectWithoutUpdate(Area* a)
1130 {
1131   if (!a) return;
1132   currentSelected->add(a);
1133 }
1134 
slotSelectionChanged()1135 void KImageMapEditor::slotSelectionChanged()
1136 {
1137   AreaListIterator it = areaList();
1138   AreaList list = currentSelected->getAreaList();
1139 
1140   while (it.hasNext()) {
1141     Area* a = it.next();
1142     if ( a->listViewItem()->isSelected() != (list.contains(a)) )
1143     {
1144       a->listViewItem()->isSelected()
1145         ? select( a )
1146         :	deselect( a );
1147 
1148       drawZone->repaintArea( *a);
1149     }
1150   }
1151 
1152 }
1153 
select(QTreeWidgetItem * item)1154 void KImageMapEditor::select( QTreeWidgetItem* item)
1155 {
1156 
1157   AreaListIterator it = areaList();
1158   while (it.hasNext()) {
1159     Area* a = it.next();
1160     if (a->listViewItem() == item )
1161     {
1162       select( a );
1163       drawZone->repaintArea( *a);
1164     }
1165   }
1166 
1167 
1168 }
1169 
areaList() const1170 AreaListIterator KImageMapEditor::areaList() const {
1171   AreaListIterator it(*areas);
1172   return it;
1173 }
1174 
1175 
slotAreaChanged(Area * area)1176 void KImageMapEditor::slotAreaChanged(Area *area)
1177 {
1178   if (!area)
1179     return;
1180 
1181   setModified(true);
1182 
1183   AreaSelection *selection = nullptr;
1184   if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
1185   {
1186     AreaListIterator it = selection->getAreaListIterator();
1187     while (it.hasNext()) {
1188       Area* a = it.next();
1189       if (a->listViewItem()) {
1190         a->listViewItem()->setText(0,a->attribute("href"));
1191         a->listViewItem()->setIcon(1,QIcon(makeListViewPix(*a)));
1192       }
1193     }
1194 
1195   }
1196   else
1197   if (area->listViewItem()) {
1198     area->listViewItem()->setText(0,area->attribute("href"));
1199     area->listViewItem()->setIcon(1,QIcon(makeListViewPix(*area)));
1200   }
1201 
1202   drawZone->repaintArea(*area);
1203 
1204 }
1205 
deselect(Area * a)1206 void KImageMapEditor::deselect(Area* a)
1207 {
1208   if (a) {
1209     currentSelected->remove(a);
1210 //		drawZone->repaintArea(*a);
1211     updateActionAccess();
1212     slotUpdateSelectionCoords();
1213   }
1214 }
1215 
deselectWithoutUpdate(Area * a)1216 void KImageMapEditor::deselectWithoutUpdate(Area* a)
1217 {
1218   if (a) {
1219     currentSelected->remove(a);
1220   }
1221 }
1222 
1223 
1224 /**
1225 * Makes sure, that the actions cut, copy, delete and
1226 * show properties
1227 * can only be executed if sth. is selected.
1228 **/
updateActionAccess()1229 void KImageMapEditor::updateActionAccess()
1230 {
1231   if (!isReadWrite())
1232      return;
1233 
1234   if ( 0 < selected()->count())
1235   {
1236     qCDebug(KIMAGEMAPEDITOR_LOG) << "actions enabled";
1237     areaPropertiesAction->setEnabled(true);
1238     deleteAction->setEnabled(true);
1239     copyAction->setEnabled(true);
1240     cutAction->setEnabled(true);
1241     moveLeftAction->setEnabled(true);
1242     moveRightAction->setEnabled(true);
1243     moveUpAction->setEnabled(true);
1244     moveDownAction->setEnabled(true);
1245     toFrontAction->setEnabled(true);
1246     toBackAction->setEnabled(true);
1247 
1248     if ( (selected()->count() == 1) )
1249     {
1250       if (selected()->type()==Area::Polygon)
1251       {
1252         increaseWidthAction->setEnabled(false);
1253         decreaseWidthAction->setEnabled(false);
1254         increaseHeightAction->setEnabled(false);
1255         decreaseHeightAction->setEnabled(false);
1256         addPointAction->setEnabled(true);
1257         removePointAction->setEnabled(true);
1258       }
1259       else
1260       {
1261         increaseWidthAction->setEnabled(true);
1262         decreaseWidthAction->setEnabled(true);
1263         increaseHeightAction->setEnabled(true);
1264         decreaseHeightAction->setEnabled(true);
1265         addPointAction->setEnabled(false);
1266         removePointAction->setEnabled(false);
1267       }
1268 
1269     }
1270     else
1271     {
1272       increaseWidthAction->setEnabled(false);
1273       decreaseWidthAction->setEnabled(false);
1274       increaseHeightAction->setEnabled(false);
1275       decreaseHeightAction->setEnabled(false);
1276       addPointAction->setEnabled(false);
1277       removePointAction->setEnabled(false);
1278     }
1279 
1280   }
1281   else
1282   {
1283     qCDebug(KIMAGEMAPEDITOR_LOG) << "Actions disabled";
1284     areaPropertiesAction->setEnabled(false);
1285     deleteAction->setEnabled(false);
1286     copyAction->setEnabled(false);
1287     cutAction->setEnabled(false);
1288     moveLeftAction->setEnabled(false);
1289     moveRightAction->setEnabled(false);
1290     moveUpAction->setEnabled(false);
1291     moveDownAction->setEnabled(false);
1292     increaseWidthAction->setEnabled(false);
1293     decreaseWidthAction->setEnabled(false);
1294     increaseHeightAction->setEnabled(false);
1295     decreaseHeightAction->setEnabled(false);
1296     toFrontAction->setEnabled(false);
1297     toBackAction->setEnabled(false);
1298     addPointAction->setEnabled(false);
1299     removePointAction->setEnabled(false);
1300 
1301   }
1302 
1303   updateUpDownBtn();
1304 }
1305 
updateUpDownBtn()1306 void KImageMapEditor::updateUpDownBtn()
1307 {
1308   if (!isReadWrite())
1309      return;
1310 
1311   AreaList list = currentSelected->getAreaList();
1312 
1313   if (list.isEmpty() || (areas->count() < 2)) {
1314     forwardOneAction->setEnabled(false);
1315     areaListView->upBtn->setEnabled(false);
1316     backOneAction->setEnabled(false);
1317     areaListView->downBtn->setEnabled(false);
1318     return;
1319   }
1320   // if the first Area is in the selection can't move up
1321   if (list.contains( areas->first() )) {
1322     forwardOneAction->setEnabled(false);
1323     areaListView->upBtn->setEnabled(false);
1324   } else {
1325     forwardOneAction->setEnabled(true);
1326     areaListView->upBtn->setEnabled(true);
1327   }
1328 
1329   drawZone->repaintArea(*currentSelected);
1330 
1331   // if the last Area is in the selection can't move down
1332   if (list.contains( areas->last() )) {
1333     backOneAction->setEnabled(false);
1334     areaListView->downBtn->setEnabled(false);
1335   }
1336   else {
1337     backOneAction->setEnabled(true);
1338     areaListView->downBtn->setEnabled(true);
1339   }
1340 
1341 }
1342 
deselectAll()1343 void KImageMapEditor::deselectAll()
1344 {
1345   QRect redrawRect= currentSelected->selectionRect();
1346   currentSelected->reset();
1347   drawZone->repaintRect(redrawRect);
1348   updateActionAccess();
1349 }
1350 
onArea(const QPoint & p) const1351 Area* KImageMapEditor::onArea(const QPoint & p) const {
1352   Area* s;
1353   foreach(s,*areas) {
1354     if (s->contains(p))
1355       return s;
1356   }
1357   return nullptr;
1358 }
1359 
1360 
showTagEditor(Area * a)1361 int KImageMapEditor::showTagEditor(Area *a) {
1362   if (!a) return 0;
1363   drawZone->repaintArea(*a);
1364 
1365   AreaDialog *dialog= new AreaDialog(this,a);
1366   connect (dialog, SIGNAL(areaChanged(Area*)), this, SLOT(slotAreaChanged(Area*)));
1367 
1368   int result = dialog->exec();
1369 
1370   return result;
1371 
1372 
1373 }
1374 
showTagEditor(QTreeWidgetItem * item)1375 int KImageMapEditor::showTagEditor(QTreeWidgetItem *item) {
1376   if (!item)
1377     return 0;
1378 
1379   Area* a;
1380   foreach(a,*areas) {
1381     if (a->listViewItem()==item) {
1382       return showTagEditor(a);
1383     }
1384   }
1385   return 0;
1386 }
1387 
showTagEditor()1388 int KImageMapEditor::showTagEditor() {
1389   return showTagEditor(selected());
1390 }
1391 
1392 
getHTMLImageMap() const1393 QString KImageMapEditor::getHTMLImageMap() const {
1394   QString retStr;
1395   retStr+="<map "+QString("name=\"")+_mapName+"\">\n";
1396 
1397   Area* a;
1398   foreach(a,*areas) {
1399     retStr+="  "+a->getHTMLCode()+'\n';
1400   }
1401 
1402   if (defaultArea && defaultArea->finished())
1403     retStr+="  "+defaultArea->getHTMLCode()+'\n';
1404 
1405   retStr+="</map>";
1406   return retStr;
1407 }
1408 
makeListViewPix(Area & a)1409 QPixmap KImageMapEditor::makeListViewPix(Area & a)
1410 {
1411   QPixmap pix=a.cutOut(drawZone->picture());
1412 
1413   double shrinkFactor=1;
1414 
1415   // picture fits into max row height ?
1416   if (maxAreaPreviewHeight < pix.height())
1417     shrinkFactor = ( (double) maxAreaPreviewHeight / pix.height() );
1418 
1419   QPixmap pix2((int)(pix.width()*shrinkFactor), (int)(pix.height()*shrinkFactor));
1420 
1421   // Give all pixels a defined color
1422   pix2.fill(Qt::white);
1423 
1424   QPainter p(&pix2);
1425 
1426   p.scale(shrinkFactor,shrinkFactor);
1427   p.drawPixmap(0,0,pix);
1428 
1429   return pix2;
1430 }
1431 
setMapName(const QString & s)1432 void KImageMapEditor::setMapName(const QString & s) {
1433     mapsListView->changeMapName(_mapName, s);
1434     _mapName=s;
1435     currentMapElement->mapTag->name = s;
1436 }
1437 
1438 
setPicture(const QUrl & url)1439 void KImageMapEditor::setPicture(const QUrl & url) {
1440   _imageUrl=url;
1441   if (QFileInfo::exists(url.path())) {
1442      QImage img(url.path());
1443 
1444      if (!img.isNull()) {
1445          setPicture(img);
1446          imageRemoveAction->setEnabled(true);
1447          imageUsemapAction->setEnabled(true);
1448      }
1449      else
1450          qCCritical(KIMAGEMAPEDITOR_LOG) << QString("The image %1 could not be opened.").arg(url.path());
1451   }
1452   else
1453      qCCritical(KIMAGEMAPEDITOR_LOG) << QString("The image %1 does not exist.").arg(url.path());
1454 }
1455 
setPicture(const QImage & pix)1456 void KImageMapEditor::setPicture(const QImage & pix) {
1457     drawZone->setPicture(pix);
1458     updateAllAreas();
1459 }
1460 
1461 
slotDrawArrow()1462 void KImageMapEditor::slotDrawArrow() {
1463   _currentToolType=KImageMapEditor::Selection;
1464 
1465 }
1466 
slotDrawCircle()1467 void KImageMapEditor::slotDrawCircle() {
1468   _currentToolType=KImageMapEditor::Circle;
1469   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotDrawCircle";
1470 
1471 }
1472 
slotDrawRectangle()1473 void KImageMapEditor::slotDrawRectangle() {
1474   _currentToolType=KImageMapEditor::Rectangle;
1475   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotDrawRectangle";
1476 
1477 }
1478 
slotDrawPolygon()1479 void KImageMapEditor::slotDrawPolygon() {
1480   _currentToolType=KImageMapEditor::Polygon;
1481   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotDrawPolygon";
1482 }
1483 
slotDrawFreehand()1484 void KImageMapEditor::slotDrawFreehand() {
1485   _currentToolType=KImageMapEditor::Freehand;
1486 }
1487 
slotDrawAddPoint()1488 void KImageMapEditor::slotDrawAddPoint() {
1489   _currentToolType=KImageMapEditor::AddPoint;
1490 }
1491 
slotDrawRemovePoint()1492 void KImageMapEditor::slotDrawRemovePoint() {
1493   _currentToolType=KImageMapEditor::RemovePoint;
1494 }
1495 
1496 
slotZoom()1497 void KImageMapEditor::slotZoom() {
1498 
1499   int i=zoomAction->currentItem();
1500   switch (i) {
1501     case 0 : drawZone->setZoom(0.25);break;
1502     case 1 : drawZone->setZoom(0.5);break;
1503     case 2 : drawZone->setZoom(1);break;
1504     case 3 : drawZone->setZoom(1.5);break;
1505     case 4 : drawZone->setZoom(2.0);break;
1506     case 5 : drawZone->setZoom(2.5);break;
1507     case 6 : drawZone->setZoom(3);break;
1508     case 7 : drawZone->setZoom(5);break;
1509     case 8 : drawZone->setZoom(7.5);break;
1510     case 9 : drawZone->setZoom(10);break;
1511   }
1512   if (i<10)
1513     zoomInAction->setEnabled(true);
1514   else
1515     zoomInAction->setEnabled(false);
1516 
1517   if (i>0)
1518     zoomOutAction->setEnabled(true);
1519   else
1520     zoomOutAction->setEnabled(false);
1521 }
1522 
slotZoomIn()1523 void KImageMapEditor::slotZoomIn() {
1524   if (zoomAction->currentItem()==(int)(zoomAction->items().count()-1))
1525     return;
1526 
1527   zoomAction->setCurrentItem(zoomAction->currentItem()+1);
1528   slotZoom();
1529 }
1530 
slotZoomOut()1531 void KImageMapEditor::slotZoomOut() {
1532   if (zoomAction->currentItem()==0)
1533     return;
1534 
1535   zoomAction->setCurrentItem(zoomAction->currentItem()-1);
1536   slotZoom();
1537 }
1538 
mapDefaultArea()1539 void KImageMapEditor::mapDefaultArea()
1540 {
1541   if (defaultArea)
1542     showTagEditor(defaultArea);
1543   else {
1544     defaultArea= new DefaultArea();
1545     showTagEditor(defaultArea);
1546   }
1547 
1548 }
1549 
mapEditName()1550 void KImageMapEditor::mapEditName()
1551 {
1552   bool ok=false;
1553   QString input = QInputDialog::getText(widget(),
1554     i18n("Enter Map Name"), i18n("Enter the name of the map:"),
1555     QLineEdit::Normal, _mapName, &ok);
1556   if (ok && !input.isEmpty()) {
1557     if (input != _mapName) {
1558         if (mapsListView->nameAlreadyExists(input))
1559             KMessageBox::sorry(this->widget(), i18n("The name <em>%1</em> already exists.", input));
1560         else {
1561             setMapName(input);
1562         }
1563     }
1564   }
1565 }
1566 
mapShowHTML()1567 void KImageMapEditor::mapShowHTML()
1568 {
1569   QDialog *dialog = new QDialog(widget());
1570   dialog->setModal(true);
1571   dialog->setWindowTitle(i18n("HTML Code of Map"));
1572   QVBoxLayout *mainLayout = new QVBoxLayout(dialog);
1573 
1574   QTextEdit *edit = new QTextEdit;
1575 
1576   edit->setPlainText(getHtmlCode());
1577   edit->setReadOnly(true);
1578   edit->setLineWrapMode(QTextEdit::NoWrap);
1579   mainLayout->addWidget(edit);
1580 //  dialog->resize(dialog->calculateSize(edit->maxLineWidth(),edit->numLines()*));
1581 //	dialog->adjustSize();
1582 
1583   QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
1584   QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
1585   okButton->setDefault(true);
1586   okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
1587   connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
1588   mainLayout->addWidget(buttonBox);
1589 
1590   dialog->resize(600,400);
1591   dialog->exec();
1592   delete dialog;
1593 }
1594 
openFile(const QUrl & url)1595 void KImageMapEditor::openFile(const QUrl & url) {
1596   if ( ! url.isEmpty()) {
1597     QMimeDatabase db;
1598     QMimeType openedFileType = db.mimeTypeForUrl(url);
1599     if (openedFileType.name().left(6) == "image/") {
1600         addImage(url);
1601     } else {
1602         openURL(url);
1603     }
1604   }
1605 }
1606 
openURL(const QUrl & url)1607 bool KImageMapEditor::openURL(const QUrl & url) {
1608     // If a local file does not exist
1609     // we start with an empty file, so
1610     // that we can return true here.
1611     // For non local files, we cannot check
1612     // the existence
1613     if (url.isLocalFile() &&
1614         ! QFile::exists(url.path()))
1615         return true;
1616     return KParts::ReadWritePart::openUrl(url);
1617 }
1618 
fileOpen()1619 void KImageMapEditor::fileOpen() {
1620 
1621   QString fileName = QFileDialog::getOpenFileName(widget(), i18n("Choose File to Open"), QString(),
1622                      i18n("Web File (*.png *.jpg *.jpeg *.gif *.htm *.html);;Images (*.png *.jpg *.jpeg *.gif *.bmp *.xbm *.xpm *.pnm *.mng);;"
1623                           "HTML Files (*.htm *.html);;All Files (*)"));
1624 
1625   openFile(QUrl::fromUserInput( fileName ));
1626 }
1627 
1628 
1629 
fileClose()1630 void KImageMapEditor::fileClose()
1631 {
1632   if (! closeUrl())
1633      return;
1634 
1635 
1636     setPicture(getBackgroundImage());
1637     recentFilesAction->setCurrentItem(-1);
1638     setModified(false);
1639 }
1640 
fileSave()1641 void KImageMapEditor::fileSave()
1642 {
1643   // if we aren't read-write, return immediately
1644   if ( ! isReadWrite() )
1645       return;
1646 
1647   if (url().isEmpty()) {
1648     fileSaveAs();
1649   }
1650   else {
1651     saveFile();
1652     setModified(false);
1653   }
1654 
1655 
1656 }
1657 
fileSaveAs()1658 void KImageMapEditor::fileSaveAs() {
1659 
1660   QUrl url = QFileDialog::getSaveFileUrl(widget(), QString(), QUrl(), i18n("HTML File (*.htm *.html);;Text File (*.txt);;All Files (*)" ));
1661   if (url.isEmpty() || !url.isValid()) {
1662     return;
1663   }
1664 
1665 
1666   saveAs(url);
1667   recentFilesAction->addUrl(url);
1668 
1669 }
1670 
1671 
openFile()1672 bool KImageMapEditor::openFile()
1673 {
1674   QUrl u = url();
1675   QFileInfo fileInfo(u.path());
1676 
1677   if ( !fileInfo.exists() )
1678   {
1679       KMessageBox::information(widget(),
1680         i18n("<qt>The file <b>%1</b> does not exist.</qt>", fileInfo.fileName()),
1681         i18n("File Does Not Exist"));
1682       return false;
1683   }
1684 
1685   openHTMLFile(u);
1686 
1687   drawZone->repaint();
1688   recentFilesAction->addUrl(u);
1689   setModified(false);
1690   backupFileCreated = false;
1691   return true;
1692 }
1693 
1694 /**
1695  * This method supposes that the given QTextStream s has just read
1696  * the &lt; of a tag. It now reads all attributes of the tag until a &gt;
1697  * The tagname itself is also read and stored as a <em>tagname</em>
1698  * attribute. After parsing the whole tag it returns a QDict<QString>
1699  * with all attributes and their values. It stores the whole read text in the
1700  * parameter readText.
1701  */
getTagAttributes(QTextStream & s,QString & readText)1702 QHash<QString,QString> KImageMapEditor::getTagAttributes(QTextStream & s, QString & readText)
1703 {
1704   QHash<QString,QString> dict;
1705   // the "<" is already read
1706   QChar w;
1707   QString attr,value;
1708 
1709   readText.clear();
1710 
1711   // get the tagname
1712   while (!s.atEnd() && w!=' ') {
1713     s >> w;
1714     readText.append(w);
1715     if (w.isSpace() || w=='>') {
1716       dict.insert("tagname",value);
1717       break;
1718     }
1719     value+=w;
1720   }
1721 
1722 
1723   // do we have a comment ?
1724   // read the comment and return
1725   if (value.right(3)=="-->")
1726     return dict;
1727 
1728   if (value.startsWith(QLatin1String("!--"))) {
1729     while (!s.atEnd()) {
1730       s >> w;
1731       readText.append(w);
1732 
1733       if (w=='-') {
1734         s >> w;
1735         readText.append(w);
1736         if (w=='-') {
1737           s >> w;
1738           readText.append(w);
1739           if (w=='>')
1740             return dict;
1741         }
1742       }
1743     }
1744   }
1745 
1746   bool attrRead=true;	// currently reading an attribute ?
1747   bool equalSign=false; // an equalsign was read?
1748   bool valueRead=false; // currently reading a value ?
1749   QChar quotation='\0'; // currently reading a value with quotation marks ?
1750   bool php=false; // currently reading a php script
1751   attr.clear();
1752   value.clear();
1753 
1754   //get the other attributes
1755   while (!s.atEnd() && w!='>')
1756   {
1757     s >> w;
1758     readText.append(w);
1759 
1760     // End of PHP Script ?
1761     if (php && (w=='?') )
1762     {
1763       s >> w;
1764       readText.append(w);
1765 
1766       if (valueRead)
1767           value+=w;
1768 
1769       if (w=='>')
1770       {
1771         php = false;
1772         s >> w;
1773         readText.append(w);
1774       }
1775     }
1776 
1777     // Wrong syntax or PHP-Script !
1778     if (!php && (w=='<'))
1779     {
1780       if (valueRead)
1781         value+=w;
1782       s >> w;
1783       readText.append(w);
1784       if (valueRead)
1785         value+=w;
1786 
1787       if (w=='?')
1788       {
1789         php = true;
1790       }
1791     } else
1792     // finished ?
1793     if (w=='>') {
1794       if (valueRead) {
1795         dict.insert(attr,value);
1796       }
1797       return dict;
1798     } else
1799     // currently reading an attribute ?
1800     if (attrRead) {
1801       // if there is a whitespace the attributename has finished
1802       // possibly there isn't any value e.g. noshade
1803       if (w.isSpace())
1804         attrRead=false;
1805       else
1806       // an equal sign signals that the value follows
1807       if (w=='=') {
1808         attrRead=false;
1809         equalSign=true;
1810       } else
1811         attr+=w;
1812     } else
1813     // an equal sign was read ? delete every whitespace
1814     if (equalSign) {
1815       if (!w.isSpace()) {
1816         equalSign=false;
1817         valueRead=true;
1818         if (w=='"' || w=='\'')
1819           quotation=w;
1820       }
1821     } else
1822     // currently reading the value
1823     if (valueRead) {
1824       // if php, read without regarding anything
1825       if (php)
1826         value+=w;
1827       // if value within quotation marks is read
1828       // only stop when another quotationmark is found
1829       else
1830       if (quotation != '\0') {
1831         if (quotation!=w) {
1832           value+=w;
1833         } else {
1834           quotation='\0';
1835           valueRead=false;
1836           dict.insert(attr,value);
1837           attr.clear();
1838           value.clear();
1839         }
1840       } else
1841       // a whitespace indicates that the value has finished
1842       if (w.isSpace()) {
1843         valueRead=false;
1844         dict.insert(attr,value);
1845         attr.clear();
1846         value.clear();
1847       }
1848     } else {
1849       if (!w.isSpace()) {
1850         attrRead=true;
1851         attr+=w;
1852       }
1853     }
1854   }
1855 
1856   return dict;
1857 
1858 }
1859 
1860 
openHTMLFile(const QUrl & url)1861 bool KImageMapEditor::openHTMLFile(const QUrl & url)
1862 {
1863   QFile f(url.path());
1864   if ( !f.exists () )
1865       return false;
1866   f.open(QIODevice::ReadOnly);
1867   QTextStream s(&f);
1868   QChar w;
1869   QHash<QString,QString> *attr = nullptr;
1870   QList<ImageTag*> images;
1871   MapTag *map = nullptr;
1872   QList<MapTag*> maps;
1873 
1874   _htmlContent.clear();
1875   currentMapElement = nullptr;
1876 
1877   QString temp;
1878   QString origcode;
1879 
1880   bool readMap=false;
1881 
1882   while (!s.atEnd()) {
1883 
1884     s >> w;
1885     if (w=='<')
1886     {
1887       if (!readMap && !origcode.isEmpty()) {
1888         _htmlContent.append( new HtmlElement(origcode));
1889         origcode.clear();
1890       }
1891 
1892       origcode.append("<");
1893       attr=new QHash<QString,QString>(getTagAttributes(s,temp));
1894       origcode.append(temp);
1895 
1896       if (attr->contains("tagname")) {
1897         QString tagName = attr->value("tagname").toLower();
1898         if (tagName =="img") {
1899           HtmlImgElement *el = new HtmlImgElement(origcode);
1900           el->imgTag = static_cast<ImageTag*>(attr);
1901           images.append(el->imgTag);
1902           _htmlContent.append(el);
1903 
1904           origcode.clear();
1905         } else
1906         if (tagName == "map") {
1907           map = new MapTag();
1908           map->name = attr->value("name");
1909 	  qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::openHTMLFile: found map with name:" << map->name;
1910 
1911           readMap=true;
1912         } else
1913         if (tagName=="/map") {
1914           readMap=false;
1915           maps.append(map);
1916           HtmlMapElement *el = new HtmlMapElement(origcode);
1917           el->mapTag = map;
1918           _htmlContent.append(el);
1919 
1920           origcode.clear();
1921         } else
1922         if (readMap) {
1923           if (tagName=="area") {
1924              map->prepend(*attr);
1925           }
1926         } else {
1927           _htmlContent.append(new HtmlElement(origcode));
1928           origcode.clear();
1929         }
1930 
1931       }
1932     } // w != "<"
1933     else {
1934       origcode.append(w);
1935     }
1936   }
1937 
1938   if (!origcode.isEmpty()) {
1939     _htmlContent.append(new HtmlElement(origcode));
1940   }
1941 
1942   f.close();
1943 
1944   QUrl imageUrl;
1945 
1946   map = nullptr;
1947 
1948     // If we have more than on map or more than one image
1949     // Let the user choose, otherwise take the only ones
1950     if (maps.count() > 1) {
1951       map = maps.first();
1952     }
1953 
1954     if (images.count() > 1) {
1955       ImageTag* imgTag = images.first();
1956       if (imgTag) {
1957         if (imgTag->contains("src")) {
1958             if (url.path().isEmpty() | !url.path().endsWith('/')) {
1959                 imageUrl = QUrl(url.path() + '/').resolved(QUrl(imgTag->value("src")));
1960             }
1961             else {
1962                 imageUrl = url.resolved(QUrl(imgTag->value("src")));
1963             }
1964         }
1965       }
1966     }
1967 
1968     // If there is more than one map and more than one image
1969     // use the map that has an image with an according usemap tag
1970     if (maps.count() > 1 && images.count() > 1) {
1971       bool found = false;
1972       MapTag *mapTag;
1973       foreach(mapTag, maps) {
1974         ImageTag *imageTag;
1975         foreach(imageTag, images) {
1976             if (imageTag->contains("usemap")) {
1977                 QString usemap = imageTag->value("usemap");
1978                 // Remove the #
1979                 QString usemapName = usemap.right(usemap.length()-1);
1980                 if (usemapName == mapTag->name) {
1981 		  if (imageTag->contains("src")) {
1982                       if (url.path().isEmpty() | !url.path().endsWith('/')) {
1983                           imageUrl = QUrl(url.path() + '/').resolved(QUrl(imageTag->value("src")));
1984                       }
1985                       else {
1986                           imageUrl = url.resolved(QUrl(imageTag->value("src")));
1987                       }
1988 		      found = true;
1989 		  }
1990                 }
1991             }
1992 	    if (found)
1993 	      break;
1994         }
1995 	if (found)
1996 	  break;
1997       }
1998       if (found) {
1999 	map = mapTag;
2000       }
2001     }
2002 
2003 
2004     // If there are more than one map or there wasn't
2005     // found a fitting image and there is something to choose
2006     // let the user choose
2007     /*    if (maps.count() >1 || (imageUrl.isEmpty() && images.count() > 1))
2008     {
2009       ImageMapChooseDialog dialog(widget(),maps,images,url);
2010       qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::openHTMLFile: before dialog->exec()";
2011       dialog.exec();
2012       qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::openHTMLFile: after dialog->exec()";
2013       map = dialog.currentMap;
2014       imageUrl = dialog.pixUrl;
2015       }*/
2016 
2017 
2018   imagesListView->clear();
2019   imagesListView->setBaseUrl(url);
2020   imagesListView->addImages(images);
2021 
2022   mapsListView->clear();
2023   mapsListView->addMaps(maps);
2024 
2025 
2026   setMapActionsEnabled(false);
2027 
2028   if (map) {
2029     mapsListView->selectMap(map->name);
2030   } else {
2031 #ifdef WITH_TABWIDGET
2032     if (tabWidget)
2033        tabWidget->showPage(mapsListView);
2034 #endif
2035   }
2036 
2037 
2038   if (!imageUrl.isEmpty()) {
2039     setPicture(imageUrl);
2040   } else {
2041     setPicture(getBackgroundImage());
2042 #ifdef WITH_TABWIDGET
2043     if (tabWidget)
2044        tabWidget->showPage(imagesListView);
2045 #endif
2046   }
2047 
2048 
2049   emit setWindowCaption(url.fileName());
2050   setModified(false);
2051   return true;
2052 }
2053 
2054 /**
2055  * Finds the first html element which contains the given text.
2056  * Returns the first matching element.
2057  * Returns 0L if no element was found.
2058  */
findHtmlElement(const QString & containingText)2059 HtmlElement* KImageMapEditor::findHtmlElement(const QString & containingText) {
2060   HtmlElement *el;
2061   foreach (el,_htmlContent) {
2062     if (el->htmlCode.contains(containingText,Qt::CaseInsensitive)) {
2063       return el;
2064     }
2065   }
2066   return nullptr;
2067 }
2068 
2069 /**
2070  * Finds the first html element which contains the given ImageTag.
2071  * Returns the first matching element.
2072  * Returns 0L if no element was found.
2073  */
findHtmlImgElement(ImageTag * tag)2074 HtmlImgElement* KImageMapEditor::findHtmlImgElement(ImageTag* tag) {
2075   HtmlElement* el;
2076   foreach(el,_htmlContent) {
2077     HtmlImgElement* imgEl = dynamic_cast<HtmlImgElement*>(el);
2078 
2079     if (imgEl && imgEl->imgTag == tag)
2080        return imgEl;
2081   }
2082   return nullptr;
2083 }
2084 
addMap(const QString & name=QString ())2085 void KImageMapEditor::addMap(const QString & name = QString()) {
2086   HtmlMapElement* el = new HtmlMapElement("\n<map></map>");
2087   MapTag* map = new MapTag();
2088   map->name = name;
2089   el->mapTag = map;
2090 
2091   // Try to find the body tag
2092   HtmlElement* bodyTag = findHtmlElement("<body");
2093 
2094   // if we found one add the new map right after the body tag
2095   if (bodyTag) {
2096      uint index = _htmlContent.indexOf(bodyTag);
2097 
2098      // Add a newline before the map
2099      _htmlContent.insert(index+1, new HtmlElement("\n"));
2100 
2101      _htmlContent.insert(index+2, el);
2102   } // if there is no body tag we add the map to the end of the file
2103   else {
2104      // Add a newline before the map
2105      _htmlContent.append(new HtmlElement("\n"));
2106 
2107      _htmlContent.append(el);
2108      qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::addMap : No <body found ! Appending new map to the end.";
2109   }
2110 
2111   mapsListView->addMap(name);
2112   mapsListView->selectMap(name);
2113 }
2114 
2115 /**
2116  * Finds the HtmlMapElement in the HtmlContent, that corresponds
2117  * to the given map name.<br>
2118  * Returns 0L if there exists no map with the given name
2119  */
findHtmlMapElement(const QString & mapName)2120 HtmlMapElement* KImageMapEditor::findHtmlMapElement(const QString & mapName) {
2121   foreach(HtmlElement * el,_htmlContent) {
2122     if (dynamic_cast<HtmlMapElement*>(el)) {
2123       HtmlMapElement *tagEl = static_cast<HtmlMapElement*>(el);
2124       if (tagEl->mapTag->name == mapName) {
2125          return tagEl;
2126       }
2127     }
2128   }
2129 
2130   qCWarning(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::findHtmlMapElement: couldn't find map '" << mapName << "'";
2131   return nullptr;
2132 }
2133 
2134 /**
2135  * Calls setMap with the HtmlMapElement with the given map name
2136  */
setMap(const QString & mapName)2137 void KImageMapEditor::setMap(const QString & mapName) {
2138     HtmlMapElement* el = findHtmlMapElement(mapName);
2139     if (!el) {
2140       qCWarning(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::setMap : Couldn't set map '" << mapName << "', because it wasn't found !";
2141       return;
2142     }
2143 
2144     setMap(el);
2145 
2146 }
2147 
setMap(MapTag * map)2148 void KImageMapEditor::setMap(MapTag* map) {
2149   HtmlElement * el;
2150   foreach(el,_htmlContent) {
2151     HtmlMapElement *tagEl = dynamic_cast<HtmlMapElement*>(el);
2152     if (tagEl) {
2153       if (tagEl->mapTag == map) {
2154          setMap(tagEl);
2155          break;
2156       }
2157     }
2158   }
2159 
2160 }
2161 
saveAreasToMapTag(MapTag * map)2162 void KImageMapEditor::saveAreasToMapTag(MapTag* map) {
2163   map->clear();
2164   Area* a;
2165   foreach(a,*areas) {
2166     QString shapeStr;
2167 
2168     switch (a->type()) {
2169       case Area::Rectangle : shapeStr = "rect";break;
2170       case Area::Circle : shapeStr = "circle";break;
2171       case Area::Polygon : shapeStr = "poly";break;
2172       default : continue;
2173     }
2174 
2175     QHash<QString,QString> dict;
2176     dict.insert("shape",shapeStr);
2177 
2178     AttributeIterator it = a->attributeIterator();
2179     while (it.hasNext())
2180     {
2181       it.next();
2182       dict.insert(it.key(),it.value());
2183     }
2184 
2185     dict.insert("coords",a->coordsToString());
2186 
2187     map->append(dict);
2188 
2189   }
2190 
2191   if (defaultArea && defaultArea->finished()) {
2192     QHash<QString,QString> dict;
2193     dict.insert("shape","default");
2194 
2195     AttributeIterator it = defaultArea->attributeIterator();
2196     while (it.hasNext())
2197     {
2198       it.next();
2199       dict.insert(it.key(),it.value());
2200     }
2201 
2202     map->append(dict);
2203   }
2204 
2205 }
2206 
setAttribute(Area * a,const AreaTag & tag,const QString & s)2207 static void setAttribute(Area* a, const AreaTag & tag, const QString & s) {
2208   if (tag.contains(s))
2209     a->setAttribute(s,tag.value(s));
2210 }
2211 
setMap(HtmlMapElement * mapElement)2212 void KImageMapEditor::setMap(HtmlMapElement* mapElement) {
2213   if (currentMapElement) {
2214     currentMapElement->mapTag->modified=true;
2215     currentMapElement->htmlCode = getHTMLImageMap();
2216     saveAreasToMapTag(currentMapElement->mapTag);
2217   }
2218 
2219   currentMapElement = mapElement;
2220   MapTag* map = currentMapElement->mapTag;
2221 
2222   // Remove old areas only if a new map is loaded
2223   deleteAllAreas();
2224   delete defaultArea;
2225   defaultArea = nullptr;
2226 //    qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::setMap : Setting new map : " << map->name;
2227     _mapName = map->name;
2228     AreaTag tag;
2229 
2230     QLinkedListIterator<AreaTag> it(*map);
2231     while (it.hasNext()) {
2232         tag = it.next();
2233         QString shape="rect";
2234         if (tag.contains("shape"))
2235           shape=tag.value("shape");
2236 
2237         Area::ShapeType type=Area::Rectangle;
2238         if (shape=="circle")
2239           type=Area::Circle;
2240         else if (shape=="poly")
2241           type=Area::Polygon;
2242         else if (shape=="default")
2243           type=Area::Default;
2244 
2245         Area* a=AreaCreator::create(type);
2246 
2247         setAttribute(a,tag,"href");
2248         setAttribute(a,tag,"alt");
2249         setAttribute(a,tag,"target");
2250         setAttribute(a,tag,"title");
2251         setAttribute(a,tag,"onclick");
2252         setAttribute(a,tag,"ondblclick");
2253         setAttribute(a,tag,"onmousedown");
2254         setAttribute(a,tag,"onmouseup");
2255         setAttribute(a,tag,"onmouseover");
2256         setAttribute(a,tag,"onmousemove");
2257         setAttribute(a,tag,"onmouseout");
2258 
2259         if (type==Area::Default) {
2260           defaultArea=a;
2261           defaultArea->setFinished(true);
2262           continue;
2263         }
2264 
2265         if (tag.contains("coords"))
2266           a->setCoords(tag.value("coords"));
2267 
2268         a->setMoving(false);
2269         addArea(a);
2270     }
2271 
2272     updateAllAreas();
2273 
2274     setMapActionsEnabled(true);
2275 }
2276 
2277 /**
2278  * Sets whether actions that depend on an selected map
2279  * are enabled
2280  */
setMapActionsEnabled(bool b)2281 void KImageMapEditor::setMapActionsEnabled(bool b) {
2282    mapDeleteAction->setEnabled(b);
2283    mapDefaultAreaAction->setEnabled(b);
2284    mapNameAction->setEnabled(b);
2285 
2286    arrowAction->setChecked(true);
2287    slotDrawArrow();
2288 
2289    arrowAction->setEnabled(b);
2290    circleAction->setEnabled(b);
2291    rectangleAction->setEnabled(b);
2292    polygonAction->setEnabled(b);
2293    freehandAction->setEnabled(b);
2294    addPointAction->setEnabled(b);
2295    removePointAction->setEnabled(b);
2296 
2297 }
2298 
getHtmlCode()2299 QString KImageMapEditor::getHtmlCode() {
2300   if (currentMapElement) {
2301     currentMapElement->htmlCode = getHTMLImageMap();
2302   }
2303 
2304   QString result;
2305 
2306   HtmlElement *el;
2307   foreach(el,_htmlContent) {
2308         result += el->htmlCode;
2309   }
2310   return result;
2311 }
2312 
2313 
2314 /**
2315  create a relative short url based in baseURL
2316 
2317  taken from qextfileinfo.cpp:
2318 
2319  From WebMaker - KDE HTML Editor
2320  Copyright (C) 1998, 1999 Alexei Dets <dets@services.ru>
2321 
2322  Rewritten for Quanta Plus: (C) 2002 Andras Mantia <amantia@freemail.hu>
2323 
2324  This program is free software; you can redistribute it and/or modify
2325  it under the terms of the GNU General Public License as published by
2326  the Free Software Foundation; either version 2 of the License, or
2327  (at your option) any later version.
2328 */
toRelative(const QUrl & urlToConvert,const QUrl & baseURL)2329 static QUrl toRelative(const QUrl& urlToConvert,const QUrl& baseURL)
2330 {
2331   QUrl resultURL = urlToConvert;
2332   if (urlToConvert.scheme() == baseURL.scheme())
2333   {
2334     QString path = urlToConvert.path();
2335     QString basePath = baseURL.path().endsWith('/') ? baseURL.path() : baseURL.path() + '/';
2336     if (path.startsWith(QLatin1String("/")) && basePath != "/")
2337     {
2338       path.remove(0, 1);
2339       basePath.remove(0, 1);
2340       if ( basePath.right(1) != "/" ) basePath.append("/");
2341 
2342       int pos=0;
2343       int pos1=0;
2344       for (;;)
2345       {
2346         pos=path.indexOf("/");
2347         pos1=basePath.indexOf("/");
2348         if ( pos<0 || pos1<0 ) break;
2349         if ( path.left(pos+1 ) == basePath.left(pos1+1) )
2350         {
2351           path.remove(0, pos+1);
2352           basePath.remove(0, pos1+1);
2353         }
2354         else
2355           break;
2356       };
2357 
2358       if ( basePath == "/" ) basePath="";
2359       int level = basePath.count("/");
2360       for (int i=0; i<level; i++)
2361       {
2362         path="../"+path;
2363       };
2364     }
2365 
2366     resultURL.setPath(QDir::cleanPath(path));
2367   }
2368 
2369   if (urlToConvert.path().endsWith('/')) resultURL.setPath(resultURL.path() + '/');
2370   return resultURL;
2371 }
2372 
2373 
saveImageMap(const QUrl & url)2374 void KImageMapEditor::saveImageMap(const QUrl & url)
2375 {
2376   if (!QFileInfo(url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()).isWritable()) {
2377     KMessageBox::error(widget(),
2378       i18n("<qt>The file <i>%1</i> could not be saved, because you do not have the required write permissions.</qt>", url.path()));
2379     return;
2380   }
2381 
2382   if (!backupFileCreated) {
2383     QString backupFile = url.path()+'~';
2384     KIO::file_copy(url, QUrl::fromUserInput(backupFile ), -1, KIO::Overwrite | KIO::HideProgressInfo);
2385     backupFileCreated = true;
2386   }
2387 
2388   setModified(false);
2389 
2390   if (mapName().isEmpty()) {
2391     mapEditName();
2392   }
2393   QFile file(url.path());
2394   file.open(QIODevice::WriteOnly);
2395 
2396   QTextStream t(&file);
2397 
2398   if (_htmlContent.isEmpty()) {
2399     t << "<html>\n"
2400       << "<head>\n"
2401       << "  <title></title>\n"
2402       << "</head>\n"
2403       << "<body>\n"
2404       << "  " << getHTMLImageMap()
2405       << "\n"
2406       << "  <img src=\"" << toRelative(_imageUrl,QUrl( url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() )).path() << "\""
2407       << " usemap=\"#" << _mapName << "\""
2408       << " width=\"" << drawZone->picture().width() << "\""
2409       << " height=\"" << drawZone->picture().height() << "\">\n"
2410       << "</body>\n"
2411       << "</html>";
2412   } else
2413   {
2414     t << getHtmlCode();
2415   }
2416 
2417   file.close();
2418 
2419 }
2420 
2421 
slotCut()2422 void KImageMapEditor::slotCut()
2423 {
2424   if ( 0 == currentSelected->count() )
2425     return;
2426   delete copyArea;
2427 
2428   copyArea= static_cast< AreaSelection* > (currentSelected->clone());
2429   pasteAction->setEnabled(true);
2430   QUndoCommand *command= new CutCommand(this,*currentSelected);
2431   commandHistory()->push(command);
2432 }
2433 
2434 
slotDelete()2435 void KImageMapEditor::slotDelete()
2436 {
2437   if ( 0 == currentSelected->count() )
2438     return;
2439 
2440   QUndoCommand *command= new DeleteCommand(this,*currentSelected);
2441   commandHistory()->push(command);
2442 }
2443 
slotCopy()2444 void KImageMapEditor::slotCopy()
2445 {
2446   delete copyArea;
2447 
2448   copyArea = static_cast< AreaSelection* > (currentSelected->clone());
2449   pasteAction->setEnabled(true);
2450 }
2451 
slotPaste()2452 void KImageMapEditor::slotPaste()
2453 {
2454   if (!copyArea)
2455     return;
2456 
2457   copyArea->moveBy(5,5);
2458   if (copyArea->rect().x()>= drawZone->getImageRect().width() ||
2459       copyArea->rect().y()>= drawZone->getImageRect().height())
2460       copyArea->moveTo(0,0);
2461 
2462   if (copyArea->rect().width()>drawZone->getImageRect().width() ||
2463       copyArea->rect().height()>drawZone->getImageRect().height())
2464       return;
2465 
2466   AreaSelection *a=static_cast< AreaSelection* > (copyArea->clone());
2467   commandHistory()->push(new PasteCommand(this,*a));
2468   delete a;
2469 //	addAreaAndEdit(a);
2470 }
2471 
2472 
2473 
slotBackOne()2474 void KImageMapEditor::slotBackOne()
2475 {
2476   if (currentSelected->isEmpty())
2477     return;
2478 
2479   AreaList list = currentSelected->getAreaList();
2480 
2481 
2482   Area *a = nullptr;
2483   // move every selected Area one step lower
2484   for (int i=areas->count()-2; i > -1; i--)
2485   {
2486     if (list.contains( areas->at(i) ))
2487     {
2488       uint j = (uint)i+1;
2489       a = areas->at(i);
2490       areas->removeAll(a);
2491       areas->insert(j,a);
2492       QTreeWidgetItem* root = areaListView->listView->invisibleRootItem();
2493       root->insertChild(j,root->takeChild(i));
2494     }
2495   }
2496   // to update the up and down buttons
2497   updateUpDownBtn();
2498 
2499 }
2500 
slotForwardOne()2501 void KImageMapEditor::slotForwardOne()
2502 {
2503   if (currentSelected->isEmpty())
2504     return;
2505 
2506   AreaList list = currentSelected->getAreaList();
2507 
2508   Area *a = nullptr;
2509   // move every selected Area one step higher
2510   for (int i=1; i < (int)areas->count(); i++)
2511   {
2512     if (list.contains( areas->at(i) ))
2513     {
2514       uint j = (uint) i-1;
2515       a = areas->at(i);
2516       areas->removeAll(a);
2517       areas->insert(j,a);
2518       QTreeWidgetItem* root = areaListView->listView->invisibleRootItem();
2519       root->insertChild(j,root->takeChild(i));
2520     }
2521   }
2522   // to update the up and down buttons
2523   updateUpDownBtn();
2524 }
2525 
slotToBack()2526 void KImageMapEditor::slotToBack()
2527 {
2528   if (currentSelected->isEmpty())
2529     return;
2530 
2531   while (backOneAction->isEnabled())
2532     slotBackOne();
2533 }
2534 
slotToFront()2535 void KImageMapEditor::slotToFront()
2536 {
2537   if (currentSelected->isEmpty())
2538     return;
2539 
2540   while (forwardOneAction->isEnabled())
2541     slotForwardOne();
2542 }
2543 
2544 
slotMoveUp()2545 void KImageMapEditor::slotMoveUp()
2546 {
2547   QRect r=selected()->rect();
2548   selected()->setMoving(true);
2549   selected()->moveBy(0,-1);
2550 
2551   commandHistory()->push(
2552     new MoveCommand( this, selected(), r.topLeft() ));
2553   selected()->setMoving(false);
2554   slotAreaChanged(selected());
2555   slotUpdateSelectionCoords();
2556 }
2557 
slotMoveDown()2558 void KImageMapEditor::slotMoveDown()
2559 {
2560   QRect r=selected()->rect();
2561   selected()->setMoving(true);
2562   selected()->moveBy(0,1);
2563 
2564   commandHistory()->push(
2565     new MoveCommand( this, selected(), r.topLeft() ));
2566   selected()->setMoving(false);
2567   slotAreaChanged(selected());
2568   slotUpdateSelectionCoords();
2569 }
2570 
slotMoveLeft()2571 void KImageMapEditor::slotMoveLeft()
2572 {
2573   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotMoveLeft";
2574   QRect r=selected()->rect();
2575   selected()->setMoving(true);
2576   selected()->moveBy(-1,0);
2577 
2578   commandHistory()->push(
2579     new MoveCommand( this, selected(), r.topLeft() ));
2580   selected()->setMoving(false);
2581   slotAreaChanged(selected());
2582   slotUpdateSelectionCoords();
2583 }
2584 
slotMoveRight()2585 void KImageMapEditor::slotMoveRight()
2586 {
2587   QRect r=selected()->rect();
2588   selected()->setMoving(true);
2589   selected()->moveBy(1,0);
2590 
2591   commandHistory()->push(
2592     new MoveCommand( this, selected(), r.topLeft() ));
2593   selected()->setMoving(false);
2594   slotAreaChanged(selected());
2595   slotUpdateSelectionCoords();
2596 }
2597 
slotCancelDrawing()2598 void KImageMapEditor::slotCancelDrawing()
2599 {
2600   drawZone->cancelDrawing();
2601 }
2602 
slotIncreaseHeight()2603 void KImageMapEditor::slotIncreaseHeight()
2604 {
2605   Area *oldArea=selected()->clone();
2606 
2607   QRect r = selected()->rect();
2608   r.setHeight( r.height()+1 );
2609   r.translate(0,-1);
2610 
2611   selected()->setRect(r);
2612 
2613   commandHistory()->push(
2614     new ResizeCommand( this, selected(), oldArea ));
2615   slotAreaChanged(selected());
2616   slotUpdateSelectionCoords();
2617 }
2618 
slotDecreaseHeight()2619 void KImageMapEditor::slotDecreaseHeight()
2620 {
2621   Area *oldArea=selected()->clone();
2622 
2623   QRect r = selected()->rect();
2624   r.setHeight( r.height()-1 );
2625   r.translate(0,1);
2626 
2627   selected()->setRect(r);
2628 
2629   commandHistory()->push(
2630     new ResizeCommand( this, selected(), oldArea ));
2631   slotAreaChanged(selected());
2632   slotUpdateSelectionCoords();
2633 }
2634 
slotIncreaseWidth()2635 void KImageMapEditor::slotIncreaseWidth()
2636 {
2637   Area *oldArea=selected()->clone();
2638 
2639   QRect r = selected()->rect();
2640   r.setWidth( r.width()+1 );
2641 
2642   selected()->setRect(r);
2643 
2644   commandHistory()->push(
2645     new ResizeCommand( this, selected(), oldArea ));
2646   slotAreaChanged(selected());
2647   slotUpdateSelectionCoords();
2648 }
2649 
slotDecreaseWidth()2650 void KImageMapEditor::slotDecreaseWidth()
2651 {
2652   Area *oldArea=selected()->clone();
2653 
2654   QRect r = selected()->rect();
2655   r.setWidth( r.width()-1 );
2656 
2657   selected()->setRect(r);
2658 
2659   commandHistory()->push(
2660     new ResizeCommand( this, selected(), oldArea ));
2661   slotAreaChanged(selected());
2662   slotUpdateSelectionCoords();
2663 }
2664 
slotHighlightAreas(bool b)2665 void KImageMapEditor::slotHighlightAreas(bool b)
2666 {
2667   Area::highlightArea = b;
2668   updateAllAreas();
2669   drawZone->repaint();
2670 }
2671 
slotShowAltTag(bool b)2672 void KImageMapEditor::slotShowAltTag(bool b)
2673 {
2674   Area::showAlt = b;
2675   drawZone->repaint();
2676 }
2677 
mapNew()2678 void KImageMapEditor::mapNew()
2679 {
2680     QString mapName = mapsListView->getUnusedMapName();
2681     addMap(mapName);
2682     mapEditName();
2683 }
2684 
mapDelete()2685 void KImageMapEditor::mapDelete()
2686 {
2687   if (mapsListView->count() == 0)
2688      return;
2689 
2690   QString selectedMap = mapsListView->selectedMap();
2691 
2692   int result = KMessageBox::warningContinueCancel(widget(),
2693     i18n("<qt>Are you sure you want to delete the map <i>%1</i>?"
2694          " <br /><b>There is no way to undo this.</b></qt>", selectedMap),
2695     i18n("Delete Map?"),KGuiItem(i18n("&Delete"),"edit-delete"));
2696 
2697   if (result == KMessageBox::Cancel)
2698      return;
2699 
2700 
2701 
2702   mapsListView->removeMap(selectedMap);
2703   HtmlMapElement* mapEl = findHtmlMapElement(selectedMap);
2704   _htmlContent.removeAll(mapEl);
2705   if (mapsListView->count() == 0) {
2706 
2707       currentMapElement = nullptr;
2708       deleteAllAreas();
2709       setMapActionsEnabled(false);
2710   }
2711   else {
2712       // The old one was deleted, so the new one got selected
2713       setMap(mapsListView->selectedMap());
2714   }
2715 }
2716 
mapPreview()2717 void KImageMapEditor::mapPreview() {
2718   HTMLPreviewDialog dialog(widget(), getHtmlCode());
2719   dialog.exec();
2720 }
2721 
deleteAllMaps()2722 void KImageMapEditor::deleteAllMaps()
2723 {
2724   deleteAllAreas();
2725   mapsListView->clear();
2726   if (isReadWrite()) {
2727     mapDeleteAction->setEnabled(false);
2728     mapDefaultAreaAction->setEnabled(false);
2729     mapNameAction->setEnabled(false);
2730   }
2731 }
2732 
2733 /**
2734  * Doesn't call the closeUrl method, because
2735  * we need the URL for the session management
2736  */
queryClose()2737 bool KImageMapEditor::queryClose() {
2738   if ( ! isModified() )
2739      return true;
2740 
2741   switch ( KMessageBox::warningYesNoCancel(
2742               widget(),
2743 	      i18n("<qt>The file <i>%1</i> has been modified.<br />Do you want to save it?</qt>",
2744 	      url().fileName()),
2745 	      QString(),
2746 	      KStandardGuiItem::save(),
2747 	      KStandardGuiItem::discard()) )
2748     {
2749     case KMessageBox::Yes :
2750       saveFile();
2751       return true;
2752     case KMessageBox::No :
2753       return true;
2754     default:
2755       return false;
2756   }
2757 }
2758 
closeUrl()2759 bool KImageMapEditor::closeUrl()
2760 {
2761   bool result = KParts::ReadWritePart::closeUrl();
2762   if (!result)
2763      return false;
2764 
2765   _htmlContent.clear();
2766   deleteAllMaps();
2767   imagesListView->clear();
2768 
2769   delete copyArea;
2770   copyArea = nullptr;
2771 
2772   delete defaultArea;
2773   defaultArea = nullptr;
2774 
2775   currentMapElement = nullptr;
2776 
2777   init();
2778   emit setWindowCaption("");
2779 
2780   return true;
2781 
2782 }
2783 
addImage(const QUrl & imgUrl)2784 void KImageMapEditor::addImage(const QUrl & imgUrl) {
2785     if (imgUrl.isEmpty())
2786         return;
2787 
2788     QString relativePath ( toRelative(imgUrl, QUrl( url().adjusted(QUrl::RemoveFilename).path() )).path() );
2789 
2790     QString imgHtml = QString("<img src=\"")+relativePath+QString("\">");
2791     ImageTag* imgTag = new ImageTag();
2792     imgTag->insert("tagname","img");
2793     imgTag->insert("src", relativePath);
2794 
2795     HtmlImgElement* imgEl = new HtmlImgElement(imgHtml);
2796     imgEl->imgTag = imgTag;
2797 
2798     HtmlElement* bodyEl = findHtmlElement("<body");
2799     if (bodyEl) {
2800         int bodyIndex = _htmlContent.indexOf(bodyEl);
2801         _htmlContent.insert(bodyIndex+1, new HtmlElement("\n"));
2802         _htmlContent.insert(bodyIndex+2, imgEl);
2803     }
2804     else {
2805         _htmlContent.append(new HtmlElement("\n"));
2806         _htmlContent.append(imgEl);
2807     }
2808 
2809     imagesListView->addImage(imgTag);
2810     imagesListView->selectImage(imgTag);
2811     setImageActionsEnabled(true);
2812 
2813     setModified(true);
2814 }
2815 
2816 /**
2817  * Sets whether the image actions that depend on an
2818  * selected image are enabled
2819  */
setImageActionsEnabled(bool b)2820 void KImageMapEditor::setImageActionsEnabled(bool b) {
2821   imageRemoveAction->setEnabled(b);
2822   imageUsemapAction->setEnabled(b);
2823 }
2824 
2825 
imageAdd()2826 void KImageMapEditor::imageAdd() {
2827     QUrl imgUrl = QFileDialog::getOpenFileUrl(widget(), i18n("Select image"),
2828                   QUrl(), i18n("Images (*.png *.jpg *.jpeg *.gif *.bmp *.xbm *.xpm *.pnm *.mng);;All Files (*)"));
2829     addImage(imgUrl);
2830 }
2831 
imageRemove()2832 void KImageMapEditor::imageRemove() {
2833     ImageTag* imgTag = imagesListView->selectedImage();
2834     HtmlImgElement* imgEl = findHtmlImgElement(imgTag);
2835     imagesListView->removeImage(imgTag);
2836     _htmlContent.removeAt(_htmlContent.indexOf(imgEl));
2837 
2838     if (imagesListView->topLevelItemCount() == 0) {
2839         setPicture(getBackgroundImage());
2840         setImageActionsEnabled(false);
2841     }
2842     else {
2843       ImageTag* selected = imagesListView->selectedImage();
2844       if (selected) {
2845 	if (selected->contains("src")) {
2846 	  setPicture(QUrl(selected->value("src")));
2847 	}
2848       }
2849     }
2850 
2851     setModified(true);
2852 }
2853 
imageUsemap()2854 void KImageMapEditor::imageUsemap() {
2855 
2856   bool ok=false;
2857   ImageTag* imageTag = imagesListView->selectedImage();
2858   if ( ! imageTag)
2859      return;
2860 
2861   QString usemap;
2862 
2863   if (imageTag->contains("usemap"))
2864       usemap = imageTag->value("usemap");
2865 
2866   QStringList maps = mapsListView->getMaps();
2867   int index = maps.indexOf(usemap);
2868   if (index == -1) {
2869     maps.prepend("");
2870     index = 0;
2871   }
2872 
2873   QString input =
2874     QInputDialog::getItem(widget(), i18n("Enter Usemap"),
2875 			  i18n("Enter the usemap value:"),
2876 			  maps, index, true, &ok);
2877   if (ok) {
2878      imageTag->insert("usemap", input);
2879      imagesListView->updateImage(imageTag);
2880      setModified(true);
2881 
2882      // Update the htmlCode of the HtmlElement
2883      HtmlImgElement* imgEl = findHtmlImgElement(imageTag);
2884 
2885      imgEl->htmlCode = QLatin1String("<");
2886      QString tagName = imgEl->imgTag->value("tagname");
2887      imgEl->htmlCode += QString(tagName);
2888      QHashIterator<QString, QString> it( *imgEl->imgTag );
2889      while (it.hasNext()) {
2890        it.next();
2891        if (it.key() != "tagname") {
2892            imgEl->htmlCode += " " + it.key() + "=\"";
2893            if (it.key() == "usemap")
2894                imgEl->htmlCode += '#';
2895            imgEl->htmlCode += it.value();
2896            imgEl->htmlCode += '"';
2897        }
2898      }
2899 
2900      imgEl->htmlCode += '>';
2901 
2902   }
2903 }
2904 
2905 #include "kimagemapeditor.moc"
2906