/***************************************************************************
 *   Copyright (C) 2005 by Daniel Stöckel                                  *
 *   the_docter@gmx.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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "configdialogimpl.h"

#include <tdelocale.h>
#include <kicondialog.h>
#include <kiconloader.h>
#include <kkeybutton.h>
#include <kcolorbutton.h>
#include <kkeydialog.h>
#include <kservicegroup.h>
#include <tdeapplication.h>
#include <dcopclient.h>

#include <tqslider.h>
#include <tqcombobox.h>
#include <tqregexp.h>
#include <tqspinbox.h>
#include <tqlineedit.h>
#include <tqmessagebox.h>
#include <tqcheckbox.h>
#include <tqwidgetstack.h>

#include "menulistviewitem.h"
#include "servicemenu.h"
#include "configuration.h"

#include <X11/Xmu/WinUtil.h>
#include <X11/Xlib.h>
#include <fixx11h.h>

ConfigDialogImpl::ConfigDialogImpl(TQWidget* parent, const char* name, WFlags fl)
    : ConfigDialog(parent,name,fl),
        configChanged(false),
        grabbing(0),
        curListView(0),
        mMenus(true)
{
    new TQListBoxPixmap(listBox,MainBarIcon("kommando",TDEIcon::SizeLarge),"Menu");
    new TQListBoxPixmap(listBox,MainBarIcon("configure_shortcuts",TDEIcon::SizeLarge),"Shortcuts");
    new TQListBoxPixmap(listBox,MainBarIcon("colors",TDEIcon::SizeLarge),"Appearance");
    listBox->setSelected(listBox->topItem(),true);

    connect(kKeyButton1,TQ_SIGNAL(capturedShortcut(const TDEShortcut&)),this,TQ_SLOT(slotShortcutChanged(const TDEShortcut&)) );

    addService->setPopup(new ServiceMenu(this, TQ_SLOT(slotAddService(KService*)),
                         TQ_SLOT(slotAddServiceGroup(KServiceGroup*)), addService));
}

void ConfigDialogImpl::readConfig()
{
    Config& config = Config::getSingleton();

    navButtonSize->setCurrentText(TQString::number(config.navButtonSize()));
    menuButtonSize->setCurrentText(TQString::number(config.menuButtonSize()));
    menuRadiusSpinbox->setValue(config.menuRadius());

    if(config.scheme()=="none"){
        customCheckbox->setChecked(true);
    } else {
        customCheckbox->setChecked(false);
        schemeCombobox->setCurrentText(config.scheme());
    }

    menuViewComboBox->clear();
    initView();
    iconButton->resetIcon();
    iconButton->setEnabled(false);
    commandoEdit->clear();
    commandoEdit->setEnabled(false);
    remove->setEnabled(false);

    kColorButton1->setColor(config.tintColor());
    opacitySlider->setValue(static_cast<int>(config.opacity()*100));

    kKeyButton1->setText(config.Shortcut());
}

void ConfigDialogImpl::setChanged(bool state)
{
    configChanged=state;
    emit changed(state);
}

/*$SPECIALIZATION$*/
void ConfigDialogImpl::slotRemoveListViewClicked()
{
    if(curListView->appName() != "default"){
        if (curListView->childCount() > 0)
            setChanged(true);
        lists->removeWidget(curListView);
        mMenus.remove(curListView);
        curListView = 0;
        menuViewComboBox->removeItem(menuViewComboBox->currentItem());
        menuViewComboBox->setCurrentText("default");
        slotChangeListView("default");
    }
}

void ConfigDialogImpl::slotNewListViewClicked()
{
    newListView->setEnabled(false);
    grabbing = true;
    setCursor(TQt::CrossCursor);
    grabMouse();
}

void ConfigDialogImpl::slotChangeListView(const TQString& appname)
{
    KommandoView* temp = mMenus.getViewOrDefault(appname);
    if(temp == curListView){
        return;
    }
    if(temp && curListView){
        curListView->disconnect();
    }
    if(temp){
        curListView = temp;
        lists->raiseWidget(curListView);
        connect(curListView, TQ_SIGNAL(clicked(TQListViewItem*)), this, TQ_SLOT(slotMenuViewClicked(TQListViewItem*)));
        slotMenuViewClicked(curListView->selectedItem());
    }
}

void ConfigDialogImpl::slotButtonDownPressed()
{
    TQListViewItem* item = curListView->selectedItem();
    if(item!=NULL){
        TQListViewItem* below = item->itemBelow();
        while((below!=NULL)&&(item->parent()!=below->parent())){
            below=below->itemBelow();
        }
        if(below!=NULL){
            item->moveItem(below);
        }
    }
    setChanged(true);
}

void ConfigDialogImpl::slotButtonUpPressed()
{
    TQListViewItem* item = curListView->selectedItem();
    if(item!=NULL){
        TQListViewItem* above = item->itemAbove();
        while((above!=NULL)&&(item->parent()!=above->parent())){
            above=above->itemAbove();
        }
        if(above!=NULL){
            above->moveItem(item);
        }
    }
    setChanged(true);
}

