#include "mapeditor.h"

#include <QGraphicsProxyWidget>
#include <QMenuBar>
#include <QObject>
#include <QPrintDialog>
#include <QPrinter>
#include <QScrollBar>

#include "branchitem.h"
#include "geometry.h"
#include "mainwindow.h"
#include "misc.h"
#include "shortcuts.h"
#include "warningdialog.h"
#include "winter.h"
#include "xlinkitem.h"

extern Main *mainWindow;
extern QString clipboardDir;
extern QString clipboardFile;
extern bool debug;
extern QPrinter *printer;

extern QMenu *branchContextMenu;
extern QMenu *canvasContextMenu;
extern QMenu *floatimageContextMenu;
extern QMenu *taskContextMenu;

extern Switchboard switchboard;
extern Settings settings;

extern QTextStream vout;

extern QString editorFocusStyle;

extern FlagRowMaster *systemFlagsMaster;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
MapEditor::MapEditor(VymModel *vm)
{
    // qDebug() << "Constructor ME " << this;

    QString shortcutScope = tr("Map Editor", "Shortcut scope");
    mapScene = new QGraphicsScene(NULL);
    mapScene->setBackgroundBrush(QBrush(Qt::white, Qt::SolidPattern));
    mapScene->setItemIndexMethod(QGraphicsScene::NoIndex);  // FIXME-2 Avoiding crashes...
                                                            // Alternatively call removeFromIndex() in destructor
                                                            // or maybe also prepareGeometryChange()

    zoomFactor = zoomFactorTarget = 1;
    angle = angleTarget = 0;

    model = vm;
    model->registerMapEditor(this);

    setScene(mapScene);

    setStyleSheet("QGraphicsView:focus {" + editorFocusStyle + "}");

    // Create bitmap cursors, platform dependant
    HandOpenCursor = QCursor(QPixmap(":/mode-move-view.png"), 1, 1);
    PickColorCursor = QCursor(QPixmap(":/cursorcolorpicker.png"), 5, 27);
    XLinkCursor = QCursor(QPixmap(":/cursorxlink.png"), 1, 7);

    editingBO = NULL;

    printFrame = true;
    printFooter = true;

    setAcceptDrops(true);

    // Shortcuts and actions
    QAction *a;

    a = new QAction("Select upper branch", this);
    a->setShortcut(Qt::Key_Up);
    a->setShortcutContext(Qt::WidgetShortcut);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorUp()));
    addAction(a);

    a = new QAction("Add upper branch to selection", this);
    a->setShortcut(Qt::Key_Up + Qt::SHIFT);
    a->setShortcutContext(Qt::WidgetShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorUpToggleSelection()));

    a = new QAction("Select lower branch", this);
    a->setShortcut(Qt::Key_Down);
    a->setShortcutContext(Qt::WidgetShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorDown()));

    a = new QAction("Add lower branch to selection", this);
    a->setShortcut(Qt::Key_Down + Qt::SHIFT);
    a->setShortcutContext(Qt::WidgetShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorDownToggleSelection()));

    a = new QAction("Select left branch", this);
    a->setShortcut(Qt::Key_Left);
    //  a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorLeft()));

    a = new QAction("Select child branch", this);
    a->setShortcut(Qt::Key_Right);
    //  a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorRight()));

    a = new QAction("Select first branch", this);
    a->setShortcut(Qt::Key_Home);
    a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorFirst()));

    a = new QAction("Select last branch", this);
    a->setShortcut(Qt::Key_End);
    a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(cursorLast()));

    // Action to embed LineEdit for heading in Scene
    lineEdit = NULL;

    a = new QAction(tr("Edit heading", "MapEditor"), this);
    a->setShortcut(Qt::Key_Return); // Edit heading
    a->setShortcutContext(Qt::WidgetShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(editHeading()));
    a = new QAction(tr("Edit heading", "MapEditor"), this);
    a->setShortcut(Qt::Key_Enter); // Edit heading
    a->setShortcutContext(Qt::WidgetShortcut);
    addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(editHeading()));

    // Selections
    selectionPen = QPen(QColor(255,255,0), 1);
    selectionBrush = QBrush(QColor(255,255,0));

    // Panning
    panningTimer = new QTimer(this);
    vPan = QPointF();
    connect(panningTimer, SIGNAL(timeout()), this, SLOT(panView()));

    // Clone actions defined in MainWindow
    foreach (QAction *qa, mainWindow->mapEditorActions) {
        a = new QAction(this);
        a->setShortcut(qa->shortcut());
        a->setShortcutContext(qa->shortcutContext());
        connect(a, SIGNAL(triggered()), qa, SLOT(trigger()));
        addAction(a);
    }

    setState(Neutral);

    winter = NULL;
}

MapEditor::~MapEditor()
{
    // qDebug ()<<"Destr MapEditor this="<<this;

    if (winter) {
        delete winter;
        winter = NULL;
    }
}

VymModel *MapEditor::getModel() { return model; }

QGraphicsScene *MapEditor::getScene() { return mapScene; }

void MapEditor::panView()
{
    if (!vPan.isNull()) {
        // Scroll if needed
        // To avoid jumping of the sceneView, only
        // show selection, if not tmp linked
        qreal px = 0;
        qreal py = 0;
        if (vPan.x() < 0)
            px = vPan.x();
        else if (vPan.x() > 0)
            px = width() + vPan.x();
        if (vPan.y() < 0)
            py = vPan.y();
        else if (vPan.y() > 0)
            py = height() + vPan.y();

        QPointF q = mapToScene(QPoint(px, py));
        QRectF r = QRectF(q, QPointF(q.x() + 1, q.y() + 1));

        // Expand view if necessary
        setScrollBarPosTarget(r);   // FIXME-2   mapToScene first?   

        // Stop possible other animations
        if (scrollBarPosAnimation.state() == QAbstractAnimation::Running)
            scrollBarPosAnimation.stop();

        // Do linear animation
        horizontalScrollBar()->setValue(horizontalScrollBar()->value() +
                                        vPan.x());
        verticalScrollBar()->setValue(verticalScrollBar()->value() + vPan.y());

        // Update currently moving object
        moveObject();
    }
}

void MapEditor::ensureAreaVisibleAnimated(const QRectF &area, bool maximizeArea) // FIXME-2 zooming in not working yet (fit to selection)
{
    // Changes viewCenter to make sure that 
    // r is  within the margins of the viewport
    //
    // Only zooms, if r NOT fit into viewport 
    // view is centered then on bounding box.
    //
    // Similar to QGraphicsItem::ensureVisible, 
    // but with animation and (if necessary)
    // zooming

    int xmargin = settings.value("/mapeditor/scrollToMarginX/", 50).toInt();
    int ymargin = settings.value("/mapeditor/scrollToMarginY/", 50).toInt();

    // Do we need to zoom out to show area?
    QRect areaViewCoord = mapFromScene(area).boundingRect();

    // Visible area within margins
    QRect visibleViewCoord = rect();
    visibleViewCoord -= QMargins(xmargin, ymargin, xmargin, ymargin);


    // Calculate required width and height considering rotation of view
    qreal a = angle / 180 * M_PI;
    qreal area_w_viewCoord = abs(sin(a) * area.height()) + abs(cos(a) * area.width());
    qreal area_h_viewCoord = abs(sin(a) * area.width()) + abs(cos(a) * area.height());
    qreal z_x = 1.0 * visibleViewCoord.width() / area_w_viewCoord;
    qreal z_y = 1.0 * visibleViewCoord.height() / area_h_viewCoord;

    qreal zf = min (z_x, z_y);

    bool zoomOutRequired = 
        (visibleViewCoord.width() < areaViewCoord.width() ||
         visibleViewCoord.height() < areaViewCoord.height());
    bool zoomInRequired = 
        (visibleViewCoord.width() > areaViewCoord.width() &&
         visibleViewCoord.height() > areaViewCoord.height());

    //qDebug() << " zoom out: " << zoomOutRequired;
    //qDebug() << " zoom  in: " << zoomInRequired << " zoomFactor=" << zoomFactor << " zf=" << zf;
    if (zoomOutRequired || maximizeArea) {
        setViewCenterTarget(area.center(), zf, angle);
        return;
    }


    // After zooming bbox would fit into margins of viewport
    long view_dx = 0;
    long view_dy = 0;
    if (areaViewCoord.left() < xmargin)
        // move left
        view_dx = areaViewCoord.left() - xmargin;
    else if (areaViewCoord.right() > viewport()->width())
        // move right
        view_dx = areaViewCoord.x() + areaViewCoord.width() - viewport()->width() + xmargin;

    if (areaViewCoord.top() < ymargin)
        // move up
        view_dy = areaViewCoord.top() - ymargin;
    else if (areaViewCoord.bottom() > viewport()->height() - ymargin)
        // move down
        view_dy = areaViewCoord.y() + areaViewCoord.height() - viewport()->height() + ymargin;

    if (abs(view_dx) > 5 || abs(view_dy) > 5)
        setViewCenterTarget(
                mapToScene(viewport()->geometry().center() + QPoint (view_dx, view_dy)),
                zoomFactor,
                angle,
                2000,
                QEasingCurve::OutQuint);
}

