/***************************************************************************
                          imagemapeditor.cpp  -  description
                            -------------------
    begin                : Wed Apr 4 2001
    copyright            : (C) 2001 by Jan Sch�er
    email                : j_schaef@informatik.uni-kl.de
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/

#include <iostream>
#include <assert.h>

// QT
#include <qlayout.h>
#include <qlistview.h>
#include <qpushbutton.h>
#include <qvbox.h>
#include <qpixmap.h>
#include <qcombobox.h>
#include <qsplitter.h>
#include <qfileinfo.h>
#include <qmultilineedit.h>
#include <qtextstream.h>
#include <qpopupmenu.h>
#include <qdict.h>
#include <qwhatsthis.h>
#include <qtooltip.h>
#include <qpainter.h>
#include <qtabwidget.h>
#include <qfontdatabase.h>
#include <qfile.h>

// KDE
#include <kcommand.h>
#include <kdebug.h>
#include <klocale.h>
#include <kaction.h>
#include <kaccel.h>
#include <kstdaction.h>
#include <kiconloader.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <kapplication.h>
#include <kkeydialog.h>
#include <kedittoolbar.h>
#include <klineeditdlg.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kstatusbar.h>
#include <kxmlguifactory.h>
#include <kdockwidget.h>
#include <kio/job.h>
#if KDE_IS_VERSION(3,1,90)
#include <kinputdialog.h>
#else
#include <qinputdialog.h>
#endif

// local
#include "kimagemapeditor.h"
#include "kimagemapeditor.moc"
#include "drawzone.h"
#include "kimedialogs.h"
#include "kimecommands.h"
#include "qextfileinfo.h"
#include "areacreator.h"
#include "arealistview.h"
#include "imageslistview.h"
#include "mapslistview.h"
#include "kimecommon.h"

#include <kparts/genericfactory.h>
#include <kinstance.h>

// Factory code for KDE 3
typedef KParts::GenericFactory<KImageMapEditor> KimeFactory;
K_EXPORT_COMPONENT_FACTORY( libkimagemapeditor , KimeFactory )

KImageMapEditor::KImageMapEditor(QWidget *parentWidget, const char *,
            QObject *parent, const char *name, const QStringList & )
  : KParts::ReadWritePart(parent,name)
{
  setInstance( KimeFactory::instance() );

//  KDockMainWindow* mainWidget;

  // Test if the MainWindow can handle DockWindows, if so create DockWidgets
  // instead of a Splitter
  mainDock = dynamic_cast<KDockMainWindow*>(parent) ;
  QSplitter * splitter = 0L;
  tabWidget = 0L;

  if (mainDock) {
//    kdDebug() << "KImageMapEditor: We got a KDockMainWindow !" << endl;

    KDockWidget* parentDock = mainDock->getMainDockWidget();
    areaDock = mainDock->createDockWidget( "Areas", 0L, 0L, i18n("Areas"), i18n("Areas"));
    mapsDock = mainDock->createDockWidget( "Maps", 0L, 0L, i18n("Maps"), i18n("Maps"));
    imagesDock = mainDock->createDockWidget( "Images", 0L, 0L, i18n("Images"), i18n("Images"));

    areaListView = new AreaListView(areaDock,"AreaListView");
    mapsListView = new MapsListView(mapsDock, "MapsListView");
    imagesListView = new ImagesListView(imagesDock, "ImagesListView");

    areaDock->setWidget(areaListView);
    mapsDock->setWidget(mapsListView);
    imagesDock->setWidget(imagesListView);

    areaDock->manualDock( (KDockWidget*) parentDock, KDockWidget::DockLeft, 30);
    mapsDock->manualDock( (KDockWidget*) areaDock, KDockWidget::DockCenter);
    imagesDock->manualDock( (KDockWidget*) mapsDock, KDockWidget::DockCenter);

    connect( mainDock->manager(), SIGNAL(change()), this, SLOT(dockingStateChanged()));
  }
  else
  {
    areaDock = 0L;
    mapsDock = 0L;
    imagesDock = 0L;
    splitter = new QSplitter(parentWidget);
    tabWidget = new QTabWidget(splitter);
    areaListView = new AreaListView(tabWidget,"AreaListView");
    mapsListView = new MapsListView(tabWidget, "MapsListView");
    imagesListView = new ImagesListView(tabWidget, "ImagesListView");

    tabWidget->addTab(areaListView,i18n("Areas"));
    tabWidget->addTab(mapsListView,i18n("Maps"));
    tabWidget->addTab(imagesListView,i18n("Images"));
  }


  connect( areaListView->listView, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));
  connect( areaListView->listView, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(showTagEditor(QListViewItem*)));
  connect( areaListView->listView, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &,int)), this,
           SLOT(slotShowPopupMenu(QListViewItem*,const QPoint &)));

  connect( mapsListView, SIGNAL( mapSelected(const QString &)),
           this, SLOT( setMap(const QString &)));

  connect( mapsListView, SIGNAL( mapRenamed(const QString &)),
           this, SLOT( setMapName(const QString &)));

  connect( mapsListView->listView(), SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &,int)), this,
           SLOT(slotShowMapPopupMenu(QListViewItem*,const QPoint &)));

  connect( imagesListView, SIGNAL( imageSelected(const KURL &)),
           this, SLOT( setPicture(const KURL &)));

  connect( imagesListView, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &,int)), this,
           SLOT(slotShowImagePopupMenu(QListViewItem*,const QPoint &)));

  // Shows the text:
  // "Drop an image or html file"
/*  QString path = KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/dropimage.png" ) + "kimagemapeditor/dropimage.png";
  if ( ! QFileInfo(path).exists() ) {
      kdError() << "Couldn't find needed dropimage.png file in "
                   "the data directory of KImageMapEditor.\n"
                   "Perhaps you have forgotten to do a make install !" << endl;
      exit(1);
  }
*/

  if (splitter) {
    drawZone = new DrawZone(splitter,this);
    splitter->setResizeMode(drawZone,QSplitter::Stretch);
    splitter->setResizeMode(tabWidget,QSplitter::KeepSize);
    setWidget(splitter);
  } else {
    drawZone = new DrawZone(parentWidget,this);
    setWidget(drawZone);
  }


  areas = new AreaList();
  currentSelected= new AreaSelection();
  _currentToolType=KImageMapEditor::Selection;
  copyArea=0L;
  defaultArea=0L;
  currentMapElement = 0L;

  setupActions();
  setupStatusBar();

  setXMLFile("kimagemapeditorpartui.rc");

  setPicture(getBackgroundImage());
  _htmlContent.setAutoDelete(true);

  init();
  readConfig();
}

KImageMapEditor::~KImageMapEditor() {
  writeConfig();

  #if KDE_VERSION < 300
    delete accel;
  #endif
  delete areas;

  delete currentSelected;
  delete copyArea;
  delete defaultArea;

  // Delete our DockWidgets
  if (areaDock) {
    areaDock->hide();
    mapsDock->hide();
    imagesDock->hide();

    delete areaDock;
    delete mapsDock;
    delete imagesDock;
  }

}

MapTag::MapTag() {
  modified = false;
  name = QString::null;
}

void KImageMapEditor::init()
{
  _htmlContent.clear();
  _imageUrl = QString::null;
  m_url = QString::null;
  HtmlElement* el = new HtmlElement("<html>\n");
  _htmlContent.append(el);
  el = new HtmlElement("<head>\n");
  _htmlContent.append(el);
  el = new HtmlElement("</head>\n");
  _htmlContent.append(el);
  el = new HtmlElement("<body>\n");
  _htmlContent.append(el);

  addMap(i18n("unnamed"));

  el = new HtmlElement("</body>\n");
  _htmlContent.append(el);
  el = new HtmlElement("</html>\n");
  _htmlContent.append(el);

  setImageActionsEnabled(false);
}

KAboutData* KImageMapEditor::createAboutData()
{
    KAboutData* aboutData =
              new KAboutData( "kimagemapeditor", I18N_NOOP("KImageMapEditor"),
              "1.0", I18N_NOOP( "An HTML imagemap editor" ),
              KAboutData::License_GPL,
              "(c) 2001-2003 Jan Sch&auml;fer <janschaefer@users.sourceforge.net>");
    return aboutData;
}


void KImageMapEditor::setReadWrite(bool)
{

  // For now it doesn't matter if its readwrite or readonly
  // it is always readwrite, because Quanta only supports ReadOnlyParts
  // at this moment and in that case it should be readwrite, too.
  ReadWritePart::setReadWrite(true);
  /*
    if (rw)
      ;
    else
    {
     actionCollection()->remove(arrowAction);
     actionCollection()->remove(circleAction);
     actionCollection()->remove(rectangleAction);
     actionCollection()->remove(polygonAction);
     actionCollection()->remove(freehandAction);
     actionCollection()->remove(addPointAction);
     actionCollection()->remove(removePointAction);

     actionCollection()->remove(cutAction);
     actionCollection()->remove(deleteAction);
     actionCollection()->remove(copyAction);
     actionCollection()->remove(pasteAction);

     actionCollection()->remove(mapNewAction);
     actionCollection()->remove(mapDeleteAction);
     actionCollection()->remove(mapNameAction);
     actionCollection()->remove(mapDefaultAreaAction);

     actionCollection()->remove(areaPropertiesAction);

     actionCollection()->remove(moveLeftAction);
     actionCollection()->remove(moveRightAction);
     actionCollection()->remove(moveUpAction);
     actionCollection()->remove(moveDownAction);

     actionCollection()->remove(increaseWidthAction);
     actionCollection()->remove(decreaseWidthAction);
     actionCollection()->remove(increaseHeightAction);
     actionCollection()->remove(decreaseHeightAction);

     actionCollection()->remove(toFrontAction);
     actionCollection()->remove(toBackAction);
     actionCollection()->remove(forwardOneAction);
     actionCollection()->remove(backOneAction);

     actionCollection()->remove(imageRemoveAction);
     actionCollection()->remove(imageAddAction);
     actionCollection()->remove(imageUsemapAction);

    }
  */

}

void KImageMapEditor::setModified(bool modified)
{
    // get a handle on our Save action and make sure it is valid
    KAction *save = actionCollection()->action(KStdAction::stdName(KStdAction::Save));
    if (!save)
        return;

    // if so, we either enable or disable it based on the current
    // state
    if (modified)
        save->setEnabled(true);
    else
        save->setEnabled(false);

    // in any event, we want our parent to do it's thing
    ReadWritePart::setModified(modified);
}