void ConfigDialogImpl::slotCustomSizeCheckboxToggled(bool mode)
{
    schemeCombobox->setEnabled(!mode);
    menuRadiusSpinbox->setEnabled(mode);
    menuButtonSize->setEnabled(mode);
    navButtonSize->setEnabled(mode);
    if(!mode){
        slotSchemeComboboxChanged(schemeCombobox->currentText());
    } else {
        Config::getSingleton().setScheme("none");
    }
    setChanged(true);
}

void ConfigDialogImpl::slotSchemeComboboxChanged(const TQString& scheme)
{
    Config& config=Config::getSingleton();
    if(scheme=="Tiny"){
        config.setMenuRadius(72);
        config.setNavButtonSize(22);
        config.setMenuButtonSize(16);
    } else if(scheme=="Small"){
        config.setMenuRadius(100);
        config.setNavButtonSize(32);
        config.setMenuButtonSize(22);
    } if(scheme=="Normal"){
        config.setMenuRadius(132);
        config.setNavButtonSize(32);
        config.setMenuButtonSize(32);
    } if(scheme=="Big"){
        config.setMenuRadius(200);
        config.setNavButtonSize(48);
        config.setMenuButtonSize(48);
    }

    config.setScheme(scheme);

    navButtonSize->setCurrentText(TQString::number(config.navButtonSize()));
    menuButtonSize->setCurrentText(TQString::number(config.menuButtonSize()));
    menuRadiusSpinbox->setValue(config.menuRadius());
    setChanged(true);
}

void ConfigDialogImpl::slotMenuRadiusSpinboxChanged(int size)
{
    Config::getSingleton().setMenuRadius(size);
    setChanged(true);
}

void ConfigDialogImpl::slotNavButtonSizeChanged(const TQString& size)
{
    Config::getSingleton().setNavButtonSize(size.toShort());
    setChanged(true);
}

void ConfigDialogImpl::slotMenuButtonSizeChanged(const TQString& size)
{
    Config::getSingleton().setMenuButtonSize(size.toShort());
    setChanged(true);
}

void ConfigDialogImpl::slotCommandoTyped(const TQString& commando)
{
    if (curListView->selectedItem() && curListView->selectedItem()->text(1) != commando) {
        curListView->selectedItem()->setText(1,commando);
        setChanged(true);
    }
}

void ConfigDialogImpl::slotMenuViewClicked(TQListViewItem* item)
{
    MenuListViewItem* temp = static_cast<MenuListViewItem*>(item);
    if(item == 0){
        iconButton->resetIcon();
        iconButton->setEnabled(false);
        commandoEdit->clear();
        commandoEdit->setEnabled(false);
        remove->setEnabled(false);
    } else {
        if(temp->iconPath()!=NULL){
            iconButton->setIcon(temp->iconPath());
        } else {
            iconButton->resetIcon();
        }
        if(temp->type()==MenuListViewItem::Button){
            commandoEdit->setEnabled(true);
            commandoEdit->setText(temp->text(1));
        } else {
            commandoEdit->setEnabled(false);
        }
        iconButton->setEnabled(true);
        remove->setEnabled(true);
    }
}

void ConfigDialogImpl::slotNewIcon()
{
    MenuListViewItem* temp = static_cast<MenuListViewItem*>(curListView->selectedItem());
    temp->setIconPath(iconButton->icon());
    setChanged(true);
}

void ConfigDialogImpl::slotRemoveClicked()
{
    TQListViewItem* temp = curListView->selectedItem()->nextSibling();
    delete curListView->selectedItem();
    curListView->setSelected(temp,true);
    if(temp==NULL){
        remove->setEnabled(false);
    }
    setChanged(true);
}

void ConfigDialogImpl::slotAddButtonClicked()
{
    createEntry("Button");
    commandoEdit->setEnabled(true);
}

void ConfigDialogImpl::slotAddMenuClicked()
{
    createEntry("Menu");
    commandoEdit->setEnabled(false);
}

void ConfigDialogImpl::createEntry(const TQString& kind)
{
    TQListViewItem* parent=NULL;
    TQListViewItem* newItem;
    MenuListViewItem* selected =static_cast<MenuListViewItem*>(curListView->selectedItem());
    MenuListViewItem::ItemType type;
    if(selected!=NULL){
        if(selected->type()==MenuListViewItem::Menu){
            parent=selected;
            selected=selected->lastChild();
        } else if(selected->parent()!=NULL){
            parent=selected->parent();
        }
    } else {
        selected=static_cast<MenuListViewItem*>(curListView->lastItem());
    }

    if(kind=="Menu"){
        type=MenuListViewItem::Menu;
    } else {
        type=MenuListViewItem::Button;
    }

    if(parent!=NULL){
        newItem=new MenuListViewItem(parent,selected,kind,type);
    } else {
        newItem=new MenuListViewItem(curListView,selected,kind,type);
    }

    newItem->setOpen(true);
    curListView->setSelected(newItem,true);
    iconButton->resetIcon();
    iconButton->setEnabled(true);
    remove->setEnabled(true);
    commandoEdit->clear();
    setChanged(true);
}