void MapEditor::ensureSelectionVisibleAnimated(bool maximizeArea)
{
    // Changes viewCenter to make sure that bounding box of all currently
    // selected items is  within the margins of the viewport
    //
    // Only zooms, if bounding box of items does NOT fit into viewport 
    // view is centered then on bounding box. (Useful also for big images)
    //
    // Similar to QGraphicsItem::ensureVisible, but with animation and (if necessary)
    // zooming

    QList <TreeItem*> selis = model->getSelectedItems();

    // Nothing to do, if nothing is selected
    if (selis.isEmpty()) return;

    // Calculate total bounding box
    QRectF bbox;
    bool firstIteration = true;

    foreach (TreeItem *ti, selis) {
        LinkableMapObj *lmo = nullptr;
        if (ti->getType() == TreeItem::Image || ti->isBranchLikeType())
            lmo = ((MapItem *)ti)->getLMO();
        if (lmo) {
            if (firstIteration) {
                bbox = lmo->getBBox();
                firstIteration = false;
            } else
                bbox = bbox.united(lmo->getBBox());
        }
    }

    ensureAreaVisibleAnimated(bbox, maximizeArea);
}

void MapEditor::scrollTo(const QModelIndex &index)
{
    if (index.isValid()) {
        LinkableMapObj *lmo = NULL;
        TreeItem *ti = static_cast<TreeItem *>(index.internalPointer());
        if (ti->getType() == TreeItem::Image || ti->isBranchLikeType())
            lmo = ((MapItem *)ti)->getLMO();
        if (lmo) {
            QRectF r = lmo->getBBox();
            setScrollBarPosTarget(r);
            animateScrollBars();
        }
    }
}

void MapEditor::setScrollBarPosTarget(QRectF rect)
{
    // Expand viewport, if rect is not contained
    if (!sceneRect().contains(rect))
        setSceneRect(sceneRect().united(rect));

    int xmargin = settings.value("/mapeditor/scrollToMarginX/", 80).toInt();
    int ymargin = settings.value("/mapeditor/scrollToMarginX/", 80).toInt();

    // Prepare scrolling
    qreal width = viewport()->width();
    qreal height = viewport()->height();
    QRectF viewRect = transform().scale(zoomFactorTarget, zoomFactorTarget).mapRect(rect);

    qreal left = horizontalScrollBar()->value();
    qreal right = left + width;
    qreal top = verticalScrollBar()->value();
    qreal bottom = top + height;

    scrollBarPosTarget = getScrollBarPos();

    if (viewRect.left() <= left + xmargin) {
        // need to scroll from the left
        scrollBarPosTarget.setX(int(viewRect.left() - xmargin - 0.5));
    }
    if (viewRect.right() >= right - xmargin) {
        // need to scroll from the right
        scrollBarPosTarget.setX(int(viewRect.right() - width + xmargin + 0.5));
    }
    if (viewRect.top() <= top + ymargin) {
        // need to scroll from the top
        scrollBarPosTarget.setY(int(viewRect.top() - ymargin - 0.5));
    }
    if (viewRect.bottom() >= bottom - ymargin) {
        // need to scroll from the bottom
        scrollBarPosTarget.setY(
            int(viewRect.bottom() - height + ymargin + 0.5));
    }
}

QPointF MapEditor::getScrollBarPosTarget() { return scrollBarPosTarget; }

void MapEditor::setScrollBarPos(const QPointF &p)
{
    scrollBarPos = p;
    horizontalScrollBar()->setValue(int(p.x()));
    verticalScrollBar()->setValue(int(p.y()));
}

QPointF MapEditor::getScrollBarPos()
{
    return QPointF(horizontalScrollBar()->value(),
                   verticalScrollBar()->value());
    // return scrollBarPos;
}

void MapEditor::animateScrollBars()
{
    if (scrollBarPosAnimation.state() == QAbstractAnimation::Running)
        scrollBarPosAnimation.stop();

    if (settings.value("/animation/use/", true).toBool()) {
        scrollBarPosAnimation.setTargetObject(this);
        scrollBarPosAnimation.setPropertyName("scrollBarPos");
        scrollBarPosAnimation.setDuration(
            settings.value("/animation/duration/scrollbar", 2000).toInt());
        scrollBarPosAnimation.setEasingCurve(QEasingCurve::OutQuint);
        scrollBarPosAnimation.setStartValue(QPointF(
            horizontalScrollBar()->value(), verticalScrollBar()->value()));
        scrollBarPosAnimation.setEndValue(scrollBarPosTarget);
        scrollBarPosAnimation.start();
    }
    else
        setScrollBarPos(scrollBarPosTarget);
}

void MapEditor::setZoomFactorTarget(const qreal &zft)
{
    zoomFactorTarget = zft;
    if (zoomAnimation.state() == QAbstractAnimation::Running)
        zoomAnimation.stop();
    if (settings.value("/animation/use/", true).toBool()) {
        zoomAnimation.setTargetObject(this);
        zoomAnimation.setPropertyName("zoomFactor");
        zoomAnimation.setDuration(
            settings.value("/animation/duration/zoom", 2000).toInt());
        zoomAnimation.setEasingCurve(QEasingCurve::OutQuint);
        zoomAnimation.setStartValue(zoomFactor);
        zoomAnimation.setEndValue(zft);
        zoomAnimation.start();
    }
    else
        setZoomFactor(zft);
}

qreal MapEditor::getZoomFactorTarget() { return zoomFactorTarget; }

void MapEditor::setZoomFactor(const qreal &zf)
{
    zoomFactor = zf;
    updateMatrix();
}

qreal MapEditor::getZoomFactor() { return zoomFactor; }

void MapEditor::setAngleTarget(const qreal &at)
{
    angleTarget = at;
    if (rotationAnimation.state() == QAbstractAnimation::Running)
        rotationAnimation.stop();
    if (settings.value("/animation/use/", true).toBool()) {
        rotationAnimation.setTargetObject(this);
        rotationAnimation.setPropertyName("angle");
        rotationAnimation.setDuration(
            settings.value("/animation/duration/rotation", 2000).toInt());
        rotationAnimation.setEasingCurve(QEasingCurve::OutQuint);
        rotationAnimation.setStartValue(angle);
        rotationAnimation.setEndValue(at);
        rotationAnimation.start();
    }
    else
        setAngle(angleTarget);
}

qreal MapEditor::getAngleTarget() { return angleTarget; }

void MapEditor::setAngle(const qreal &a)
{
    angle = a;
    updateMatrix();
    if (winter)
        winter->updateView();
}

qreal MapEditor::getAngle() { return angle; }

void MapEditor::setViewCenterTarget(const QPointF &p, const qreal &zft,
                                    const qreal &at, const int duration,
                                    const QEasingCurve &easingCurve)
{
    viewCenterTarget = p;
    zoomFactorTarget = zft;
    angleTarget = at;

    viewCenter = mapToScene(viewport()->geometry()).boundingRect().center();

    if (viewCenterAnimation.state() == QAbstractAnimation::Running)
        viewCenterAnimation.stop();
    if (rotationAnimation.state() == QAbstractAnimation::Running)
        rotationAnimation.stop();
    if (zoomAnimation.state() == QAbstractAnimation::Running)
        zoomAnimation.stop();

    if (settings.value("/animation/use/", true).toBool()) {
        viewCenterAnimation.setTargetObject(this);
        viewCenterAnimation.setPropertyName("viewCenter");
        viewCenterAnimation.setDuration(
            settings.value("/animation/duration/scrollbar", duration).toInt());
        viewCenterAnimation.setEasingCurve(easingCurve);
        viewCenterAnimation.setStartValue(viewCenter);
        viewCenterAnimation.setEndValue(viewCenterTarget);
        viewCenterAnimation.start();

        rotationAnimation.setTargetObject(this);
        rotationAnimation.setPropertyName("angle");
        rotationAnimation.setDuration(
            settings.value("/animation/duration/rotation", duration).toInt());
        rotationAnimation.setEasingCurve(easingCurve);
        rotationAnimation.setStartValue(angle);
        rotationAnimation.setEndValue(angleTarget);
        rotationAnimation.start();

        zoomAnimation.setTargetObject(this);
        zoomAnimation.setPropertyName("zoomFactor");
        zoomAnimation.setDuration(
            settings.value("/animation/duration/zoom", duration).toInt());
        zoomAnimation.setEasingCurve(easingCurve);
        zoomAnimation.setStartValue(zoomFactor);
        zoomAnimation.setEndValue(zoomFactorTarget);
        zoomAnimation.start();
    }
    else {
        setAngle(angleTarget);
        setZoomFactor(zft);
        setViewCenter(viewCenterTarget);
    }
}

void MapEditor::setViewCenterTarget()
{
    MapItem *selti = (MapItem *)(model->getSelectedItem());
    if (selti) {
        LinkableMapObj *lmo = selti->getLMO();
        if (lmo)
            setViewCenterTarget(lmo->getBBox().center(), 1, 0);
    }
}

QPointF MapEditor::getViewCenterTarget() { return viewCenterTarget; }

void MapEditor::setViewCenter(const QPointF &vc) { centerOn(vc); }

QPointF MapEditor::getViewCenter() { return viewCenter; }

void MapEditor::updateMatrix()
{
    QTransform t_zoom;
    t_zoom.scale(zoomFactor, zoomFactor);
    QTransform t_rot;
    t_rot.rotate(angle);
    setTransform(t_zoom * t_rot);
}

void MapEditor::minimizeView() {
    // If we only would set scene rectangle to existing items, then 
    // view fould "jump", when Qt automatically tries to center. 
    // Better consider the currently visible viewport (with slight offset)
    QRectF r = mapToScene(viewport()->geometry()).boundingRect();
    r.translate(-2,-3);
    setSceneRect(scene()->itemsBoundingRect().united(r));
}