KConfig *KImageMapEditor::config()
{
    return KimeFactory::instance()->config();
}

void KImageMapEditor::readConfig(KConfig* config) {
  recentFilesAction->loadEntries(config,"Data");
}

void KImageMapEditor::writeConfig(KConfig* config) {
  config->writeEntry("highlightareas",highlightAreasAction->isChecked());
  config->writeEntry("showalt",showAltAction->isChecked());
	recentFilesAction->saveEntries(config,"Data");
  saveLastURL(config);

}

void KImageMapEditor::readConfig() {
  config()->setGroup("General Options");
  readConfig(config());
  slotConfigChanged();
}

void KImageMapEditor::writeConfig() {
  config()->setGroup("General Options");
  writeConfig(config());
  config()->sync();
}


void KImageMapEditor::saveProperties(KConfig *config)
{
  saveLastURL(config);
}

void KImageMapEditor::readProperties(KConfig * config)
{
  openLastURL(config);
}

void KImageMapEditor::slotConfigChanged()
{
  config()->setGroup("Appearance");
  int newHeight=config()->readNumEntry("maximum-preview-height",50);
  config()->setGroup("General Options");
  _commandHistory->setUndoLimit(config()->readNumEntry("undo-level",20));
  _commandHistory->setRedoLimit(config()->readNumEntry("redo-level",20));
  Area::highlightArea = config()->readBoolEntry("highlightareas",true);
  highlightAreasAction->setChecked(Area::highlightArea);
  Area::showAlt = config()->readBoolEntry("showalt",true);
  showAltAction->setChecked(Area::showAlt);

  // if the image preview size changed update all images
  if (maxAreaPreviewHeight!=newHeight) {
    maxAreaPreviewHeight=newHeight;
  }

  updateAllAreas();
  drawZone->viewport()->repaint();
}

void KImageMapEditor::openLastURL(KConfig* config) {
  KURL lastURL ( config->readPathEntry("lastopenurl") );
  QString lastMap = config->readEntry("lastactivemap");
  QString lastImage = config->readPathEntry("lastactiveimage");


//  kdDebug() << "loading from group : " << config->group() << endl;

//  kdDebug() << "loading entry lastopenurl : " << lastURL.path() << endl;
//  KMessageBox::information(0L, config->group()+" "+lastURL.path());
  if (!lastURL.isEmpty()) {
//    kdDebug() << "opening HTML file with map " << lastMap << " and image " << lastImage << endl;
    if ( openHTMLFile(lastURL, lastMap, lastImage) )
        m_url = lastURL;
    else
        m_url = QString::null;
  }
}

void KImageMapEditor::saveLastURL(KConfig* config) {
  config->writePathEntry("lastopenurl",url().path());
  config->writeEntry("lastactivemap",mapName());
  config->writePathEntry("lastactiveimage",_imageUrl.path());
//  kdDebug() << "writing entry lastopenurl : " << url().path() << endl;
//  kdDebug() << "writing entry lastactivemap : " << mapName() << endl;
//  kdDebug() << "writing entry lastactiveimage : " << _imageUrl.path() << endl;
  //KMessageBox::information(0L, QString("Group: %1 Saving ... %2").arg(config->group()).arg(url().path()));
}

void KImageMapEditor::setupActions()
{
	// File Open
  KAction *temp=KStdAction::open(this, SLOT(fileOpen()), actionCollection());
  QMimeSourceFactory::defaultFactory()->setPixmap( "openimage", SmallIcon("fileopen") );
	temp->setWhatsThis(i18n("<h3>Open File</h3>Click this to <em>open</em> a new picture or HTML file."));
	temp->setToolTip(i18n("Open new picture or HTML file"));

	// File Open Recent
  recentFilesAction = KStdAction::openRecent(this, SLOT(openURL(const KURL&)),
                                      actionCollection());
	// File Save
  temp =KStdAction::save(this, SLOT(fileSave()), actionCollection());
  QMimeSourceFactory::defaultFactory()->setPixmap( "saveimage", SmallIcon("filesave") );
	temp->setWhatsThis(i18n("<h3>Save File</h3>Click this to <em>save</em> the changes to the HTML file."));
	temp->setToolTip(i18n("Save HTML file"));


	// File Save As
  (void)KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());

	// File Close
  temp=KStdAction::close(this, SLOT(fileClose()), actionCollection());
  QMimeSourceFactory::defaultFactory()->setPixmap( "closeimage", SmallIcon("fileclose") );
	temp->setWhatsThis(i18n("<h3>Close File</h3>Click this to <em>close</em> the currently open HTML file."));
	temp->setToolTip(i18n("Close HTML file"));

  // Edit Copy
  copyAction=KStdAction::copy(this, SLOT(slotCopy()), actionCollection());
  QMimeSourceFactory::defaultFactory()->setPixmap( "editcopyimage", SmallIcon("editcopy") );
  copyAction->setWhatsThis(i18n("<h3>Copy</h3>"
                          "Click this to <em>copy</em> the selected area."));
  copyAction->setEnabled(false);

  // Edit Cut
  cutAction=KStdAction::cut(this, SLOT(slotCut()), actionCollection());
  QMimeSourceFactory::defaultFactory()->setPixmap( "editcutimage", SmallIcon("editcut") );
  cutAction->setWhatsThis(i18n("<h3>Cut</h3>"
                          "Click this to <em>cut</em> the selected area."));
  cutAction->setEnabled(false);

  // Edit Paste
  pasteAction=KStdAction::paste(this, SLOT(slotPaste()), actionCollection());
  QMimeSourceFactory::defaultFactory()->setPixmap( "editpasteimage", SmallIcon("editpaste") );
  pasteAction->setWhatsThis(i18n("<h3>Paste</h3>"
                          "Click this to <em>paste</em> the copied area."));
  pasteAction->setEnabled(false);


  // Edit Delete
  deleteAction=new KAction(i18n("&Delete"), "editdelete",
              Key_Delete,this,SLOT (slotDelete()),actionCollection(), "edit_delete");
  QMimeSourceFactory::defaultFactory()->setPixmap( "editdeleteimage", SmallIcon("editdelete") );
  deleteAction->setWhatsThis(i18n("<h3>Delete</h3>"
                          "Click this to <em>delete</em> the selected area."));
  deleteAction->setEnabled(false);

  // Edit Undo/Redo
  _commandHistory = new KCommandHistory( actionCollection(), true);

  // Edit Properties
  areaPropertiesAction= new KAction(i18n("Pr&operties"),0,this,SLOT(showTagEditor()),
    actionCollection(), "edit_properties");
  areaPropertiesAction->setEnabled(false);

  // View Zoom In
  zoomInAction=KStdAction::zoomIn(this, SLOT(slotZoomIn()), actionCollection());
  // View Zoom Out
  zoomOutAction=KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection());

  // View Zoom
  zoomAction=new KSelectAction(i18n("Zoom"), 0,this,SLOT (slotZoom()),
      actionCollection(), "view_zoom");
  zoomAction->setWhatsThis(i18n("<h3>Zoom</h3>"
                          "Choose the desired zoom level."));
  zoomAction->setItems(QStringList()
    << i18n("25%")
    << i18n("50%")
    << i18n("100%")
    << i18n("150%")
    << i18n("200%")
    << i18n("250%")
    << i18n("300%")
    << i18n("500%")
    << i18n("750%")
    << i18n("1000%"));

  zoomAction->setCurrentItem(2);

  highlightAreasAction = new KToggleAction(i18n("Highlight Areas"),0, this, SLOT (slotHightlightAreas()),
      actionCollection(), "view_highlightareas");

  showAltAction = new KToggleAction(i18n("Show Alt Tag"),0, this, SLOT (slotShowAltTag()),
      actionCollection(), "view_showalt");
#if KDE_IS_VERSION(3,2,90)
  showAltAction->setCheckedState(i18n("Hide Alt Tag"));
#endif

  mapNameAction= new KAction(i18n("Map &Name..."),0,this,SLOT(mapEditName()),
    actionCollection(), "map_name");

  mapNewAction = new KAction(i18n("Ne&w Map..."),0,this,SLOT(mapNew()),
    actionCollection(), "map_new");
  mapNewAction->setToolTip(i18n("Create a new map"));

  mapDeleteAction = new KAction(i18n("D&elete Map"),0,this,SLOT(mapDelete()),
    actionCollection(), "map_delete");
  mapDeleteAction->setToolTip(i18n("Delete the current active map"));

  mapDefaultAreaAction = new KAction(i18n("Edit &Default Area..."),0,this,SLOT(mapDefaultArea()),
    actionCollection(), "map_defaultarea");
  mapDefaultAreaAction->setToolTip(i18n("Edit the default area of the current active map"));

  temp = new KAction(i18n("&Preview"),0,this,SLOT(mapPreview()),
    actionCollection(), "map_preview");
  temp->setToolTip(i18n("Show a preview"));

  // IMAGE
  i18n("&Image");

  imageAddAction = new KAction(i18n("Add Image..."),0,this,SLOT(imageAdd()),
    actionCollection(), "image_add");
  imageAddAction->setToolTip(i18n("Add a new image"));

  imageRemoveAction = new KAction(i18n("Remove Image"),0,this,SLOT(imageRemove()),
    actionCollection(), "image_remove");
  imageRemoveAction->setToolTip(i18n("Remove the current visible image"));

  imageUsemapAction = new KAction(i18n("Edit Usemap..."),0,this,SLOT(imageUsemap()),
    actionCollection(), "image_usemap");
  imageUsemapAction->setToolTip(i18n("Edit the usemap tag of the current visible image"));

  temp= new KAction(i18n("Show &HTML"),0,this,SLOT(mapShowHTML()),
    actionCollection(), "map_showhtml");


  // Selection Tool
  arrowAction=new KRadioAction(i18n("&Selection"), "arrow",
            0,this,SLOT (slotDrawArrow()),
      actionCollection(), "tool_arrow");
  QMimeSourceFactory::defaultFactory()->setPixmap( "arrowimage", SmallIcon("arrow") );
  arrowAction->setWhatsThis(i18n("<h3>Selection</h3>"
                          "Click this to select areas."));
  arrowAction->setExclusiveGroup("drawing");
  arrowAction->setChecked(true);

  // Circle
  circleAction=new KRadioAction(i18n("&Circle"), "circle",
            0,this,SLOT (slotDrawCircle()),
      actionCollection(), "tool_circle");
  QMimeSourceFactory::defaultFactory()->setPixmap( "circleimage", SmallIcon("drawcircle") );
  circleAction->setWhatsThis(i18n("<h3>Circle</h3>"
                          "Click this to start drawing a circle."));
  circleAction->setExclusiveGroup("drawing");

  // Rectangle
  rectangleAction=new KRadioAction(i18n("&Rectangle"), "rectangle",
            0,this,SLOT (slotDrawRectangle()),
      actionCollection(), "tool_rectangle");
  QMimeSourceFactory::defaultFactory()->setPixmap( "rectangleimage", SmallIcon("drawrectangle") );
  rectangleAction->setWhatsThis(i18n("<h3>Rectangle</h3>"
                          "Click this to start drawing a rectangle."));
  rectangleAction->setExclusiveGroup("drawing");

  // Polygon
  polygonAction=new KRadioAction(i18n("&Polygon"), "polygon",
            0,this,SLOT (slotDrawPolygon()),
      actionCollection(), "tool_polygon");
  QMimeSourceFactory::defaultFactory()->setPixmap( "polygonimage", SmallIcon("drawpolygon") );
  polygonAction->setWhatsThis(i18n("<h3>Polygon</h3>"
                          "Click this to start drawing a polygon."));
  polygonAction->setExclusiveGroup("drawing");

  // Freehand
  freehandAction=new KRadioAction(i18n("&Freehand Polygon"), "freehand",
            0,this,SLOT (slotDrawFreehand()),
      actionCollection(), "tool_freehand");
  QMimeSourceFactory::defaultFactory()->setPixmap( "freehandimage", SmallIcon("freehand") );
  freehandAction->setWhatsThis(i18n("<h3>Freehandpolygon</h3>"
                          "Click this to start drawing a freehand polygon."));
  freehandAction->setExclusiveGroup("drawing");

  // Add Point
  addPointAction=new KRadioAction(i18n("&Add Point"), "addpoint",
            0,this,SLOT (slotDrawAddPoint()),
      actionCollection(), "tool_addpoint");
  QMimeSourceFactory::defaultFactory()->setPixmap( "addpointimage", SmallIcon("addpoint") );
  addPointAction->setWhatsThis(i18n("<h3>Add Point</h3>"
                          "Click this to add points to a polygon."));
  addPointAction->setExclusiveGroup("drawing");

  // Remove Point
  removePointAction=new KRadioAction(i18n("&Remove Point"), "removepoint",
            0,this,SLOT (slotDrawRemovePoint()),
      actionCollection(), "tool_removepoint");
  QMimeSourceFactory::defaultFactory()->setPixmap( "removepointimage", SmallIcon("removepoint") );
  removePointAction->setWhatsThis(i18n("<h3>Remove Point</h3>"
                          "Click this to remove points from a polygon."));
  removePointAction->setExclusiveGroup("drawing");

