/*
    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.
*/

/*
  Copyright (C) 2005 Francois Chazal <neptune3k@free.fr>
  Copyright (C) 2006-2007 Eike Hein <hein@kde.org>
*/


#include "tabbed_widget.h"
#include "tabbed_widget.moc"
#include "settings.h"

#include <tqcursor.h>
#include <tqwhatsthis.h>

#include <tdeaction.h>
#include <tdepopupmenu.h>
#include <tdemainwindow.h>
#include <kiconloader.h>


TabbedWidget::TabbedWidget(TQWidget* parent, const char* name, bool translucency)
    : TranslucentWidget(parent, name, translucency)
{
    current_position = -1;
    pressed = false;
    pressed_position = -1;
    edited_position = -1;

    context_menu = 0;

    if (root_pixmap)
    {
        connect(root_pixmap, TQ_SIGNAL(backgroundUpdated(const TQPixmap &)), this, TQ_SLOT(slotUpdateBuffer(const TQPixmap &)));
        root_pixmap->setCustomPainting(true);
    }

    inline_edit = new TQLineEdit(this);
    inline_edit->hide();

    connect(inline_edit, TQ_SIGNAL(returnPressed()), this, TQ_SLOT(slotRenameSelected()));
    connect(inline_edit, TQ_SIGNAL(lostFocus()), inline_edit, TQ_SLOT(hide()));
    connect(inline_edit, TQ_SIGNAL(lostFocus()), this, TQ_SLOT(slotResetEditedPosition()));

    selected_font = font();
    unselected_font = font();
    selected_font.setBold(true);

    refreshBuffer();
}

TabbedWidget::~TabbedWidget()
{
    delete context_menu;
}

int TabbedWidget::pressedPosition()
{
    return pressed_position;
}

void TabbedWidget::createContextMenu()
{
    context_menu = new TDEPopupMenu();

    static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
        action("split_horizontally")->plug(context_menu);
    static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
        action("split_vertically")->plug(context_menu);
    static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
        action("remove_terminal")->plug(context_menu);

    context_menu->insertSeparator();

    static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
        action("move_tab_left")->plug(context_menu);
    static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
        action("move_tab_right")->plug(context_menu);

    context_menu->insertSeparator();

    static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
        action("edit_name")->plug(context_menu);

    static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
        action("remove_tab")->plug(context_menu);

}

void TabbedWidget::addItem(int session_id)
{
    items.append(session_id);
    areas.append(0);
    captions.append(lowestAvailableCaption());

    refreshBuffer();
}

TQString TabbedWidget::defaultTabCaption(int id)
{
    return i18n("Shell", "Shell No. %n", id+1);
}

TQString TabbedWidget::lowestAvailableCaption()
{
    TQString newTitle = defaultTabCaption(0);

    bool nameOk;
    int count = 0;

    do
    {
        nameOk = true;

        TQValueList<TQString>::iterator it;

        for (it = captions.begin(); it != captions.end(); ++it)
        {
            if (newTitle == (*it))
            {
                nameOk = false;
                break;
            }
        }

        if (!nameOk)
        {
            count++;
            newTitle = newTitle = defaultTabCaption(count);
        }
    }
    while (!nameOk);

    return newTitle;
}

int TabbedWidget::removeItem(int session_id)
{
    uint position = items.findIndex(session_id);

    items.remove(items.at(position));
    areas.remove(areas.at(position));
    captions.remove(captions.at(position));

    if (position != items.count())
        current_position = position;
    else if (position != 0)
        current_position = position - 1;
    else
        current_position = -1;

    refreshBuffer();

    if (current_position != -1)
        emit itemSelected(items[current_position]);

    return current_position;
}

const TQString TabbedWidget::itemName(int session_id)
{
    int position = items.findIndex(session_id);

    if (position == -1) return 0;

    return captions[position];
}

void TabbedWidget::renameItem(int session_id, const TQString& namep)
{
    int position = items.findIndex(session_id);

    if (position == -1) return;

    TQString name = namep.stripWhiteSpace();
    captions[position] = !name.isEmpty() ? name : captions[position];

    refreshBuffer();
}

void TabbedWidget::interactiveRename()
{
    if (pressed_position != -1)
    {
        interactiveRename(pressed_position);
        pressed_position = -1;
    }
    else
    {
        interactiveRename(current_position);
    }
}

void TabbedWidget::interactiveRename(int position)
{
    if (position >= 0 && position < int(items.count()) && !items.isEmpty())
    {
        edited_position = position;

        int index;
        int width;

        for (index = 0, width = 0; index < position; index++)
            width += areas[index];

        inline_edit->setText(captions[position]);
        inline_edit->setGeometry(width, 0, areas[position], height());
        inline_edit->setAlignment(TQt::AlignHCenter);
        inline_edit->setFrame(false);
        inline_edit->selectAll();
        inline_edit->setFocus();
        inline_edit->show();
    }
}