void MapEditor::print()
{
    QRectF totalBBox = getTotalBBox();

    if (!printer)
        printer = mainWindow->setupPrinter();

    // Try to set orientation automagically
    // Note: Interpretation of generated postscript is amibiguous, if
    // there are problems with landscape mode, see
    // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html

    if (totalBBox.width() > totalBBox.height())
        // recommend landscape
        printer->setPageOrientation(QPageLayout::Landscape);
    else
        // recommend portrait
        printer->setPageOrientation(QPageLayout::Portrait);

    QPrintDialog dialog(printer, this);
    dialog.setWindowTitle(tr("Print vym map", "MapEditor"));
    if (dialog.exec() == QDialog::Accepted) {
        QPainter pp(printer);

        pp.setRenderHint(QPainter::Antialiasing, true);

        // Don't print the visualisation of selection
        model->unselectAll();

        QRectF mapRect = totalBBox;
        QGraphicsRectItem *frame = NULL;

        if (printFrame) {
            // Print frame around map
            mapRect.setRect(totalBBox.x() - 10, totalBBox.y() - 10,
                            totalBBox.width() + 20, totalBBox.height() + 20);
            frame = mapScene->addRect(mapRect, QPen(Qt::black),
                                      QBrush(Qt::NoBrush));
            frame->setZValue(0);
            frame->show();
        }

        double paperAspect =
            (double)printer->width() / (double)printer->height();
        double mapAspect = (double)mapRect.width() / (double)mapRect.height();
        int viewBottom;
        if (mapAspect >= paperAspect) {
            // Fit horizontally to paper width
            // pp.setViewport(0,0,
            // printer->width(),(int)(printer->width()/mapAspect) );
            viewBottom = (int)(printer->width() / mapAspect);
        }
        else {
            // Fit vertically to paper height
            // pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height());
            viewBottom = printer->height();
        }

        if (printFooter) {
            // Print footer below map
            QFont font;
            font.setPointSize(10);
            pp.setFont(font);
            QRectF footerBox(0, viewBottom, printer->width(), 15);
            pp.drawText(footerBox, Qt::AlignLeft,
                        "VYM - " + model->getFileName());
            pp.drawText(footerBox, Qt::AlignRight,
                        QDate::currentDate().toString(Qt::TextDate));
        }
        mapScene->render(&pp,
                         QRectF(0, 0, printer->width(), printer->height() - 15),
                         QRectF(mapRect.x(), mapRect.y(), mapRect.width(),
                                mapRect.height()));

        // Viewport has paper dimension
        if (frame)
            delete (frame);

        // Restore selection
        model->reselect();
    }
}

QRectF MapEditor::getTotalBBox()    // FIXME-2 really needed? Overlaps with scene and VM...
{
    minimizeView();
    return sceneRect();
}

QImage MapEditor::getImage(QPointF &offset)
{
    QRectF mapRect = getTotalBBox(); // minimized sceneRect

    int d = 10; // border
    offset = QPointF(mapRect.x() - d / 2, mapRect.y() - d / 2);
    QImage pix(mapRect.width() + d, mapRect.height() + d, QImage::Format_RGB32);

    QPainter pp(&pix);
    pp.setRenderHints(renderHints());
    mapScene->render(&pp,
                     // Destination:
                     QRectF(0, 0, mapRect.width() + d, mapRect.height() + d),
                     // Source in scene:
                     QRectF(mapRect.x() - d / 2, mapRect.y() - d / 2,
                            mapRect.width() + d, mapRect.height() + d));
    return pix;
}

void MapEditor::setAntiAlias(bool b)
{
    setRenderHint(QPainter::Antialiasing, b);
}

void MapEditor::setSmoothPixmap(bool b)
{
    setRenderHint(QPainter::SmoothPixmapTransform, b);
}

void MapEditor::autoLayout()
{
    // Create list with all bounding polygons
    QList<LinkableMapObj *> mapobjects;
    QList<ConvexPolygon> polys;
    ConvexPolygon p;
    QList<Vector> vectors;
    QList<Vector> orgpos;
    QStringList headings; // FIXME-3 testing only
    Vector v;
    BranchItem *bi;
    BranchItem *bi2;
    BranchObj *bo;

    // Outer loop: Iterate until we no more changes in orientation
    bool orientationChanged = true;
    while (orientationChanged) {
        BranchItem *ri = model->getRootItem();
        for (int i = 0; i < ri->branchCount(); ++i) {
            bi = ri->getBranchNum(i);
            bo = (BranchObj *)bi->getLMO();
            if (bo) {
                mapobjects.append(bo);
                p = bo->getBoundingPolygon();
                p.calcCentroid();
                polys.append(p);
                vectors.append(QPointF(0, 0));
                orgpos.append(p.at(0));
                headings.append(bi->getHeadingPlain());
            }
            for (int j = 0; j < bi->branchCount(); ++j) {
                bi2 = bi->getBranchNum(j);
                bo = (BranchObj *)bi2->getLMO();
                if (bo) {
                    mapobjects.append(bo);
                    p = bo->getBoundingPolygon();
                    p.calcCentroid();
                    polys.append(p);
                    vectors.append(QPointF(0, 0));
                    orgpos.append(p.at(0));
                    headings.append(bi2->getHeadingPlain());
                }
            }
        }

        // Iterate moving bounding polygons until we have no more collisions
        int collisions = 1;
        while (collisions > 0) {
            collisions = 0;
            for (int i = 0; i < polys.size() - 1; ++i) {
                for (int j = i + 1; j < polys.size(); ++j) {
                    if (polygonCollision(polys.at(i), polys.at(j),
                                         QPointF(0, 0))
                            .intersect) {
                        collisions++;
                        if (debug)
                            qDebug() << "Collision: " << headings[i] << " - "
                                     << headings[j];
                        v = polys.at(j).centroid() - polys.at(i).centroid();
                        v.normalize();
                        // Add random direction, if only two polygons with
                        // identical y or x
                        if (v.x() == 0 || v.y() == 0) {
                            Vector w(cos(double((int)rand() % 1000)),
                                     sin(double((int)rand() % 1000)));
                            w.normalize();
                            v = v + w;
                        }

                        // Scale translation vector by area of polygons
                        vectors[j] = v * 10000 / polys.at(j).weight();
                        vectors[i] = v * 10000 / polys.at(i).weight();
                        vectors[i].invert();
                        // FIXME-3 outer loop, "i" get's changed several
                        // times...
                        // Better not move away from centroid of 2 colliding
                        // polys, but from centroid of _all_
                    }
                }
            }
            for (int i = 0; i < vectors.size(); i++) {
                // qDebug() << " v="<<vectors[i]<<" "<<headings[i];
                if (!vectors[i].isNull())
                    polys[i].translate(vectors[i]);
            }
            // if (debug) qDebug()<< "Collisions total: "<<collisions;
            // collisions=0;
        }

        // Finally move the real objects and update
        QList<LinkableMapObj::Orientation> orients;
        for (int i = 0; i < polys.size(); i++) {
            Vector v = polys[i].at(0) - orgpos[i];
            orients.append(mapobjects[i]->getOrientation());
            if (!v.isNull()) {
                if (debug)
                    qDebug() << " Moving " << polys.at(i).weight() << " "
                             << mapobjects[i]->getAbsPos() << " -> "
                             << mapobjects[i]->getAbsPos() + v << "  "
                             << headings[i];
                // mapobjects[i]->moveBy(v.x(),v.y() );
                // mapobjects[i]->setRelPos();
                model->startAnimation((BranchObj *)mapobjects[i], v);
                if (debug)
                    qDebug() << i << " Weight: " << polys.at(i).weight() << " "
                             << v << " " << headings.at(i);
            }
        }
        /*
        model->reposition();
        orientationChanged=false;
        for (int i=0;i<polys.size();i++)
            if (orients[i]!=mapobjects[i]->getOrientation())
            {
            orientationChanged=true;
            break;
            }
        */

        break;

        // orientationChanged=false;
    } // loop if orientation has changed

    model->emitSelectionChanged();
}

TreeItem *MapEditor::findMapItem(QPointF p, TreeItem *exclude)
{
    // Search XLinks
    Link *link;
    for (int i = 0; i < model->xlinkCount(); i++) {
        link = model->getXLinkNum(i);
        if (link) {
            XLinkObj *xlo = link->getXLinkObj();
            if (xlo && xlo->isInClickBox(p)) {
                // Found XLink, now return the nearest XLinkItem of p
                qreal d0 = Geometry::distance(p, xlo->getBeginPos());
                qreal d1 = Geometry::distance(p, xlo->getEndPos());
                if (d0 > d1)
                    return link->getBeginLinkItem();
                else
                    return link->getEndLinkItem();
            }
        }
    }

    // Search branches (and their childs, e.g. images
    // Start with mapcenter, no images allowed at rootItem
    int i = 0;
    BranchItem *bi = model->getRootItem()->getFirstBranch();
    TreeItem *found = NULL;
    while (bi) {
        found = bi->findMapItem(p, exclude);
        if (found)
            return found;
        i++;
        bi = model->getRootItem()->getBranchNum(i);
    }
    return NULL;
}

void MapEditor::testFunction1() {}

void MapEditor::testFunction2() { autoLayout(); }

void MapEditor::toggleWinter()
{
    if (winter) {
        delete winter;
        winter = NULL;
    }
    else {
        winter = new Winter(this);
        QList<QRectF> obstacles;
        BranchObj *bo;
        BranchItem *cur = NULL;
        BranchItem *prev = NULL;
        model->nextBranch(cur, prev);
        while (cur) {
            if (!cur->hasHiddenExportParent()) {
                // Branches
                bo = (BranchObj *)(cur->getLMO());
                if (bo && bo->isVisibleObj())
                    obstacles.append(bo->getBBox());
            }
            model->nextBranch(cur, prev);
        }
        winter->setObstacles(obstacles);
    }
}