#if KDE_VERSION < 300
    KAction *cancelAction =
#endif
      new KAction(i18n("Cancel Drawing"), Key_Escape, this, SLOT( slotCancelDrawing() ),
                              actionCollection(), "canceldrawing" );

  moveLeftAction = new KAction(i18n("Move Left"), Key_Left, this, SLOT( slotMoveLeft() ),
                              actionCollection() , "moveleft" );

  moveRightAction = new KAction(i18n("Move Right"), Key_Right, this, SLOT( slotMoveRight() ),
                              actionCollection() , "moveright" );

  moveUpAction = new KAction(i18n("Move Up"), Key_Up, this, SLOT( slotMoveUp() ),
                              actionCollection() , "moveup" );

  moveDownAction = new KAction(i18n("Move Down"), Key_Down, this, SLOT( slotMoveDown() ),
                              actionCollection() , "movedown" );

  increaseWidthAction = new KAction(i18n("Increase Width"), Key_Right + SHIFT, this, SLOT( slotIncreaseWidth() ),
                              actionCollection() , "increasewidth" );

  decreaseWidthAction = new KAction(i18n("Decrease Width"), Key_Left + SHIFT, this, SLOT( slotDecreaseWidth() ),
                              actionCollection() , "decreasewidth" );

  increaseHeightAction = new KAction(i18n("Increase Height"), Key_Up + SHIFT, this, SLOT( slotIncreaseHeight() ),
                              actionCollection() , "increaseheight" );

  decreaseHeightAction = new KAction(i18n("Decrease Height"), Key_Down + SHIFT, this, SLOT( slotDecreaseHeight() ),
                              actionCollection() , "decreaseheight" );
#if KDE_VERSION < 300
    accel = new KAccel(widget());
    cancelAction->plugAccel(accel, true);
    moveLeftAction->plugAccel(accel, true);
    moveRightAction->plugAccel(accel, true);
    moveUpAction->plugAccel(accel, true);
    moveDownAction->plugAccel(accel, true);
    increaseWidthAction->plugAccel(accel, true);
    decreaseWidthAction->plugAccel(accel, true);
    increaseHeightAction->plugAccel(accel, true);
    decreaseHeightAction->plugAccel(accel, true);
#endif

  toFrontAction = new KAction(i18n("Bring to Front"), 0 , this, SLOT( slotToFront() ),
                              actionCollection() , "tofront" );

  toBackAction  = new KAction(i18n("Send to Back"), 0 , this, SLOT( slotToBack() ),
                              actionCollection() , "toback" );

  forwardOneAction  = new KAction(i18n("Bring Forward One"), "raise" ,0, this, SLOT( slotForwardOne() ),
                              actionCollection() , "forwardone" );
  backOneAction = new KAction(i18n("Send Back One"), "lower" ,0, this, SLOT( slotBackOne() ),
                              actionCollection() , "backone" );

  forwardOneAction->plug(areaListView->upBtn);
  backOneAction->plug(areaListView->downBtn);

  connect( areaListView->upBtn, SIGNAL(pressed()), forwardOneAction, SLOT(activate()));
  connect( areaListView->downBtn, SIGNAL(pressed()), backOneAction, SLOT(activate()));

  new KAction( i18n("Configure KImageMapEditor..."), "configure", 0,
                        this, SLOT(slotShowPreferences()),
                        actionCollection(), "configure_kimagemapeditor" );

  if (areaDock) {
    configureShowAreaListAction = new KToggleAction( i18n("Show Area List"), 0L, 0,
                        this, SLOT(configureShowAreaList()),
                        actionCollection(), "configure_show_arealist" );

    configureShowMapListAction = new KToggleAction( i18n("Show Map List"), 0L, 0,
                        this, SLOT(configureShowMapList()),
                        actionCollection(), "configure_show_maplist" );

    configureShowImageListAction = new KToggleAction( i18n("Show Image List"), 0L, 0,
                        this, SLOT(configureShowImageList()),
                        actionCollection(), "configure_show_imagelist" );
#if KDE_IS_VERSION(3,2,90)
    configureShowAreaListAction->setCheckedState(i18n("Hide Area List"));
    configureShowMapListAction->setCheckedState(i18n("Hide Map List"));
    configureShowImageListAction->setCheckedState(i18n("Hide Image List"));
#endif
  }

  updateActionAccess();
}

void KImageMapEditor::setupStatusBar()
{

//  We can't do this with a KPart !
//	widget()->statusBar()->insertItem(i18n(" Cursor")+" : x: 0 ,y: 0",STATUS_CURSOR);
//	widget()->statusBar()->insertItem(i18n(" Selection")+" : - ",STATUS_SELECTION);
  emit setStatusBarText( i18n(" Selection: -  Cursor: x: 0, y: 0 "));
}

void KImageMapEditor::slotShowPreferences()
{
  PreferencesDialog *dialog = new PreferencesDialog(widget(),config());
  connect(dialog, SIGNAL(applyClicked()), this, SLOT(slotConfigChanged()));
  dialog->exec();
  delete dialog;
}


void KImageMapEditor::showPopupMenu(const QPoint & pos, const QString & name)
{
  QPopupMenu* pop = static_cast<QPopupMenu *>(factory()->container(name, this));

  if (!pop) {
      kdWarning() << QString("KImageMapEditorPart: Missing XML definition for %1\n").arg(name) << endl;
      return;
  }

  pop->popup(pos);
}

void KImageMapEditor::slotShowMainPopupMenu(const QPoint & pos)
{
  showPopupMenu(pos,"popup_main");
}

void KImageMapEditor::slotShowMapPopupMenu(QListViewItem* item,const QPoint & pos)
{
  if (isReadWrite()) {
    mapDeleteAction->setEnabled(item);
    mapNameAction->setEnabled(item);
    mapDefaultAreaAction->setEnabled(item);
  }

  if (item)
     mapsListView->selectMap(item);

  showPopupMenu(pos,"popup_map");
}

void KImageMapEditor::slotShowImagePopupMenu(QListViewItem* item,const QPoint & pos)
{
  imageRemoveAction->setEnabled(item);
  imageUsemapAction->setEnabled(item);

  if (item)
     imagesListView->setSelected(item,true);

  showPopupMenu(pos,"popup_image");
}

void KImageMapEditor::slotShowPopupMenu(QListViewItem* item,const QPoint & p)
{
  if (!item)
    return;

  if (!item->isSelected())
  {
    deselectAll();
    select(item);
  }

  slotShowMainPopupMenu(p);
}

void KImageMapEditor::updateStatusBar()
{
  emit setStatusBarText(selectionStatusText+"  "+cursorStatusText);
}

void KImageMapEditor::slotChangeStatusCoords(int x,int y)
{
//	statusBar()->changeItem(QString(" Cursor : x: %1 ,y: %2 ").arg(x).arg(y),STATUS_CURSOR);
  cursorStatusText = i18n(" Cursor: x: %1, y: %2 ").arg(x).arg(y);
  updateStatusBar();
}

void KImageMapEditor::slotUpdateSelectionCoords() {
  if (selected()->count()>0) {
    QRect r=selected()->rect();
//		statusBar()->changeItem(
    selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height());

//		  ,STATUS_SELECTION);
    kapp->processEvents();
  } else
    selectionStatusText = i18n(" Selection: - ");
    //statusBar()->changeItem(" Selection : - ",STATUS_SELECTION);

  updateStatusBar();
}

void KImageMapEditor::slotUpdateSelectionCoords( const QRect & r )
{
  selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height());
  updateStatusBar();
  kapp->processEvents();
}

KApplication* KImageMapEditor::app() const
{
  return kapp;
}


void KImageMapEditor::drawToCenter(QPainter* p, const QString & str, int y, int width) {
  int xmid = width / 2;

  QFontMetrics fm = p->fontMetrics();
  QRect strBounds = fm.boundingRect(str);

  p->drawText(xmid-(strBounds.width()/2),y,str);
}