void TabbedWidget::slotRenameSelected()
{
    if (edited_position >= 0 && edited_position < int(items.count()))
    {
        TQString text = inline_edit->text().stripWhiteSpace();
        captions[edited_position] = !text.isEmpty() ? text : captions[edited_position];

        inline_edit->hide();

        edited_position = -1;

        refreshBuffer();
    }
}

void TabbedWidget::slotResetEditedPosition()
{
    edited_position = -1;
}

int TabbedWidget::tabPositionForSessionId(int session_id)
{
    return items.findIndex(session_id);
}

int TabbedWidget::sessionIdForTabPosition(int position)
{
    if (position < int(items.count()) && !items.isEmpty())
        return items[position];
    else
        return -1;
}

void TabbedWidget::selectItem(int session_id)
{
    int new_position = items.findIndex(session_id);

    if (new_position != -1)
    {
        current_position = new_position;
        refreshBuffer();
    }
}

void TabbedWidget::selectPosition(int position)
{
    if (position < int(items.count()) && !items.isEmpty())
    {
        current_position = position;

        refreshBuffer();

        emit itemSelected(items[current_position]);
    }
}

void TabbedWidget::selectNextItem()
{
    if (current_position != int(items.count()) - 1)
        current_position++;
    else
        current_position = 0;

    refreshBuffer();

    emit itemSelected(items[current_position]);
}

void TabbedWidget::selectPreviousItem()
{
    if (current_position != 0)
        current_position--;
    else
        current_position = items.count() - 1;

    refreshBuffer();

    emit itemSelected(items[current_position]);
}

void TabbedWidget::moveItemLeft()
{
    if (pressed_position != -1)
    {
        moveItemLeft(pressed_position);
        pressed_position = -1;
    }
    else
        moveItemLeft(current_position);
}


void TabbedWidget::moveItemLeft(int position)
{
    if (position > 0)
    {
        int session_id = items[position];
        TQString caption = captions[position];

        int neighbor_session_id = items[position-1];
        TQString neighbor_caption = captions[position-1];

        items[position-1] = session_id;
        captions[position-1] = caption;

        items[position] = neighbor_session_id;
        captions[position] = neighbor_caption;

        if (position == current_position)
            current_position--;
        else if (position == current_position + 1)
            current_position++;

        refreshBuffer();
    }
}

void TabbedWidget::moveItemRight()
{
    if (pressed_position != -1)
    {
        moveItemRight(pressed_position);
        pressed_position = -1;
    }
    else
        moveItemRight(current_position);
}

void TabbedWidget::moveItemRight(int position)
{
    if (position < int(items.count()) - 1)
    {
        int session_id = items[position];
        TQString caption = captions[position];

        int neighbor_session_id = items[position+1];
        TQString neighbor_caption = captions[position+1];

        items[position+1] = session_id;
        captions[position+1] = caption;

        items[position] = neighbor_session_id;
        captions[position] = neighbor_caption;

        if (position == current_position)
            current_position++;
        else if (position == current_position - 1)
            current_position--;

        refreshBuffer();
    }
}

void TabbedWidget::setFontColor(const TQColor & color)
{
    font_color = color;
}

void TabbedWidget::setBackgroundPixmap(const TQString & path)
{
    background_image.load(path);
    resize(width(), background_image.height());

    repaint();
}

void TabbedWidget::setSeparatorPixmap(const TQString & path)
{
    separator_image.load(path);
}

void TabbedWidget::setUnselectedPixmap(const TQString & path)
{
    unselected_image.load(path);
}

void TabbedWidget::setSelectedPixmap(const TQString & path)
{
    selected_image.load(path);
}

void TabbedWidget::setSelectedLeftPixmap(const TQString & path)
{
    selected_left_image.load(path);
}

void TabbedWidget::setSelectedRightPixmap(const TQString & path)
{
    selected_right_image.load(path);
}

void TabbedWidget::keyPressEvent(TQKeyEvent* e)
{
    if (e->key() == Key_Escape && inline_edit->isShown())
    {
        inline_edit->hide();
        edited_position = -1;
    }

    TQWidget::keyPressEvent(e);
}

void TabbedWidget::wheelEvent(TQWheelEvent* e)
{
    if (e->delta() < 0)
        selectNextItem();
    else
        selectPreviousItem();
}