BranchItem *MapEditor::getBranchDirectAbove(BranchItem *bi)
{
    if (bi) {
        int i = bi->num();
        if (i > 0)
            return bi->parent()->getBranchNum(i - 1);
    }
    return NULL;
}

BranchItem *MapEditor::getBranchAbove(BranchItem *selbi)
{
    if (selbi) {
        int dz = selbi->depth(); // original depth
        bool invert = false;
        if (selbi->getLMO()->getOrientation() == LinkableMapObj::LeftOfCenter)
            invert = true;

        BranchItem *bi;

        // Look for branch with same parent but directly above
        if (dz == 1 && invert)
            bi = getBranchDirectBelow(selbi);
        else
            bi = getBranchDirectAbove(selbi);

        if (bi)
            // direct predecessor
            return bi;

        // Go towards center and look for predecessor
        while (selbi->depth() > 0) {
            selbi = (BranchItem *)(selbi->parent());
            if (selbi->depth() == 1 && invert)
                bi = getBranchDirectBelow(selbi);
            else
                bi = getBranchDirectAbove(selbi);
            if (bi) {
                // turn
                selbi = bi;
                while (selbi->depth() < dz) {
                    // try to get back to original depth dz
                    bi = selbi->getLastBranch();
                    if (!bi) {
                        return selbi;
                    }
                    selbi = bi;
                }
                return selbi;
            }
        }
    }
    return NULL;
}

BranchItem *MapEditor::getBranchDirectBelow(BranchItem *bi)
{
    if (bi) {
        int i = bi->num();
        if (i + 1 < bi->parent()->branchCount())
            return bi->parent()->getBranchNum(i + 1);
    }
    return NULL;
}

BranchItem *MapEditor::getBranchBelow(BranchItem *selbi)
{
    if (selbi) {
        BranchItem *bi;
        int dz = selbi->depth(); // original depth
        bool invert = false;
        if (selbi->getLMO()->getOrientation() == LinkableMapObj::LeftOfCenter)
            invert = true;

        // Look for branch with same parent but directly below
        if (dz == 1 && invert)
            bi = getBranchDirectAbove(selbi);
        else
            bi = getBranchDirectBelow(selbi);
        if (bi)
            // direct successor
            return bi;

        // Go towards center and look for neighbour
        while (selbi->depth() > 0) {
            selbi = (BranchItem *)(selbi->parent());
            if (selbi->depth() == 1 && invert)
                bi = getBranchDirectAbove(selbi);
            else
                bi = getBranchDirectBelow(selbi);
            if (bi) {
                // turn
                selbi = bi;
                while (selbi->depth() < dz) {
                    // try to get back to original depth dz
                    bi = selbi->getFirstBranch();
                    if (!bi) {
                        return selbi;
                    }
                    selbi = bi;
                }
                return selbi;
            }
        }
    }
    return NULL;
}

BranchItem *MapEditor::getLeftBranch(TreeItem *ti)
{
    if (!ti)
        return NULL;

    if (ti->isBranchLikeType()) {
        BranchItem *bi = (BranchItem *)ti;
        if (bi->depth() == 0) {
            // Special case: use alternative selection index
            BranchItem *newbi = bi->getLastSelectedBranchAlt();
            if (!newbi) {
                BranchObj *bo;
                // Try to find a mainbranch left of center
                for (int i = 0; i < bi->branchCount(); i++) {
                    newbi = bi->getBranchNum(i);
                    bo = newbi->getBranchObj();
                    if (bo &&
                        bo->getOrientation() == LinkableMapObj::LeftOfCenter)
                        break;
                }
            }
            return newbi;
        }
        if (bi->getBranchObj()->getOrientation() ==
            LinkableMapObj::RightOfCenter)
            // right of center
            return (BranchItem *)(bi->parent());
        else
            // left of center
            if (bi->getType() == TreeItem::Branch)
            return bi->getLastSelectedBranch();
    }

    if (ti->parent() && ti->parent()->isBranchLikeType())
        return (BranchItem *)(ti->parent());
    return NULL;
}

BranchItem *MapEditor::getRightBranch(TreeItem *ti)
{
    if (!ti)
        return NULL;

    if (ti->isBranchLikeType()) {
        BranchItem *bi = (BranchItem *)ti;
        if (bi->depth() == 0) {
            // Special case: use alternative selection index
            BranchItem *newbi = bi->getLastSelectedBranch();
            if (!newbi) {
                BranchObj *bo;
                // Try to find a mainbranch right of center
                for (int i = 0; i < bi->branchCount(); i++) {
                    newbi = bi->getBranchNum(i);
                    bo = newbi->getBranchObj();
                    if (bo &&
                        bo->getOrientation() == LinkableMapObj::RightOfCenter)
                        qDebug()
                            << "BI found right: " << newbi->getHeadingPlain();
                }
            }
            return newbi;
        }
        if (bi->getBranchObj()->getOrientation() ==
            LinkableMapObj::LeftOfCenter)
            // left of center
            return (BranchItem *)(bi->parent());
        else
            // right of center
            if (bi->getType() == TreeItem::Branch)
            return (BranchItem *)bi->getLastSelectedBranch();
    }

    if (ti->parent() && ti->parent()->isBranchLikeType())
        return (BranchItem *)(ti->parent());

    return NULL;
}

void MapEditor::cursorUp()
{
    if (state == MapEditor::EditingHeading)
        return;

    BranchItem *selbi = model->getSelectedBranch();
    BranchItem *bi;
    if (selbi) {
        // Exactly one branch is currently selected
        bi = getBranchAbove(selbi);
        if (bi) {
            model->select(bi);
        } 
    } else {
        // Nothing selected or already multiple selections
        TreeItem *ti = model->lastToggledItem();
        if (ti && ti->isBranchLikeType()) {
            bi = getBranchAbove( (BranchItem*)ti);
            if (bi) 
                model->select(bi);
        }
    }
}

void MapEditor::cursorUpToggleSelection()
{
    if (state == MapEditor::EditingHeading)
        return;

    BranchItem *selbi = model->getSelectedBranch();
    BranchItem *bi;

    if (selbi) {
        // Exactly one branch is currently selected
        bi = getBranchAbove(selbi);
        if (bi) model->selectToggle(bi);
    } else {
        // Nothing selected or already multiple selections
        TreeItem *ti = model->lastToggledItem();
        if (ti && ti->isBranchLikeType()) {
            if (lastToggleDirection == toggleUp)
                bi = getBranchAbove( (BranchItem*)ti);
            else
                bi = (BranchItem*)ti;

            if (bi) 
                model->selectToggle(bi);
        }
    }
    lastToggleDirection = toggleUp;
}

void MapEditor::cursorDown()
{
    if (state == MapEditor::EditingHeading)
        return;

    BranchItem *selbi = model->getSelectedBranch();
    BranchItem *bi;
    if (selbi) {
        // Exactly one branch is currently selected
        bi = getBranchBelow(selbi);
        if (bi) {
            model->select(bi);
        } 
    } else {
        // Nothing selected or already multiple selections
        TreeItem *ti = model->lastToggledItem();
        if (ti && ti->isBranchLikeType()) {
            bi = getBranchBelow( (BranchItem*)ti);

            if (bi) 
                model->select(bi);
        }
    }
}

void MapEditor::cursorDownToggleSelection()
{
    if (state == MapEditor::EditingHeading)
        return;

    BranchItem *selbi = model->getSelectedBranch();
    BranchItem *bi;
    if (selbi) {
        // Exactly one branch is currently selected
        bi = getBranchBelow(selbi);
        if (bi) {
            model->selectToggle(bi);
        } 
    } else {
        // Nothing selected or already multiple selections
        TreeItem *ti = model->lastToggledItem();
        if (ti && ti->isBranchLikeType()) {
            if (lastToggleDirection == toggleDown)
                bi = getBranchBelow( (BranchItem*)ti);
            else
                bi = (BranchItem*)ti;

            if (bi) 
                model->selectToggle(bi);
        }
    }
    lastToggleDirection = toggleDown;
}

void MapEditor::cursorLeft()
{
    TreeItem *ti = model->getSelectedItem();
    if (!ti) {
        ti = model->lastToggledItem();
        if (!ti) return;
    }

    BranchItem *bi = getLeftBranch(ti);
    if (bi)
        model->select(bi);
    else {
        ImageItem *ii = ti->getFirstImage();
        if (ii)
            model->select(ii);
    }
}

void MapEditor::cursorRight()
{
    TreeItem *ti = model->getSelectedItem();
    if (!ti) {
        ti = model->lastToggledItem();
        if (!ti) return;
    }

    BranchItem *bi = getRightBranch(ti);
    if (bi)
        model->select(bi);
    else {
        ImageItem *ii = ti->getFirstImage();
        if (ii)
            model->select(ii);
    }
}

void MapEditor::cursorFirst() { model->selectFirstBranch(); }

void MapEditor::cursorLast() { model->selectLastBranch(); }