void ConfigDialogImpl::slotListBoxClicked(TQListBoxItem* item)
{
    if(item!=NULL){
        if(item->text()=="Menu"){
            pages->raiseWidget(0);
        } else if(item->text()=="Shortcuts"){
            pages->raiseWidget(1);
        } else if(item->text()=="Appearance"){
            pages->raiseWidget(2);
        }
    }
}

void ConfigDialogImpl::slotDefaultsClicked()
{
    Config::getSingleton().setDefaultValues();
    readConfig();
    setChanged(true);
}

void ConfigDialogImpl::slotApplyClicked()
{
    Config& config = Config::getSingleton();
    config.fromConfigDlg(mMenus);
    config.writeConfigFile();
    kapp->dcopClient()->send("kded", "kommandod", "reparseConfiguration()", TQString::null);
    setChanged(false);
}

void ConfigDialogImpl::slotShortcutChanged(const TDEShortcut & cut )
{
    if(!KKeyChooser::checkGlobalShortcutsConflict(cut,true,this)){
        kKeyButton1->setText(cut.toString());
        Config::getSingleton().setShortcut(cut.toString());
        setChanged(true);
    }
}

void ConfigDialogImpl::slotColorButtonClicked(const TQColor& color)
{
    Config::getSingleton().setTintColor(color);
    setChanged(true);
}

void ConfigDialogImpl::slotOpacitySliderChanged( int value )
{
    Config::getSingleton().setOpacity(static_cast<float>(value)/100.0f);
    setChanged(true);
}

void ConfigDialogImpl::slotAddService(KService* service)
{
    slotAddButtonClicked();

    TQString commando = service->exec();
    commando.remove(TQRegExp(" %.\\b"));
    commando.remove(" -caption \"%c\"");
    commandoEdit->setText(commando);
    curListView->selectedItem()->setText(1, commando);
    iconButton->setIcon(service->icon());
    slotNewIcon();
}

void ConfigDialogImpl::slotAddServiceGroup(KServiceGroup* group)
{
    slotAddMenuClicked();

    iconButton->setIcon(group->icon());
    slotNewIcon();

    KServiceGroup::List list = group->entries(true, true, false, false);
    KServiceGroup::List::ConstIterator it = list.begin();
    for (; it != list.end(); ++it) {
        KSycocaEntry *e = *it;
        if (e->isType(KST_KServiceGroup)) {
            KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e));
            if (g->childCount() > 0) {
                slotAddServiceGroup(g);
            }
        } else if (e->isType(KST_KService)) {
            slotAddService(static_cast<KService *>(e));
        }
    }
}

bool ConfigDialogImpl::event( TQEvent * evt )
{
    if(grabbing){
        switch(evt->type()){
            case TQEvent::MouseButtonPress:
                switch(static_cast<TQMouseEvent*>(evt)->button()){
                    case TQt::LeftButton:
                        releaseMouse();
                        listViewFromClick();
                        grabbing = false;
                        break;
                    default:
                        releaseMouse();
                        grabbing = false;
                }
                break;
            case TQEvent::KeyPress:
                if(static_cast<TQKeyEvent*>(evt)->key() == TQt::Key_Escape){
                    releaseMouse();
                    grabbing = false;
                }
                break;
            default:
                return ConfigDialog::event(evt);
        }
        if(!grabbing){
            newListView->setEnabled(true);
            unsetCursor();
        }
    }
    return ConfigDialog::event(evt);
}

void ConfigDialogImpl::initView( )
{
    mMenus.clear();
    curListView = 0;
    Config::getSingleton().toListView(mMenus, lists);
    for(KommandoView* it = mMenus.first(); it != 0; it = mMenus.next()){
        menuViewComboBox->insertItem(it->appName());
    }
    menuViewComboBox->setCurrentText("default");
    slotChangeListView("default");
}

void ConfigDialogImpl::listViewFromClick( )
{
    Window   rep_root, rep_child;
    int      rep_rootx, rep_rooty;
    unsigned int  rep_mask;
    int      mousex, mousey;
    Display* dpy = tqt_xdisplay();
    Window   win = tqt_xrootwin();
    XClassHint hint;

    hint.res_class = 0;
    hint.res_name = 0;

    //Get mouse coursor position and the application name of the window under the coursor
    XQueryPointer (dpy, win, &rep_root, &rep_child, &rep_rootx, &rep_rooty, &mousex, &mousey, &rep_mask);

    rep_child = XmuClientWindow(dpy,rep_child);
    if(XGetClassHint(dpy,rep_child,&hint) != 0){
        if(!mMenus.contains(hint.res_class)){
            KommandoView* view = new KommandoView(lists, hint.res_class);
            lists->addWidget(view);
            mMenus.append(view);
            menuViewComboBox->insertItem(hint.res_class,0);
            menuViewComboBox->setCurrentItem(0);
            slotChangeListView(hint.res_class);
        }
    }
    if(hint.res_class){
        XFree(hint.res_class);
    }
    if(hint.res_name){
        XFree(hint.res_name);
    }
}

#include "configdialogimpl.moc"