QImage KImageMapEditor::getBackgroundImage() {

  // Lazy initialisation
  if ( _backgroundImage.isNull() ) {


//  QString filename = QString("dropimage_")+KGlobal::locale()->language()+".png";
//  QString path = QString::null; //KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/"+filename ) + "kimagemapeditor/"+filename;
//  kdDebug() << "getBackgroundPic : loaded image : " << path << endl;

//  if ( ! QFileInfo(path).exists() ) {
    int width = 400;
    int height = 400;
    int border = 20;
    int fontSize = 58;

    QPixmap pix(width,height);
    pix.fill(QColor(74,76,74));
    QPainter p(&pix);

    QFont font;
    font.setFamily("Sans");
    font.setPixelSize(fontSize);
    font.setBold(true);
    p.setFont( font );
    
    p.setRasterOp(Qt::CopyROP);
    p.setPen(QPen(QColor(112,114,112),1));

    // The translated string must be divided into
    // parts with about the same size that fit to the image
    QString str = i18n("Drop an image or HTML file");
    QStringList strList = QStringList::split(" ",str);

    // Get the string parts
    QString tmp;
    QStringList outputStrList;
    QFontMetrics fm = p.fontMetrics();

    for ( QStringList::Iterator it = strList.begin(); it != strList.end(); ++it ) {
      QString tmp2 = tmp + *it;

        if (fm.boundingRect(tmp2).width() > width-border) {
           outputStrList.append(tmp);
           tmp = *it + " ";
        }
        else
          tmp = tmp2 + " ";
    }

    // Last one was forgotten so add it.
    outputStrList.append(tmp);

    // Try to adjust the text vertically centered
    int step = myround(float(height) / (outputStrList.size()+1));
    int y = step;

    for ( QStringList::Iterator it = outputStrList.begin(); it != outputStrList.end(); ++it ) {
        drawToCenter(&p, *it, y, pix.width());
        y += step;
    }

    p.end();

    _backgroundImage = pix.convertToImage();
  }


  return _backgroundImage;

/*
        QFontDatabase fdb;
    QStringList families = fdb.families();
    for ( QStringList::Iterator f = families.begin(); f != families.end(); ++f ) {
        QString family = *f;
        qDebug( family );
        QStringList styles = fdb.styles( family );
        for ( QStringList::Iterator s = styles.begin(); s != styles.end(); ++s ) {
            QString style = *s;
            QString dstyle = "\t" + style + " (";
            QValueList<int> smoothies = fdb.smoothSizes( family, style );
            for ( QValueList<int>::Iterator points = smoothies.begin();
                  points != smoothies.end(); ++points ) {
                dstyle += QString::number( *points ) + " ";
            }
            dstyle = dstyle.left( dstyle.length() - 1 ) + ")";
            qDebug( dstyle );
        }
    }


    path = KGlobal::dirs()->saveLocation( "data", "kimagemapeditor/" ) +filename;
    kdDebug() << "getBackgroundPic : save new image to : " << path << endl;
    pix.save(path,"PNG",100);
  }

  if ( ! QFileInfo(path).exists() ) {
      kdError() << "Couldn't find needed " << filename << " file in "
                   "the data directory of KImageMapEditor.\n"
                   "Perhaps you have forgotten to do a make install !" << endl;
      exit(1);
  }
*/
}


void KImageMapEditor::addArea(Area* area) {
  if (!area) return;

  // Perhaps we've got a selection of areas
  // so test it and add all areas of the selection
  // nested selections are possible but doesn't exist
  AreaSelection *selection=0L;
  if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
  {
    AreaList list = selection->getAreaList();

    for (Area* a = list.first(); a != 0L; a = list.next() )
    {
      areas->prepend(a);
      a->setListViewItem(new QListViewItem(areaListView->listView,a->attribute("href")));
      a->listViewItem()->setPixmap(1,makeListViewPix(*a));
    }
  }
  else
  {
    areas->prepend(area);
    area->setListViewItem(new QListViewItem(areaListView->listView,area->attribute("href")));
    area->listViewItem()->setPixmap(1,makeListViewPix(*area));
  }

  setModified(true);

}

void KImageMapEditor::addAreaAndEdit(Area* s)
{
  areas->prepend(s);
  s->setListViewItem(new QListViewItem(areaListView->listView,s->attribute("href")));
  s->listViewItem()->setPixmap(1,makeListViewPix(*s));
  deselectAll();
  select(s);
  if (!showTagEditor(selected())) {
    // If the user has pressed cancel
    // he undos the creation
    commandHistory()->undo();
  }
}

void KImageMapEditor::deleteArea( Area * area )
{
  if (!area) return;

  // only for repaint reasons
  QRect redrawRect = area->selectionRect();

  // Perhaps we've got a selection of areas
  // so test it and delete the whole selection
  // nested selections are possible but doesn't exist
  AreaSelection *selection=0L;
    if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
  {
    AreaList list = selection->getAreaList();

    for (Area* a = list.first(); a != 0L; a = list.next() )
    {
      currentSelected->remove(a);
      areas->remove( a );
      a->deleteListViewItem();
    }
  }
  else
  {
    deselect( area );
    areas->remove( area );
    area->deleteListViewItem();
  }

  drawZone->repaintRect(redrawRect);


  // Only to disable cut and copy actions
  if (areas->count()==0)
    deselectAll();

  setModified(true);
}

void KImageMapEditor::deleteSelected() {

  Area *a;
  AreaList list=currentSelected->getAreaList();

  for ( a=list.first(); a != 0; a=list.next() )	{
    currentSelected->remove( a );
    areas->remove( a );
    delete a->listViewItem();
  }


  drawZone->repaintArea( *currentSelected );
  // Only to disable cut and copy actions
  if (areas->count()==0)
    deselectAll();

  setModified(true);
}

void KImageMapEditor::deleteAllAreas()
{
  for (Area* a=areas->first();a!=0L;)
  {
    deselect( a );
    areas->remove( a );
    a->deleteListViewItem();
    a=areas->first(); // because the current is deleted
  }

  drawZone->viewport()->repaint();

}

void KImageMapEditor::updateAllAreas()
{
//  kdDebug() << "KImageMapEditor::updateAllAreas" << endl;
  for (Area* a=areas->first();a!=0L;a=areas->next()) {
    a->listViewItem()->setPixmap(1,makeListViewPix(*a));
  }
  drawZone->viewport()->repaint();
}

void KImageMapEditor::updateSelection() const {
  areaListView->listView->triggerUpdate();
}

AreaSelection* KImageMapEditor::selected() const {
  return currentSelected;
}

void KImageMapEditor::select(Area* a)
{
  if (!a) return;

  currentSelected->add(a);
  updateActionAccess();
  slotUpdateSelectionCoords();
//	drawZone->repaintArea( *a);

}

void KImageMapEditor::selectWithoutUpdate(Area* a)
{
  if (!a) return;
  currentSelected->add(a);
}

void KImageMapEditor::slotSelectionChanged()
{
  AreaListIterator it = areaList();
  AreaList list = currentSelected->getAreaList();

  for ( ; it.current() != 0L; ++it)
  {
    if ( it.current()->listViewItem()->isSelected() != (list.containsRef(it.current()) > 0) )
    {
      it.current()->listViewItem()->isSelected()
        ? select( it.current() )
        :	deselect( it.current() );

      drawZone->repaintArea( *it.current());
    }
  }

}

void KImageMapEditor::select( QListViewItem* item)
{

  AreaListIterator it = areaList();

  for ( ; it.current() != 0L; ++it)
  {
    if (it.current()->listViewItem() == item )
    {
      select( it.current() );
      drawZone->repaintArea( *it.current());
    }
  }


}

AreaListIterator KImageMapEditor::areaList() const {
  AreaListIterator it(*areas);
  return it;
}


void KImageMapEditor::slotAreaChanged(Area *area)
{
  if (!area)
    return;

  setModified(true);

  AreaSelection *selection=0L;
  if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) )
  {
    AreaListIterator it = selection->getAreaListIterator();

    for ( ; it.current() != 0L; ++it )
    {
      if (it.current()->listViewItem()) {
        it.current()->listViewItem()->setText(0,it.current()->attribute("href"));
        it.current()->listViewItem()->setPixmap(1,makeListViewPix(*it.current()));
      }
    }

  }
  else
  if (area->listViewItem()) {
    area->listViewItem()->setText(0,area->attribute("href"));
    area->listViewItem()->setPixmap(1,makeListViewPix(*area));
  }

  drawZone->repaintArea(*area);

}

void KImageMapEditor::deselect(Area* a)
{
  if (a) {
    currentSelected->remove(a);
//		drawZone->repaintArea(*a);
    updateActionAccess();
    slotUpdateSelectionCoords();
  }
}

void KImageMapEditor::deselectWithoutUpdate(Area* a)
{
  if (a) {
    currentSelected->remove(a);
  }
}


/**
* Makes sure, that the actions cut, copy, delete and
* show properties
* can only be executed if sth. is selected.
**/
void KImageMapEditor::updateActionAccess()
{
  if (!isReadWrite())
     return;

  if ( 0 < selected()->count())
  {
    areaPropertiesAction->setEnabled(true);
    deleteAction->setEnabled(true);
    copyAction->setEnabled(true);
    cutAction->setEnabled(true);
    moveLeftAction->setEnabled(true);
    moveRightAction->setEnabled(true);
    moveUpAction->setEnabled(true);
    moveDownAction->setEnabled(true);
    toFrontAction->setEnabled(true);
    toBackAction->setEnabled(true);

    if ( (selected()->count() == 1) )
    {
      if (selected()->type()==Area::Polygon)
      {
        increaseWidthAction->setEnabled(false);
        decreaseWidthAction->setEnabled(false);
        increaseHeightAction->setEnabled(false);
        decreaseHeightAction->setEnabled(false);
        addPointAction->setEnabled(true);
        removePointAction->setEnabled(true);
      }
      else
      {
        increaseWidthAction->setEnabled(true);
        decreaseWidthAction->setEnabled(true);
        increaseHeightAction->setEnabled(true);
        decreaseHeightAction->setEnabled(true);
        addPointAction->setEnabled(false);
        removePointAction->setEnabled(false);
      }

    }
    else
    {
      increaseWidthAction->setEnabled(false);
      decreaseWidthAction->setEnabled(false);
      increaseHeightAction->setEnabled(false);
      decreaseHeightAction->setEnabled(false);
      addPointAction->setEnabled(false);
      removePointAction->setEnabled(false);
    }

  }
  else
  {
    areaPropertiesAction->setEnabled(false);
    deleteAction->setEnabled(false);
    copyAction->setEnabled(false);
    cutAction->setEnabled(false);
    moveLeftAction->setEnabled(false);
    moveRightAction->setEnabled(false);
    moveUpAction->setEnabled(false);
    moveDownAction->setEnabled(false);
    increaseWidthAction->setEnabled(false);
    decreaseWidthAction->setEnabled(false);
    increaseHeightAction->setEnabled(false);
    decreaseHeightAction->setEnabled(false);
    toFrontAction->setEnabled(false);
    toBackAction->setEnabled(false);
    addPointAction->setEnabled(false);
    removePointAction->setEnabled(false);

  }

  updateUpDownBtn();
}