void MapEditor::editHeading()
{
    if (state == EditingHeading) {
        editHeadingFinished();
        return;
    }

    BranchObj *bo = model->getSelectedBranchObj();
    BranchItem *bi = model->getSelectedBranch();
    if (bo && bi) {
        VymText heading = bi->getHeading();
        if (heading.isRichText() || bi->getHeadingPlain().contains("\n")) {
            mainWindow->windowShowHeadingEditor();
            ensureSelectionVisibleAnimated();
            return;
        }
        model->setSelectionBlocked(true);

        lineEdit = new QLineEdit;
        QGraphicsProxyWidget *pw = mapScene->addWidget(lineEdit);
        pw->setZValue(Z_LINEEDIT);
        lineEdit->setCursor(Qt::IBeamCursor);
        lineEdit->setCursorPosition(1);

#if defined(Q_OS_WINDOWS)
        QFont font = lineEdit->font();
        font.setPointSize(font.pointSize() + 4);
        lineEdit->setFont(font);
#endif

        QPointF tl;
        QPointF br;
        qreal w = 230;
        qreal h = 30;
        if (bo->getOrientation() != LinkableMapObj::LeftOfCenter) {
            tl = bo->getOrnamentsBBox().topLeft();
            br = tl + QPointF(w, h);
        }
        else {
            br = bo->getOrnamentsBBox().bottomRight();
            tl = br - QPointF(w, h);
        }
        QRectF r(tl, br);
        lineEdit->setGeometry(r.toRect());
        pw->setGeometry(r.toRect());

        minimizeView();

        // Set focus to MapEditor first
        // To avoid problems with Cursor up/down
        setFocus();

        ensureAreaVisibleAnimated(r);

        if (heading.getTextASCII() == " ")
            heading.setPlainText("");
        lineEdit->setText(heading.getTextASCII());
        lineEdit->setFocus();
        lineEdit->selectAll(); // Hack to enable cursor in lineEdit
        lineEdit->deselect();  // probably a Qt bug...

        setState(EditingHeading);
    }
}

void MapEditor::editHeadingFinished()
{
    if (state != EditingHeading || !lineEdit ) {
        qWarning() << "ME::editHeadingFinished not editing heading!";
    } else {
        lineEdit->clearFocus();
        QString s = lineEdit->text();
        s.replace(QRegExp("\\n"), " "); // Don't paste newline chars
        if (s.length() == 0)
            s = " "; // Don't allow empty lines, which would screw up drawing
        model->setHeadingPlainText(s);
        delete (lineEdit);
        lineEdit = nullptr;

        // FIXME-2 ensureAreaVisible like in starting editing?

        // Maybe reselect previous branch
        mainWindow->editHeadingFinished(model);

        // Autolayout to avoid overlapping branches with longer headings
        if (settings.value("/mainwindow/autoLayout/use", "true") == "true")
            autoLayout();
    }

    model->setSelectionBlocked(false);
    setState(Neutral);
}

void MapEditor::contextMenuEvent(QContextMenuEvent *e)
{
    // Lineedits are already closed by preceding
    // mouseEvent, we don't need to close here.

    QPointF p = mapToScene(e->pos());
    TreeItem *ti = findMapItem(p, NULL);

    if (ti) { // MapObj was found
        model->select(ti);

        LinkableMapObj *lmo = NULL;
        BranchItem *selbi = model->getSelectedBranch();
        if (ti)
            lmo = ((MapItem *)ti)->getLMO();

        // Context Menu
        if (lmo && selbi) {
            QString sysFlagName;
            QUuid uid = ((BranchObj *)lmo)->findSystemFlagUidByPos(p);
            if (!uid.isNull()) {
                Flag *flag = systemFlagsMaster->findFlagByUid(uid);
                if (flag)
                    sysFlagName = flag->getName();
            }

            if (sysFlagName.startsWith("system-task"))
                taskContextMenu->popup(e->globalPos());
            else
                // Context Menu on branch or mapcenter
                branchContextMenu->popup(e->globalPos());
        }
        else {
            if (model->getSelectedImage()) {
                // Context Menu on floatimage
                floatimageContextMenu->popup(e->globalPos());
            }
            else {
                if (model->getSelectedXLink())
                    // Context Menu on XLink
                    model->editXLink();
            }
        }
    }
    else { // No MapObj found, we are on the Canvas itself
        // Context Menu on scene

        // Open context menu synchronously to position new mapcenter
        model->setContextPos(p);
        canvasContextMenu->exec(e->globalPos());
        model->unsetContextPos();
    }
    e->accept();
}

void MapEditor::keyPressEvent(QKeyEvent *e)
{
    if (e->key() == Qt::Key_PageUp || e->key() == Qt::Key_PageDown)
        // Ignore PageUP/Down to avoid scrolling with keys
        return;

    if (e->modifiers() & Qt::ShiftModifier) {
        switch (mainWindow->getModMode()) {
        case Main::ModModePoint:
            setCursor(Qt::ArrowCursor);
            break;
        case Main::ModModeColor:
            setCursor(PickColorCursor);
            break;
        case Main::ModModeXLink:
            setCursor(XLinkCursor);
            break;
        case Main::ModModeMoveObject:
            setCursor(Qt::PointingHandCursor);
            break;
        case Main::ModModeMoveView:
            setCursor(QPixmap(":/mode-move-view.png"));
            break;
        default:
            setCursor(Qt::ArrowCursor);
            break;
        }
    }
    QGraphicsView::keyPressEvent(e);
}

void MapEditor::keyReleaseEvent(QKeyEvent *e)
{
    if (!(e->modifiers() & Qt::ControlModifier))
        setCursor(Qt::ArrowCursor);
}

void MapEditor::startMovingView(QMouseEvent *e)
{
    setState(MovingView);
    movingObj = NULL; // move Content not Obj
    movingObj_offset = e->globalPos();
    movingCont_start =
        QPointF(horizontalScrollBar()->value(), verticalScrollBar()->value());
    movingVec = QPointF(0, 0);
    setCursor(HandOpenCursor);
}

void MapEditor::mousePressEvent(QMouseEvent *e)
{
    // Ignore right clicks
    if (e->button() == Qt::RightButton) {
        e->ignore();
        QGraphicsView::mousePressEvent(e);
        return;
    }

    // Check if we need to reset zoomFactor for middle button + Ctrl
    if (e->button() == Qt::MidButton && e->modifiers() & Qt::ControlModifier) {
        setZoomFactorTarget(1);
        setAngleTarget(0);
        return;
    }

    QPointF p = mapToScene(e->pos());
    TreeItem *ti_found = findMapItem(p, NULL);
    LinkableMapObj *lmo_found = NULL;
    if (ti_found)
        lmo_found = ((MapItem *)ti_found)->getLMO();


    // Allow selecting text in QLineEdit if necessary
    if (model->isSelectionBlocked()) {
        e->ignore();
        QGraphicsView::mousePressEvent(e);
        return;
    }

    // Stop editing in LineEdit
    if (state == EditingHeading) editHeadingFinished();

    QString sysFlagName;
    QUuid uid;
    if (lmo_found) {
        uid = ((BranchObj *)lmo_found)->findSystemFlagUidByPos(p);
        if (!uid.isNull()) {
            Flag *flag = systemFlagsMaster->findFlagByUid(uid);
            if (flag)
                sysFlagName = flag->getName();
        }
    }

    /*
    qDebug() << "ME::mouse pressed\n";
    qDebug() << "  lmo_found=" << lmo_found;
    qDebug() << "   ti_found=" << ti_found;
    //if (ti_found) qDebug() << "   ti_found="<<ti_found->getHeading();
    qDebug() << " flag=" << sysFlagName;
    */

    // Check modifier key (before selecting object!)
    if (ti_found && (e->modifiers() & Qt::ShiftModifier)) {
        if (mainWindow->getModMode() == Main::ModModeColor) {
            setState(PickingColor);
            mainWindow->setCurrentColor(ti_found->getHeadingColor());
            if (e->modifiers() & Qt::ControlModifier)
                model->colorBranch(ti_found->getHeadingColor());
            else
                model->colorSubtree(ti_found->getHeadingColor());
            return;
        }

        if (mainWindow->getModMode() == Main::ModModeMoveView) {
            startMovingView(e);
            return;
        }
    }

    // Check vymlink  modifier (before selecting object!)
    if (ti_found && sysFlagName == "system-vymLink") {
        model->select(ti_found);
        if (e->modifiers() & Qt::ControlModifier) {
            if (e->modifiers() & Qt::ShiftModifier)
                model->deleteVymLink();
            else
                mainWindow->editOpenVymLink(true);
        } else
            mainWindow->editOpenVymLink(false);
        return;
    }

    // Select the clicked object, if not moving without linking
    if (ti_found && (e->modifiers() & Qt::ShiftModifier)) {
        if (mainWindow->getModMode() == Main::ModModePoint) {
            model->selectToggle(ti_found);
            lastToggleDirection = toggleUndefined;
        }
    }
    else
        model->select(ti_found);

    e->accept();

    // Take care of  remaining system flags _or_ modifier modes
    if (lmo_found) {
        if (!sysFlagName.isEmpty()) {
            // systemFlag clicked
            if (sysFlagName.contains("system-url")) {
                if (e->modifiers() & Qt::ControlModifier)
                    mainWindow->editOpenURLTab();
                else
                    mainWindow->editOpenURL();
            }
            else if (sysFlagName == "system-note")
                mainWindow->windowToggleNoteEditor();
            else if (sysFlagName == "hideInExport")
                model->toggleHideExport();
            else if (sysFlagName.startsWith("system-task-"))
                model->cycleTaskStatus();
            return;
        }
        else {
            // Take care of xLink: Open context menu with targets
            // if clicked near to begin of xlink
            if (ti_found->xlinkCount() > 0 &&
                ti_found->getType() != TreeItem::MapCenter &&
                lmo_found->getBBox().width() > 30) {
                if ((lmo_found->getOrientation() !=
                         LinkableMapObj::RightOfCenter &&
                     p.x() < lmo_found->getBBox().left() + 10) ||
                    (lmo_found->getOrientation() !=
                         LinkableMapObj::LeftOfCenter &&
                     p.x() > lmo_found->getBBox().right() - 10)) {
                    // FIXME-4 similar code in mainwindow::updateActions
                    QMenu menu;
                    QList<QAction *> alist;
                    QList<BranchItem *> blist;
                    for (int i = 0; i < ti_found->xlinkCount(); i++) {
                        XLinkItem *xli = ti_found->getXLinkItemNum(i);
                        BranchItem *bit = xli->getPartnerBranch();
                        if (bit)
                            alist.append(
                                new QAction(ti_found->getXLinkItemNum(i)
                                                ->getPartnerBranch()
                                                ->getHeadingPlain(),
                                            &menu));
                    }
                    menu.addActions(alist);
                    QAction *ra = menu.exec(e->globalPos());
                    if (ra)
                        model->select(blist.at(alist.indexOf(ra)));
                    while (!alist.isEmpty()) {
                        QAction *a = alist.takeFirst();
                        delete a;
                    }
                    return;
                }
            }
        }
    }

    // XLink modifier, create new XLink
    BranchItem *selbi = model->getSelectedBranch();
    if (selbi && mainWindow->getModMode() == Main::ModModeXLink &&
        (e->modifiers() & Qt::ShiftModifier)) {
        setState(DrawingLink);
        tmpLink = new Link(model);
        tmpLink->setBeginBranch(selbi);
        tmpLink->createMapObj();
        tmpLink->setStyleBegin("None");
        tmpLink->setStyleEnd("None");
        tmpLink->setEndPoint(mapToScene(e->pos()));
        tmpLink->updateLink();
        return;
    }

    // Start moving around
    if (lmo_found) {
        // Left Button	    Move Branches
        if (e->button() == Qt::LeftButton) {
            // No system flag clicked, take care of moving modes or simply
            // moving
            movingObj_offset.setX(p.x() - lmo_found->x());
            movingObj_offset.setY(p.y() - lmo_found->y());
            movingObj_orgPos.setX(lmo_found->x());
            movingObj_orgPos.setY(lmo_found->y());
            if (ti_found->depth() > 0) {
                lmo_found->setRelPos();
                movingObj_orgRelPos = lmo_found->getRelPos();
            }

            if (mainWindow->getModMode() == Main::ModModeMoveObject &&
                e->modifiers() & Qt::ShiftModifier) {
                setState(MovingObjectWithoutLinking);
            }
            else
                setState(MovingObject);

            movingObj = model->getSelectedLMO();
        }
        else
            // Middle Button    Toggle Scroll
            // (On Mac OS X this won't work, but we still have
            // a button in the toolbar)
            if (e->button() == Qt::MidButton)
            model->toggleScroll();
    }
    else { // No lmo found, check XLinks
        if (ti_found) {
            if (ti_found->getType() == TreeItem::XLink) {
                XLinkObj *xlo = (XLinkObj *)((MapItem *)ti_found)->getMO();
                if (xlo) {
                    setState(DrawingXLink);
                    int i = xlo->ctrlPointInClickBox(p);
                    if (i >= 0)
                        xlo->setSelection(i);
                    movingObj_offset.setX(p.x() - xlo->x());
                    movingObj_offset.setY(p.y() - xlo->y());
                    movingObj_orgPos.setX(xlo->x());
                    movingObj_orgPos.setY(xlo->y());
                }
            }
        }
        else { // No MapObj found, we are on the scene itself
            // Left Button	    move Pos of sceneView
            if (e->button() == Qt::LeftButton ||
                e->button() == Qt::MiddleButton) {
                startMovingView(e);
                return;
            }
        }
    }
}