void TabbedWidget::mousePressEvent(TQMouseEvent* e)
{
    if (TQWhatsThis::inWhatsThisMode()) return;

    int position;
    int width;

    if (e->x() < 0)
        return ;

    for (position = 0, width = 0; (position < int(areas.count())) && (e->x() >= width); position++)
        width += areas[position];

    if ((e->x() <= width) && (e->button() == TQt::LeftButton) && !(current_position == position - 1))
    {
        pressed = true;
        pressed_position = position - 1;
    }
    else if ((e->x() <= width) && (e->button() == TQt::RightButton))
    {
        pressed_position = position - 1;

        if (!context_menu) createContextMenu();

        static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
            action("move_tab_left")->setEnabled((position - 1 > 0));
        static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
            action("move_tab_right")->setEnabled((position - 1 < int(items.count()) - 1));

        context_menu->exec(TQCursor::pos());

        static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
            action("move_tab_left")->setEnabled(true);
        static_cast<TDEMainWindow*>(parent()->parent())->actionCollection()->
            action("move_tab_right")->setEnabled(true);
    }
}

void TabbedWidget::mouseReleaseEvent(TQMouseEvent* e)
{
    if (TQWhatsThis::inWhatsThisMode()) return;

    int position;
    int width;

    if (e->x() < 0)
        return ;

    for (position = 0, width = 0; (position < int(areas.count())) && (e->x() >= width); position++)
        width += areas[position];

    if ((e->x() <= width) && (e->button() == TQt::LeftButton) && !(current_position == position - 1))
    {
        if (pressed && pressed_position == (position - 1))
        {
            current_position = position - 1;

            refreshBuffer();

            emit itemSelected(items[current_position]);
        }
    }

    pressed = false;
}

void TabbedWidget::mouseDoubleClickEvent(TQMouseEvent* e)
{
    if (TQWhatsThis::inWhatsThisMode()) return;

    int position;
    int width;

    inline_edit->hide();

    if (e->x() < 0)
        return ;

    for (position = 0, width = 0; (position < int(areas.count())) && (e->x() >= width); position++)
        width += areas[position];

    if ((e->x() <= width) && (e->button() == TQt::LeftButton) && current_position == position - 1)
    {
        interactiveRename(position - 1);
    }
    else if ((e->x() > width) && (e->button() == TQt::LeftButton))
        emit addItem();
}

void TabbedWidget::leaveEvent(TQEvent* e)
{
    pressed = false;

    TQWidget::leaveEvent(e);
}

void TabbedWidget::paintEvent(TQPaintEvent*)
{
    bitBlt(this, 0, 0, &buffer_image);
}

void TabbedWidget::refreshBuffer()
{
    /* Refreshes the back buffer. */

    int x = 0;
    TQPainter painter;

    buffer_image.resize(size());
    painter.begin(&buffer_image);

    if (useTranslucency())
        painter.drawTiledPixmap(0, 0, width(), height(), desktop_image);
    else
        buffer_image.fill(Settings::skinbgcolor());

    for (uint i = 0; i < items.count(); i++)
        x = drawButton(i, painter);

    painter.drawTiledPixmap(x, 0, width() - x, height(), background_image);

    painter.end();

    repaint();
}

const int TabbedWidget::drawButton(int position, TQPainter& painter)
{
    /* Draws the tab buttons. */

    static int x = 0;
    TQPixmap tmp_pixmap;

    areas[position] = 0;
    x = (!position) ? 0 : x;

    // Initialize the painter.
    painter.setPen(font_color);
    painter.setFont((position == current_position) ? selected_font : unselected_font);

    // Draw the left border.
    if (position == current_position)
        tmp_pixmap = selected_left_image;
    else if (position != current_position + 1)
        tmp_pixmap = separator_image;

    painter.drawPixmap(x, 0, tmp_pixmap);
    areas[position] += tmp_pixmap.width();
    x += tmp_pixmap.width();

    // Draw the main contents.
    int width;
    TQFontMetrics metrics(painter.font());

    width = metrics.width(captions[position]) + 10;

    tmp_pixmap = (position == current_position) ? selected_image : unselected_image;
    painter.drawTiledPixmap(x, 0, width, height(), tmp_pixmap);

    painter.drawText(x, 0, width + 1, height() + 1,
                     TQt::AlignHCenter | TQt::AlignVCenter,  captions[position]);

    areas[position] += width;
    x += width;

    // Draw the right border if needed.
    if (position == current_position)
    {
        painter.drawPixmap(x, 0, selected_right_image);
        areas[position] += selected_right_image.width();
        x += selected_right_image.width();
    }
    else if (position == (int) items.count() - 1)
    {
        painter.drawPixmap(x, 0, separator_image);
        areas[position] += separator_image.width();
        x += separator_image.width();
    }

    return x;
}

void TabbedWidget::slotUpdateBuffer(const TQPixmap& pixmap)
{
    desktop_image = pixmap;

    refreshBuffer();
}