void KImageMapEditor::updateUpDownBtn()
{
  if (!isReadWrite())
     return;

  AreaList list = currentSelected->getAreaList();

  if (list.isEmpty() || (areas->count() < 2))
  {
    forwardOneAction->setEnabled(false);
    areaListView->upBtn->setEnabled(false);
    backOneAction->setEnabled(false);
    areaListView->downBtn->setEnabled(false);
    return;
  }
  // if the first Area is in the selection can't move up
  if (list.find( areas->getFirst() ) == -1)
  {
    forwardOneAction->setEnabled(true);
    areaListView->upBtn->setEnabled(true);
  }
  else {
    forwardOneAction->setEnabled(false);
    areaListView->upBtn->setEnabled(false);
  }

  drawZone->repaintArea(*currentSelected);

  // if the last Area is in the selection can't move down
  if (list.find( areas->getLast() ) == -1)
  {
    backOneAction->setEnabled(true);
    areaListView->downBtn->setEnabled(true);
  }
  else {
    backOneAction->setEnabled(false);
    areaListView->downBtn->setEnabled(false);
  }

}

void KImageMapEditor::deselectAll()
{
  QRect redrawRect= currentSelected->selectionRect();
  currentSelected->reset();
  drawZone->repaintRect(redrawRect);
  updateActionAccess();
}

Area* KImageMapEditor::onArea(const QPoint & p) const {
  for (Area* s=areas->first();s!=0L;s=areas->next()) {
    if (s->contains(p))
      return s;
  }
  return 0L;
}


int KImageMapEditor::showTagEditor(Area *a) {
  if (!a) return 0;
  drawZone->repaintArea(*a);

  AreaDialog *dialog= new AreaDialog(this,a);
  connect (dialog, SIGNAL(areaChanged(Area*)), this, SLOT(slotAreaChanged(Area*)));

  int result = dialog->exec();

  return result;


}

int KImageMapEditor::showTagEditor(QListViewItem *item) {
  if (!item) return 0;
  for (Area* a=areas->first();a!=0L;a=areas->next()) {
    if (a->listViewItem()==item) {
      return showTagEditor(a);
    }
  }
  return 0;
}

int KImageMapEditor::showTagEditor() {
  return showTagEditor(selected());
}


QString KImageMapEditor::getHTMLImageMap() const {
  QString retStr;
  retStr+="<map "+QString("name=\"")+_mapName+"\">\n";

  for (Area* a=areas->first();a!=0L;a=areas->next()) {
    retStr+="  "+a->getHTMLCode()+"\n";
  }

  if (defaultArea && defaultArea->finished())
    retStr+="  "+defaultArea->getHTMLCode()+"\n";

  retStr+="</map>";
  return retStr;
}

QPixmap KImageMapEditor::makeListViewPix(Area & a)
{
  QPixmap pix=a.cutOut(drawZone->picture());

  double shrinkFactor=1;

  // picture fits into max row height ?
  if (maxAreaPreviewHeight < pix.height())
    shrinkFactor = ( (double) maxAreaPreviewHeight / pix.height() );

  QPixmap pix2((int)(pix.width()*shrinkFactor), (int)(pix.height()*shrinkFactor));

  // Give all pixels a defined color
  pix2.fill(Qt::white);

  QPainter p(&pix2);

  p.scale(shrinkFactor,shrinkFactor);
  p.drawPixmap(0,0,pix);

  return pix2;
}

void KImageMapEditor::setMapName(const QString & s) {
    mapsListView->changeMapName(_mapName, s);
    _mapName=s;
    currentMapElement->mapTag->name = s;
}


void KImageMapEditor::setPicture(const KURL & url) {
  _imageUrl=url;
  if (QFileInfo(url.path()).exists()) {
     QImage img(url.path());

     if (!img.isNull()) {
         setPicture(img);
         imageRemoveAction->setEnabled(true);
         imageUsemapAction->setEnabled(true);
     }
     else
         kdError() << QString("The image %1 could not be opened.").arg(url.path()) << endl;
  }
  else
     kdError() << QString("The image %1 does not exist.").arg(url.path()) << endl;
}

void KImageMapEditor::setPicture(const QImage & pix) {
    drawZone->setPicture(pix);
    updateAllAreas();
}


void KImageMapEditor::slotDrawArrow() {
  _currentToolType=KImageMapEditor::Selection;

}

void KImageMapEditor::slotDrawCircle() {
  _currentToolType=KImageMapEditor::Circle;

}

void KImageMapEditor::slotDrawRectangle() {
  _currentToolType=KImageMapEditor::Rectangle;

}

void KImageMapEditor::slotDrawPolygon() {
  _currentToolType=KImageMapEditor::Polygon;
}

void KImageMapEditor::slotDrawFreehand() {
  _currentToolType=KImageMapEditor::Freehand;
}

void KImageMapEditor::slotDrawAddPoint() {
  _currentToolType=KImageMapEditor::AddPoint;
}

void KImageMapEditor::slotDrawRemovePoint() {
  _currentToolType=KImageMapEditor::RemovePoint;
}


void KImageMapEditor::slotZoom() {

  int i=zoomAction->currentItem();
  switch (i) {
    case 0 : drawZone->setZoom(0.25);break;
    case 1 : drawZone->setZoom(0.5);break;
    case 2 : drawZone->setZoom(1);break;
    case 3 : drawZone->setZoom(1.5);break;
    case 4 : drawZone->setZoom(2.0);break;
    case 5 : drawZone->setZoom(2.5);break;
    case 6 : drawZone->setZoom(3);break;
    case 7 : drawZone->setZoom(5);break;
    case 8 : drawZone->setZoom(7.5);break;
    case 9 : drawZone->setZoom(10);break;
  }
  if (i<10)
    zoomInAction->setEnabled(true);
  else
    zoomInAction->setEnabled(false);

  if (i>0)
    zoomOutAction->setEnabled(true);
  else
    zoomOutAction->setEnabled(false);
}

void KImageMapEditor::slotZoomIn() {
  if (zoomAction->currentItem()==(int)(zoomAction->items().count()-1))
    return;

  zoomAction->setCurrentItem(zoomAction->currentItem()+1);
  slotZoom();
}

void KImageMapEditor::slotZoomOut() {
  if (zoomAction->currentItem()==0)
    return;

  zoomAction->setCurrentItem(zoomAction->currentItem()-1);
  slotZoom();
}

void KImageMapEditor::mapDefaultArea()
{
  if (defaultArea)
    showTagEditor(defaultArea);
  else {
    defaultArea= new DefaultArea();
    showTagEditor(defaultArea);
  }

}

void KImageMapEditor::mapEditName()
{
  bool ok=false;
#if KDE_IS_VERSION(3, 1, 90)
  QString input = KInputDialog::getText(i18n("Enter Map Name"),
    i18n("Enter the name of the map:"),
    _mapName,&ok,widget());
#else
  QString input = KLineEditDlg::getText(i18n("Enter Map Name"),
    i18n("Enter the name of the map:"),
    _mapName,&ok,widget());
#endif
  if (ok) {
    if (input != _mapName) {
        if (mapsListView->nameAlreadyExists(input))
            KMessageBox::sorry(this->widget(), i18n("The name <em>%1</em> already exists.").arg(input));
        else {
            setMapName(input);
        }
    }
  }
}

void KImageMapEditor::mapShowHTML()
{
  KDialogBase *dialog= new KDialogBase(widget(),QString::null,true,i18n("HTML Code of Map"),KDialogBase::Ok);
  QMultiLineEdit *edit = new QMultiLineEdit(dialog);

  edit->setText(getHtmlCode());
  edit->setReadOnly(true);
  edit->setWordWrap(QTextEdit::NoWrap);
  dialog->setMainWidget(edit);
//  dialog->resize(dialog->calculateSize(edit->maxLineWidth(),edit->numLines()*));
//	dialog->adjustSize();
  dialog->resize(600,400);
  dialog->exec();
}

void KImageMapEditor::openFile(const KURL & url) {
  if ( ! url.isEmpty()) {
    QString ext=QFileInfo(url.path()).extension().lower();

    if (ext=="png" || ext=="jpg" || ext=="jpeg" || ext=="gif" ||
        ext=="bmp" || ext=="xbm" || ext=="xpm" || ext=="mng" || ext=="pnm")
        addImage(url);
    else
        openURL(url);
  }
}

bool KImageMapEditor::openURL(const KURL & url) {
    // If a local file does not exist
    // we start with an empty file, so
    // that we can return true here.
    // For non local files, we cannot check
    // the existance
    if (url.isLocalFile() &&
        ! QFile::exists(url.path()))
        return true;
    return KParts::ReadOnlyPart::openURL(url);
}

void KImageMapEditor::fileOpen() {

  QString fileName = KFileDialog::getOpenFileName(QString::null,
          i18n("*.png *.jpg *.jpeg *.gif *.htm *.html|Web File\n"
          "*.png *.jpg *.jpeg *.gif *.bmp *.xbm *.xpm *.pnm *.mng|Images\n"
          "*.htm *.html|HTML Files\n"
          "*.png|PNG Images\n*.jpg *.jpeg|JPEG Images\n*.gif|GIF-Images\n*|All Files"),
          widget(),i18n("Choose File to Open"));

  openFile(KURL( fileName ));
}



void KImageMapEditor::fileClose()
{
  if (! closeURL())
     return;


    setPicture(getBackgroundImage());
    recentFilesAction->setCurrentItem(-1);
    setModified(false);
}

void KImageMapEditor::fileSave()
{
  // if we aren't read-write, return immediately
  if ( ! isReadWrite() )
      return;

  if (url().isEmpty()) {
    fileSaveAs();
  }
  else {
    saveFile();
    setModified(false);
  }


}