void MapEditor::mouseMoveEvent(QMouseEvent *e)
{
    // Show mouse position for debugging in statusBar
    if (debug && e->modifiers() & Qt::ControlModifier)
        mainWindow->statusMessage(
            QString("ME::mousePressEvent  Scene: %1  widget: %2")
                .arg(qpointFToString(mapToScene(e->pos())))
                .arg(qpointFToString(e->pos())));

    // Allow selecting text in QLineEdit if necessary
    if (model->isSelectionBlocked()) {
        e->ignore();
        QGraphicsView::mouseMoveEvent(e);
        return;
    }

    // Move sceneView
    if (state == MovingView &&
        (e->buttons() == Qt::LeftButton || e->buttons() == Qt::MiddleButton)) {
        QPointF p = e->globalPos();
        movingVec.setX(-p.x() + movingObj_offset.x());
        movingVec.setY(-p.y() + movingObj_offset.y());
        horizontalScrollBar()->setSliderPosition(
            (int)(movingCont_start.x() + movingVec.x()));
        verticalScrollBar()->setSliderPosition(
            (int)(movingCont_start.y() + movingVec.y()));
        // Avoid flickering
        scrollBarPosAnimation.stop();
        viewCenterAnimation.stop();
        rotationAnimation.stop();
        // zoomAnimation.stop();

        return;
    }

    TreeItem *seli = model->getSelectedItem();

    MapObj *mosel = NULL;
    if (seli)
        mosel = ((MapItem *)seli)->getMO();

    // If not already happened during mousepress, we might need to switch state
    if (mainWindow->getModMode() == Main::ModModeMoveObject &&
        e->modifiers() & Qt::ShiftModifier && e->buttons() == Qt::LeftButton) {
        state = MovingObjectWithoutLinking;
    }

    // Move the selected MapObj
    if (mosel &&
        (state == MovingObject || state == MovingObjectWithoutLinking ||
         state == DrawingXLink)) {
        int margin = 50;

        // Check if we have to scroll
        vPan.setX(0);
        vPan.setY(0);
        if (e->y() >= 0 && e->y() <= margin)
            vPan.setY(e->y() - margin);
        else if (e->y() <= height() && e->y() > height() - margin)
            vPan.setY(e->y() - height() + margin);
        if (e->x() >= 0 && e->x() <= margin)
            vPan.setX(e->x() - margin);
        else if (e->x() <= width() && e->x() > width() - margin)
            vPan.setX(e->x() - width() + margin);

        pointerPos = e->pos();
        pointerMod = e->modifiers();
        moveObject();
    } // selection && moving_obj

    // Draw a link from one branch to another
    if (state == DrawingLink) {
        tmpLink->setEndPoint(mapToScene(e->pos()));
        tmpLink->updateLink();
    }
}

void MapEditor::moveObject()
{
    if (!panningTimer->isActive())
        panningTimer->start(50);

    QPointF p = mapToScene(pointerPos);
    TreeItem *seli = model->getSelectedItem();
    LinkableMapObj *lmosel = NULL;
    if (seli)
        lmosel = ((MapItem *)seli)->getLMO();

    objectMoved = true;

    // reset cursor if we are moving and don't copy

    // Check if we could link
    TreeItem *ti_found = findMapItem(p, seli);
    BranchItem *bi_dst = NULL;
    LinkableMapObj *lmo_dst = NULL;
    if (ti_found && ti_found != seli && ti_found->isBranchLikeType()) {
        bi_dst = (BranchItem *)ti_found;
        lmo_dst = bi_dst->getLMO();
    }
    else
        bi_dst = NULL;

    if (lmosel) {
        if (seli->getType() == TreeItem::Image) {
            FloatImageObj *fio = (FloatImageObj *)lmosel;
            fio->moveCenter(p.x() - movingObj_offset.x(),
                            p.y() - movingObj_offset.y());
            fio->setRelPos();
            fio->updateLinkGeometry(); // no need for reposition, if we update
                                       // link here
            model->emitSelectionChanged(); // position has changed

            // Relink float to new mapcenter or branch, if shift is pressed
            // Only relink, if selection really has a new parent
            if (pointerMod == Qt::ShiftModifier && bi_dst &&
                bi_dst != seli->parent()) {
                // Also save the move which was done so far
                QString pold = qpointFToString(movingObj_orgRelPos);
                QString pnow = qpointFToString(fio->getRelPos());
                model->saveState(seli, "moveRel " + pold, seli,
                                 "moveRel " + pnow,
                                 QString("Move %1 to relative position %2")
                                     .arg(model->getObjectName(lmosel))
                                     .arg(pnow));
                model->reposition();

                model->relinkImage((ImageItem *)seli, bi_dst);
                model->select(seli);
            }
        }
        else if (seli->isBranchLikeType()) { // selection != a FloatObj
            if (seli->depth() == 0) {
                // Move mapcenter
                lmosel->move(p - movingObj_offset);
                if (pointerMod == Qt::ControlModifier) {
                    // Move only mapcenter, leave its children where they are
                    QPointF v;
                    v = lmosel->getAbsPos();
                    for (int i = 0; i < seli->branchCount(); ++i) {
                        seli->getBranchObjNum(i)->setRelPos();
                        seli->getBranchObjNum(i)->setOrientation();
                    }
                }
            }
            else {
                if (seli->depth() == 1) {
                    // Move mainbranch
                    if (!lmosel->hasParObjTmp())
                        lmosel->move(p - movingObj_offset);
                    lmosel->setRelPos();
                }
                else {
                    // d>1, move ordinary branch
                    if (lmosel->getOrientation() ==
                        LinkableMapObj::LeftOfCenter)
                        // Add width of bbox here, otherwise alignRelTo will
                        // cause jumping around
                        lmosel->move(p.x() - movingObj_offset.x(),
                                     p.y() - movingObj_offset.y() +
                                         lmosel->getTopPad());
                    else
                        lmosel->move(p.x() - movingObj_offset.x(),
                                     p.y() - movingObj_offset.y() -
                                         lmosel->getTopPad());
                    BranchItem *selbi = ((BranchItem *)seli);
                    if (selbi->parentBranch()->getChildrenLayout() ==
                        BranchItem::FreePositioning)
                        lmosel->setRelPos();
                }

            } // depth>0

            // Maybe we can relink temporary?
            if (bi_dst && state != MovingObjectWithoutLinking) {
                if (pointerMod == Qt::ControlModifier) {
                    // Special case: CTRL to link below dst
                    lmosel->setParObjTmp(lmo_dst, p, +1);
                }
                else if (pointerMod == Qt::ShiftModifier)
                    lmosel->setParObjTmp(lmo_dst, p, -1);
                else
                    lmosel->setParObjTmp(lmo_dst, p, 0);
            }
            else
                lmosel->unsetParObjTmp();

            // reposition subbranch
            lmosel->reposition();

            QItemSelection sel = model->getSelectionModel()->selection();
            updateSelection(sel, sel); // position has changed

            // In winter mode shake snow from heading
            if (winter)
                model->emitDataChanged(seli);
        } // Moving branchLikeType
    }     // End of lmosel != NULL
    else if (seli && seli->getType() == TreeItem::XLink) {
        // Move XLink control point
        MapObj *mosel = ((MapItem *)seli)->getMO();
        if (mosel) {
            mosel->move(p - movingObj_offset); // FIXME-3 Missing savestate
            model->setChanged();
            model->emitSelectionChanged();
        }
    }
    else
        qWarning("ME::moveObject  Huh? I'm confused.");

    scene()->update();

    return;
}

