/*
 *  copyright (C) 2004
 *  Umbrello UML Modeller Authors <uml-devel@ uml.sf.net>
 */

/***************************************************************************
 *                                                                         *
 *   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 "aligntoolbar.h"
#include "uml.h"
#include "umldoc.h"
#include "umlview.h"
#include "umlwidget.h"
#include "umlwidgetlist.h"

#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>

AlignToolBar::AlignToolBar(QMainWindow* parentWindow, const char* name)
        : KToolBar(parentWindow,Qt::DockRight,false,name)
{
    // load images for the buttons
    loadPixmaps();

    // create the buttons
    insertButton(m_Pixmaps[alac_align_left], alac_align_left, true, i18n("Align Left"));
    insertButton(m_Pixmaps[alac_align_right], alac_align_right, true, i18n("Align Right"));
    insertButton(m_Pixmaps[alac_align_top], alac_align_top, true, i18n("Align Top"));
    insertButton(m_Pixmaps[alac_align_bottom], alac_align_bottom, true, i18n("Align Bottom"));
    insertButton(m_Pixmaps[alac_align_vertical_middle], alac_align_vertical_middle, true, i18n("Align Vertical Middle"));
    insertButton(m_Pixmaps[alac_align_horizontal_middle], alac_align_horizontal_middle, true, i18n("Align Horizontal Middle"));

    setOrientation( Qt::Vertical );
    setVerticalStretchable( true );

    // gets called whenever a button in the toolbar is clicked
    connect( this, SIGNAL( released( int ) ), this, SLOT( slotButtonChanged (int ) ) );
}

AlignToolBar::~AlignToolBar()
{
}

/* ------ private functions ------ */

int AlignToolBar::getSmallestX(UMLWidgetList widgetList)
{
    UMLWidgetListIt it(widgetList);
    UMLWidget * widget;

    int smallest_x = it.toFirst()->getX();
    ++it;

    while ((widget = it.current()) != 0)
    {
        ++it;
        if (smallest_x > widget->getX())
            smallest_x = widget->getX();
    }

    return smallest_x;
}

int AlignToolBar::getSmallestY(UMLWidgetList widgetList)
{
    UMLWidgetListIt it(widgetList);
    UMLWidget * widget;

    int smallest_y = it.toFirst()->getY();
    ++it;

    while ((widget = it.current()) != 0)
    {
        ++it;
        if (smallest_y > widget->getY())
            smallest_y = widget->getY();
    }

    return smallest_y;
}

int AlignToolBar::getBiggestX(UMLWidgetList widgetList)
{
    UMLWidgetListIt it(widgetList);
    UMLWidget * widget;

    int biggest_x = it.toFirst()->getX();
    biggest_x += it.current()->getWidth();
    ++it;

    while ((widget = it.current()) != 0)
    {
        ++it;
        if (biggest_x < widget->getX() + widget->getWidth())
            biggest_x = widget->getX() + widget->getWidth();
    }

    return biggest_x;
}

int AlignToolBar::getBiggestY(UMLWidgetList widgetList)
{
    UMLWidgetListIt it(widgetList);
    UMLWidget * widget;

    int biggest_y = it.toFirst()->getY();
    biggest_y += it.current()->getHeight();
    ++it;

    while ((widget = it.current()) != 0)
    {
        ++it;
        if (biggest_y < widget->getY() + widget->getHeight())
            biggest_y = widget->getY() + widget->getHeight();
    }

    return biggest_y;
}

void AlignToolBar::loadPixmaps()
{
    KStandardDirs * dirs = KGlobal::dirs();
    QString dataDir = dirs -> findResourceDir( "data", "umbrello/pics/object.png" );
    dataDir += "/umbrello/pics/";

    m_Pixmaps[alac_align_left].load( dataDir + "align_left.png" );
    m_Pixmaps[alac_align_right].load( dataDir + "align_right.png" );
    m_Pixmaps[alac_align_top].load( dataDir + "align_top.png" );
    m_Pixmaps[alac_align_bottom].load( dataDir + "align_bottom.png" );
    m_Pixmaps[alac_align_vertical_middle].load( dataDir + "align_vert_middle.png" );
    m_Pixmaps[alac_align_horizontal_middle].load( dataDir + "align_hori_middle.png" );

    return;
}

/* ------ private slots ------ */

void AlignToolBar::slotButtonChanged(int btn)
{
    UMLView* view = UMLApp::app()->getDocument()->getCurrentView();
    UMLWidgetList widgetList;
    UMLWidget * widget;

    int smallest_x = 0;
    int biggest_x = 0;
    int smallest_y = 0;
    int biggest_y = 0;
    int middle = 0;

    // get the list with selected widgets (not associations)
    view->getSelectedWidgets(widgetList);
    UMLWidgetListIt it(widgetList);

    // at least 2 widgets must be selected
    if (widgetList.count() > 1)
    {
        // now perform alignment according to the clicked button
        switch (btn)
        {
            // align left
        case alac_align_left:
            smallest_x = getSmallestX(widgetList);

            it.toFirst();
            while ((widget = it.current()) != 0)
            {
                ++it;
                widget->setX(smallest_x);
            }
            break;

            // align right
        case alac_align_right:
            biggest_x = getBiggestX(widgetList);

            it.toFirst();
            while ((widget = it.current()) != 0)
            {
                ++it;
                widget->setX(biggest_x - widget->getWidth());
            }
            break;

            // align top
        case alac_align_top:
            smallest_y = getSmallestY(widgetList);

            it.toFirst();
            while ((widget = it.current()) != 0)
            {
                ++it;
                widget->setY(smallest_y);
            }
            break;

            // align bottom
        case alac_align_bottom:
            biggest_y = getBiggestY(widgetList);

            it.toFirst();
            while ((widget = it.current()) != 0)
            {
                ++it;
                widget->setY(biggest_y - widget->getHeight());
            }
            break;

            // align vertical middle
        case alac_align_vertical_middle:
            smallest_x = getSmallestX(widgetList);
            biggest_x = getBiggestX(widgetList);
            middle = int((biggest_x - smallest_x) / 2) + smallest_x;

            it.toFirst();
            while ((widget = it.current()) != 0)
            {
                ++it;
                widget->setX(middle - int(widget->getWidth() / 2));
            }
            break;

            // align horizontal middle
        case alac_align_horizontal_middle:
            smallest_y = getSmallestY(widgetList);
            biggest_y = getBiggestY(widgetList);
            middle = int((biggest_y - smallest_y) / 2) + smallest_y;

            it.toFirst();
            while ((widget = it.current()) != 0)
            {
                ++it;
                widget->setY(middle - int(widget->getHeight() / 2));
            }
            break;

        } // switch (btn)

        // update associations
        it.toFirst();
        while ((widget = it.current()) != 0)
        {
            ++it;
            widget->updateWidget();
        }
        UMLApp::app()->getDocument()->setModified();
    } else {
        KMessageBox::messageBox(0, KMessageBox::Information,
                                i18n("For alignment you have to select at least 2 objects like classes or actors. You can not align associations."),
                                i18n("Information"), i18n("&OK"), QString("")
#if KDE_IS_VERSION(3,2,0)
                                , "showAlignInformation"
#endif
                               );
    } // if (widgetList.count() > 1)

    return;
}

#include "aligntoolbar.moc"