void KImageMapEditor::fileSaveAs() {

  KURL url = KFileDialog::getSaveURL(0L,"*.htm *.html|" + i18n( "HTML File" ) +
                                     "\n*.txt|" + i18n( "Text File" ) + "\n*|" + i18n( "All Files" ),widget());
  if (url.isEmpty() || !url.isValid()) {
    return;
  }


  QFileInfo fileInfo(url.path());

  if ( fileInfo.exists() )
  {
  	if (KMessageBox::warningContinueCancel(widget(),
      i18n("<qt>The file <em>%1</em> already exists.<br>Do you want to overwrite it?</qt>").arg(fileInfo.fileName()),
      i18n("Overwrite File?"), i18n("Overwrite"))==KMessageBox::Cancel)
      return;

    if(!fileInfo.isWritable()) {
      KMessageBox::sorry(widget(), i18n("<qt>You do not have write permission for the file <em>%1</em>.</qt>").arg(fileInfo.fileName()));
      return;
    }
  }


  saveAs(url);
  recentFilesAction->addURL(url);

}


bool KImageMapEditor::openFile()
{
  QFileInfo fileInfo(url().path());

  if ( !fileInfo.exists() )
  {
      KMessageBox::information(widget(),
        i18n("<qt>The file <b>%1</b> does not exist.</qt>").arg(fileInfo.fileName()),
        i18n("File Does Not Exist"));
      return false;
  }

  openHTMLFile(url());

  drawZone->viewport()->repaint();
  recentFilesAction->addURL(url());
  setModified(false);
  backupFileCreated = false;
  return true;
}

/**
 * This methods supposes that the given QTextStream s has just read
 * the &lt; of a tag. It now reads all attributes of the tag until a &gt;
 * The tagname itself is also read and stored as a <em>tagname</em>
 * attribute. After parsing the whole tag it returns a QDict<QString>
 * with all attributes and their values. It stores the whole read text in the
 * parameter readText.
 */
QDict<QString> KImageMapEditor::getTagAttributes(QTextStream & s, QString & readText)
{
  QDict<QString> dict(17,false);
  // the "<" is already read
  QChar w;
  QString attr,value;

  readText = QString::null;

  // get the tagname
  while (!s.atEnd() && w!=" ") {
    s >> w;
    readText.append(w);
    if (w==" " || w==">") {
      dict.insert("tagname",new QString(value));
      break;
    }
    value+=w;
  }


  // do we have a comment ?
  // read the comment and return
  if (value.right(3)=="-->")
    return dict;

  if (value.startsWith("!--")) {
    while (!s.atEnd()) {
      s >> w;
      readText.append(w);

      if (w=="-") {
        s >> w;
        readText.append(w);
        if (w=="-") {
          s >> w;
          readText.append(w);
          if (w==">")
            return dict;
        }
      }
    }
  }

  bool attrRead=true;	// currently reading an attribute ?
  bool equalSign=false; // an equalsign was read?
  bool valueRead=false; // currently reading a value ?
  QChar quotation='\0'; // currently reading a value with quotation marks ?
  bool php=false; // currently reading a php script
  attr=QString::null;
  value=QString::null;

  //get the other attributes
  while (!s.atEnd() && w!=">")
  {
    s >> w;
    readText.append(w);

    // End of PHP Script ?
    if (php && (w=="?") )
    {
      s >> w;
      readText.append(w);

      if (valueRead)
          value+=w;

      if (w==">")
      {
        php = false;
        s >> w;
        readText.append(w);
      }
    }

    // Wrong syntax or PHP-Skript !
    if (!php && (w=="<"))
    {
      if (valueRead)
        value+=w;
      s >> w;
      readText.append(w);
      if (valueRead)
        value+=w;

      if (w=="?")
      {
        php = true;
      }
    } else
    // finished ?
    if (w==">") {
      if (valueRead)
        dict.insert(attr,new QString(value));
        return dict;
    } else
    // currently reading an attribute ?
    if (attrRead) {
      // if there is a whitespace the attributename has finished
      // possibly there isn't any value e.g. noshade
      if (w==" ")
        attrRead=false;
      else
      // an equal sign signals that the value follows
      if (w=="=") {
        attrRead=false;
        equalSign=true;
      } else
        attr+=w;
    } else
    // an equal sign was read ? delete every whitespace
    if (equalSign) {
      if (w!=" ") {
        equalSign=false;
        valueRead=true;
        if (w=="\"" || w=="'")
          quotation=w;
      }
    } else
    // currently reading the value
    if (valueRead) {
      // if php, read without regarding anything
      if (php)
        value+=w;
      // if value within quotation marks is read
      // only stop when another quotationmark is found
      else
      if (quotation != '\0') {
        if (quotation!=w) {
          value+=w;
        } else {
          quotation='\0';
          valueRead=false;
          dict.insert(attr,new QString(value));
          attr = value = QString::null;

        }
      } else
      // a whitespace indicates that the value has finished
      if (w==" ") {
        valueRead=false;
        dict.insert(attr,new QString(value));
        attr = value = QString::null;
      }
    } else {
      if (w!=" ") {
        attrRead=true;
        attr+=w;
      }
    }
  }

  return dict;

}


bool KImageMapEditor::openHTMLFile(const KURL & url, const QString & mapName, const QString & imagePath)
{
  QFile f(url.path());
  if ( !f.exists () )
      return false;
  f.open(IO_ReadOnly);
  QTextStream s(&f);
  QString str;
  QChar w;
  QDict<QString> *attr=0L;
  QPtrList<ImageTag> *images= new QPtrList<ImageTag>;
  MapTag *map=0L;
  QPtrList<MapTag> *maps = new QPtrList<MapTag>;

  _htmlContent.clear();
  currentMapElement = 0L;

  QString temp;
  QString origcode;

  bool readMap=false;

  while (!s.atEnd()) {

    s >> w;
    if (w=="<")
    {
      if (!readMap && !origcode.isEmpty()) {
        _htmlContent.append( new HtmlElement(origcode));
        origcode = QString::null;
      }

      origcode.append("<");
      attr=new QDict<QString>(getTagAttributes(s,temp));
      origcode.append(temp);

      if (attr->find("tagname")) {

        if (attr->find("tagname")->lower()=="img") {
          HtmlImgElement *el = new HtmlImgElement(origcode);
          el->imgTag = static_cast<ImageTag*>(attr);
          images->append(el->imgTag);
          _htmlContent.append(el);

          origcode = QString::null;
        } else
        if (attr->find("tagname")->lower()=="map") {
          map = new MapTag();
          map->name=(*attr->find("name"));
          readMap=true;
        } else
        if (attr->find("tagname")->lower()=="/map") {
          readMap=false;
          maps->append(map);
          HtmlMapElement *el = new HtmlMapElement(origcode);
          el->mapTag = map;
          _htmlContent.append(el);

          origcode = QString::null;
        } else
        if (readMap) {
          if (attr->find("tagname")->lower()=="area") {
             map->prepend(attr);
          }
        } else {
          _htmlContent.append(new HtmlElement(origcode));
          origcode = QString::null;
        }

      }
    } // w != "<"
    else {
      origcode.append(w);
    }
  }

  if (!origcode.isEmpty()) {
    _htmlContent.append(new HtmlElement(origcode));
  }

  f.close();

  KURL imageUrl;
  map = 0L;



  // If there is a preselection of map and image
  // don't let the user choose something
  if (imagePath.isNull() || mapName.isNull()) {
    // If we have more than on map or more than one image
    // Let the user choose, otherwise take the only ones
    if (maps->count() == 1) {
      map = maps->first();
    }

    if (images->count() == 1) {
      if (images->first()) {
        ImageTag* imgTag = images->first();
        QString *src = imgTag->find("src");
        if (src)
          imageUrl = KURL(url,*src);
      }
    }

    // If there is only one map and more than one image
    // try to find out the image with the according usemap tag
    if (maps->count() == 1 && images->count() > 1) {
        ImageTag* imageTag;
        for ( imageTag = images->first(); imageTag; imageTag = images->next() )
        {
            QString *usemap = imageTag->find("usemap");
            if (usemap) {
                // Remove the #
                QString usemapName = usemap->right(usemap->length()-1);
                if (usemapName == map->name) {
                    QString *src = imageTag->find("src");
                    if (src)
                      imageUrl = KURL(url,*src);
                }
            }
        }
    }


    // If there are more than one map or there wasn't
    // found a fitting image and there is something to choose
    // let the user choose
    if (maps->count() >1 || (imageUrl.isEmpty() && images->count() > 1))
    {
      ImageMapChooseDialog dialog(widget(),maps,images,url);
      dialog.exec();
      map=dialog.currentMap;
      imageUrl=dialog.pixUrl;
    }
  }
  else
    imageUrl = imagePath;

  imagesListView->clear();
  imagesListView->setBaseUrl(url);
  imagesListView->addImages(images);

  mapsListView->clear();
  mapsListView->addMaps(maps);


  setMapActionsEnabled(false);

  if (map) {
    mapsListView->selectMap(map->name);
  }
  else if ( ! mapName.isNull()) {
    mapsListView->selectMap(mapName);
  } else {
    if (tabWidget)
       tabWidget->showPage(mapsListView);
  }

  if (!imageUrl.isEmpty()) {
    setPicture(imageUrl);
  } else {
    setPicture(getBackgroundImage());
    if (tabWidget)
       tabWidget->showPage(imagesListView);
  }


  emit setWindowCaption(url.fileName());
  setModified(false);
  return true;
}

/**
 * Finds the first html element which contains the given text.
 * Returns the first matching element.
 * Returns 0L if no element was found.
 */
HtmlElement* KImageMapEditor::findHtmlElement(const QString & containingText) {
  for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) {
    if (el->htmlCode.contains(containingText,false)) {
      return el;
    }
  }
  return 0L;
}

/**
 * Finds the first html element which contains the given ImageTag.
 * Returns the first matching element.
 * Returns 0L if no element was found.
 */
HtmlImgElement* KImageMapEditor::findHtmlImgElement(ImageTag* tag) {
  for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) {
    HtmlImgElement* imgEl = dynamic_cast<HtmlImgElement*>(el);

    if (imgEl && imgEl->imgTag == tag)
       return imgEl;
  }
  return 0L;
}