void MapEditor::mouseReleaseEvent(QMouseEvent *e)
{
    // Allow selecting text in QLineEdit if necessary
    if (model->isSelectionBlocked()) {
        e->ignore();
        QGraphicsView::mouseReleaseEvent(e);
        return;
    }

    QPointF p = mapToScene(e->pos());
    TreeItem *seli = model->getSelectedItem();

    TreeItem *dsti = NULL;
    if (seli)
        dsti = findMapItem(p, seli);
    LinkableMapObj *dst = NULL;
    BranchItem *selbi = model->getSelectedBranch();
    if (dsti && dsti->isBranchLikeType())
        dst = ((MapItem *)dsti)->getLMO();
    else
        dsti = NULL;

    // Have we been picking color?
    if (state == PickingColor) {
        setCursor(Qt::ArrowCursor);
        // Check if we are over another branch
        if (dst) {
            if (e->modifiers() & Qt::ShiftModifier)
                model->colorBranch(mainWindow->getCurrentColor());
            else
                model->colorSubtree(mainWindow->getCurrentColor());
        }
        setState(Neutral);
        return;
    }

    // Have we been drawing a link?
    if (state == DrawingLink) {
        setState(Neutral);
        // Check if we are over another branch
        if (dsti) {
            tmpLink->setEndBranch(((BranchItem *)dsti));
            tmpLink->activate();
            tmpLink->updateLink();
            if (model->createLink(tmpLink)) {
                model->saveState(
                    tmpLink->getBeginLinkItem(), "remove ()", seli,
                    QString("addXLink (\"%1\",\"%2\",%3,\"%4\",\"%5\")")
                        .arg(model->getSelectString(tmpLink->getBeginBranch()))
                        .arg(model->getSelectString(tmpLink->getEndBranch()))
                        .arg(tmpLink->getPen().width())
                        .arg(tmpLink->getPen().color().name())
                        .arg(penStyleToString(tmpLink->getPen().style())),
                    QString("Adding Link from %1 to %2")
                        .arg(model->getObjectName(seli))
                        .arg(model->getObjectName(dsti)));
                return;
            }
        }
        delete (tmpLink);
        tmpLink = NULL;
        return;
    }

    // Have we been moving something?
    if (seli && state == MovingObject) {
        panningTimer->stop();
        if (seli->getType() == TreeItem::Image) {
            FloatImageObj *fio = (FloatImageObj *)(((MapItem *)seli)->getLMO());
            if (fio) {
                // Moved Image, we need to reposition
                QString pold = qpointFToString(movingObj_orgRelPos);
                QString pnow = qpointFToString(fio->getRelPos());
                model->saveState(seli, "moveRel " + pold, seli,
                                 "moveRel " + pnow,
                                 QString("Move %1 to relative position %2")
                                     .arg(model->getObjectName(seli))
                                     .arg(pnow));

                model->emitDataChanged(
                    seli->parent()); // Parent of image has changed
                model->reposition();
            }
        }

        if (selbi && selbi->depth() == 0) {
            if (movingObj_orgPos != selbi->getBranchObj()->getAbsPos()) {
                QString pold = qpointFToString(movingObj_orgPos);
                QString pnow =
                    qpointFToString(selbi->getBranchObj()->getAbsPos());

                model->saveState(selbi, "move " + pold, selbi, "move " + pnow,
                                 QString("Move mapcenter %1 to position %2")
                                     .arg(model->getObjectName(selbi))
                                     .arg(pnow));
            }
        }

        if (seli->isBranchLikeType()) //(seli->getType() == TreeItem::Branch )
        {                             // A branch was moved
            LinkableMapObj *lmosel = NULL;
            lmosel = ((MapItem *)seli)->getLMO();

            // save the position in case we link to mapcenter
            QPointF savePos = QPointF(lmosel->getAbsPos());

            // Reset the temporary drawn link to the original one
            lmosel->unsetParObjTmp();

            // For Redo we may need to save original selection
            QString preSelStr = model->getSelectString(seli);

            if (dsti && objectMoved && state != MovingObjectWithoutLinking) {
                // We have a destination, relink to that
                BranchObj *selbo = model->getSelectedBranchObj();

                QString preParStr = model->getSelectString(seli->parent());
                QString preNum = QString::number(seli->num(), 10);
                QString preDstParStr;

                if (e->modifiers() & Qt::ShiftModifier &&
                    dsti->parent()) { // Link above dst
                    preDstParStr = model->getSelectString(dsti->parent());
                    model->relinkBranch((BranchItem *)seli,
                                        (BranchItem *)dsti->parent(),
                                        ((BranchItem *)dsti)->num(), true);
                }
                else if (e->modifiers() & Qt::ControlModifier &&
                         dsti->parent()) {
                    // Link below dst
                    preDstParStr = model->getSelectString(dsti->parent());
                    model->relinkBranch((BranchItem *)seli,
                                        (BranchItem *)dsti->parent(),
                                        ((BranchItem *)dsti)->num() + 1, true);
                }
                else { // Append to dst
                    preDstParStr = model->getSelectString(dsti);
                    model->relinkBranch((BranchItem *)seli, (BranchItem *)dsti,
                                        -1, true, movingObj_orgPos);
                    if (dsti->depth() == 0)
                        selbo->move(savePos);
                }
            }
            else {
                // No destination, undo  temporary move

                if (seli->depth() == 1) {
                    // The select string might be different _after_ moving
                    // around. Therefor reposition and then use string of old
                    // selection, too
                    model->reposition();

                    QPointF rp(lmosel->getRelPos());
                    if (rp != movingObj_orgRelPos) {
                        QString ps = qpointFToString(rp);
                        model->saveState(
                            model->getSelectString(lmosel),
                            "moveRel " + qpointFToString(movingObj_orgRelPos),
                            preSelStr, "moveRel " + ps,
                            QString("Move %1 to relative position %2")
                                .arg(model->getObjectName(lmosel))
                                .arg(ps));
                    }
                }

                if (selbi->parentBranch()->getChildrenLayout() ==
                    BranchItem::FreePositioning) {
                    lmosel->setRelPos();
                    model->reposition();
                }
                else {

                    // Draw the original link, before selection was moved around
                    if (settings.value("/animation/use", true).toBool() &&
                        seli->depth() > 1
                        //		    && distance
                        //(lmosel->getRelPos(),movingObj_orgRelPos)<3
                    ) {
                        lmosel->setRelPos(); // calc relPos first for starting
                                             // point

                        model->startAnimation((BranchObj *)lmosel,
                                              lmosel->getRelPos(),
                                              movingObj_orgRelPos);
                    }
                    else
                        model->reposition();
                }
            }
        }
        // Finally resize scene, if needed
        scene()->update();
        movingObj = NULL;
        objectMoved = false;
        vPan = QPoint();
    }
    else
        // maybe we moved View: set old cursor
        setCursor(Qt::ArrowCursor);

    if (state != EditingHeading)
        setState(Neutral); // Continue editing after double click!

    QGraphicsView::mouseReleaseEvent(e);
}

void MapEditor::mouseDoubleClickEvent(QMouseEvent *e)
{
    // Allow selecting text in QLineEdit if necessary
    if (model->isSelectionBlocked()) {
        e->ignore();
        QGraphicsView::mouseDoubleClickEvent(e);
        return;
    }

    if (e->button() == Qt::LeftButton) {
        QPointF p = mapToScene(e->pos());
        TreeItem *ti = findMapItem(p, NULL);
        LinkableMapObj *lmo;
        if (ti) {
            if (state == EditingHeading)
                editHeadingFinished();
            model->select(ti);
            BranchItem *selbi = model->getSelectedBranch();
            if (selbi) {
                lmo = ((MapItem *)ti)->getLMO();
                if (lmo) {
                    QUuid uid = ((BranchObj *)lmo)->findSystemFlagUidByPos(p);

                    // Don't edit heading when double clicking system flag:
                    if (!uid.isNull())
                        return;
                }
            }
            e->accept();
            editHeading();
        }
    }
}

