/**********************************************************************
** Copyright (C) 2000-2001 Trolltech AS.  All rights reserved.
**
** This file is part of TQt Designer.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

#include "globaldefs.h"
#include "hierarchyview.h"
#include "formwindow.h"
#include "mainwindow.h"
#include "command.h"
#include "widgetfactory.h"
#include "widgetdatabase.h"
#include "pixmapchooser.h"
#include "propertyeditor.h"
#include "listeditor.h"

#include <tqpalette.h>
#include <tqobjectlist.h>
#include <tqheader.h>
#include <tqpopupmenu.h>
#include <tqtabwidget.h>
#include <tqwizard.h>
#include <tqwidgetstack.h>
#include <tqtabbar.h>
#include <tqfeatures.h>
#include <tqapplication.h>
#include <tqtimer.h>
#include <tqworkspace.h>
#include <tqaccel.h>

#include <tdelocale.h>

#include <stdlib.h>

static const char * const folder_xpm[]={
    "16 16 6 1",
    ". c None",
    "b c #ffff00",
    "d c #000000",
    "* c #999999",
    "a c #cccccc",
    "c c #ffffff",
    "................",
    "................",
    "..*****.........",
    ".*ababa*........",
    "*abababa******..",
    "*cccccccccccc*d.",
    "*cbababababab*d.",
    "*cabababababa*d.",
    "*cbababababab*d.",
    "*cabababababa*d.",
    "*cbababababab*d.",
    "*cabababababa*d.",
    "*cbababababab*d.",
    "**************d.",
    ".dddddddddddddd.",
    "................"};

TQListViewItem *newItem = 0;

HierarchyItem::HierarchyItem( Type type, TQListViewItem *parent,
            const TQString &txt1, const TQString &txt2, const TQString &txt3 )
    : TQListViewItem( parent, txt1, txt2, txt3 ), typ( type )
{
}

HierarchyItem::HierarchyItem( Type type, TQListView *parent,
            const TQString &txt1, const TQString &txt2, const TQString &txt3 )
    : TQListViewItem( parent, txt1, txt2, txt3 ), typ( type )
{
}

void HierarchyItem::paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align )
{
    TQColorGroup g( cg );
    g.setColor( TQColorGroup::Base, backgroundColor() );
    g.setColor( TQColorGroup::Foreground, TQt::black );
    g.setColor( TQColorGroup::Text, TQt::black );
    TQString txt = text( 0 );
    if ( rtti() == Slot &&
   ( txt == "init()" || txt == "destroy()" ) ) {
  listView()->setUpdatesEnabled( false );
  if ( txt == "init()" )
      setText( 0, txt + " " + i18n( "(Constructor)" ) );
  else
      setText( 0, txt + " " + i18n( "(Destructor)" ) );
  TQListViewItem::paintCell( p, g, column, width, align );
  setText( 0, txt );
  listView()->setUpdatesEnabled( true );
    } else {
  TQListViewItem::paintCell( p, g, column, width, align );
    }
    p->save();
    p->setPen( TQPen( cg.dark(), 1 ) );
    if ( column == 0 )
  p->drawLine( 0, 0, 0, height() - 1 );
    if ( listView()->firstChild() != this ) {
  if ( nextSibling() != itemBelow() && itemBelow()->depth() < depth() ) {
      int d = depth() - itemBelow()->depth();
      p->drawLine( -listView()->treeStepSize() * d, height() - 1, 0, height() - 1 );
  }
    }
    p->drawLine( 0, height() - 1, width, height() - 1 );
    p->drawLine( width - 1, 0, width - 1, height() );
    p->restore();
}

TQColor HierarchyItem::backgroundColor()
{
    updateBackColor();
    return backColor;
}

void HierarchyItem::updateBackColor()
{
    if ( listView()->firstChild() == this ) {
  backColor = *backColor1;
  return;
    }

    TQListViewItemIterator it( this );
    --it;
    if ( it.current() ) {
  if ( ( ( HierarchyItem*)it.current() )->backColor == *backColor1 )
      backColor = *backColor2;
  else
      backColor = *backColor1;
    } else {
  backColor = *backColor1;
    }
}

void HierarchyItem::setWidget( TQWidget *w )
{
    wid = w;
}

TQWidget *HierarchyItem::widget() const
{
    return wid;
}

void HierarchyItem::okRename( int col )
{
    if ( newItem == this )
  newItem = 0;
    TQListViewItem::okRename( col );
}

void HierarchyItem::cancelRename( int col )
{
    if ( newItem == this ) {
  newItem = 0;
  TQListViewItem::cancelRename( col );
  delete this;
  return;
    }
    TQListViewItem::cancelRename( col );
}




HierarchyList::HierarchyList( TQWidget *parent, FormWindow *fw, bool doConnects )
    : TQListView( parent ), formWindow( fw )
{
    init_colors();

    setDefaultRenameAction( Accept );
    header()->setMovingEnabled( false );
    header()->setStretchEnabled( true );
    normalMenu = 0;
    tabWidgetMenu = 0;
    addColumn( i18n("Name" ) );
    addColumn( i18n("Class" ) );
    TQPalette p( palette() );
    p.setColor( TQColorGroup::Base, TQColor( *backColor2 ) );
    (void)*selectedBack; // hack
    setPalette( p );
    disconnect( header(), TQ_SIGNAL( sectionClicked( int ) ),
    this, TQ_SLOT( changeSortColumn( int ) ) );
    setSorting( -1 );
    setHScrollBarMode( AlwaysOff );
    setVScrollBarMode( AlwaysOn );
    if ( doConnects ) {
  connect( this, TQ_SIGNAL( clicked( TQListViewItem * ) ),
     this, TQ_SLOT( objectClicked( TQListViewItem * ) ) );
  connect( this, TQ_SIGNAL( returnPressed( TQListViewItem * ) ),
     this, TQ_SLOT( objectClicked( TQListViewItem * ) ) );
  connect( this, TQ_SIGNAL( contextMenuRequested( TQListViewItem *, const TQPoint&, int ) ),
     this, TQ_SLOT( showRMBMenu( TQListViewItem *, const TQPoint & ) ) );
    }
    deselect = true;
    setColumnWidthMode( 1, Manual );
}

void HierarchyList::keyPressEvent( TQKeyEvent *e )
{
    if ( e->key() == Key_Shift || e->key() == Key_Control )
  deselect = false;
    else
  deselect = true;
    TQListView::keyPressEvent( e );
}

void HierarchyList::keyReleaseEvent( TQKeyEvent *e )
{
    deselect = true;
    TQListView::keyReleaseEvent( e );
}

void HierarchyList::viewportMousePressEvent( TQMouseEvent *e )
{
    if ( e->state() & ShiftButton || e->state() & ControlButton )
  deselect = false;
    else
  deselect = true;
    TQListView::viewportMousePressEvent( e );
}

void HierarchyList::viewportMouseReleaseEvent( TQMouseEvent *e )
{
    TQListView::viewportMouseReleaseEvent( e );
}

void HierarchyList::objectClicked( TQListViewItem *i )
{
    if ( !i )
  return;

    TQWidget *w = findWidget( i );
    if ( !w )
  return;
    if ( formWindow == w ) {
  if ( deselect )
      formWindow->clearSelection( false );
  formWindow->emitShowProperties( formWindow );
  return;
    }

    if ( !formWindow->widgets()->find( w ) ) {
  if ( w->parent() && w->parent()->inherits( "TQWidgetStack" ) &&
       w->parent()->parent() &&
       ( w->parent()->parent()->inherits( "TQTabWidget" ) ||
         w->parent()->parent()->inherits( "TQWizard" ) ) ) {
      if ( w->parent()->parent()->inherits( "TQTabWidget" ) )
    ( (TQTabWidget*)w->parent()->parent() )->showPage( w );
      else
        ( (QDesignerWizard*)w->parent()->parent() )->setCurrentPage( ( (QDesignerWizard*)w->parent()->parent() )->pageNum( w ) );
      w = (TQWidget*)w->parent()->parent();
      formWindow->emitUpdateProperties( formWindow->currentWidget() );
  } else {
      return;
  }
    }

    if ( deselect )
  formWindow->clearSelection( false );
    if ( w->isVisibleTo( formWindow ) )
  formWindow->selectWidget( w, true );
}

TQWidget *HierarchyList::findWidget( TQListViewItem *i )
{
    return ( (HierarchyItem*)i )->widget();
}

TQListViewItem *HierarchyList::findItem( TQWidget *w )
{
    TQListViewItemIterator it( this );
    while ( it.current() ) {
  if ( ( (HierarchyItem*)it.current() )->widget() == w )
      return it.current();
  ++it;
    }
    return 0;
}

TQWidget *HierarchyList::current() const
{
    if ( currentItem() )
  return ( (HierarchyItem*)currentItem() )->widget();
    return 0;
}

void HierarchyList::changeNameOf( TQWidget *w, const TQString &name )
{
    TQListViewItem *item = findItem( w );
    if ( !item )
  return;
    item->setText( 0, name );
}


void HierarchyList::changeDatabaseOf( TQWidget *w, const TQString & info )
{
#ifndef TQT_NO_SQL
    if ( !formWindow->isDatabaseAware() )
  return;
    TQListViewItem *item = findItem( w );
    if ( !item )
  return;
    item->setText( 2, info );
#else
  Q_UNUSED(w);
  Q_UNUSED(info);
#endif
}

void HierarchyList::setup()
{
    if ( !formWindow )
  return;
    clear();
    TQWidget *w = formWindow->mainContainer();
#ifndef TQT_NO_SQL
    if ( formWindow->isDatabaseAware() ) {
  if ( columns() == 2 ) {
      addColumn( i18n("Database" ) );
      header()->resizeSection( 0, 1 );
      header()->resizeSection( 1, 1 );
      header()->resizeSection( 2, 1 );
      header()->adjustHeaderSize();
  }
    } else {
  if ( columns() == 3 ) {
      removeColumn( 2 );
  }
    }
#endif
    if ( w )
  insertObject( w, 0 );
}

void HierarchyList::setOpen( TQListViewItem *i, bool b )
{
    TQListView::setOpen( i, b );
}

void HierarchyList::insertObject( TQObject *o, TQListViewItem *parent )
{
    bool fakeMainWindow = false;
    if ( o && o->inherits( "TQMainWindow" ) ) {
  TQObject *cw = ( (TQMainWindow*)o )->centralWidget();
  if ( cw ) {
      o = cw;
      fakeMainWindow = true;
  }
    }
    TQListViewItem *item = 0;
    TQString className = WidgetFactory::classNameOf( o );
    if ( o->inherits( "TQLayoutWidget" ) ) {
  switch ( WidgetFactory::layoutType( (TQWidget*)o ) ) {
  case WidgetFactory::HBox:
      className = "HBox";
      break;
  case WidgetFactory::VBox:
      className = "VBox";
      break;
  case WidgetFactory::Grid:
      className = "Grid";
      break;
  default:
      break;
  }
    }

    TQString dbInfo;
#ifndef TQT_NO_SQL
    dbInfo = MetaDataBase::fakeProperty( o, "database" ).toStringList().join(".");
#endif

    TQString name = o->name();
    if ( o->parent() && o->parent()->inherits( "TQWidgetStack" ) &&
   o->parent()->parent() ) {
  if ( o->parent()->parent()->inherits( "TQTabWidget" ) )
      name = ( (TQTabWidget*)o->parent()->parent() )->tabLabel( (TQWidget*)o );
  else if ( o->parent()->parent()->inherits( "TQWizard" ) )
      name = ( (TQWizard*)o->parent()->parent() )->title( (TQWidget*)o );
    }

    TQToolBox *tb;
    if ( o->parent() && o->parent()->parent() &&
     (tb = ::tqt_cast<TQToolBox*>(o->parent()->parent()->parent())) )
    name = tb->itemLabel( tb->indexOf((TQWidget*)o) );


    if ( fakeMainWindow ) {
  name = o->parent()->name();
  className = "TQMainWindow";
    }

    if ( !parent )
  item = new HierarchyItem( HierarchyItem::Widget, this, name, className, dbInfo );
    else
  item = new HierarchyItem( HierarchyItem::Widget, parent, name, className, dbInfo );
    if ( !parent )
  item->setPixmap( 0, PixmapChooser::loadPixmap( "form.xpm", PixmapChooser::Mini ) );
    else if ( o->inherits( "TQLayoutWidget") )
  item->setPixmap( 0, PixmapChooser::loadPixmap( "layout.xpm", PixmapChooser::Small ) );
    else
  item->setPixmap( 0, WidgetDatabase::iconSet( WidgetDatabase::idFromClassName( WidgetFactory::classNameOf( o ) ) ).
       pixmap( TQIconSet::Small, TQIconSet::Normal ) );
    ( (HierarchyItem*)item )->setWidget( (TQWidget*)o );

    const TQObjectList l = o->childrenListObject();
    if ( l.isEmpty() )
  return;
    TQObjectListIt it( l );
    it.toLast();
    for ( ; it.current(); --it ) {
  if ( !it.current()->isWidgetType() || ( (TQWidget*)it.current() )->isHidden() )
      continue;
  if (  !formWindow->widgets()->find( (TQWidget*)it.current() ) ) {
      if ( it.current()->parent() &&
     ( it.current()->parent()->inherits( "TQTabWidget" ) ||
       it.current()->parent()->inherits( "TQWizard" ) ) &&
     it.current()->inherits( "TQWidgetStack" ) ) {
    TQObject *obj = it.current();
    TQObjectList *l2 = obj->queryList( "TQWidget", 0, true, false );
    QDesignerTabWidget *tw = 0;
    QDesignerWizard *dw = 0;
    if ( it.current()->parent()->inherits( "TQTabWidget" ) )
        tw = (QDesignerTabWidget*)it.current()->parent();
    if ( it.current()->parent()->inherits( "TQWizard" ) )
      dw = (QDesignerWizard*)it.current()->parent();
    TQWidgetStack *stack = (TQWidgetStack*)obj;
    for ( obj = l2->last(); obj; obj = l2->prev() ) {
        if ( qstrcmp( obj->className(), "TQWidgetStackPrivate::Invisible" ) == 0 ||
       ( tw && !tw->tabBar()->tab( stack->id( (TQWidget*)obj ) ) ) ||
       ( dw && dw->isPageRemoved( (TQWidget*)obj ) ) )
      continue;
        insertObject( obj, item );
    }
    delete l2;
      } else if ( ::tqt_cast<TQToolBox*>(it.current()->parent()) ) {
            if ( !::tqt_cast<TQScrollView*>(it.current()) )
            continue;
            TQToolBox *tb = (TQToolBox*)it.current()->parent();
            for ( int i = tb->count() - 1; i >= 0; --i )
            insertObject( tb->item( i ), item );
        }
      continue;
  }
  insertObject( it.current(), item );
    }

    if ( item->firstChild() )
  item->setOpen( true );
}

void HierarchyList::setCurrent( TQWidget *w )
{
    TQListViewItemIterator it( this );
    while ( it.current() ) {
  if ( ( (HierarchyItem*)it.current() )->widget() == w ) {
      blockSignals( true );
      setCurrentItem( it.current() );
      ensureItemVisible( it.current() );
      blockSignals( false );
      return;
  }
  ++it;
    }
}

void HierarchyList::showRMBMenu( TQListViewItem *i, const TQPoint & p )
{
    if ( !i )
  return;


    TQWidget *w = findWidget( i );
    if ( !w )
  return;

    if ( w != formWindow &&
   !formWindow->widgets()->find( w ) )
  return;

    if ( w->isVisibleTo( formWindow ) ) {
  if ( !w->inherits( "TQTabWidget" ) && !w->inherits( "TQWizard" ) ) {
      if ( !normalMenu )
    normalMenu = formWindow->mainWindow()->setupNormalHierarchyMenu( this );
      normalMenu->popup( p );
  } else {
      if ( !tabWidgetMenu )
    tabWidgetMenu =
        formWindow->mainWindow()->setupTabWidgetHierarchyMenu( this, TQ_SLOT( addTabPage() ),
                        TQ_SLOT( removeTabPage() ) );
      tabWidgetMenu->popup( p );
  }
    }
}

void HierarchyList::addTabPage()
{
    TQWidget *w = current();
    if ( !w )
  return;
    if ( w->inherits( "TQTabWidget" ) ) {
  TQTabWidget *tw = (TQTabWidget*)w;
  AddTabPageCommand *cmd = new AddTabPageCommand( i18n("Add Page to %1" ).arg( tw->name() ), formWindow,
              tw, "Tab" );
  formWindow->commandHistory()->addCommand( cmd );
  cmd->execute();
    } else if ( w->inherits( "TQWizard" ) ) {
  TQWizard *wiz = (TQWizard*)formWindow->mainContainer();
  AddWizardPageCommand *cmd = new AddWizardPageCommand( i18n("Add Page to %1" ).arg( wiz->name() ), formWindow,
                    wiz, "Page" );
  formWindow->commandHistory()->addCommand( cmd );
  cmd->execute();
    }
}

void HierarchyList::removeTabPage()
{
    TQWidget *w = current();
    if ( !w )
  return;
    if ( w->inherits( "TQTabWidget" ) ) {
  TQTabWidget *tw = (TQTabWidget*)w;
  if ( tw->currentPage() ) {
      QDesignerTabWidget *dtw = (QDesignerTabWidget*)tw;
      DeleteTabPageCommand *cmd = new DeleteTabPageCommand( i18n("Delete Page %1 of %2" ).
                  arg( dtw->pageTitle() ).arg( tw->name() ),
                  formWindow, tw, tw->currentPage() );
      formWindow->commandHistory()->addCommand( cmd );
      cmd->execute();
  }
    } else if ( w->inherits( "TQWizard" ) ) {
  TQWizard *wiz = (TQWizard*)formWindow->mainContainer();
  if ( wiz->currentPage() ) {
      QDesignerWizard *dw = (QDesignerWizard*)wiz;
      DeleteWizardPageCommand *cmd = new DeleteWizardPageCommand( i18n("Delete Page %1 of %2" ).
                  arg( dw->pageTitle() ).arg( wiz->name() ),
                  formWindow, wiz,
                  wiz->indexOf( wiz->currentPage() ), true );
      formWindow->commandHistory()->addCommand( cmd );
      cmd->execute();
  }
    }
}

// ------------------------------------------------------------


// ------------------------------------------------------------
static HierarchyItem::Type getChildType( int type )
{
    switch ( (HierarchyItem::Type)type ) {
    case HierarchyItem::Widget:
    case HierarchyItem::SlotParent:
  tqWarning( "getChildType: Inserting childs dynamically to Widget or SlotParent is not allwowed!" );
  return (HierarchyItem::Type)type;
    case HierarchyItem::Public:
    case HierarchyItem::Protected:
    case HierarchyItem::Private:
    case HierarchyItem::Slot:
  return HierarchyItem::Slot;
    case HierarchyItem::DefinitionParent:
    case HierarchyItem::Definition:
  return HierarchyItem::Definition;
    case HierarchyItem::Event:
    case HierarchyItem::EventFunction:
  return HierarchyItem::Event;
    }
    return (HierarchyItem::Type)type;
}

void HierarchyList::insertEntry( TQListViewItem *i, const TQPixmap &pix, const TQString &s )
{
    HierarchyItem *item = new HierarchyItem( getChildType( i->rtti() ), i, s,
               TQString(), TQString() );
    if ( !pix.isNull() )
  item->setPixmap( 0, pix );
    item->setRenameEnabled( 0, true );
    setCurrentItem( item );
    ensureItemVisible( item );
    tqApp->processEvents();
    newItem = item;
    item->startRename( 0 );
}

HierarchyView::HierarchyView( TQWidget *parent )
    : TQTabWidget( parent, 0, WStyle_Customize | WStyle_NormalBorder | WStyle_Title |
      WStyle_Tool |WStyle_MinMax | WStyle_SysMenu )
{
    formwindow = 0;
    setIcon( PixmapChooser::loadPixmap( "logo" ) );
    listview = new HierarchyList( this, formWindow() );
    addTab( listview, i18n("Widgets" ) );
}

HierarchyView::~HierarchyView()
{
}

void HierarchyView::clear()
{
    listview->clear();
}

void HierarchyView::setFormWindow( FormWindow *fw, TQWidget *w )
{
  if (fw == 0 || w == 0)
  {
    listview->clear();
    listview->setFormWindow(fw);
    formwindow = 0;
  }

  if (fw == formwindow)
  {
    listview->setCurrent(w);
    if (MainWindow::self->qWorkspace()->activeWindow() == fw)
      showPage(listview);
    return;
  }

  formwindow = fw;
  listview->setFormWindow(fw);
  listview->setup();
  listview->setCurrent(w);

  if (MainWindow::self->qWorkspace()->activeWindow() == fw)
    showPage(listview);
}

FormWindow *HierarchyView::formWindow() const
{
    return formwindow;
}

void HierarchyView::closeEvent( TQCloseEvent *e )
{
  emit hidden();
  e->accept();
}

void HierarchyView::widgetInserted( TQWidget * )
{
    listview->setup();
}

void HierarchyView::widgetRemoved( TQWidget * )
{
    listview->setup();
}

void HierarchyView::widgetsInserted( const TQWidgetList & )
{
    listview->setup();
}

void HierarchyView::widgetsRemoved( const TQWidgetList & )
{
    listview->setup();
}

void HierarchyView::namePropertyChanged( TQWidget *w, const TQVariant & )
{
    TQWidget *w2 = w;
    if ( w->inherits( "TQMainWindow" ) )
  w2 = ( (TQMainWindow*)w )->centralWidget();
    listview->changeNameOf( w2, w->name() );
}


void HierarchyView::databasePropertyChanged( TQWidget *w, const TQStringList& info )
{
#ifndef TQT_NO_SQL
    TQString i = info.join( "." );
    listview->changeDatabaseOf( w, i );
#else
  Q_UNUSED(w);
  Q_UNUSED(info);
#endif
}


void HierarchyView::tabsChanged( TQTabWidget * )
{
    listview->setup();
}

void HierarchyView::tabsChanged( TQToolBox * )
{
    listview->setup();
}

void HierarchyView::pagesChanged( TQWizard * )
{
    listview->setup();
}

void HierarchyView::rebuild()
{
    listview->setup();
}

void HierarchyView::closed( FormWindow *fw )
{
  if ( fw == formwindow ) 
    listview->clear();
}

#include "hierarchyview.moc"