void KImageMapEditor::addMap(const QString & name = QString::null) {
  HtmlMapElement* el = new HtmlMapElement("\n<map></map>");
  MapTag* map = new MapTag();
  map->name = name;
  el->mapTag = map;

  // Try to find the body tag
  HtmlElement* bodyTag = findHtmlElement("<body");

  // if we found one add the new map right after the body tag
  if (bodyTag) {
     uint index = _htmlContent.find(bodyTag);

     // Add a newline before the map
     _htmlContent.insert(index+1, new HtmlElement("\n"));

     _htmlContent.insert(index+2, el);
  } // if there is no body tag we add the map to the end of the file
  else {
     // Add a newline before the map
     _htmlContent.append(new HtmlElement("\n"));

     _htmlContent.append(el);
     kdDebug() << "KImageMapEditor::addMap : No <body found ! Appending new map to the end." << endl;
  }

  mapsListView->addMap(name);
  mapsListView->selectMap(name);
}

/**
 * Finds the HtmlMapElement in the HtmlContent, that corresponds
 * to the given map name.<br>
 * Returns 0L if there exists no map with the given name
 */
HtmlMapElement* KImageMapEditor::findHtmlMapElement(const QString & mapName) {
  for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) {
    if (dynamic_cast<HtmlMapElement*>(el)) {
      HtmlMapElement *tagEl = static_cast<HtmlMapElement*>(el);
      if (tagEl->mapTag->name == mapName) {
         return tagEl;
      }
    }
  }

  kdWarning() << "KImageMapEditor::findHtmlMapElement: couldn't find map '" << mapName << "'" << endl;
  return 0L;
}

/**
 * Calls setMap with the HtmlMapElement with the given map name
 */
void KImageMapEditor::setMap(const QString & mapName) {
    HtmlMapElement* el = findHtmlMapElement(mapName);
    if (!el) {
      kdWarning() << "KImageMapEditor::setMap : Couldn't set map '" << mapName << "', because it wasn't found !" << endl;
      return;
    }

    setMap(el);

}

void KImageMapEditor::setMap(MapTag* map) {
  for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) {
    HtmlMapElement *tagEl = dynamic_cast<HtmlMapElement*>(el);
    if (tagEl) {
      if (tagEl->mapTag == map) {
         setMap(tagEl);
         break;
      }
    }
  }

}

void KImageMapEditor::saveAreasToMapTag(MapTag* map) {
  map->clear();
  for (Area* a=areas->first();a!=0L;a=areas->next()) {
    QDict<QString> *dict = new QDict<QString>(17,false);
    QString *shapeStr = 0L;

    switch (a->type()) {
      case Area::Rectangle : shapeStr = new QString("rect");break;
      case Area::Circle : shapeStr = new QString("circle");break;
      case Area::Polygon : shapeStr = new QString("poly");break;
      default : continue;
    }

    dict->insert("shape",shapeStr);

    for (AttributeIterator it = a->firstAttribute();it!=a->lastAttribute();++it)  {
      dict->insert(it.key(),new QString(it.data()));
    }

    dict->insert("coords",new QString(a->coordsToString()));

    map->append(dict);

  }

  if (defaultArea && defaultArea->finished()) {
    QDict<QString> *dict = new QDict<QString>(17,false);
    dict->insert("shape",new QString("default"));

    for (AttributeIterator it = defaultArea->firstAttribute();it!=defaultArea->lastAttribute();++it)  {
      dict->insert(it.key(),new QString(it.data()));
    }

    map->append(dict);
  }

}

void KImageMapEditor::setMap(HtmlMapElement* mapElement) {
  if (currentMapElement) {
    currentMapElement->mapTag->modified=true;
    currentMapElement->htmlCode = getHTMLImageMap();
    saveAreasToMapTag(currentMapElement->mapTag);
  }

  currentMapElement = mapElement;
  MapTag* map = currentMapElement->mapTag;

  // Remove old areas only if a new map is loaded
    deleteAllAreas();
    delete defaultArea;
    defaultArea = 0L;
//    kdDebug() << "KImageMapEditor::setMap : Setting new map : " << map->name << endl;
    _mapName = map->name;
    for (AreaTag *tag=map->first();tag!=0L;tag=map->next())
    {
        QString shape="rect";
        if (tag->find("shape"))
          shape=*tag->find("shape");

        Area::ShapeType type=Area::Rectangle;
        if (shape=="circle")
          type=Area::Circle;
        else if (shape=="poly")
          type=Area::Polygon;
        else if (shape=="default")
          type=Area::Default;

        Area* a=AreaCreator::create(type);

        if (tag->find("href"))
          a->setAttribute("href",*tag->find("href"));

        if (tag->find("alt"))
          a->setAttribute("alt",*tag->find("alt"));

        if (tag->find("target"))
          a->setAttribute("target",*tag->find("target"));

        if (tag->find("title"))
          a->setAttribute("title",*tag->find("title"));

        if (tag->find("onclick"))
          a->setAttribute("onclick",*tag->find("onclick"));

        if (tag->find("onmousedown"))
          a->setAttribute("onmousedown",*tag->find("onmousedown"));

        if (tag->find("onmouseup"))
          a->setAttribute("onmouseup",*tag->find("onmouseup"));

        if (tag->find("onmouseover"))
          a->setAttribute("onmouseover",*tag->find("onmouseover"));

        if (tag->find("onmousemove"))
          a->setAttribute("onmousemove",*tag->find("onmousemove"));

        if (tag->find("onmouseout"))
          a->setAttribute("onmouseout",*tag->find("onmouseout"));



        if (type==Area::Default) {
          defaultArea=a;
          defaultArea->setFinished(true);
          continue;
        }

        if (tag->find("coords"))
          a->setCoords(*tag->find("coords"));

        a->setMoving(false);
        addArea(a);
    }

    updateAllAreas();

    setMapActionsEnabled(true);
}

/**
 * Sets wether actions that depend on an selected map
 * are enabled
 */
void KImageMapEditor::setMapActionsEnabled(bool b) {
   mapDeleteAction->setEnabled(b);
   mapDefaultAreaAction->setEnabled(b);
   mapNameAction->setEnabled(b);

   arrowAction->setChecked(true);
   slotDrawArrow();

   arrowAction->setEnabled(b);
   circleAction->setEnabled(b);
   rectangleAction->setEnabled(b);
   polygonAction->setEnabled(b);
   freehandAction->setEnabled(b);
   addPointAction->setEnabled(b);
   removePointAction->setEnabled(b);

}

QString KImageMapEditor::getHtmlCode() {
  if (currentMapElement) {
    currentMapElement->htmlCode = getHTMLImageMap();
  }

  QString result;

  HtmlElement *el;
    for ( el = _htmlContent.first(); el; el = _htmlContent.next() ) {
        result += el->htmlCode;
        //kdDebug() << "KImageMapEditor::getHtmlCode : Writing : " << el->htmlCode << endl;

    }
  return result;
}

void KImageMapEditor::saveImageMap(const KURL & url)
{
  QFileInfo fileInfo(url.path());

  if (!QFileInfo(url.directory()).isWritable()) {
    KMessageBox::error(widget(),
      i18n("<qt>The file <i>%1</i> could not be saved, because you do not have the required write permissions.</qt>").arg(url.path()));
    return;
  }

  if (!backupFileCreated) {
    QString backupFile = url.path()+"~";
    KIO::file_copy(url, KURL::fromPathOrURL( backupFile ), -1, true, false, false);
    backupFileCreated = true;
  }

  setModified(false);

  if (mapName().isEmpty()) {
    mapEditName();
  }
  QFile file(url.path());
  file.open(IO_WriteOnly);

  QTextStream t(&file);

  if (_htmlContent.isEmpty()) {
    t << "<html>\n"
      << "<head>\n"
      << "  <title></title>\n"
      << "</head>\n"
      << "<body>\n"
      << "  " << getHTMLImageMap()
      << "\n"
      << "  <img src=\"" << QExtFileInfo::toRelative(_imageUrl,KURL( url.directory() )).path() << "\""
      << " usemap=\"#" << _mapName << "\""
      << " width=\"" << drawZone->picture().width() << "\""
      << " height=\"" << drawZone->picture().height() << "\">\n"
      << "</body>\n"
      << "</html>";
  } else
  {
    t << getHtmlCode();
  }

  file.close();

}


void KImageMapEditor::slotCut()
{
  if ( 0 == currentSelected->count() )
    return;
  delete copyArea;

  copyArea= static_cast< AreaSelection* > (currentSelected->clone());
  pasteAction->setEnabled(true);
  KCommand *command= new CutCommand(this,*currentSelected);
  commandHistory()->addCommand( command ,true);
}


void KImageMapEditor::slotDelete()
{
  if ( 0 == currentSelected->count() )
    return;

  KCommand *command= new DeleteCommand(this,*currentSelected);
  commandHistory()->addCommand( command ,true);
}

void KImageMapEditor::slotCopy()
{
  delete copyArea;

  copyArea = static_cast< AreaSelection* > (currentSelected->clone());
  pasteAction->setEnabled(true);
}

void KImageMapEditor::slotPaste()
{
  if (!copyArea)
    return;

  copyArea->moveBy(5,5);
  if (copyArea->rect().x()>= drawZone->getImageRect().width() ||
      copyArea->rect().y()>= drawZone->getImageRect().height())
      copyArea->moveTo(0,0);

  if (copyArea->rect().width()>drawZone->getImageRect().width() ||
      copyArea->rect().height()>drawZone->getImageRect().height())
      return;

  AreaSelection *a=static_cast< AreaSelection* > (copyArea->clone());
  commandHistory()->addCommand( new PasteCommand(this,*a),true);
  delete a;
//	addAreaAndEdit(a);
}



void KImageMapEditor::slotBackOne()
{
  if (currentSelected->isEmpty())
    return;

  AreaList list = currentSelected->getAreaList();


  Area *a = 0L;
  // move every selected Area one step lower
  for (int i=areas->count()-2; i > -1; i--)
  {
    if (list.find( areas->at(i) ) > -1 )
    {
      a = areas->at(i);
      areas->remove(a);
      areas->insert((uint)i+1,a);
      a->listViewItem()->moveItem( areas->at(i)->listViewItem() );
    }
  }
  // to update the up and down buttons
  updateUpDownBtn();

}

void KImageMapEditor::slotForwardOne()
{
  if (currentSelected->isEmpty())
    return;

  AreaList list = currentSelected->getAreaList();

  Area *a = 0L;
  // move every selected Area one step higher
  for (int i=1; i < (int)areas->count(); i++)
  {
    if (list.find( areas->at(i) ) > -1 )
    {
      a = areas->at(i);
      areas->remove(a);
      areas->insert((uint)i-1,a);
      areas->at(i)->listViewItem()->moveItem( a->listViewItem() );
    }
  }
  // to update the up and down buttons
  updateUpDownBtn();
}

