File indexing completed on 2023-05-30 11:08:59

0001 /***************************************************************************
0002                           imagemapeditor.cpp  -  description
0003                             -------------------
0004     begin                : Wed Apr 4 2001
0005     copyright            : (C) 2001 by Jan Schäfer
0006     email                : j_schaef@informatik.uni-kl.de
0007 ***************************************************************************/
0008 
0009 /***************************************************************************
0010 *                                                                         *
0011 *   This program is free software; you can redistribute it and/or modify  *
0012 *   it under the terms of the GNU General Public License as published by  *
0013 *   the Free Software Foundation; either version 2 of the License, or     *
0014 *   (at your option) any later version.                                   *
0015 *                                                                         *
0016 ***************************************************************************/
0017 
0018 #include "kimagemapeditor.h"
0019 
0020 #include <iostream>
0021 #include <assert.h>
0022 
0023 // Qt
0024 #include <QAction>
0025 #include <QActionGroup>
0026 #include <QApplication>
0027 #include <QComboBox>
0028 #include <QDialogButtonBox>
0029 #include <QFile>
0030 #include <QFileDialog>
0031 #include <QFileInfo>
0032 #include <QFontDatabase>
0033 #include <QIcon>
0034 #include <QInputDialog>
0035 #include <QLayout>
0036 #include <QListWidget>
0037 #include <QMenu>
0038 #include <QMimeDatabase>
0039 #include <QMimeType>
0040 #include <QPainter>
0041 #include <QPixmap>
0042 #include <QPushButton>
0043 #include <QScrollArea>
0044 #include <QSplitter>
0045 #include <QStandardPaths>
0046 #include <QTabWidget>
0047 #include <QTextEdit>
0048 #include <QTextStream>
0049 #include <QToolTip>
0050 #include <QUndoStack>
0051 #include <QVBoxLayout>
0052 
0053 // KDE Frameworks
0054 #include <kwidgetsaddons_version.h>
0055 #include <KPluginMetaData>
0056 #include <KActionCollection>
0057 #include <KConfigGroup>
0058 #include <KIO/Job>
0059 #include <KLocalizedString>
0060 #include <KMessageBox>
0061 #include <KPluginFactory>
0062 #include <KSharedConfig>
0063 #include <KUndoActions>
0064 #include <KXMLGUIFactory>
0065 #include <KXmlGuiWindow>
0066 
0067 // local
0068 #include "kimagemapeditor_debug.h"
0069 #include "drawzone.h"
0070 #include "kimedialogs.h"
0071 #include "kimecommands.h"
0072 #include "areacreator.h"
0073 #include "arealistview.h"
0074 #include "imageslistview.h"
0075 #include "mapslistview.h"
0076 #include "kimecommon.h"
0077 #include "imagemapchoosedialog.h"
0078 #include "kimagemapeditor_version.h"
0079 
0080 K_PLUGIN_FACTORY_WITH_JSON(KImageMapEditorFactory, "kimagemapeditorpart.json", registerPlugin<KImageMapEditor>();)
0081 
0082 KImageMapEditor::KImageMapEditor(QWidget *parentWidget, QObject *parent,
0083                                  const KPluginMetaData &metaData,
0084                                  const QVariantList & )
0085   : KParts::ReadWritePart(parent)
0086 {
0087   setMetaData(metaData);
0088 
0089 //  KDockMainWindow* mainWidget;
0090 
0091   mainWindow = dynamic_cast<KXmlGuiWindow*>(parent) ;
0092   QSplitter * splitter = nullptr;
0093   tabWidget = nullptr;
0094 
0095   if (mainWindow) {
0096 //    qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: We got a KDockMainWindow !";
0097 
0098 //    K3DockWidget* parentDock = mainDock->getMainDockWidget();
0099     areaDock = new QDockWidget(i18n("Areas"),mainWindow);
0100     mapsDock = new QDockWidget(i18n("Maps"),mainWindow);
0101     imagesDock = new QDockWidget(i18n("Images"),mainWindow);
0102 
0103     // Needed to save their state
0104     areaDock->setObjectName("areaDock");
0105     mapsDock->setObjectName("mapsDock");
0106     imagesDock->setObjectName("imagesDock");
0107 
0108     mainWindow->addDockWidget( Qt::LeftDockWidgetArea, areaDock);
0109     mainWindow->addDockWidget( Qt::LeftDockWidgetArea, mapsDock);
0110     mainWindow->addDockWidget( Qt::LeftDockWidgetArea, imagesDock);
0111 
0112     areaListView = new AreaListView(areaDock);
0113     mapsListView = new MapsListView(mapsDock);
0114     imagesListView = new ImagesListView(imagesDock);
0115 
0116     areaDock->setWidget(areaListView);
0117     mapsDock->setWidget(mapsListView);
0118     imagesDock->setWidget(imagesListView);
0119 
0120   }
0121   else
0122   {
0123     areaDock = nullptr;
0124     mapsDock = nullptr;
0125     imagesDock = nullptr;
0126     splitter = new QSplitter(parentWidget);
0127     tabWidget = new QTabWidget(splitter);
0128     areaListView = new AreaListView(tabWidget);
0129     mapsListView = new MapsListView(tabWidget);
0130     imagesListView = new ImagesListView(tabWidget);
0131 
0132     tabWidget->addTab(areaListView,i18n("Areas"));
0133     tabWidget->addTab(mapsListView,i18n("Maps"));
0134     tabWidget->addTab(imagesListView,i18n("Images"));
0135   }
0136 
0137 
0138   connect( areaListView->listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged()));
0139   connect( areaListView->listView,
0140            SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
0141            this,
0142            SLOT(showTagEditor(QTreeWidgetItem*)));
0143   connect( areaListView->listView,
0144            SIGNAL(customContextMenuRequested(QPoint)),
0145            this,
0146            SLOT(slotShowPopupMenu(QPoint)));
0147 
0148   connect( mapsListView, SIGNAL(mapSelected(QString)),
0149            this, SLOT(setMap(QString)));
0150 
0151   connect( mapsListView, SIGNAL(mapRenamed(QString)),
0152            this, SLOT(setMapName(QString)));
0153 
0154   connect( mapsListView->listView(),
0155            SIGNAL(customContextMenuRequested(QPoint)),
0156            this,
0157            SLOT(slotShowMapPopupMenu(QPoint)));
0158 
0159   connect( imagesListView, &ImagesListView::imageSelected,
0160            this, QOverload<const QUrl &>::of(&KImageMapEditor::setPicture));
0161 
0162   connect( imagesListView,
0163            SIGNAL(customContextMenuRequested(QPoint)),
0164            this,
0165            SLOT(slotShowImagePopupMenu(QPoint)));
0166 
0167   if (splitter) {
0168     drawZone = new DrawZone(splitter,this);
0169     splitter->setStretchFactor(splitter->indexOf(tabWidget), 0);
0170     splitter->setStretchFactor(splitter->indexOf(drawZone), 1);
0171     setWidget(splitter);
0172   } else {
0173     QScrollArea *sa = new QScrollArea(mainWindow);
0174     drawZone = new DrawZone(nullptr,this);
0175     mainWindow->setCentralWidget(sa);
0176     sa->setWidget(drawZone);
0177     setWidget(mainWindow);
0178     //    sa->setWidgetResizable(true);
0179   }
0180 
0181 
0182   areas = new AreaList();
0183   currentSelected= new AreaSelection();
0184   _currentToolType=KImageMapEditor::Selection;
0185   copyArea = nullptr;
0186   defaultArea = nullptr;
0187   currentMapElement = nullptr;
0188 
0189   setupActions();
0190   setupStatusBar();
0191 
0192   setXMLFile("kimagemapeditorpartui.rc");
0193 
0194   setPicture(getBackgroundImage());
0195 
0196   init();
0197   readConfig();
0198 }
0199 
0200 KImageMapEditor::~KImageMapEditor() {
0201   writeConfig();
0202 
0203   delete areas;
0204 
0205   delete currentSelected;
0206   delete copyArea;
0207   delete defaultArea;
0208 
0209   // Delete our DockWidgets
0210   if (areaDock) {
0211     areaDock->hide();
0212     mapsDock->hide();
0213     imagesDock->hide();
0214 
0215     delete areaDock;
0216     delete mapsDock;
0217     delete imagesDock;
0218   }
0219 
0220 }
0221 
0222 QString KImageMapEditor::componentName() const
0223 {
0224     // the part ui.rc file is in the program folder, not a separate one
0225     // TODO: change the component name to "kimagemapeditorpart" by removing this method and
0226     // adapting the folder where the file is placed.
0227     // Needs a way to also move any potential custom user ui.rc files
0228     // from kimagemapeditor/ to kimagemapeditorpart/
0229     return QStringLiteral("kimagemapeditor");
0230 }
0231 
0232 MapTag::MapTag() {
0233   modified = false;
0234   name.clear();
0235 }
0236 
0237 void KImageMapEditor::init()
0238 {
0239   _htmlContent.clear();
0240   _imageUrl.clear();
0241   //  closeUrl();
0242   HtmlElement* el = new HtmlElement("<html>\n");
0243   _htmlContent.append(el);
0244   el = new HtmlElement("<head>\n");
0245   _htmlContent.append(el);
0246   el = new HtmlElement("</head>\n");
0247   _htmlContent.append(el);
0248   el = new HtmlElement("<body>\n");
0249   _htmlContent.append(el);
0250 
0251   addMap(i18n("unnamed"));
0252 
0253   el = new HtmlElement("</body>\n");
0254   _htmlContent.append(el);
0255   el = new HtmlElement("</html>\n");
0256   _htmlContent.append(el);
0257 
0258   setImageActionsEnabled(false);
0259 }
0260 
0261 void KImageMapEditor::setReadWrite(bool)
0262 {
0263 
0264   // For now it does not matter if it is readwrite or readonly
0265   // it is always readwrite, because Quanta only supports ReadOnlyParts
0266   // at this moment and in that case it should be readwrite, too.
0267   ReadWritePart::setReadWrite(true);
0268   /*
0269     if (rw)
0270       ;
0271     else
0272     {
0273      actionCollection()->remove(arrowAction);
0274      actionCollection()->remove(circleAction);
0275      actionCollection()->remove(rectangleAction);
0276      actionCollection()->remove(polygonAction);
0277      actionCollection()->remove(freehandAction);
0278      actionCollection()->remove(addPointAction);
0279      actionCollection()->remove(removePointAction);
0280 
0281      actionCollection()->remove(cutAction);
0282      actionCollection()->remove(deleteAction);
0283      actionCollection()->remove(copyAction);
0284      actionCollection()->remove(pasteAction);
0285 
0286      actionCollection()->remove(mapNewAction);
0287      actionCollection()->remove(mapDeleteAction);
0288      actionCollection()->remove(mapNameAction);
0289      actionCollection()->remove(mapDefaultAreaAction);
0290 
0291      actionCollection()->remove(areaPropertiesAction);
0292 
0293      actionCollection()->remove(moveLeftAction);
0294      actionCollection()->remove(moveRightAction);
0295      actionCollection()->remove(moveUpAction);
0296      actionCollection()->remove(moveDownAction);
0297 
0298      actionCollection()->remove(increaseWidthAction);
0299      actionCollection()->remove(decreaseWidthAction);
0300      actionCollection()->remove(increaseHeightAction);
0301      actionCollection()->remove(decreaseHeightAction);
0302 
0303      actionCollection()->remove(toFrontAction);
0304      actionCollection()->remove(toBackAction);
0305      actionCollection()->remove(forwardOneAction);
0306      actionCollection()->remove(backOneAction);
0307 
0308      actionCollection()->remove(imageRemoveAction);
0309      actionCollection()->remove(imageAddAction);
0310      actionCollection()->remove(imageUsemapAction);
0311 
0312     }
0313   */
0314 
0315 }
0316 
0317 void KImageMapEditor::setModified(bool modified)
0318 {
0319     // get a handle on our Save action and make sure it is valid
0320     QAction *save = actionCollection()->action(KStandardAction::name(KStandardAction::Save));
0321     if (!save)
0322         return;
0323 
0324     // if so, we either enable or disable it based on the current
0325     // state
0326     if (modified)
0327         save->setEnabled(true);
0328     else
0329         save->setEnabled(false);
0330 
0331     // in any event, we want our parent to do it's thing
0332     ReadWritePart::setModified(modified);
0333 }
0334 
0335 
0336 KConfig *KImageMapEditor::config()
0337 {
0338     /* TODO KF5
0339     KSharedConfigPtr tmp = KimeFactory::componentData().config();
0340     return tmp.data();
0341     */
0342     return new KConfig();
0343 }
0344 
0345 void KImageMapEditor::readConfig(const KConfigGroup &config) {
0346   KConfigGroup data = config.parent().group( "Data" );
0347   recentFilesAction->loadEntries( data );
0348 }
0349 
0350 void KImageMapEditor::writeConfig(KConfigGroup& config) {
0351   config.writeEntry("highlightareas",highlightAreasAction->isChecked());
0352   config.writeEntry("showalt",showAltAction->isChecked());
0353   KConfigGroup data = config.parent().group( "Data" );
0354   recentFilesAction->saveEntries( data );
0355   saveLastURL(config);
0356 
0357 }
0358 
0359 void KImageMapEditor::readConfig() {
0360   readConfig(config()->group("General Options" ) );
0361   slotConfigChanged();
0362 }
0363 
0364 void KImageMapEditor::writeConfig() {
0365   KConfigGroup cg( config(), "General Options");
0366   writeConfig( cg );
0367   config()->sync();
0368 }
0369 
0370 
0371 void KImageMapEditor::saveProperties(KConfigGroup &config)
0372 {
0373   saveLastURL(config);
0374 }
0375 
0376 void KImageMapEditor::readProperties(const KConfigGroup& config)
0377 {
0378   openLastURL(config);
0379 }
0380 
0381 void KImageMapEditor::slotConfigChanged()
0382 {
0383   KConfigGroup group = config()->group("Appearance");
0384   int newHeight=group.readEntry("maximum-preview-height",50);
0385   group = config()->group("General Options");
0386   _commandHistory->setUndoLimit(group.readEntry("undo-level",100));
0387 #if 0
0388   _commandHistory->setRedoLimit(group.readEntry("redo-level",100));
0389 #endif
0390   Area::highlightArea = group.readEntry("highlightareas",true);
0391   highlightAreasAction->setChecked(Area::highlightArea);
0392   Area::showAlt = group.readEntry("showalt",true);
0393   showAltAction->setChecked(Area::showAlt);
0394 
0395   // if the image preview size changed update all images
0396   if (maxAreaPreviewHeight!=newHeight) {
0397     maxAreaPreviewHeight=newHeight;
0398     areaListView->listView->setIconSize(QSize(newHeight,newHeight));
0399   }
0400 
0401   updateAllAreas();
0402   drawZone->repaint();
0403 }
0404 
0405 void KImageMapEditor::openLastURL(const KConfigGroup & config) {
0406   QUrl lastURL ( config.readPathEntry("lastopenurl", QString()) );
0407   QString lastMap = config.readEntry("lastactivemap");
0408   QString lastImage = config.readPathEntry("lastactiveimage", QString());
0409 
0410 
0411 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "loading from group : " << config.group();
0412 
0413 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "loading entry lastopenurl : " << lastURL.path();
0414 //  KMessageBox::information(0L, config.group()+" "+lastURL.path());
0415   if (!lastURL.isEmpty()) {
0416     openUrl(lastURL);
0417     if (!lastMap.isEmpty())
0418       mapsListView->selectMap(lastMap);
0419     if (!lastImage.isEmpty())
0420       setPicture(QUrl::fromLocalFile(lastImage));
0421 //    qCDebug(KIMAGEMAPEDITOR_LOG) << "opening HTML file with map " << lastMap << " and image " << lastImage;
0422 //    if (! openHTMLFile(lastURL, lastMap, lastImage) )
0423 //      closeUrl();
0424       //openUrl(lastURL);
0425       //    else
0426       //closeUrl();
0427   }
0428 }
0429 
0430 void KImageMapEditor::saveLastURL(KConfigGroup & config) {
0431   qCDebug(KIMAGEMAPEDITOR_LOG) << "saveLastURL: " << url().path();
0432   config.writePathEntry("lastopenurl",url().path());
0433   config.writeEntry("lastactivemap",mapName());
0434   config.writePathEntry("lastactiveimage",_imageUrl.path());
0435 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "writing entry lastopenurl : " << url().path();
0436 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "writing entry lastactivemap : " << mapName();
0437 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "writing entry lastactiveimage : " << _imageUrl.path();
0438   //KMessageBox::information(0L, QString("Group: %1 Saving ... %2").arg(config.group()).arg(url().path()));
0439 }
0440 
0441 void KImageMapEditor::setupActions()
0442 {
0443     // File Open
0444   QAction *temp =
0445     KStandardAction::open(this, SLOT(fileOpen()),
0446               actionCollection());
0447   temp->setWhatsThis(i18n("<h3>Open File</h3>Click this to <em>open</em> a new picture or HTML file."));
0448   temp->setToolTip(i18n("Open new picture or HTML file"));
0449 
0450   // File Open Recent
0451   recentFilesAction = KStandardAction::openRecent(this, SLOT(openURL(QUrl)),
0452                                       actionCollection());
0453     // File Save
0454   temp =KStandardAction::save(this, SLOT(fileSave()), actionCollection());
0455     temp->setWhatsThis(i18n("<h3>Save File</h3>Click this to <em>save</em> the changes to the HTML file."));
0456     temp->setToolTip(i18n("Save HTML file"));
0457 
0458 
0459     // File Save As
0460   (void)KStandardAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
0461 
0462     // File Close
0463   temp=KStandardAction::close(this, SLOT(fileClose()), actionCollection());
0464     temp->setWhatsThis(i18n("<h3>Close File</h3>Click this to <em>close</em> the currently open HTML file."));
0465     temp->setToolTip(i18n("Close HTML file"));
0466 
0467   // Edit Copy
0468   copyAction=KStandardAction::copy(this, SLOT(slotCopy()), actionCollection());
0469   copyAction->setWhatsThis(i18n("<h3>Copy</h3>"
0470                           "Click this to <em>copy</em> the selected area."));
0471   copyAction->setEnabled(false);
0472 
0473   // Edit Cut
0474   cutAction=KStandardAction::cut(this, SLOT(slotCut()), actionCollection());
0475   cutAction->setWhatsThis(i18n("<h3>Cut</h3>"
0476                           "Click this to <em>cut</em> the selected area."));
0477   cutAction->setEnabled(false);
0478 
0479   // Edit Paste
0480   pasteAction=KStandardAction::paste(this, SLOT(slotPaste()), actionCollection());
0481   pasteAction->setWhatsThis(i18n("<h3>Paste</h3>"
0482                           "Click this to <em>paste</em> the copied area."));
0483   pasteAction->setEnabled(false);
0484 
0485 
0486   // Edit Delete
0487   deleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")),
0488       i18n("&Delete"), this);
0489   actionCollection()->addAction("edit_delete", deleteAction );
0490   connect(deleteAction, SIGNAL(triggered(bool)), SLOT (slotDelete()));
0491   actionCollection()->setDefaultShortcut(deleteAction, QKeySequence(Qt::Key_Delete));
0492   deleteAction->setWhatsThis(i18n("<h3>Delete</h3>"
0493                           "Click this to <em>delete</em> the selected area."));
0494   deleteAction->setEnabled(false);
0495 
0496   // Edit Undo/Redo
0497   _commandHistory = new QUndoStack(this);
0498   KUndoActions::createUndoAction(_commandHistory, actionCollection());
0499   KUndoActions::createRedoAction(_commandHistory, actionCollection());
0500 
0501   // Edit Properties
0502     areaPropertiesAction  = new QAction(i18n("Pr&operties"), this);
0503     actionCollection()->addAction("edit_properties", areaPropertiesAction );
0504   connect(areaPropertiesAction, SIGNAL(triggered(bool)), SLOT(showTagEditor()));
0505   areaPropertiesAction->setEnabled(false);
0506 
0507   // View Zoom In
0508   zoomInAction=KStandardAction::zoomIn(this, SLOT(slotZoomIn()), actionCollection());
0509   // View Zoom Out
0510   zoomOutAction=KStandardAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection());
0511 
0512   // View Zoom
0513   zoomAction  = new KSelectAction(i18n("Zoom"), this);
0514   actionCollection()->addAction("view_zoom", zoomAction );
0515   connect(zoomAction, &KSelectAction::indexTriggered, this, &KImageMapEditor::slotZoom);
0516   zoomAction->setWhatsThis(i18n("<h3>Zoom</h3>"
0517                           "Choose the desired zoom level."));
0518   zoomAction->setItems(QStringList()
0519     << i18n("25%")
0520     << i18n("50%")
0521     << i18n("100%")
0522     << i18n("150%")
0523     << i18n("200%")
0524     << i18n("250%")
0525     << i18n("300%")
0526     << i18n("500%")
0527     << i18n("750%")
0528     << i18n("1000%"));
0529 
0530   zoomAction->setCurrentItem(2);
0531 
0532   highlightAreasAction = actionCollection()->add<KToggleAction>("view_highlightareas");
0533   highlightAreasAction->setText(i18n("Highlight Areas"));
0534 
0535   connect(highlightAreasAction, SIGNAL(toggled(bool)),
0536       this, SLOT(slotHighlightAreas(bool)));
0537 
0538   showAltAction =   actionCollection()->add<KToggleAction>("view_showalt");
0539   showAltAction->setText(i18n("Show Alt Tag"));
0540   connect(showAltAction, SIGNAL(toggled(bool)),this, SLOT (slotShowAltTag(bool)));
0541 
0542     mapNameAction  = new QAction(i18n("Map &Name..."), this);
0543     actionCollection()->addAction("map_name", mapNameAction );
0544   connect(mapNameAction, SIGNAL(triggered(bool)), SLOT(mapEditName()));
0545 
0546     mapNewAction  = new QAction(i18n("Ne&w Map..."), this);
0547     actionCollection()->addAction("map_new", mapNewAction );
0548   connect(mapNewAction, SIGNAL(triggered(bool)), SLOT(mapNew()));
0549   mapNewAction->setToolTip(i18n("Create a new map"));
0550 
0551     mapDeleteAction  = new QAction(i18n("D&elete Map"), this);
0552     actionCollection()->addAction("map_delete", mapDeleteAction );
0553   connect(mapDeleteAction, SIGNAL(triggered(bool)), SLOT(mapDelete()));
0554   mapDeleteAction->setToolTip(i18n("Delete the current active map"));
0555 
0556     mapDefaultAreaAction  = new QAction(i18n("Edit &Default Area..."), this);
0557     actionCollection()->addAction("map_defaultarea", mapDefaultAreaAction );
0558   connect(mapDefaultAreaAction, SIGNAL(triggered(bool)), SLOT(mapDefaultArea()));
0559   mapDefaultAreaAction->setToolTip(i18n("Edit the default area of the current active map"));
0560 
0561     temp  = new QAction(i18n("&Preview"), this);
0562     actionCollection()->addAction("map_preview", temp );
0563   connect(temp, SIGNAL(triggered(bool)), SLOT(mapPreview()));
0564   temp->setToolTip(i18n("Show a preview"));
0565 
0566   // IMAGE
0567   i18n("&Image");
0568 
0569   imageAddAction  = new QAction(i18n("Add Image..."), this);
0570   actionCollection()->addAction("image_add", imageAddAction );
0571   connect(imageAddAction, SIGNAL(triggered(bool)), SLOT(imageAdd()));
0572   imageAddAction->setToolTip(i18n("Add a new image"));
0573 
0574     imageRemoveAction  = new QAction(i18n("Remove Image"), this);
0575     actionCollection()->addAction("image_remove", imageRemoveAction );
0576   connect(imageRemoveAction, SIGNAL(triggered(bool)), SLOT(imageRemove()));
0577   imageRemoveAction->setToolTip(i18n("Remove the current visible image"));
0578 
0579     imageUsemapAction  = new QAction(i18n("Edit Usemap..."), this);
0580     actionCollection()->addAction("image_usemap", imageUsemapAction );
0581   connect(imageUsemapAction, SIGNAL(triggered(bool)), SLOT(imageUsemap()));
0582   imageUsemapAction->setToolTip(i18n("Edit the usemap tag of the current visible image"));
0583 
0584     temp  = new QAction(i18n("Show &HTML"), this);
0585     actionCollection()->addAction("map_showhtml", temp );
0586   connect(temp, SIGNAL(triggered(bool)), SLOT(mapShowHTML()));
0587 
0588 
0589   QActionGroup *drawingGroup = new QActionGroup(this);
0590   // Selection Tool
0591   arrowAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("arrow")), i18n("&Selection"), this);
0592   actionCollection()->setDefaultShortcut(arrowAction, QKeySequence("s"));
0593   actionCollection()->addAction("tool_arrow", arrowAction);
0594   connect(arrowAction, SIGNAL(triggered(bool)), SLOT (slotDrawArrow()));
0595   arrowAction->setWhatsThis(i18n("<h3>Selection</h3>"
0596                           "Click this to select areas."));
0597   drawingGroup->addAction(arrowAction);
0598   arrowAction->setChecked(true);
0599 
0600   // Circle
0601   circleAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("circle")), i18n("&Circle"), this);
0602   actionCollection()->setDefaultShortcut(circleAction, QKeySequence("c"));
0603 
0604   actionCollection()->addAction("tool_circle", circleAction);
0605   connect(circleAction, SIGNAL(triggered(bool)), this, SLOT(slotDrawCircle()));
0606   circleAction->setWhatsThis(i18n("<h3>Circle</h3>"
0607                           "Click this to start drawing a circle."));
0608   drawingGroup->addAction(circleAction);
0609 
0610   // Rectangle
0611     rectangleAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("rectangle")), i18n("&Rectangle"), this);
0612   actionCollection()->setDefaultShortcut(rectangleAction, QKeySequence("r"));
0613     actionCollection()->addAction("tool_rectangle", rectangleAction);
0614   connect(rectangleAction, SIGNAL(triggered(bool)), this, SLOT(slotDrawRectangle()));
0615   rectangleAction->setWhatsThis(i18n("<h3>Rectangle</h3>"
0616                           "Click this to start drawing a rectangle."));
0617   drawingGroup->addAction(rectangleAction);
0618 
0619   // Polygon
0620     polygonAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("polygon")), i18n("&Polygon"), this);
0621   actionCollection()->setDefaultShortcut(polygonAction, QKeySequence("p"));
0622     actionCollection()->addAction("tool_polygon", polygonAction);
0623   connect(polygonAction, SIGNAL(triggered(bool)), SLOT(slotDrawPolygon()));
0624   polygonAction->setWhatsThis(i18n("<h3>Polygon</h3>"
0625                           "Click this to start drawing a polygon."));
0626   drawingGroup->addAction(polygonAction);
0627 
0628   // Freehand
0629     freehandAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("freehand")), i18n("&Freehand Polygon"), this);
0630   actionCollection()->setDefaultShortcut(freehandAction, QKeySequence("f"));
0631     actionCollection()->addAction("tool_freehand", freehandAction);
0632   connect(freehandAction, SIGNAL(triggered(bool)), SLOT(slotDrawFreehand()));
0633   freehandAction->setWhatsThis(i18n("<h3>Freehandpolygon</h3>"
0634                           "Click this to start drawing a freehand polygon."));
0635   drawingGroup->addAction(freehandAction);
0636 
0637   // Add Point
0638     addPointAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("addpoint")), i18n("&Add Point"), this);
0639   actionCollection()->setDefaultShortcut(addPointAction, QKeySequence("a"));
0640     actionCollection()->addAction("tool_addpoint", addPointAction);
0641   connect(addPointAction, SIGNAL(triggered(bool)), SLOT(slotDrawAddPoint()));
0642   addPointAction->setWhatsThis(i18n("<h3>Add Point</h3>"
0643                           "Click this to add points to a polygon."));
0644   drawingGroup->addAction(addPointAction);
0645 
0646   // Remove Point
0647   removePointAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("removepoint")), i18n("&Remove Point"), this);
0648   actionCollection()->setDefaultShortcut(removePointAction, QKeySequence("e"));
0649   actionCollection()->addAction("tool_removepoint", removePointAction);
0650   connect(removePointAction, SIGNAL(triggered(bool)), 
0651           SLOT(slotDrawRemovePoint()));
0652   removePointAction->setWhatsThis(i18n("<h3>Remove Point</h3>"
0653                           "Click this to remove points from a polygon."));
0654   drawingGroup->addAction(removePointAction);
0655 
0656     QAction *action  = new QAction(i18n("Cancel Drawing"), this);
0657     actionCollection()->addAction("canceldrawing", action );
0658   connect(action, SIGNAL(triggered(bool)), SLOT(slotCancelDrawing()));
0659   actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Escape));
0660 
0661   moveLeftAction  = new QAction(i18n("Move Left"), this);
0662   actionCollection()->addAction("moveleft", moveLeftAction );
0663   connect(moveLeftAction, SIGNAL(triggered(bool)),
0664          SLOT(slotMoveLeft()));
0665   actionCollection()->setDefaultShortcut(moveLeftAction, QKeySequence(Qt::Key_Left));
0666 
0667     moveRightAction  = new QAction(i18n("Move Right"), this);
0668     actionCollection()->addAction("moveright", moveRightAction );
0669   connect(moveRightAction, SIGNAL(triggered(bool)), SLOT(slotMoveRight()));
0670   actionCollection()->setDefaultShortcut(moveRightAction, QKeySequence(Qt::Key_Right));
0671 
0672     moveUpAction  = new QAction(i18n("Move Up"), this);
0673     actionCollection()->addAction("moveup", moveUpAction );
0674   connect(moveUpAction, SIGNAL(triggered(bool)), SLOT(slotMoveUp()));
0675   actionCollection()->setDefaultShortcut(moveUpAction, QKeySequence(Qt::Key_Up));
0676 
0677     moveDownAction  = new QAction(i18n("Move Down"), this);
0678     actionCollection()->addAction("movedown", moveDownAction );
0679   connect(moveDownAction, SIGNAL(triggered(bool)), SLOT(slotMoveDown()));
0680   actionCollection()->setDefaultShortcut(moveDownAction, QKeySequence(Qt::Key_Down));
0681 
0682     increaseWidthAction  = new QAction(i18n("Increase Width"), this);
0683     actionCollection()->addAction("increasewidth", increaseWidthAction );
0684   connect(increaseWidthAction, SIGNAL(triggered(bool)), SLOT(slotIncreaseWidth()));
0685   actionCollection()->setDefaultShortcut(increaseWidthAction, QKeySequence(Qt::Key_Right | Qt::SHIFT));
0686 
0687     decreaseWidthAction  = new QAction(i18n("Decrease Width"), this);
0688     actionCollection()->addAction("decreasewidth", decreaseWidthAction );
0689   connect(decreaseWidthAction, SIGNAL(triggered(bool)), SLOT(slotDecreaseWidth()));
0690   actionCollection()->setDefaultShortcut(decreaseWidthAction, QKeySequence(Qt::Key_Left | Qt::SHIFT));
0691 
0692     increaseHeightAction  = new QAction(i18n("Increase Height"), this);
0693     actionCollection()->addAction("increaseheight", increaseHeightAction );
0694   connect(increaseHeightAction, SIGNAL(triggered(bool)), SLOT(slotIncreaseHeight()));
0695   actionCollection()->setDefaultShortcut(increaseHeightAction, QKeySequence(Qt::Key_Up | Qt::SHIFT));
0696 
0697     decreaseHeightAction  = new QAction(i18n("Decrease Height"), this);
0698     actionCollection()->addAction("decreaseheight", decreaseHeightAction );
0699   connect(decreaseHeightAction, SIGNAL(triggered(bool)), SLOT(slotDecreaseHeight()));
0700   actionCollection()->setDefaultShortcut(decreaseHeightAction, QKeySequence(Qt::Key_Down | Qt::SHIFT));
0701 
0702     toFrontAction  = new QAction(i18n("Bring to Front"), this);
0703     actionCollection()->addAction("tofront", toFrontAction );
0704   connect(toFrontAction, SIGNAL(triggered(bool)), SLOT(slotToFront()));
0705 
0706     toBackAction  = new QAction(i18n("Send to Back"), this);
0707     actionCollection()->addAction("toback", toBackAction );
0708   connect(toBackAction, SIGNAL(triggered(bool)), SLOT(slotToBack()));
0709 
0710     forwardOneAction  = new QAction(QIcon::fromTheme(QStringLiteral("raise")), i18n("Bring Forward One"), this);
0711     actionCollection()->addAction("forwardone", forwardOneAction );
0712   connect(forwardOneAction, SIGNAL(triggered(bool)), SLOT(slotForwardOne()));
0713     backOneAction  = new QAction(QIcon::fromTheme(QStringLiteral("lower")), i18n("Send Back One"), this);
0714     actionCollection()->addAction("backone", backOneAction );
0715   connect(backOneAction, SIGNAL(triggered(bool)), SLOT(slotBackOne()));
0716 
0717   areaListView->upBtn->addAction(forwardOneAction);
0718   areaListView->downBtn->addAction(backOneAction);
0719 
0720   connect( areaListView->upBtn, SIGNAL(pressed()), forwardOneAction, SLOT(trigger()));
0721   connect( areaListView->downBtn, SIGNAL(pressed()), backOneAction, SLOT(trigger()));
0722 
0723     action  = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure KImageMapEditor..."), this);
0724     actionCollection()->addAction("configure_kimagemapeditor", action );
0725   connect(action, SIGNAL(triggered(bool)), SLOT(slotShowPreferences()));
0726 
0727   qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: 1";
0728 
0729   if (areaDock) {
0730 
0731     QAction* a =  areaDock->toggleViewAction();
0732     a->setText(i18n("Show Area List"));
0733     actionCollection()->addAction("configure_show_arealist",
0734                   a);
0735 
0736     a = mapsDock->toggleViewAction();
0737     a->setText(i18n("Show Map List"));
0738     actionCollection()->addAction("configure_show_maplist", a );
0739 
0740     a = imagesDock->toggleViewAction();
0741     a->setText(i18n("Show Image List"));
0742     actionCollection()->addAction("configure_show_imagelist", a );
0743   }
0744 
0745   qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: 2";
0746   updateActionAccess();
0747   qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor: 3";
0748 }
0749 
0750 void KImageMapEditor::setupStatusBar()
0751 {
0752 
0753 //  We can't do this with a KPart !
0754 //  widget()->statusBar()->insertItem(i18n(" Cursor")+" : x: 0 ,y: 0",STATUS_CURSOR);
0755 //  widget()->statusBar()->insertItem(i18n(" Selection")+" : - ",STATUS_SELECTION);
0756   emit setStatusBarText( i18n(" Selection: -  Cursor: x: 0, y: 0 "));
0757 }
0758 
0759 void KImageMapEditor::slotShowPreferences()
0760 {
0761   PreferencesDialog *dialog = new PreferencesDialog(widget(),config());
0762   connect(dialog, SIGNAL(preferencesChanged()), this, SLOT(slotConfigChanged()));
0763   dialog->exec();
0764   delete dialog;
0765 }
0766 
0767 
0768 void KImageMapEditor::showPopupMenu(const QPoint & pos, const QString & name)
0769 {
0770   QMenu* pop = static_cast<QMenu *>(factory()->container(name, this));
0771 
0772   if (!pop) {
0773       qCWarning(KIMAGEMAPEDITOR_LOG) << QString("KImageMapEditorPart: Missing XML definition for %1\n").arg(name);
0774       return;
0775   }
0776 
0777   pop->popup(pos);
0778 }
0779 
0780 void KImageMapEditor::slotShowMainPopupMenu(const QPoint & pos)
0781 {
0782   showPopupMenu(pos,"popup_main");
0783 }
0784 
0785 void KImageMapEditor::slotShowMapPopupMenu(const QPoint & pos)
0786 {
0787   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotShowMapPopupMenu";
0788   QTreeWidgetItem* item = mapsListView->listView()->itemAt(pos);
0789 
0790   if (isReadWrite()) {
0791     mapDeleteAction->setEnabled(item);
0792     mapNameAction->setEnabled(item);
0793     mapDefaultAreaAction->setEnabled(item);
0794   }
0795 
0796   if (item)
0797      mapsListView->selectMap(item);
0798 
0799   showPopupMenu(mapsListView->listView()->viewport()->mapToGlobal(pos),"popup_map");
0800 }
0801 
0802 void KImageMapEditor::slotShowImagePopupMenu(const QPoint & pos)
0803 {
0804   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotShowImagePopupMenu";
0805   QTreeWidgetItem* item = imagesListView->itemAt(pos);
0806 
0807   imageRemoveAction->setEnabled(item);
0808   imageUsemapAction->setEnabled(item);
0809 
0810   if (item)
0811      imagesListView->setCurrentItem(item);
0812 
0813   showPopupMenu(imagesListView->viewport()->mapToGlobal(pos),"popup_image");
0814 }
0815 
0816 void KImageMapEditor::slotShowPopupMenu(const QPoint & p)
0817 {
0818   QTreeWidgetItem* item = areaListView->listView->itemAt(p);
0819 
0820   if (!item)
0821     return;
0822 
0823   if (!item->isSelected())
0824   {
0825     deselectAll();
0826     select(item);
0827   }
0828 
0829   slotShowMainPopupMenu(areaListView->listView->viewport()->mapToGlobal(p));
0830 }
0831 
0832 void KImageMapEditor::updateStatusBar()
0833 {
0834   emit setStatusBarText(selectionStatusText+"  "+cursorStatusText);
0835 }
0836 
0837 void KImageMapEditor::slotChangeStatusCoords(int x,int y)
0838 {
0839 //  statusBar()->changeItem(QString(" Cursor : x: %1 ,y: %2 ").arg(x).arg(y),STATUS_CURSOR);
0840   cursorStatusText = i18n(" Cursor: x: %1, y: %2 ", x, y);
0841   updateStatusBar();
0842 }
0843 
0844 void KImageMapEditor::slotUpdateSelectionCoords() {
0845   if (selected()->count()>0) {
0846     QRect r=selected()->rect();
0847 //      statusBar()->changeItem(
0848     selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ", r.left(), r.top(), r.width(), r.height());
0849 
0850 //        ,STATUS_SELECTION);
0851     qApp->processEvents();
0852   } else
0853     selectionStatusText = i18n(" Selection: - ");
0854     //statusBar()->changeItem(" Selection : - ",STATUS_SELECTION);
0855 
0856   updateStatusBar();
0857 }
0858 
0859 void KImageMapEditor::slotUpdateSelectionCoords( const QRect & r )
0860 {
0861   selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ", r.left(), r.top(), r.width(), r.height());
0862   updateStatusBar();
0863   qApp->processEvents();
0864 }
0865 
0866 void KImageMapEditor::drawToCenter(QPainter* p, const QString & str, int y, int width) {
0867   int xmid = width / 2;
0868 
0869   QFontMetrics fm = p->fontMetrics();
0870   QRect strBounds = fm.boundingRect(str);
0871 
0872   p->drawText(xmid-(strBounds.width()/2),y,str);
0873 }
0874 
0875 
0876 QImage KImageMapEditor::getBackgroundImage() {
0877 
0878   // Lazy initialisation
0879   if ( _backgroundImage.isNull() ) {
0880 
0881 
0882 //  QString filename = QString("dropimage_")+KGlobal::locale()->language()+".png";
0883 //  QString path = QString(); //KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/"+filename ) + "kimagemapeditor/"+filename;
0884 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "getBackgroundPic : loaded image : " << path;
0885 
0886 //  if ( ! QFileInfo(path).exists() ) {
0887     int width = 400;
0888     int height = 400;
0889     int border = 20;
0890     int fontSize = 58;
0891 
0892     QPixmap pix(width,height);
0893     pix.fill(QColor(74,76,74));
0894     QPainter p(&pix);
0895 
0896     //    QFont font = QFontDatabase().font("Luxi Sans","Bold",fontSize);
0897     QFont font;
0898     font.setBold(true);
0899     font.setPixelSize(fontSize);
0900     p.setFont( font );
0901     p.setCompositionMode(QPainter::CompositionMode_Source);
0902     p.setPen(QPen(QColor(112,114,112),1));
0903 
0904     // The translated string must be divided into
0905     // parts with about the same size that fit to the image
0906     QString str = i18n("Drop an image or HTML file");
0907     const QStringList strList = str.split(' ');
0908 
0909     // Get the string parts
0910     QString tmp;
0911     QStringList outputStrList;
0912     QFontMetrics fm = p.fontMetrics();
0913 
0914     for ( QStringList::ConstIterator it = strList.begin(); it != strList.end(); ++it ) {
0915       QString tmp2 = tmp + *it;
0916 
0917         if (fm.boundingRect(tmp2).width() > width-border) {
0918            outputStrList.append(tmp);
0919            tmp = *it + ' ';
0920         }
0921         else
0922           tmp = tmp2 + ' ';
0923     }
0924 
0925     // Last one was forgotten so add it.
0926     outputStrList.append(tmp);
0927 
0928     // Try to adjust the text vertically centered
0929     int step = myround(float(height) / (outputStrList.size()+1));
0930     int y = step;
0931 
0932     for ( QStringList::Iterator it = outputStrList.begin(); it != outputStrList.end(); ++it ) {
0933         drawToCenter(&p, *it, y, pix.width());
0934         y += step;
0935     }
0936 
0937     p.end();
0938 
0939     _backgroundImage = pix.toImage();
0940   }
0941 
0942 
0943   return _backgroundImage;
0944 
0945 /*
0946         QFontDatabase fdb;
0947     QStringList families = fdb.families();
0948     for ( QStringList::Iterator f = families.begin(); f != families.end(); ++f ) {
0949         QString family = *f;
0950         qDebug( family );
0951         QStringList styles = fdb.styles( family );
0952         for ( QStringList::Iterator s = styles.begin(); s != styles.end(); ++s ) {
0953             QString style = *s;
0954             QString dstyle = "\t" + style + " (";
0955             QValueList<int> smoothies = fdb.smoothSizes( family, style );
0956             for ( QValueList<int>::Iterator points = smoothies.begin();
0957                   points != smoothies.end(); ++points ) {
0958                 dstyle += QString::number( *points ) + " ";
0959             }
0960             dstyle = dstyle.left( dstyle.length() - 1 ) + ")";
0961             qDebug( dstyle );
0962         }
0963     }
0964 
0965 
0966     path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "kimagemapeditor/" ) +filename;
0967     qCDebug(KIMAGEMAPEDITOR_LOG) << "getBackgroundPic : save new image to : " << path;
0968     pix.save(path,"PNG",100);
0969   }
0970 
0971   if ( ! QFileInfo(path).exists() ) {
0972       qCCritical(KIMAGEMAPEDITOR_LOG) << "Couldn't find needed " << filename << " file in "
0973                    "the data directory of KImageMapEditor.\n"
0974                    "Perhaps you have forgotten to do a make install !";
0975       exit(1);
0976   }
0977 */
0978 }
0979 
0980 
0981 void KImageMapEditor::addArea(Area* area) {
0982   if (!area) return;
0983 
0984   // Perhaps we've got a selection of areas
0985   // so test it and add all areas of the selection
0986   // nested selections are possible but doesn't exist
0987   AreaSelection *selection = nullptr;
0988   if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
0989   {
0990     AreaListIterator it = selection->getAreaListIterator();
0991     while (it.hasNext()) {
0992       Area* a = it.next();
0993       areas->prepend(a);
0994       a->setListViewItem(new QTreeWidgetItem(
0995           areaListView->listView,
0996           QStringList(a->attribute("href"))));
0997       a->listViewItem()->setIcon(1,QIcon(makeListViewPix(*a)));
0998     }
0999   }
1000   else
1001   {
1002     areas->prepend(area);
1003     area->setListViewItem(new QTreeWidgetItem(
1004       areaListView->listView,
1005       QStringList(area->attribute("href"))));
1006     area->listViewItem()->setIcon(1,QIcon(makeListViewPix(*area)));
1007   }
1008 
1009   setModified(true);
1010 
1011 }
1012 
1013 void KImageMapEditor::addAreaAndEdit(Area* s)
1014 {
1015   areas->prepend(s);
1016   s->setListViewItem(new QTreeWidgetItem(
1017     areaListView->listView,
1018     QStringList(s->attribute("href"))));
1019   s->listViewItem()->setIcon(1,QIcon(makeListViewPix(*s)));
1020   deselectAll();
1021   select(s);
1022   if (!showTagEditor(selected())) {
1023     // If the user has pressed cancel
1024     // he undos the creation
1025     commandHistory()->undo();
1026   }
1027 }
1028 
1029 void KImageMapEditor::deleteArea( Area * area )
1030 {
1031   if (!area) return;
1032 
1033   // only for repaint reasons
1034   QRect redrawRect = area->selectionRect();
1035 
1036   // Perhaps we've got a selection of areas
1037   // so test it and delete the whole selection
1038   // nested selections are possible but doesn't exist
1039   AreaSelection *selection = nullptr;
1040     if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
1041   {
1042     AreaListIterator it = selection->getAreaListIterator();
1043     while (it.hasNext()) {
1044       Area* a = it.next();
1045       currentSelected->remove(a);
1046       areas->removeAll( a );
1047       a->deleteListViewItem();
1048     }
1049   }
1050   else
1051   {
1052     deselect( area );
1053     areas->removeAll( area );
1054     area->deleteListViewItem();
1055   }
1056 
1057   drawZone->repaintRect(redrawRect);
1058 
1059 
1060   // Only to disable cut and copy actions
1061   if (areas->count()==0)
1062     deselectAll();
1063 
1064   setModified(true);
1065 }
1066 
1067 void KImageMapEditor::deleteSelected() {
1068 
1069   AreaListIterator it = currentSelected->getAreaListIterator();
1070   while (it.hasNext()) {
1071     Area *a = it.next();
1072     currentSelected->remove( a );
1073     areas->removeAll( a );
1074     delete a->listViewItem();
1075   }
1076 
1077 
1078   drawZone->repaintArea( *currentSelected );
1079   // Only to disable cut and copy actions
1080   if (areas->count()==0)
1081     deselectAll();
1082 
1083   setModified(true);
1084 }
1085 
1086 void KImageMapEditor::deleteAllAreas()
1087 {
1088   Area* a;
1089   foreach (a,*areas) {
1090     deselect( a );
1091     areas->removeAll( a );
1092     a->deleteListViewItem();
1093     if (!areas->isEmpty())
1094       a = areas->first(); // because the current is deleted
1095   }
1096 
1097   drawZone->repaint();
1098 
1099 }
1100 
1101 void KImageMapEditor::updateAllAreas()
1102 {
1103 //  qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::updateAllAreas";
1104   Area* a;
1105   foreach(a,*areas) {
1106     a->listViewItem()->setIcon(1,QIcon(makeListViewPix(*a)));
1107   }
1108   drawZone->repaint();
1109 }
1110 
1111 void KImageMapEditor::updateSelection() const {
1112   //FIXME: areaListView->listView->triggerUpdate();
1113 }
1114 
1115 AreaSelection* KImageMapEditor::selected() const {
1116   return currentSelected;
1117 }
1118 
1119 void KImageMapEditor::select(Area* a)
1120 {
1121   if (!a) return;
1122 
1123   currentSelected->add(a);
1124   updateActionAccess();
1125   slotUpdateSelectionCoords();
1126 //  drawZone->repaintArea( *a);
1127 
1128 }
1129 
1130 void KImageMapEditor::selectWithoutUpdate(Area* a)
1131 {
1132   if (!a) return;
1133   currentSelected->add(a);
1134 }
1135 
1136 void KImageMapEditor::slotSelectionChanged()
1137 {
1138   AreaListIterator it = areaList();
1139   AreaList list = currentSelected->getAreaList();
1140 
1141   while (it.hasNext()) {
1142     Area* a = it.next();
1143     if ( a->listViewItem()->isSelected() != (list.contains(a)) )
1144     {
1145       a->listViewItem()->isSelected()
1146         ? select( a )
1147         :   deselect( a );
1148 
1149       drawZone->repaintArea( *a);
1150     }
1151   }
1152 
1153 }
1154 
1155 void KImageMapEditor::select( QTreeWidgetItem* item)
1156 {
1157 
1158   AreaListIterator it = areaList();
1159   while (it.hasNext()) {
1160     Area* a = it.next();
1161     if (a->listViewItem() == item )
1162     {
1163       select( a );
1164       drawZone->repaintArea( *a);
1165     }
1166   }
1167 
1168 
1169 }
1170 
1171 AreaListIterator KImageMapEditor::areaList() const {
1172   AreaListIterator it(*areas);
1173   return it;
1174 }
1175 
1176 
1177 void KImageMapEditor::slotAreaChanged(Area *area)
1178 {
1179   if (!area)
1180     return;
1181 
1182   setModified(true);
1183 
1184   AreaSelection *selection = nullptr;
1185   if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
1186   {
1187     AreaListIterator it = selection->getAreaListIterator();
1188     while (it.hasNext()) {
1189       Area* a = it.next();
1190       if (a->listViewItem()) {
1191         a->listViewItem()->setText(0,a->attribute("href"));
1192         a->listViewItem()->setIcon(1,QIcon(makeListViewPix(*a)));
1193       }
1194     }
1195 
1196   }
1197   else
1198   if (area->listViewItem()) {
1199     area->listViewItem()->setText(0,area->attribute("href"));
1200     area->listViewItem()->setIcon(1,QIcon(makeListViewPix(*area)));
1201   }
1202 
1203   drawZone->repaintArea(*area);
1204 
1205 }
1206 
1207 void KImageMapEditor::deselect(Area* a)
1208 {
1209   if (a) {
1210     currentSelected->remove(a);
1211 //      drawZone->repaintArea(*a);
1212     updateActionAccess();
1213     slotUpdateSelectionCoords();
1214   }
1215 }
1216 
1217 void KImageMapEditor::deselectWithoutUpdate(Area* a)
1218 {
1219   if (a) {
1220     currentSelected->remove(a);
1221   }
1222 }
1223 
1224 
1225 /**
1226 * Makes sure, that the actions cut, copy, delete and
1227 * show properties
1228 * can only be executed if sth. is selected.
1229 **/
1230 void KImageMapEditor::updateActionAccess()
1231 {
1232   if (!isReadWrite())
1233      return;
1234 
1235   if ( 0 < selected()->count())
1236   {
1237     qCDebug(KIMAGEMAPEDITOR_LOG) << "actions enabled";
1238     areaPropertiesAction->setEnabled(true);
1239     deleteAction->setEnabled(true);
1240     copyAction->setEnabled(true);
1241     cutAction->setEnabled(true);
1242     moveLeftAction->setEnabled(true);
1243     moveRightAction->setEnabled(true);
1244     moveUpAction->setEnabled(true);
1245     moveDownAction->setEnabled(true);
1246     toFrontAction->setEnabled(true);
1247     toBackAction->setEnabled(true);
1248 
1249     if ( (selected()->count() == 1) )
1250     {
1251       if (selected()->type()==Area::Polygon)
1252       {
1253         increaseWidthAction->setEnabled(false);
1254         decreaseWidthAction->setEnabled(false);
1255         increaseHeightAction->setEnabled(false);
1256         decreaseHeightAction->setEnabled(false);
1257         addPointAction->setEnabled(true);
1258         removePointAction->setEnabled(true);
1259       }
1260       else
1261       {
1262         increaseWidthAction->setEnabled(true);
1263         decreaseWidthAction->setEnabled(true);
1264         increaseHeightAction->setEnabled(true);
1265         decreaseHeightAction->setEnabled(true);
1266         addPointAction->setEnabled(false);
1267         removePointAction->setEnabled(false);
1268       }
1269 
1270     }
1271     else
1272     {
1273       increaseWidthAction->setEnabled(false);
1274       decreaseWidthAction->setEnabled(false);
1275       increaseHeightAction->setEnabled(false);
1276       decreaseHeightAction->setEnabled(false);
1277       addPointAction->setEnabled(false);
1278       removePointAction->setEnabled(false);
1279     }
1280 
1281   }
1282   else
1283   {
1284     qCDebug(KIMAGEMAPEDITOR_LOG) << "Actions disabled";
1285     areaPropertiesAction->setEnabled(false);
1286     deleteAction->setEnabled(false);
1287     copyAction->setEnabled(false);
1288     cutAction->setEnabled(false);
1289     moveLeftAction->setEnabled(false);
1290     moveRightAction->setEnabled(false);
1291     moveUpAction->setEnabled(false);
1292     moveDownAction->setEnabled(false);
1293     increaseWidthAction->setEnabled(false);
1294     decreaseWidthAction->setEnabled(false);
1295     increaseHeightAction->setEnabled(false);
1296     decreaseHeightAction->setEnabled(false);
1297     toFrontAction->setEnabled(false);
1298     toBackAction->setEnabled(false);
1299     addPointAction->setEnabled(false);
1300     removePointAction->setEnabled(false);
1301 
1302   }
1303 
1304   updateUpDownBtn();
1305 }
1306 
1307 void KImageMapEditor::updateUpDownBtn()
1308 {
1309   if (!isReadWrite())
1310      return;
1311 
1312   AreaList list = currentSelected->getAreaList();
1313 
1314   if (list.isEmpty() || (areas->count() < 2)) {
1315     forwardOneAction->setEnabled(false);
1316     areaListView->upBtn->setEnabled(false);
1317     backOneAction->setEnabled(false);
1318     areaListView->downBtn->setEnabled(false);
1319     return;
1320   }
1321   // if the first Area is in the selection can't move up
1322   if (list.contains( areas->first() )) {
1323     forwardOneAction->setEnabled(false);
1324     areaListView->upBtn->setEnabled(false);
1325   } else {
1326     forwardOneAction->setEnabled(true);
1327     areaListView->upBtn->setEnabled(true);
1328   }
1329 
1330   drawZone->repaintArea(*currentSelected);
1331 
1332   // if the last Area is in the selection can't move down
1333   if (list.contains( areas->last() )) {
1334     backOneAction->setEnabled(false);
1335     areaListView->downBtn->setEnabled(false);
1336   }
1337   else {
1338     backOneAction->setEnabled(true);
1339     areaListView->downBtn->setEnabled(true);
1340   }
1341 
1342 }
1343 
1344 void KImageMapEditor::deselectAll()
1345 {
1346   QRect redrawRect= currentSelected->selectionRect();
1347   currentSelected->reset();
1348   drawZone->repaintRect(redrawRect);
1349   updateActionAccess();
1350 }
1351 
1352 Area* KImageMapEditor::onArea(const QPoint & p) const {
1353   Area* s;
1354   foreach(s,*areas) {
1355     if (s->contains(p))
1356       return s;
1357   }
1358   return nullptr;
1359 }
1360 
1361 
1362 int KImageMapEditor::showTagEditor(Area *a) {
1363   if (!a) return 0;
1364   drawZone->repaintArea(*a);
1365 
1366   AreaDialog *dialog= new AreaDialog(this,a);
1367   connect (dialog, SIGNAL(areaChanged(Area*)), this, SLOT(slotAreaChanged(Area*)));
1368 
1369   int result = dialog->exec();
1370 
1371   return result;
1372 
1373 
1374 }
1375 
1376 int KImageMapEditor::showTagEditor(QTreeWidgetItem *item) {
1377   if (!item)
1378     return 0;
1379 
1380   Area* a;
1381   foreach(a,*areas) {
1382     if (a->listViewItem()==item) {
1383       return showTagEditor(a);
1384     }
1385   }
1386   return 0;
1387 }
1388 
1389 int KImageMapEditor::showTagEditor() {
1390   return showTagEditor(selected());
1391 }
1392 
1393 
1394 QString KImageMapEditor::getHTMLImageMap() const {
1395   QString retStr;
1396   retStr+="<map "+QString("name=\"")+_mapName+"\">\n";
1397 
1398   Area* a;
1399   foreach(a,*areas) {
1400     retStr+="  "+a->getHTMLCode()+'\n';
1401   }
1402 
1403   if (defaultArea && defaultArea->finished())
1404     retStr+="  "+defaultArea->getHTMLCode()+'\n';
1405 
1406   retStr+="</map>";
1407   return retStr;
1408 }
1409 
1410 QPixmap KImageMapEditor::makeListViewPix(Area & a)
1411 {
1412   QPixmap pix=a.cutOut(drawZone->picture());
1413 
1414   double shrinkFactor=1;
1415 
1416   // picture fits into max row height ?
1417   if (maxAreaPreviewHeight < pix.height())
1418     shrinkFactor = ( (double) maxAreaPreviewHeight / pix.height() );
1419 
1420   QPixmap pix2((int)(pix.width()*shrinkFactor), (int)(pix.height()*shrinkFactor));
1421 
1422   // Give all pixels a defined color
1423   pix2.fill(Qt::white);
1424 
1425   QPainter p(&pix2);
1426 
1427   p.scale(shrinkFactor,shrinkFactor);
1428   p.drawPixmap(0,0,pix);
1429 
1430   return pix2;
1431 }
1432 
1433 void KImageMapEditor::setMapName(const QString & s) {
1434     mapsListView->changeMapName(_mapName, s);
1435     _mapName=s;
1436     currentMapElement->mapTag->name = s;
1437 }
1438 
1439 
1440 void KImageMapEditor::setPicture(const QUrl & url) {
1441   _imageUrl=url;
1442   if (QFileInfo::exists(url.path())) {
1443      QImage img(url.path());
1444 
1445      if (!img.isNull()) {
1446          setPicture(img);
1447          imageRemoveAction->setEnabled(true);
1448          imageUsemapAction->setEnabled(true);
1449      }
1450      else
1451          qCCritical(KIMAGEMAPEDITOR_LOG) << QString("The image %1 could not be opened.").arg(url.path());
1452   }
1453   else
1454      qCCritical(KIMAGEMAPEDITOR_LOG) << QString("The image %1 does not exist.").arg(url.path());
1455 }
1456 
1457 void KImageMapEditor::setPicture(const QImage & pix) {
1458     drawZone->setPicture(pix);
1459     updateAllAreas();
1460 }
1461 
1462 
1463 void KImageMapEditor::slotDrawArrow() {
1464   _currentToolType=KImageMapEditor::Selection;
1465 
1466 }
1467 
1468 void KImageMapEditor::slotDrawCircle() {
1469   _currentToolType=KImageMapEditor::Circle;
1470   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotDrawCircle";
1471 
1472 }
1473 
1474 void KImageMapEditor::slotDrawRectangle() {
1475   _currentToolType=KImageMapEditor::Rectangle;
1476   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotDrawRectangle";
1477 
1478 }
1479 
1480 void KImageMapEditor::slotDrawPolygon() {
1481   _currentToolType=KImageMapEditor::Polygon;
1482   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotDrawPolygon";
1483 }
1484 
1485 void KImageMapEditor::slotDrawFreehand() {
1486   _currentToolType=KImageMapEditor::Freehand;
1487 }
1488 
1489 void KImageMapEditor::slotDrawAddPoint() {
1490   _currentToolType=KImageMapEditor::AddPoint;
1491 }
1492 
1493 void KImageMapEditor::slotDrawRemovePoint() {
1494   _currentToolType=KImageMapEditor::RemovePoint;
1495 }
1496 
1497 
1498 void KImageMapEditor::slotZoom() {
1499 
1500   int i=zoomAction->currentItem();
1501   switch (i) {
1502     case 0 : drawZone->setZoom(0.25);break;
1503     case 1 : drawZone->setZoom(0.5);break;
1504     case 2 : drawZone->setZoom(1);break;
1505     case 3 : drawZone->setZoom(1.5);break;
1506     case 4 : drawZone->setZoom(2.0);break;
1507     case 5 : drawZone->setZoom(2.5);break;
1508     case 6 : drawZone->setZoom(3);break;
1509     case 7 : drawZone->setZoom(5);break;
1510     case 8 : drawZone->setZoom(7.5);break;
1511     case 9 : drawZone->setZoom(10);break;
1512   }
1513   if (i<10)
1514     zoomInAction->setEnabled(true);
1515   else
1516     zoomInAction->setEnabled(false);
1517 
1518   if (i>0)
1519     zoomOutAction->setEnabled(true);
1520   else
1521     zoomOutAction->setEnabled(false);
1522 }
1523 
1524 void KImageMapEditor::slotZoomIn() {
1525   if (zoomAction->currentItem()==(int)(zoomAction->items().count()-1))
1526     return;
1527 
1528   zoomAction->setCurrentItem(zoomAction->currentItem()+1);
1529   slotZoom();
1530 }
1531 
1532 void KImageMapEditor::slotZoomOut() {
1533   if (zoomAction->currentItem()==0)
1534     return;
1535 
1536   zoomAction->setCurrentItem(zoomAction->currentItem()-1);
1537   slotZoom();
1538 }
1539 
1540 void KImageMapEditor::mapDefaultArea()
1541 {
1542   if (defaultArea)
1543     showTagEditor(defaultArea);
1544   else {
1545     defaultArea= new DefaultArea();
1546     showTagEditor(defaultArea);
1547   }
1548 
1549 }
1550 
1551 void KImageMapEditor::mapEditName()
1552 {
1553   bool ok=false;
1554   QString input = QInputDialog::getText(widget(),
1555     i18n("Enter Map Name"), i18n("Enter the name of the map:"),
1556     QLineEdit::Normal, _mapName, &ok);
1557   if (ok && !input.isEmpty()) {
1558     if (input != _mapName) {
1559         if (mapsListView->nameAlreadyExists(input))
1560             KMessageBox::error(this->widget(), i18n("The name <em>%1</em> already exists.", input));
1561         else {
1562             setMapName(input);
1563         }
1564     }
1565   }
1566 }
1567 
1568 void KImageMapEditor::mapShowHTML()
1569 {
1570   QDialog *dialog = new QDialog(widget());
1571   dialog->setModal(true);
1572   dialog->setWindowTitle(i18n("HTML Code of Map"));
1573   QVBoxLayout *mainLayout = new QVBoxLayout(dialog);
1574 
1575   QTextEdit *edit = new QTextEdit;
1576 
1577   edit->setPlainText(getHtmlCode());
1578   edit->setReadOnly(true);
1579   edit->setLineWrapMode(QTextEdit::NoWrap);
1580   mainLayout->addWidget(edit);
1581 //  dialog->resize(dialog->calculateSize(edit->maxLineWidth(),edit->numLines()*));
1582 //  dialog->adjustSize();
1583 
1584   QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
1585   QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
1586   okButton->setDefault(true);
1587   okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
1588   connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
1589   mainLayout->addWidget(buttonBox);
1590 
1591   dialog->resize(600,400);
1592   dialog->exec();
1593   delete dialog;
1594 }
1595 
1596 void KImageMapEditor::openFile(const QUrl & url) {
1597   if ( ! url.isEmpty()) {
1598     QMimeDatabase db;
1599     QMimeType openedFileType = db.mimeTypeForUrl(url);
1600     if (openedFileType.name().left(6) == "image/") {
1601         addImage(url);
1602     } else {
1603         openURL(url);
1604     }
1605   }
1606 }
1607 
1608 bool KImageMapEditor::openURL(const QUrl & url) {
1609     // If a local file does not exist
1610     // we start with an empty file, so
1611     // that we can return true here.
1612     // For non local files, we cannot check
1613     // the existence
1614     if (url.isLocalFile() &&
1615         ! QFile::exists(url.path()))
1616         return true;
1617     return KParts::ReadWritePart::openUrl(url);
1618 }
1619 
1620 void KImageMapEditor::fileOpen() {
1621 
1622   QString fileName = QFileDialog::getOpenFileName(widget(), i18n("Choose File to Open"), QString(),
1623                      i18n("Web File (*.png *.jpg *.jpeg *.gif *.htm *.html);;Images (*.png *.jpg *.jpeg *.gif *.bmp *.xbm *.xpm *.pnm *.mng);;"
1624                           "HTML Files (*.htm *.html);;All Files (*)"));
1625 
1626   openFile(QUrl::fromUserInput( fileName ));
1627 }
1628 
1629 
1630 
1631 void KImageMapEditor::fileClose()
1632 {
1633   if (! closeUrl())
1634      return;
1635 
1636 
1637     setPicture(getBackgroundImage());
1638     recentFilesAction->setCurrentItem(-1);
1639     setModified(false);
1640 }
1641 
1642 void KImageMapEditor::fileSave()
1643 {
1644   // if we aren't read-write, return immediately
1645   if ( ! isReadWrite() )
1646       return;
1647 
1648   if (url().isEmpty()) {
1649     fileSaveAs();
1650   }
1651   else {
1652     saveFile();
1653     setModified(false);
1654   }
1655 
1656 
1657 }
1658 
1659 void KImageMapEditor::fileSaveAs() {
1660 
1661   QUrl url = QFileDialog::getSaveFileUrl(widget(), QString(), QUrl(), i18n("HTML File (*.htm *.html);;Text File (*.txt);;All Files (*)" ));
1662   if (url.isEmpty() || !url.isValid()) {
1663     return;
1664   }
1665 
1666 
1667   saveAs(url);
1668   recentFilesAction->addUrl(url);
1669 
1670 }
1671 
1672 
1673 bool KImageMapEditor::openFile()
1674 {
1675   QUrl u = url();
1676   QFileInfo fileInfo(u.path());
1677 
1678   if ( !fileInfo.exists() )
1679   {
1680       KMessageBox::information(widget(),
1681         i18n("<qt>The file <b>%1</b> does not exist.</qt>", fileInfo.fileName()),
1682         i18n("File Does Not Exist"));
1683       return false;
1684   }
1685 
1686   openHTMLFile(u);
1687 
1688   drawZone->repaint();
1689   recentFilesAction->addUrl(u);
1690   setModified(false);
1691   backupFileCreated = false;
1692   return true;
1693 }
1694 
1695 /**
1696  * This method supposes that the given QTextStream s has just read
1697  * the &lt; of a tag. It now reads all attributes of the tag until a &gt;
1698  * The tagname itself is also read and stored as a <em>tagname</em>
1699  * attribute. After parsing the whole tag it returns a QDict<QString>
1700  * with all attributes and their values. It stores the whole read text in the
1701  * parameter readText.
1702  */
1703 QHash<QString,QString> KImageMapEditor::getTagAttributes(QTextStream & s, QString & readText)
1704 {
1705   QHash<QString,QString> dict;
1706   // the "<" is already read
1707   QChar w;
1708   QString attr,value;
1709 
1710   readText.clear();
1711 
1712   // get the tagname
1713   while (!s.atEnd() && w!=' ') {
1714     s >> w;
1715     readText.append(w);
1716     if (w.isSpace() || w=='>') {
1717       dict.insert("tagname",value);
1718       break;
1719     }
1720     value+=w;
1721   }
1722 
1723 
1724   // do we have a comment ?
1725   // read the comment and return
1726   if (value.right(3)=="-->")
1727     return dict;
1728 
1729   if (value.startsWith(QLatin1String("!--"))) {
1730     while (!s.atEnd()) {
1731       s >> w;
1732       readText.append(w);
1733 
1734       if (w=='-') {
1735         s >> w;
1736         readText.append(w);
1737         if (w=='-') {
1738           s >> w;
1739           readText.append(w);
1740           if (w=='>')
1741             return dict;
1742         }
1743       }
1744     }
1745   }
1746 
1747   bool attrRead=true;   // currently reading an attribute ?
1748   bool equalSign=false; // an equalsign was read?
1749   bool valueRead=false; // currently reading a value ?
1750   QChar quotation='\0'; // currently reading a value with quotation marks ?
1751   bool php=false; // currently reading a php script
1752   attr.clear();
1753   value.clear();
1754 
1755   //get the other attributes
1756   while (!s.atEnd() && w!='>')
1757   {
1758     s >> w;
1759     readText.append(w);
1760 
1761     // End of PHP Script ?
1762     if (php && (w=='?') )
1763     {
1764       s >> w;
1765       readText.append(w);
1766 
1767       if (valueRead)
1768           value+=w;
1769 
1770       if (w=='>')
1771       {
1772         php = false;
1773         s >> w;
1774         readText.append(w);
1775       }
1776     }
1777 
1778     // Wrong syntax or PHP-Script !
1779     if (!php && (w=='<'))
1780     {
1781       if (valueRead)
1782         value+=w;
1783       s >> w;
1784       readText.append(w);
1785       if (valueRead)
1786         value+=w;
1787 
1788       if (w=='?')
1789       {
1790         php = true;
1791       }
1792     } else
1793     // finished ?
1794     if (w=='>') {
1795       if (valueRead) {
1796         dict.insert(attr,value);
1797       }
1798       return dict;
1799     } else
1800     // currently reading an attribute ?
1801     if (attrRead) {
1802       // if there is a whitespace the attributename has finished
1803       // possibly there isn't any value e.g. noshade
1804       if (w.isSpace())
1805         attrRead=false;
1806       else
1807       // an equal sign signals that the value follows
1808       if (w=='=') {
1809         attrRead=false;
1810         equalSign=true;
1811       } else
1812         attr+=w;
1813     } else
1814     // an equal sign was read ? delete every whitespace
1815     if (equalSign) {
1816       if (!w.isSpace()) {
1817         equalSign=false;
1818         valueRead=true;
1819         if (w=='"' || w=='\'')
1820           quotation=w;
1821       }
1822     } else
1823     // currently reading the value
1824     if (valueRead) {
1825       // if php, read without regarding anything
1826       if (php)
1827         value+=w;
1828       // if value within quotation marks is read
1829       // only stop when another quotationmark is found
1830       else
1831       if (quotation != '\0') {
1832         if (quotation!=w) {
1833           value+=w;
1834         } else {
1835           quotation='\0';
1836           valueRead=false;
1837           dict.insert(attr,value);
1838           attr.clear();
1839           value.clear();
1840         }
1841       } else
1842       // a whitespace indicates that the value has finished
1843       if (w.isSpace()) {
1844         valueRead=false;
1845         dict.insert(attr,value);
1846         attr.clear();
1847         value.clear();
1848       }
1849     } else {
1850       if (!w.isSpace()) {
1851         attrRead=true;
1852         attr+=w;
1853       }
1854     }
1855   }
1856 
1857   return dict;
1858 
1859 }
1860 
1861 
1862 bool KImageMapEditor::openHTMLFile(const QUrl & url)
1863 {
1864   QFile f(url.path());
1865   if ( !f.exists () )
1866       return false;
1867   f.open(QIODevice::ReadOnly);
1868   QTextStream s(&f);
1869   QChar w;
1870   QHash<QString,QString> *attr = nullptr;
1871   QList<ImageTag*> images;
1872   MapTag *map = nullptr;
1873   QList<MapTag*> maps;
1874 
1875   _htmlContent.clear();
1876   currentMapElement = nullptr;
1877 
1878   QString temp;
1879   QString origcode;
1880 
1881   bool readMap=false;
1882 
1883   while (!s.atEnd()) {
1884 
1885     s >> w;
1886     if (w=='<')
1887     {
1888       if (!readMap && !origcode.isEmpty()) {
1889         _htmlContent.append( new HtmlElement(origcode));
1890         origcode.clear();
1891       }
1892 
1893       origcode.append("<");
1894       attr=new QHash<QString,QString>(getTagAttributes(s,temp));
1895       origcode.append(temp);
1896 
1897       if (attr->contains("tagname")) {
1898         QString tagName = attr->value("tagname").toLower();
1899         if (tagName =="img") {
1900           HtmlImgElement *el = new HtmlImgElement(origcode);
1901           el->imgTag = static_cast<ImageTag*>(attr);
1902           images.append(el->imgTag);
1903           _htmlContent.append(el);
1904 
1905           origcode.clear();
1906         } else
1907         if (tagName == "map") {
1908           map = new MapTag();
1909           map->name = attr->value("name");
1910       qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::openHTMLFile: found map with name:" << map->name;
1911       
1912           readMap=true;
1913         } else
1914         if (tagName=="/map") {
1915           readMap=false;
1916           maps.append(map);
1917           HtmlMapElement *el = new HtmlMapElement(origcode);
1918           el->mapTag = map;
1919           _htmlContent.append(el);
1920 
1921           origcode.clear();
1922         } else
1923         if (readMap) {
1924           if (tagName=="area") {
1925              map->push_front(*attr);
1926           }
1927         } else {
1928           _htmlContent.append(new HtmlElement(origcode));
1929           origcode.clear();
1930         }
1931 
1932       }
1933     } // w != "<"
1934     else {
1935       origcode.append(w);
1936     }
1937   }
1938 
1939   if (!origcode.isEmpty()) {
1940     _htmlContent.append(new HtmlElement(origcode));
1941   }
1942 
1943   f.close();
1944 
1945   QUrl imageUrl;
1946 
1947   map = nullptr;
1948 
1949     // If we have more than on map or more than one image
1950     // Let the user choose, otherwise take the only ones
1951     if (maps.count() > 1) {
1952       map = maps.first();
1953     }
1954 
1955     if (images.count() > 1) {
1956       ImageTag* imgTag = images.first();
1957       if (imgTag) {
1958         if (imgTag->contains("src")) {
1959             if (url.path().isEmpty() | !url.path().endsWith('/')) {
1960                 imageUrl = QUrl(url.path() + '/').resolved(QUrl(imgTag->value("src")));
1961             }
1962             else {
1963                 imageUrl = url.resolved(QUrl(imgTag->value("src")));
1964             }
1965         }
1966       }
1967     }
1968 
1969     // If there is more than one map and more than one image
1970     // use the map that has an image with an according usemap tag
1971     if (maps.count() > 1 && images.count() > 1) {
1972       bool found = false;
1973       MapTag *mapTag;
1974       foreach(mapTag, maps) {
1975         ImageTag *imageTag;
1976         foreach(imageTag, images) {
1977             if (imageTag->contains("usemap")) {
1978                 QString usemap = imageTag->value("usemap");
1979                 // Remove the #
1980                 QString usemapName = usemap.right(usemap.length()-1);
1981                 if (usemapName == mapTag->name) {
1982           if (imageTag->contains("src")) {
1983                       if (url.path().isEmpty() | !url.path().endsWith('/')) {
1984                           imageUrl = QUrl(url.path() + '/').resolved(QUrl(imageTag->value("src")));
1985                       }
1986                       else {
1987                           imageUrl = url.resolved(QUrl(imageTag->value("src")));
1988                       }
1989               found = true;
1990           }
1991                 }
1992             }
1993         if (found)
1994           break;
1995         }
1996     if (found)
1997       break;
1998       }
1999       if (found) {
2000     map = mapTag;
2001       }
2002     }
2003 
2004 
2005     // If there are more than one map or there wasn't
2006     // found a fitting image and there is something to choose
2007     // let the user choose
2008     /*    if (maps.count() >1 || (imageUrl.isEmpty() && images.count() > 1))
2009     {
2010       ImageMapChooseDialog dialog(widget(),maps,images,url);
2011       qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::openHTMLFile: before dialog->exec()";
2012       dialog.exec();
2013       qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::openHTMLFile: after dialog->exec()";
2014       map = dialog.currentMap;
2015       imageUrl = dialog.pixUrl;
2016       }*/
2017   
2018 
2019   imagesListView->clear();
2020   imagesListView->setBaseUrl(url);
2021   imagesListView->addImages(images);
2022 
2023   mapsListView->clear();
2024   mapsListView->addMaps(maps);
2025 
2026 
2027   setMapActionsEnabled(false);
2028 
2029   if (map) {
2030     mapsListView->selectMap(map->name);
2031   } else {
2032 #ifdef WITH_TABWIDGET
2033     if (tabWidget)
2034        tabWidget->showPage(mapsListView);
2035 #endif
2036   }
2037 
2038 
2039   if (!imageUrl.isEmpty()) {
2040     setPicture(imageUrl);
2041   } else {
2042     setPicture(getBackgroundImage());
2043 #ifdef WITH_TABWIDGET
2044     if (tabWidget)
2045        tabWidget->showPage(imagesListView);
2046 #endif
2047   }
2048 
2049 
2050   emit setWindowCaption(url.fileName());
2051   setModified(false);
2052   return true;
2053 }
2054 
2055 /**
2056  * Finds the first html element which contains the given text.
2057  * Returns the first matching element.
2058  * Returns 0L if no element was found.
2059  */
2060 HtmlElement* KImageMapEditor::findHtmlElement(const QString & containingText) {
2061   HtmlElement *el;
2062   foreach (el,_htmlContent) {
2063     if (el->htmlCode.contains(containingText,Qt::CaseInsensitive)) {
2064       return el;
2065     }
2066   }
2067   return nullptr;
2068 }
2069 
2070 /**
2071  * Finds the first html element which contains the given ImageTag.
2072  * Returns the first matching element.
2073  * Returns 0L if no element was found.
2074  */
2075 HtmlImgElement* KImageMapEditor::findHtmlImgElement(ImageTag* tag) {
2076   HtmlElement* el;
2077   foreach(el,_htmlContent) {
2078     HtmlImgElement* imgEl = dynamic_cast<HtmlImgElement*>(el);
2079 
2080     if (imgEl && imgEl->imgTag == tag)
2081        return imgEl;
2082   }
2083   return nullptr;
2084 }
2085 
2086 void KImageMapEditor::addMap(const QString & name = QString()) {
2087   HtmlMapElement* el = new HtmlMapElement("\n<map></map>");
2088   MapTag* map = new MapTag();
2089   map->name = name;
2090   el->mapTag = map;
2091 
2092   // Try to find the body tag
2093   HtmlElement* bodyTag = findHtmlElement("<body");
2094 
2095   // if we found one add the new map right after the body tag
2096   if (bodyTag) {
2097      uint index = _htmlContent.indexOf(bodyTag);
2098 
2099      // Add a newline before the map
2100      _htmlContent.insert(index+1, new HtmlElement("\n"));
2101 
2102      _htmlContent.insert(index+2, el);
2103   } // if there is no body tag we add the map to the end of the file
2104   else {
2105      // Add a newline before the map
2106      _htmlContent.append(new HtmlElement("\n"));
2107 
2108      _htmlContent.append(el);
2109      qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::addMap : No <body found ! Appending new map to the end.";
2110   }
2111 
2112   mapsListView->addMap(name);
2113   mapsListView->selectMap(name);
2114 }
2115 
2116 /**
2117  * Finds the HtmlMapElement in the HtmlContent, that corresponds
2118  * to the given map name.<br>
2119  * Returns 0L if there exists no map with the given name
2120  */
2121 HtmlMapElement* KImageMapEditor::findHtmlMapElement(const QString & mapName) {
2122   foreach(HtmlElement * el,_htmlContent) {
2123     if (dynamic_cast<HtmlMapElement*>(el)) {
2124       HtmlMapElement *tagEl = static_cast<HtmlMapElement*>(el);
2125       if (tagEl->mapTag->name == mapName) {
2126          return tagEl;
2127       }
2128     }
2129   }
2130 
2131   qCWarning(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::findHtmlMapElement: couldn't find map '" << mapName << "'";
2132   return nullptr;
2133 }
2134 
2135 /**
2136  * Calls setMap with the HtmlMapElement with the given map name
2137  */
2138 void KImageMapEditor::setMap(const QString & mapName) {
2139     HtmlMapElement* el = findHtmlMapElement(mapName);
2140     if (!el) {
2141       qCWarning(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::setMap : Couldn't set map '" << mapName << "', because it wasn't found !";
2142       return;
2143     }
2144 
2145     setMap(el);
2146 
2147 }
2148 
2149 void KImageMapEditor::setMap(MapTag* map) {
2150   HtmlElement * el;
2151   foreach(el,_htmlContent) {
2152     HtmlMapElement *tagEl = dynamic_cast<HtmlMapElement*>(el);
2153     if (tagEl) {
2154       if (tagEl->mapTag == map) {
2155          setMap(tagEl);
2156          break;
2157       }
2158     }
2159   }
2160 
2161 }
2162 
2163 void KImageMapEditor::saveAreasToMapTag(MapTag* map) {
2164   map->clear();
2165   Area* a;
2166   foreach(a,*areas) {
2167     QString shapeStr;
2168 
2169     switch (a->type()) {
2170       case Area::Rectangle : shapeStr = "rect";break;
2171       case Area::Circle : shapeStr = "circle";break;
2172       case Area::Polygon : shapeStr = "poly";break;
2173       default : continue;
2174     }
2175 
2176     QHash<QString,QString> dict;
2177     dict.insert("shape",shapeStr);
2178 
2179     AttributeIterator it = a->attributeIterator();
2180     while (it.hasNext())
2181     {
2182       it.next();
2183       dict.insert(it.key(),it.value());
2184     }
2185 
2186     dict.insert("coords",a->coordsToString());
2187 
2188     map->push_back(dict);
2189 
2190   }
2191 
2192   if (defaultArea && defaultArea->finished()) {
2193     QHash<QString,QString> dict;
2194     dict.insert("shape","default");
2195 
2196     AttributeIterator it = defaultArea->attributeIterator();
2197     while (it.hasNext())
2198     {
2199       it.next();
2200       dict.insert(it.key(),it.value());
2201     }
2202 
2203     map->push_back(dict);
2204   }
2205 
2206 }
2207 
2208 static void setAttribute(Area* a, const AreaTag & tag, const QString & s) {
2209   if (tag.contains(s))
2210     a->setAttribute(s,tag.value(s));
2211 }
2212 
2213 void KImageMapEditor::setMap(HtmlMapElement* mapElement) {
2214   if (currentMapElement) {
2215     currentMapElement->mapTag->modified=true;
2216     currentMapElement->htmlCode = getHTMLImageMap();
2217     saveAreasToMapTag(currentMapElement->mapTag);
2218   }
2219 
2220   currentMapElement = mapElement;
2221   MapTag* map = currentMapElement->mapTag;
2222 
2223   // Remove old areas only if a new map is loaded
2224   deleteAllAreas();
2225   delete defaultArea;
2226   defaultArea = nullptr;
2227 //    qCDebug(KIMAGEMAPEDITOR_LOG) << "KImageMapEditor::setMap : Setting new map : " << map->name;
2228     _mapName = map->name;
2229     AreaTag tag;
2230 
2231     for (const AreaTag &tag : *map) {
2232         QString shape="rect";
2233         if (tag.contains("shape"))
2234           shape=tag.value("shape");
2235 
2236         Area::ShapeType type=Area::Rectangle;
2237         if (shape=="circle")
2238           type=Area::Circle;
2239         else if (shape=="poly")
2240           type=Area::Polygon;
2241         else if (shape=="default")
2242           type=Area::Default;
2243 
2244         Area* a=AreaCreator::create(type);
2245 
2246         setAttribute(a,tag,"href");
2247         setAttribute(a,tag,"alt");
2248         setAttribute(a,tag,"target");
2249         setAttribute(a,tag,"title");
2250         setAttribute(a,tag,"onclick");
2251         setAttribute(a,tag,"ondblclick");
2252         setAttribute(a,tag,"onmousedown");
2253         setAttribute(a,tag,"onmouseup"); 
2254         setAttribute(a,tag,"onmouseover");
2255         setAttribute(a,tag,"onmousemove");
2256         setAttribute(a,tag,"onmouseout");
2257 
2258         if (type==Area::Default) {
2259           defaultArea=a;
2260           defaultArea->setFinished(true);
2261           continue;
2262         }
2263 
2264         if (tag.contains("coords"))
2265           a->setCoords(tag.value("coords"));
2266 
2267         a->setMoving(false);
2268         addArea(a);
2269     }
2270 
2271     updateAllAreas();
2272 
2273     setMapActionsEnabled(true);
2274 }
2275 
2276 /**
2277  * Sets whether actions that depend on an selected map
2278  * are enabled
2279  */
2280 void KImageMapEditor::setMapActionsEnabled(bool b) {
2281    mapDeleteAction->setEnabled(b);
2282    mapDefaultAreaAction->setEnabled(b);
2283    mapNameAction->setEnabled(b);
2284 
2285    arrowAction->setChecked(true);
2286    slotDrawArrow();
2287 
2288    arrowAction->setEnabled(b);
2289    circleAction->setEnabled(b);
2290    rectangleAction->setEnabled(b);
2291    polygonAction->setEnabled(b);
2292    freehandAction->setEnabled(b);
2293    addPointAction->setEnabled(b);
2294    removePointAction->setEnabled(b);
2295 
2296 }
2297 
2298 QString KImageMapEditor::getHtmlCode() {
2299   if (currentMapElement) {
2300     currentMapElement->htmlCode = getHTMLImageMap();
2301   }
2302 
2303   QString result;
2304 
2305   HtmlElement *el;
2306   foreach(el,_htmlContent) {
2307         result += el->htmlCode;
2308   }
2309   return result;
2310 }
2311 
2312 
2313 /**
2314  create a relative short url based in baseURL
2315 
2316  taken from qextfileinfo.cpp:
2317 
2318  From WebMaker - KDE HTML Editor
2319  Copyright (C) 1998, 1999 Alexei Dets <dets@services.ru>
2320 
2321  Rewritten for Quanta Plus: (C) 2002 Andras Mantia <amantia@freemail.hu>
2322 
2323  This program is free software; you can redistribute it and/or modify
2324  it under the terms of the GNU General Public License as published by
2325  the Free Software Foundation; either version 2 of the License, or
2326  (at your option) any later version.
2327 */
2328 static QUrl toRelative(const QUrl& urlToConvert,const QUrl& baseURL)
2329 {
2330   QUrl resultURL = urlToConvert;
2331   if (urlToConvert.scheme() == baseURL.scheme())
2332   {
2333     QString path = urlToConvert.path();
2334     QString basePath = baseURL.path().endsWith('/') ? baseURL.path() : baseURL.path() + '/';
2335     if (path.startsWith(QLatin1String("/")) && basePath != "/")
2336     {
2337       path.remove(0, 1);
2338       basePath.remove(0, 1);
2339       if ( basePath.right(1) != "/" ) basePath.append("/");
2340 
2341       int pos=0;
2342       int pos1=0;
2343       for (;;)
2344       {
2345         pos=path.indexOf("/");
2346         pos1=basePath.indexOf("/");
2347         if ( pos<0 || pos1<0 ) break;
2348         if ( path.left(pos+1 ) == basePath.left(pos1+1) )
2349         {
2350           path.remove(0, pos+1);
2351           basePath.remove(0, pos1+1);
2352         }
2353         else
2354           break;
2355       };
2356 
2357       if ( basePath == "/" ) basePath="";
2358       int level = basePath.count("/");
2359       for (int i=0; i<level; i++)
2360       {
2361         path="../"+path;
2362       };
2363     }
2364 
2365     resultURL.setPath(QDir::cleanPath(path));
2366   }
2367 
2368   if (urlToConvert.path().endsWith('/')) resultURL.setPath(resultURL.path() + '/');
2369   return resultURL;
2370 }
2371 
2372 
2373 void KImageMapEditor::saveImageMap(const QUrl & url)
2374 {
2375   if (!QFileInfo(url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()).isWritable()) {
2376     KMessageBox::error(widget(),
2377       i18n("<qt>The file <i>%1</i> could not be saved, because you do not have the required write permissions.</qt>", url.path()));
2378     return;
2379   }
2380 
2381   if (!backupFileCreated) {
2382     QString backupFile = url.path()+'~';
2383     KIO::file_copy(url, QUrl::fromUserInput(backupFile ), -1, KIO::Overwrite | KIO::HideProgressInfo);
2384     backupFileCreated = true;
2385   }
2386 
2387   setModified(false);
2388 
2389   if (mapName().isEmpty()) {
2390     mapEditName();
2391   }
2392   QFile file(url.path());
2393   file.open(QIODevice::WriteOnly);
2394 
2395   QTextStream t(&file);
2396 
2397   if (_htmlContent.isEmpty()) {
2398     t << "<html>\n"
2399       << "<head>\n"
2400       << "  <title></title>\n"
2401       << "</head>\n"
2402       << "<body>\n"
2403       << "  " << getHTMLImageMap()
2404       << "\n"
2405       << "  <img src=\"" << toRelative(_imageUrl,QUrl( url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() )).path() << "\""
2406       << " usemap=\"#" << _mapName << "\""
2407       << " width=\"" << drawZone->picture().width() << "\""
2408       << " height=\"" << drawZone->picture().height() << "\">\n"
2409       << "</body>\n"
2410       << "</html>";
2411   } else
2412   {
2413     t << getHtmlCode();
2414   }
2415 
2416   file.close();
2417 
2418 }
2419 
2420 
2421 void KImageMapEditor::slotCut()
2422 {
2423   if ( 0 == currentSelected->count() )
2424     return;
2425   delete copyArea;
2426 
2427   copyArea= static_cast< AreaSelection* > (currentSelected->clone());
2428   pasteAction->setEnabled(true);
2429   QUndoCommand *command= new CutCommand(this,*currentSelected);
2430   commandHistory()->push(command);
2431 }
2432 
2433 
2434 void KImageMapEditor::slotDelete()
2435 {
2436   if ( 0 == currentSelected->count() )
2437     return;
2438 
2439   QUndoCommand *command= new DeleteCommand(this,*currentSelected);
2440   commandHistory()->push(command);
2441 }
2442 
2443 void KImageMapEditor::slotCopy()
2444 {
2445   delete copyArea;
2446 
2447   copyArea = static_cast< AreaSelection* > (currentSelected->clone());
2448   pasteAction->setEnabled(true);
2449 }
2450 
2451 void KImageMapEditor::slotPaste()
2452 {
2453   if (!copyArea)
2454     return;
2455 
2456   copyArea->moveBy(5,5);
2457   if (copyArea->rect().x()>= drawZone->getImageRect().width() ||
2458       copyArea->rect().y()>= drawZone->getImageRect().height())
2459       copyArea->moveTo(0,0);
2460 
2461   if (copyArea->rect().width()>drawZone->getImageRect().width() ||
2462       copyArea->rect().height()>drawZone->getImageRect().height())
2463       return;
2464 
2465   AreaSelection *a=static_cast< AreaSelection* > (copyArea->clone());
2466   commandHistory()->push(new PasteCommand(this,*a));
2467   delete a;
2468 //  addAreaAndEdit(a);
2469 }
2470 
2471 
2472 
2473 void KImageMapEditor::slotBackOne()
2474 {
2475   if (currentSelected->isEmpty())
2476     return;
2477 
2478   AreaList list = currentSelected->getAreaList();
2479 
2480 
2481   Area *a = nullptr;
2482   // move every selected Area one step lower
2483   for (int i=areas->count()-2; i > -1; i--)
2484   {
2485     if (list.contains( areas->at(i) ))
2486     {
2487       uint j = (uint)i+1;
2488       a = areas->at(i);
2489       areas->removeAll(a);
2490       areas->insert(j,a);
2491       QTreeWidgetItem* root = areaListView->listView->invisibleRootItem();
2492       root->insertChild(j,root->takeChild(i));
2493     }
2494   }
2495   // to update the up and down buttons
2496   updateUpDownBtn();
2497 
2498 }
2499 
2500 void KImageMapEditor::slotForwardOne()
2501 {
2502   if (currentSelected->isEmpty())
2503     return;
2504 
2505   AreaList list = currentSelected->getAreaList();
2506 
2507   Area *a = nullptr;
2508   // move every selected Area one step higher
2509   for (int i=1; i < (int)areas->count(); i++)
2510   {
2511     if (list.contains( areas->at(i) ))
2512     {
2513       uint j = (uint) i-1;
2514       a = areas->at(i);
2515       areas->removeAll(a);
2516       areas->insert(j,a);
2517       QTreeWidgetItem* root = areaListView->listView->invisibleRootItem();
2518       root->insertChild(j,root->takeChild(i));
2519     }
2520   }
2521   // to update the up and down buttons
2522   updateUpDownBtn();
2523 }
2524 
2525 void KImageMapEditor::slotToBack()
2526 {
2527   if (currentSelected->isEmpty())
2528     return;
2529 
2530   while (backOneAction->isEnabled())
2531     slotBackOne();
2532 }
2533 
2534 void KImageMapEditor::slotToFront()
2535 {
2536   if (currentSelected->isEmpty())
2537     return;
2538 
2539   while (forwardOneAction->isEnabled())
2540     slotForwardOne();
2541 }
2542 
2543 
2544 void KImageMapEditor::slotMoveUp()
2545 {
2546   QRect r=selected()->rect();
2547   selected()->setMoving(true);
2548   selected()->moveBy(0,-1);
2549 
2550   commandHistory()->push(
2551     new MoveCommand( this, selected(), r.topLeft() ));
2552   selected()->setMoving(false);
2553   slotAreaChanged(selected());
2554   slotUpdateSelectionCoords();
2555 }
2556 
2557 void KImageMapEditor::slotMoveDown()
2558 {
2559   QRect r=selected()->rect();
2560   selected()->setMoving(true);
2561   selected()->moveBy(0,1);
2562 
2563   commandHistory()->push(
2564     new MoveCommand( this, selected(), r.topLeft() ));
2565   selected()->setMoving(false);
2566   slotAreaChanged(selected());
2567   slotUpdateSelectionCoords();
2568 }
2569 
2570 void KImageMapEditor::slotMoveLeft()
2571 {
2572   qCDebug(KIMAGEMAPEDITOR_LOG) << "slotMoveLeft";
2573   QRect r=selected()->rect();
2574   selected()->setMoving(true);
2575   selected()->moveBy(-1,0);
2576 
2577   commandHistory()->push(
2578     new MoveCommand( this, selected(), r.topLeft() ));
2579   selected()->setMoving(false);
2580   slotAreaChanged(selected());
2581   slotUpdateSelectionCoords();
2582 }
2583 
2584 void KImageMapEditor::slotMoveRight()
2585 {
2586   QRect r=selected()->rect();
2587   selected()->setMoving(true);
2588   selected()->moveBy(1,0);
2589 
2590   commandHistory()->push(
2591     new MoveCommand( this, selected(), r.topLeft() ));
2592   selected()->setMoving(false);
2593   slotAreaChanged(selected());
2594   slotUpdateSelectionCoords();
2595 }
2596 
2597 void KImageMapEditor::slotCancelDrawing()
2598 {
2599   drawZone->cancelDrawing();
2600 }
2601 
2602 void KImageMapEditor::slotIncreaseHeight()
2603 {
2604   Area *oldArea=selected()->clone();
2605 
2606   QRect r = selected()->rect();
2607   r.setHeight( r.height()+1 );
2608   r.translate(0,-1);
2609 
2610   selected()->setRect(r);
2611 
2612   commandHistory()->push(
2613     new ResizeCommand( this, selected(), oldArea ));
2614   slotAreaChanged(selected());
2615   slotUpdateSelectionCoords();
2616 }
2617 
2618 void KImageMapEditor::slotDecreaseHeight()
2619 {
2620   Area *oldArea=selected()->clone();
2621 
2622   QRect r = selected()->rect();
2623   r.setHeight( r.height()-1 );
2624   r.translate(0,1);
2625 
2626   selected()->setRect(r);
2627 
2628   commandHistory()->push(
2629     new ResizeCommand( this, selected(), oldArea ));
2630   slotAreaChanged(selected());
2631   slotUpdateSelectionCoords();
2632 }
2633 
2634 void KImageMapEditor::slotIncreaseWidth()
2635 {
2636   Area *oldArea=selected()->clone();
2637 
2638   QRect r = selected()->rect();
2639   r.setWidth( r.width()+1 );
2640 
2641   selected()->setRect(r);
2642 
2643   commandHistory()->push(
2644     new ResizeCommand( this, selected(), oldArea ));
2645   slotAreaChanged(selected());
2646   slotUpdateSelectionCoords();
2647 }
2648 
2649 void KImageMapEditor::slotDecreaseWidth()
2650 {
2651   Area *oldArea=selected()->clone();
2652 
2653   QRect r = selected()->rect();
2654   r.setWidth( r.width()-1 );
2655 
2656   selected()->setRect(r);
2657 
2658   commandHistory()->push(
2659     new ResizeCommand( this, selected(), oldArea ));
2660   slotAreaChanged(selected());
2661   slotUpdateSelectionCoords();
2662 }
2663 
2664 void KImageMapEditor::slotHighlightAreas(bool b)
2665 {
2666   Area::highlightArea = b;
2667   updateAllAreas();
2668   drawZone->repaint();
2669 }
2670 
2671 void KImageMapEditor::slotShowAltTag(bool b)
2672 {
2673   Area::showAlt = b;
2674   drawZone->repaint();
2675 }
2676 
2677 void KImageMapEditor::mapNew()
2678 {
2679     QString mapName = mapsListView->getUnusedMapName();
2680     addMap(mapName);
2681     mapEditName();
2682 }
2683 
2684 void KImageMapEditor::mapDelete()
2685 {
2686   if (mapsListView->count() == 0)
2687      return;
2688 
2689   QString selectedMap = mapsListView->selectedMap();
2690 
2691   int result = KMessageBox::warningContinueCancel(widget(),
2692     i18n("<qt>Are you sure you want to delete the map <i>%1</i>?"
2693          " <br /><b>There is no way to undo this.</b></qt>", selectedMap),
2694     i18n("Delete Map?"),KGuiItem(i18n("&Delete"),"edit-delete"));
2695 
2696   if (result == KMessageBox::Cancel)
2697      return;
2698 
2699 
2700 
2701   mapsListView->removeMap(selectedMap);
2702   HtmlMapElement* mapEl = findHtmlMapElement(selectedMap);
2703   _htmlContent.removeAll(mapEl);
2704   if (mapsListView->count() == 0) {
2705 
2706       currentMapElement = nullptr;
2707       deleteAllAreas();
2708       setMapActionsEnabled(false);
2709   }
2710   else {
2711       // The old one was deleted, so the new one got selected
2712       setMap(mapsListView->selectedMap());
2713   }
2714 }
2715 
2716 void KImageMapEditor::mapPreview() {
2717   HTMLPreviewDialog dialog(widget(), getHtmlCode());
2718   dialog.exec();
2719 }
2720 
2721 void KImageMapEditor::deleteAllMaps()
2722 {
2723   deleteAllAreas();
2724   mapsListView->clear();
2725   if (isReadWrite()) {
2726     mapDeleteAction->setEnabled(false);
2727     mapDefaultAreaAction->setEnabled(false);
2728     mapNameAction->setEnabled(false);
2729   }
2730 }
2731 
2732 /**
2733  * Doesn't call the closeUrl method, because
2734  * we need the URL for the session management
2735  */
2736 bool KImageMapEditor::queryClose() {
2737   if ( ! isModified() )
2738      return true;
2739 
2740 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
2741   switch ( KMessageBox::warningTwoActionsCancel(
2742 #else
2743   switch ( KMessageBox::warningYesNoCancel(
2744 #endif
2745               widget(),
2746           i18n("<qt>The file <i>%1</i> has been modified.<br />Do you want to save it?</qt>",
2747           url().fileName()),
2748           QString(),
2749           KStandardGuiItem::save(),
2750           KStandardGuiItem::discard()) )
2751     {
2752 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
2753     case KMessageBox::PrimaryAction :
2754 #else
2755     case KMessageBox::Yes :
2756 #endif
2757       saveFile();
2758       return true;
2759 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
2760     case KMessageBox::SecondaryAction :
2761 #else
2762     case KMessageBox::No :
2763 #endif
2764       return true;
2765     default:
2766       return false;
2767   }
2768 }
2769 
2770 bool KImageMapEditor::closeUrl()
2771 {
2772   bool result = KParts::ReadWritePart::closeUrl();
2773   if (!result)
2774      return false;
2775 
2776   _htmlContent.clear();
2777   deleteAllMaps();
2778   imagesListView->clear();
2779 
2780   delete copyArea;
2781   copyArea = nullptr;
2782 
2783   delete defaultArea;
2784   defaultArea = nullptr;
2785 
2786   currentMapElement = nullptr;
2787 
2788   init();
2789   emit setWindowCaption("");
2790 
2791   return true;
2792 
2793 }
2794 
2795 void KImageMapEditor::addImage(const QUrl & imgUrl) {
2796     if (imgUrl.isEmpty())
2797         return;
2798 
2799     QString relativePath ( toRelative(imgUrl, QUrl( url().adjusted(QUrl::RemoveFilename).path() )).path() );
2800 
2801     QString imgHtml = QString("<img src=\"")+relativePath+QString("\">");
2802     ImageTag* imgTag = new ImageTag();
2803     imgTag->insert("tagname","img");
2804     imgTag->insert("src", relativePath);
2805 
2806     HtmlImgElement* imgEl = new HtmlImgElement(imgHtml);
2807     imgEl->imgTag = imgTag;
2808 
2809     HtmlElement* bodyEl = findHtmlElement("<body");
2810     if (bodyEl) {
2811         int bodyIndex = _htmlContent.indexOf(bodyEl);
2812         _htmlContent.insert(bodyIndex+1, new HtmlElement("\n"));
2813         _htmlContent.insert(bodyIndex+2, imgEl);
2814     }
2815     else {
2816         _htmlContent.append(new HtmlElement("\n"));
2817         _htmlContent.append(imgEl);
2818     }
2819 
2820     imagesListView->addImage(imgTag);
2821     imagesListView->selectImage(imgTag);
2822     setImageActionsEnabled(true);
2823 
2824     setModified(true);
2825 }
2826 
2827 /**
2828  * Sets whether the image actions that depend on an
2829  * selected image are enabled
2830  */
2831 void KImageMapEditor::setImageActionsEnabled(bool b) {
2832   imageRemoveAction->setEnabled(b);
2833   imageUsemapAction->setEnabled(b);
2834 }
2835 
2836 
2837 void KImageMapEditor::imageAdd() {
2838     QUrl imgUrl = QFileDialog::getOpenFileUrl(widget(), i18n("Select image"),
2839                   QUrl(), i18n("Images (*.png *.jpg *.jpeg *.gif *.bmp *.xbm *.xpm *.pnm *.mng);;All Files (*)"));
2840     addImage(imgUrl);
2841 }
2842 
2843 void KImageMapEditor::imageRemove() {
2844     ImageTag* imgTag = imagesListView->selectedImage();
2845     HtmlImgElement* imgEl = findHtmlImgElement(imgTag);
2846     imagesListView->removeImage(imgTag);
2847     _htmlContent.removeAt(_htmlContent.indexOf(imgEl));
2848 
2849     if (imagesListView->topLevelItemCount() == 0) {
2850         setPicture(getBackgroundImage());
2851         setImageActionsEnabled(false);
2852     }
2853     else {
2854       ImageTag* selected = imagesListView->selectedImage();
2855       if (selected) {
2856     if (selected->contains("src")) {
2857       setPicture(QUrl(selected->value("src")));
2858     }
2859       }
2860     }
2861 
2862     setModified(true);
2863 }
2864 
2865 void KImageMapEditor::imageUsemap() {
2866 
2867   bool ok=false;
2868   ImageTag* imageTag = imagesListView->selectedImage();
2869   if ( ! imageTag)
2870      return;
2871 
2872   QString usemap;
2873 
2874   if (imageTag->contains("usemap"))
2875       usemap = imageTag->value("usemap");
2876 
2877   QStringList maps = mapsListView->getMaps();
2878   int index = maps.indexOf(usemap);
2879   if (index == -1) {
2880     maps.prepend("");
2881     index = 0;
2882   }
2883 
2884   QString input =
2885     QInputDialog::getItem(widget(), i18n("Enter Usemap"),
2886               i18n("Enter the usemap value:"),
2887               maps, index, true, &ok);
2888   if (ok) {
2889      imageTag->insert("usemap", input);
2890      imagesListView->updateImage(imageTag);
2891      setModified(true);
2892 
2893      // Update the htmlCode of the HtmlElement
2894      HtmlImgElement* imgEl = findHtmlImgElement(imageTag);
2895 
2896      imgEl->htmlCode = QLatin1String("<");
2897      QString tagName = imgEl->imgTag->value("tagname");
2898      imgEl->htmlCode += QString(tagName);
2899      QHashIterator<QString, QString> it( *imgEl->imgTag );
2900      while (it.hasNext()) {
2901        it.next();
2902        if (it.key() != "tagname") {
2903            imgEl->htmlCode += " " + it.key() + "=\"";
2904            if (it.key() == "usemap")
2905                imgEl->htmlCode += '#';
2906            imgEl->htmlCode += it.value();
2907            imgEl->htmlCode += '"';
2908        }
2909      }
2910 
2911      imgEl->htmlCode += '>';
2912 
2913   }
2914 }
2915 
2916 #include "kimagemapeditor.moc"