void MapEditor::wheelEvent(QWheelEvent *e)
{
    if (e->modifiers() & Qt::ControlModifier &&
        e->angleDelta().y() != 0) {
        QPointF p = mapToScene(e->position().toPoint());
        if (e->angleDelta().y() > 0)
            // setZoomFactorTarget (zoomFactorTarget*1.15);
            setViewCenterTarget(p, zoomFactorTarget * 1.15, angleTarget);
        else
            // setZoomFactorTarget (zoomFactorTarget*0.85);
            setViewCenterTarget(p, zoomFactorTarget * 0.85, angleTarget);
    }
    else {
        scrollBarPosAnimation.stop();
        QGraphicsView::wheelEvent(e);
    }
}

void MapEditor::focusOutEvent(QFocusEvent *)
{
    // qDebug()<<"ME::focusOutEvent"<<e->reason();
    if (state == EditingHeading)
        editHeadingFinished();
}

void MapEditor::resizeEvent(QResizeEvent *e) { QGraphicsView::resizeEvent(e); }

void MapEditor::dragEnterEvent(QDragEnterEvent *event)
{
    // for (unsigned int i=0;event->format(i);i++) // Debug mime type
    //	cerr << event->format(i) << endl;

    if (event->mimeData()->hasImage())
        event->acceptProposedAction();
    else if (event->mimeData()->hasUrls())
        event->acceptProposedAction();
}

void MapEditor::dragMoveEvent(QDragMoveEvent *) {}

void MapEditor::dragLeaveEvent(QDragLeaveEvent *event) { event->accept(); }

void MapEditor::dropEvent(QDropEvent *event)
{
    BranchItem *selbi = model->getSelectedBranch();
    if (selbi) {
        if (debug) {
            foreach (QString format, event->mimeData()->formats())
                qDebug() << "MapEditor: Dropped format: " << qPrintable(format);
            foreach (QUrl url, event->mimeData()->urls()) {
                qDebug() << "  URL-path:" << url.path();
                qDebug() << "URL-string:" << url.toString();
                qDebug() << "       enc:" << url.toEncoded();
                qDebug() << "     valid:" << url.isValid();
            }
            qDebug() << "============== mimeData ===================";
            qDebug() << "has-img : " << event->mimeData()->hasImage();
            qDebug() << "has-urls: " << event->mimeData()->hasUrls();
            qDebug() << "    text: " << event->mimeData()->text();
            qDebug() << "===========================================";
        }

        if (event->mimeData()->hasUrls()) {
            // Try text representation first, which works on windows, but in
            // Linux only for https, not local images
            QString url = event->mimeData()->text();
            if (url.isEmpty()) {
                QByteArray ba =
                    event->mimeData()->urls().first().path().toLatin1();
                QByteArray ba2;
                for (int i = 0; i < ba.count(); i++)
                    if (ba.at(i) != 0)
                        ba2.append(ba.at(i));
                url = ba2;
            }

            BranchItem *bi = NULL;
            // Workaround to avoid adding empty branches
            if (!url.isEmpty()) {
                if (url.startsWith("file://"))
                    url.remove(0, 7);

#if defined(Q_OS_WIN32)
                if (url.startsWith("/"))
                    url.remove(0, 1);
#endif
                if (isImage(url)) {
                    if (debug)
                        qDebug() << "dropped url seems to be image: " << url;
                    // Image, try to download or set image from local file
                    if (url.startsWith("http"))
                        model->downloadImage(url);
                    else
                        model->loadImage(bi, url);
                    if (debug)
                        qDebug() << "finished loading image";
                }
                else {
                    bi = model->addNewBranch();
                    if (bi) {
                        model->select(bi);
                        if (url.endsWith(".vym", Qt::CaseInsensitive))
                            model->setVymLink(url);
                        else {
                            model->setURL(url);

                            // Shorten long URLs for heading
                            int i = url.indexOf("?");
                            QString url_short = url.left(i);
                            if (i > 0) 
                                url_short = url_short + "...";
                            model->setHeadingPlainText(url_short);
                        }

                        model->select(bi->parent());
                    }
                }
            }
        }
    }
    event->acceptProposedAction();
}

void MapEditor::setState(EditorState s)
{
    if (state != Neutral && s != Neutral)
        qWarning() << "MapEditor::setState  switching directly from " << state
                   << " to " << s;
    state = s;
    /* if (debug)
    {
        QString s;
        switch (state)
        {
        case Neutral:
            s = "Neutral";
            break;
        case EditingHeading:
            s = "EditingHeading";
            break;
        case EditingLink:
            s = "EditingLink";
            break;
        case MovingObject:
            s = "MovingObject";
            break;
        case MovingObjectWithoutLinking:
            s = "MovingObjectWithoutLinking";
            break;
        case MovingView:
            s = "MovingView";
            break;
        case PickingColor:
            s = "PickingColor";
            break;
        case DrawingLink:
            s = "DrawingLink";
            break;
        }
        qDebug() << "MapEditor: State " << s << " of " << model->getMapName();
    }
    */
}

MapEditor::EditorState MapEditor::getState() { return state; }

void MapEditor::updateSelection(QItemSelection nsel, QItemSelection dsel)
{
    Q_UNUSED(nsel);

    QList<MapItem *> itemsSelected;
    QList<MapItem *> itemsDeselected;

    QItemSelection sel = model->getSelectionModel()->selection();

    LinkableMapObj *lmo;

    // Add new selected objects
    if (sel.indexes().count() > 1)
        mainWindow->statusMessage(
            tr("%1 items selected").arg(sel.indexes().count()));

    foreach (QModelIndex ix, sel.indexes()) {
        MapItem *mi = static_cast<MapItem *>(ix.internalPointer());
        if (mi->isBranchLikeType() || mi->getType() == TreeItem::Image ||
            mi->getType() == TreeItem::XLink)
            if (!itemsSelected.contains(mi))
                itemsSelected.append(mi);
        lmo = mi->getLMO();
        if (lmo)
            mi->getLMO()->updateVisibility();
    }

    // Delete objects meanwhile removed from selection
    foreach (QModelIndex ix, dsel.indexes()) {
        MapItem *mi = static_cast<MapItem *>(ix.internalPointer());
        if (mi->isBranchLikeType() || mi->getType() == TreeItem::Image ||
            mi->getType() == TreeItem::XLink)
            if (!itemsDeselected.contains(mi))
                itemsDeselected.append(mi);
        lmo = mi->getLMO(); // FIXME-2 xlink does return nullptr
        if (lmo)
            mi->getLMO()->updateVisibility();
    }

    // Trim list of selection paths
    while (itemsSelected.count() < selPathList.count())
        delete selPathList.takeFirst();

    // Reduce polygons
    while (itemsSelected.count() < selPathList.count())
        delete selPathList.takeFirst();

    // Add additonal polygons
    QGraphicsPathItem *sp;
    while (itemsSelected.count() > selPathList.count()) {
        sp = mapScene->addPath(QPainterPath());
        sp->show();
        selPathList.append(sp);
    }

    // Reposition polygons
    for (int i = 0; i < itemsSelected.count(); ++i) {
        MapObj *mo = itemsSelected.at(i)->getMO();
        sp = selPathList.at(i);
        sp->setPath(mo->getSelectionPath());
        sp->setPen(selectionPen);
        sp->setBrush(selectionBrush);
        sp->setParentItem(mo);
        sp->setZValue(dZ_SELBOX);

        // Reposition also LineEdit for heading during animation
        if (lineEdit)
            lineEdit->move(mo->getAbsPos().toPoint());
    }

    scene()->update();
}

void MapEditor::updateData(const QModelIndex &sel)
{
    TreeItem *ti = static_cast<TreeItem *>(sel.internalPointer());

    /* testing
        qDebug() << "ME::updateData";
        if (!ti)
        {
        qDebug() << "  ti=NULL";
        return;
        }
        qDebug() << "  ti="<<ti;
        qDebug() << "  h="<<ti->getHeadingPlain();
    */

    if (ti && ti->isBranchLikeType()) {
        BranchObj *bo = (BranchObj *)(((MapItem *)ti)->getLMO());
        bo->updateVisuals();
    }

    if (winter) {
        QList<QRectF> obstacles;
        BranchObj *bo;
        BranchItem *cur = NULL;
        BranchItem *prev = NULL;
        model->nextBranch(cur, prev);
        while (cur) {
            if (!cur->hasHiddenExportParent()) {
                // Branches
                bo = (BranchObj *)(cur->getLMO());
                if (bo && bo->isVisibleObj())
                    obstacles.append(bo->getBBox());
            }
            model->nextBranch(cur, prev);
        }
        winter->setObstacles(obstacles);
    }
}

void MapEditor::togglePresentationMode()
{
    mainWindow->togglePresentationMode();
}

void MapEditor::setSelectionPen(const QPen &p)
{
    selectionPen = p;
    QItemSelection sel = model->getSelectionModel()->selection();
    updateSelection(sel, sel);
}

QPen MapEditor::getSelectionPen() { return selectionPen; }

void MapEditor::setSelectionBrush(const QBrush &b)
{
    selectionBrush = b;
    QItemSelection sel = model->getSelectionModel()->selection();
    updateSelection(sel, sel);
}

QBrush MapEditor::getSelectionBrush() { return selectionBrush; }