void KImageMapEditor::slotToBack()
{
  if (currentSelected->isEmpty())
    return;

  while (backOneAction->isEnabled())
    slotBackOne();
}

void KImageMapEditor::slotToFront()
{
  if (currentSelected->isEmpty())
    return;

  while (forwardOneAction->isEnabled())
    slotForwardOne();
}


void KImageMapEditor::slotMoveUp()
{
  QRect r=selected()->rect();
  selected()->setMoving(true);
  selected()->moveBy(0,-1);

  commandHistory()->addCommand(
    new MoveCommand( this, selected(), r.topLeft() ) ,true );
  selected()->setMoving(false);
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotMoveDown()
{
  QRect r=selected()->rect();
  selected()->setMoving(true);
  selected()->moveBy(0,1);

  commandHistory()->addCommand(
    new MoveCommand( this, selected(), r.topLeft() ) ,true );
  selected()->setMoving(false);
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotMoveLeft()
{
  QRect r=selected()->rect();
  selected()->setMoving(true);
  selected()->moveBy(-1,0);

  commandHistory()->addCommand(
    new MoveCommand( this, selected(), r.topLeft() ) ,true );
  selected()->setMoving(false);
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotMoveRight()
{
  QRect r=selected()->rect();
  selected()->setMoving(true);
  selected()->moveBy(1,0);

  commandHistory()->addCommand(
    new MoveCommand( this, selected(), r.topLeft() ) ,true );
  selected()->setMoving(false);
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotCancelDrawing()
{
  drawZone->cancelDrawing();
}

void KImageMapEditor::slotIncreaseHeight()
{
  Area *oldArea=selected()->clone();

  QRect r = selected()->rect();
  r.setHeight( r.height()+1 );
  r.moveBy(0,-1);

  selected()->setRect(r);

  commandHistory()->addCommand(
    new ResizeCommand( this, selected(), oldArea ) ,true );
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotDecreaseHeight()
{
  Area *oldArea=selected()->clone();

  QRect r = selected()->rect();
  r.setHeight( r.height()-1 );
  r.moveBy(0,1);

  selected()->setRect(r);

  commandHistory()->addCommand(
    new ResizeCommand( this, selected(), oldArea ) ,true );
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotIncreaseWidth()
{
  Area *oldArea=selected()->clone();

  QRect r = selected()->rect();
  r.setWidth( r.width()+1 );

  selected()->setRect(r);

  commandHistory()->addCommand(
    new ResizeCommand( this, selected(), oldArea ) ,true );
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotDecreaseWidth()
{
  Area *oldArea=selected()->clone();

  QRect r = selected()->rect();
  r.setWidth( r.width()-1 );

  selected()->setRect(r);

  commandHistory()->addCommand(
    new ResizeCommand( this, selected(), oldArea ) ,true );
  slotAreaChanged(selected());
  slotUpdateSelectionCoords();
}

void KImageMapEditor::slotHightlightAreas()
{
  bool b = highlightAreasAction->isChecked();

//  highlightAreasAction->setChecked(b);
  Area::highlightArea = b;
  updateAllAreas();
  drawZone->viewport()->repaint();
}

void KImageMapEditor::slotShowAltTag()
{
  bool b = showAltAction->isChecked();
//  showAltAction->setChecked(b);
  Area::showAlt = b;
  drawZone->viewport()->repaint();
}

void KImageMapEditor::mapNew()
{
    QString mapName = mapsListView->getUnusedMapName();
    addMap(mapName);
    mapEditName();
}

void KImageMapEditor::mapDelete()
{
  if (mapsListView->count() == 0)
     return;

  QString selectedMap = mapsListView->selectedMap();

  int result = KMessageBox::warningContinueCancel(widget(),
    i18n("<qt>Are you sure you want to delete the map <i>%1</i>?"
         " <br><b>There is no way to undo this.</b></qt>").arg(selectedMap),
    i18n("Delete Map?"),KGuiItem(i18n("&Delete"),"editdelete"));

  if (result == KMessageBox::No)
     return;



  mapsListView->removeMap(selectedMap);
  HtmlMapElement* mapEl = findHtmlMapElement(selectedMap);
  _htmlContent.remove(mapEl);
  if (mapsListView->count() == 0) {

      currentMapElement = 0L;
      deleteAllAreas();
      setMapActionsEnabled(false);
  }
  else {
      // The old one was deleted, so the new one got selected
      setMap(mapsListView->selectedMap());
  }
}

void KImageMapEditor::mapPreview() {
  HTMLPreviewDialog dialog(widget(), url(), getHtmlCode());
  dialog.exec();
}

void KImageMapEditor::deleteAllMaps()
{
  deleteAllAreas();
  mapsListView->clear();
  if (isReadWrite()) {
    mapDeleteAction->setEnabled(false);
    mapDefaultAreaAction->setEnabled(false);
    mapNameAction->setEnabled(false);
  }
}

/**
 * Doesn't call the closeURL method, because
 * we need the URL for the session management
 */
bool KImageMapEditor::queryClose() {
  if ( ! isModified() )
     return true;

  switch ( KMessageBox::warningYesNoCancel( widget(),
   i18n("<qt>The file <i>%1</i> has been modified.<br>Do you want to save it?</qt>").arg(url().fileName()), QString::null, KStdGuiItem::save(), KStdGuiItem::discard()) ) {
           case KMessageBox::Yes :
             saveFile();
             return true;
           case KMessageBox::No :
             return true;
           default:
             return false;
  }
}

bool KImageMapEditor::closeURL()
{
  bool result = KParts::ReadWritePart::closeURL();
  if (!result)
     return false;

  _htmlContent.clear();
  deleteAllMaps();
  imagesListView->clear();

  delete copyArea;
  copyArea=0L;

  delete defaultArea;
  defaultArea=0L;

  currentMapElement = 0L;

  init();
  emit setWindowCaption("");

  return true;

}

void KImageMapEditor::addImage(const KURL & imgUrl) {
    if (imgUrl.isEmpty())
        return;

    QString relativePath ( QExtFileInfo::toRelative(imgUrl, KURL( url().directory() )).path() );

    QString imgHtml = QString("<img src=\"")+relativePath+QString("\">");
    ImageTag *imgTag = new ImageTag();
    imgTag->insert("tagname",new QString("img"));
    imgTag->insert("src", new QString(relativePath));

    HtmlImgElement *imgEl = new HtmlImgElement(imgHtml);
    imgEl->imgTag = imgTag;

    HtmlElement *bodyEl = findHtmlElement("<body");
    if (bodyEl) {
        int bodyIndex = _htmlContent.find(bodyEl);
        _htmlContent.insert(bodyIndex+1, new HtmlElement("\n"));
        _htmlContent.insert(bodyIndex+2, imgEl);
    }
    else {
        _htmlContent.append(new HtmlElement("\n"));
        _htmlContent.append(imgEl);
    }

    imagesListView->addImage(imgTag);
    imagesListView->selectImage(imgTag);
    setImageActionsEnabled(true);

    setModified(true);
}

/**
 * Sets whether the image actions that depend on an
 * selected image are enabled
 */
void KImageMapEditor::setImageActionsEnabled(bool b) {
  imageRemoveAction->setEnabled(b);
  imageUsemapAction->setEnabled(b);
}


void KImageMapEditor::imageAdd() {
    KURL imgUrl = KFileDialog::getImageOpenURL();
    addImage(imgUrl);
}

void KImageMapEditor::imageRemove() {
    ImageTag* imgTag = imagesListView->selectedImage();
    HtmlImgElement* imgEl = findHtmlImgElement(imgTag);
    imagesListView->removeImage(imgTag);
    _htmlContent.remove(imgEl);

    if (imagesListView->childCount() == 0) {
        setPicture(getBackgroundImage());
        setImageActionsEnabled(false);
    }
    else {
        ImageTag* selected = imagesListView->selectedImage();
        if (selected) {
            QString *url = selected->find("src");
            if (url) {
                setPicture(KURL(*url));
            }
        }
    }

    setModified(true);
}

void KImageMapEditor::imageUsemap() {

  bool ok=false;
  ImageTag* imageTag = imagesListView->selectedImage();
  if ( ! imageTag)
     return;

  QString usemap;

  if (imageTag->find("usemap"))
      usemap=*imageTag->find("usemap");

  QStringList maps = mapsListView->getMaps();
  int index = maps.findIndex(usemap);
  if (index == -1) {
    maps.prepend("");
    index = 0;
  }

#if KDE_IS_VERSION(3, 1, 90)
  QString input = KInputDialog::getItem(i18n("Enter Usemap"),
#else
  QString input = QInputDialog::getItem(i18n("Enter Usemap"),
#endif
    i18n("Enter the usemap value:"),
    maps,index,true,&ok,widget());
  if (ok) {
     imageTag->replace("usemap", new QString(input));
     imagesListView->updateImage(imageTag);
     setModified(true);

     // Update the htmlCode of the HtmlElement
     HtmlImgElement* imgEl = findHtmlImgElement(imageTag);

     imgEl->htmlCode = "<";
     QString *tagName = imgEl->imgTag->find("tagname");
     imgEl->htmlCode += QString(*tagName);

     QDictIterator<QString> it( *imgEl->imgTag );
     for( ; it.current(); ++it ) {
        if (it.currentKey() != "tagname") {
           imgEl->htmlCode += " " + it.currentKey() + "=\"";
           imgEl->htmlCode += *it.current();
           imgEl->htmlCode += "\"";
        }
     }

     imgEl->htmlCode += ">";

  }
}

void KImageMapEditor::configureShowAreaList() {
  if (configureShowAreaListAction->isChecked())
    mainDock->makeDockVisible(areaDock);
  else
    mainDock->makeDockInvisible(areaDock);
}

void KImageMapEditor::configureShowMapList() {
  if (configureShowMapListAction->isChecked())
    mainDock->makeDockVisible(mapsDock);
  else
    mainDock->makeDockInvisible(mapsDock);
}

void KImageMapEditor::configureShowImageList() {
  if (configureShowImageListAction->isChecked())
    mainDock->makeDockVisible(imagesDock);
  else
    mainDock->makeDockInvisible(imagesDock);
}

void KImageMapEditor::dockingStateChanged() {
  if (areaDock) {
    configureShowImageListAction->setChecked( imagesDock->isVisible() );
    configureShowAreaListAction->setChecked( areaDock->isVisible() );
    configureShowMapListAction->setChecked( mapsDock->isVisible() );
  }
}
