/* This file is part of the KDE libraries
   Copyright (C) 2007, 2008 Matthew Woehlke <mw_triad@users.sourceforge.net>
   Copyright (C) 2001-2003 Christoph Cullmann <cullmann@kde.org>
   Copyright (C) 2002, 2003 Anders Lund <anders.lund@lund.tdcadsl.dk>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

//BEGIN Includes
#include "kateschema.h"
#include "kateschema.moc"

#include "kateconfig.h"
#include "katedocument.h"
#include "kateglobal.h"
#include "kateview.h"
#include "katerenderer.h"
#include "kateextendedattribute.h"
#include "katestyletreewidget.h"

#include "ui_schemaconfigcolortab.h"
#include "ui_howtoimportschema.h"

#include <kcolorscheme.h>
#include <kcolorutils.h>
#include <klocale.h>
#include <kdialog.h>
#include <kcolorbutton.h>
#include <kcombobox.h>
#include <kinputdialog.h>
#include <kfontdialog.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kmenu.h>
#include <kcolordialog.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <ktexteditor/markinterface.h>
#include <khbox.h>
#include <ktabwidget.h>
#include <kfiledialog.h>

#include <QtGui/QCheckBox>
#include <QtGui/QDialog>
#include <QtGui/QLabel>
#include <QtCore/QTextCodec>
#include <QtGui/QLayout>
#include <QtGui/QPainter>
#include <QtCore/QObject>
#include <QtGui/QPixmap>
#include <QtGui/QPushButton>
#include <QtGui/QRadioButton>
#include <QtGui/QSpinBox>
#include <QtCore/QStringList>
#include <QtGui/QPolygon>
#include <QtGui/QGroupBox>
#include <QtGui/QTreeWidget>
#include <QtGui/QProgressDialog>
//END


//BEGIN KateSchemaManager
QString KateSchemaManager::normalSchema ()
{
  return KGlobal::mainComponent().aboutData()->appName () + QString (" - Normal");
}

QString KateSchemaManager::printingSchema ()
{
  return KGlobal::mainComponent().aboutData()->appName () + QString (" - Printing");
}

KateSchemaManager::KateSchemaManager ()
    : m_config ("kateschemarc", KConfig::NoGlobals)
{
  update ();
}

KateSchemaManager::~KateSchemaManager ()
{
}

//
// read the types from config file and update the internal list
//
void KateSchemaManager::update (bool readfromfile)
{
  if (readfromfile)
    m_config.reparseConfiguration ();

  m_schemas = m_config.groupList();
  m_schemas.sort ();

  m_schemas.removeAll (printingSchema());
  m_schemas.removeAll (normalSchema());
  m_schemas.prepend (printingSchema());
  m_schemas.prepend (normalSchema());
}

//
// get the right group
// special handling of the default schemas ;)
//
KConfigGroup KateSchemaManager::schema (uint number)
{
  if ((number>1) && (number < (uint)m_schemas.count()))
    return m_config.group (m_schemas[number]);
  else if (number == 1)
    return m_config.group (printingSchema());
  else
    return m_config.group (normalSchema());
}

void KateSchemaManager::addSchema (const QString &t)
{
  m_config.group(t).writeEntry("Color Background", KColorScheme(QPalette::Active, KColorScheme::View).background().color());

  update (false);
}

void KateSchemaManager::removeSchema (uint number)
{
  if (number >= (uint)m_schemas.count())
    return;

  if (number < 2)
    return;

  m_config.deleteGroup (name (number));

  update (false);
}

bool KateSchemaManager::validSchema (uint number)
{
  if (number < (uint)m_schemas.count())
    return true;

  return false;
}

bool KateSchemaManager::validSchema (const QString &name)
{
  if (name == normalSchema() || name == printingSchema())
    return true;

  for (int i = 0; i < m_schemas.size(); ++i)
    if (m_schemas[i] == name)
      return true;

  return false;
}

uint KateSchemaManager::number (const QString &name)
{
  if (name == normalSchema())
    return 0;

  if (name == printingSchema())
    return 1;

  int i;
  if ((i = m_schemas.indexOf(name)) > -1)
    return i;

  return 0;
}

QString KateSchemaManager::name (uint number)
{
  if ((number>1) && (number < (uint)m_schemas.count()))
    return m_schemas[number];
  else if (number == 1)
    return printingSchema();

  return normalSchema();
}
//END

//
// DIALOGS !!!
//

//BEGIN KateSchemaConfigColorTab -- 'Colors' tab
KateSchemaConfigColorTab::KateSchemaConfigColorTab()
  : ui(new Ui::SchemaConfigColorTab())
{
  m_schema = -1;

  ui->setupUi(this);

  // Markers from kdelibs/interfaces/ktextinterface/markinterface.h
  // add the predefined mark types as defined in markinterface.h
  ui->combobox->addItem(i18n("Bookmark"));            // markType01
  ui->combobox->addItem(i18n("Active Breakpoint"));   // markType02
  ui->combobox->addItem(i18n("Reached Breakpoint"));  // markType03
  ui->combobox->addItem(i18n("Disabled Breakpoint")); // markType04
  ui->combobox->addItem(i18n("Execution"));           // markType05
  ui->combobox->addItem(i18n("Warning"));             // markType06
  ui->combobox->addItem(i18n("Error"));               // markType07
  ui->combobox->addItem(i18n("Template Background"));
  ui->combobox->addItem(i18n("Template Editable Placeholder"));
  ui->combobox->addItem(i18n("Template Focused Editable Placeholder"));
  ui->combobox->addItem(i18n("Template Not Editable Placeholder"));
  ui->combobox->setCurrentIndex(0);

  connect( ui->combobox  , SIGNAL(activated(int))        , SLOT(slotComboBoxChanged(int)) );
  connect( ui->back      , SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->selected  , SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->current   , SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->bracket   , SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->wwmarker  , SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->iconborder, SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->tmarker   , SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->linenumber, SIGNAL(changed(QColor)), SIGNAL(changed()) );
  connect( ui->markers   , SIGNAL(changed(QColor)), SLOT(slotMarkerColorChanged(QColor)) );
  connect( ui->spellingmistakeline, SIGNAL(changed(QColor)), SIGNAL(changed()) );
}

KateSchemaConfigColorTab::~KateSchemaConfigColorTab()
{
  delete ui;
}

void KateSchemaConfigColorTab::schemaChanged ( int newSchema )
{
  // save curent schema
  if ( m_schema > -1 )
  {
    m_schemas[ m_schema ].back = ui->back->color();
    m_schemas[ m_schema ].selected = ui->selected->color();
    m_schemas[ m_schema ].current = ui->current->color();
    m_schemas[ m_schema ].bracket = ui->bracket->color();
    m_schemas[ m_schema ].wwmarker = ui->wwmarker->color();
    m_schemas[ m_schema ].iconborder = ui->iconborder->color();
    m_schemas[ m_schema ].tmarker = ui->tmarker->color();
    m_schemas[ m_schema ].linenumber = ui->linenumber->color();
    m_schemas[ m_schema ].spellingmistakeline = ui->spellingmistakeline->color();
  }

  if ( newSchema == m_schema ) return;

  // switch
  m_schema = newSchema;

  // first block signals otherwise setColor emits changed
  bool blocked = blockSignals(true);

  // If we havent this schema, read in from config file
  if ( ! m_schemas.contains( newSchema ) )
  {
    // fallback defaults
    // NOTE keep in sync with KateRendererConfig::setSchemaInternal
    KColorScheme schemeView(QPalette::Active, KColorScheme::View);
    KColorScheme schemeWindow(QPalette::Active, KColorScheme::Window);
    KColorScheme schemeSelection(QPalette::Active, KColorScheme::Selection);
    QColor tmp0( schemeView.background().color() );
    QColor tmp1( schemeSelection.background().color() );
    QColor tmp2( schemeView.background(KColorScheme::AlternateBackground).color() );
  // using KColorUtils::shade wasn't working really well
    qreal bgLuma = KColorUtils::luma( tmp0 );
    QColor tmp3( KColorUtils::tint(tmp0, schemeView.decoration(KColorScheme::HoverColor).color()) );
    QColor tmp4( KColorUtils::shade( tmp0, bgLuma > 0.3 ? -0.15 : 0.03 ) );
    QColor tmp5( KColorUtils::shade( tmp0, bgLuma > 0.7 ? -0.35 : 0.3 ) );
    QColor tmp6( schemeWindow.background().color() );
    QColor tmp7( schemeWindow.foreground().color() );
    QColor tmp8( Qt::red );

    // same std colors like in KateDocument::markColor
    QVector <QColor> mark(KTextEditor::MarkInterface::reservedMarkersCount());
    Q_ASSERT(mark.size() > 6);
    mark[0] = Qt::blue;
    mark[1] = Qt::red;
    mark[2] = Qt::yellow;
    mark[3] = Qt::magenta;
    mark[4] = Qt::gray;
    mark[5] = Qt::green;
    mark[6] = Qt::red;

    SchemaColors c;
    KConfigGroup config = KateGlobal::self()->schemaManager()->schema(newSchema);

    c.back= config.readEntry("Color Background", tmp0);
    c.selected = config.readEntry("Color Selection", tmp1);
    c.current = config.readEntry("Color Highlighted Line", tmp2);
    c.bracket = config.readEntry("Color Highlighted Bracket", tmp3);
    c.wwmarker = config.readEntry("Color Word Wrap Marker", tmp4);
    c.tmarker = config.readEntry("Color Tab Marker", tmp5);
    c.iconborder = config.readEntry("Color Icon Bar", tmp6);
    c.linenumber = config.readEntry("Color Line Number", tmp7);
    c.spellingmistakeline = config.readEntry("Color Spelling Mistake Line", tmp8);

    for (int i = 0; i < KTextEditor::MarkInterface::reservedMarkersCount(); i++)
      c.markerColors[i] =  config.readEntry( QString("Color MarkType%1").arg(i+1), mark[i] );

    c.templateColors[0] = config.readEntry(QString("Color Template Background"),QColor(0xcc,0xcc,0xcc));
    c.templateColors[1] = config.readEntry(QString("Color Template Editable Placeholder"),QColor(0xcc,0xff,0xcc));
    c.templateColors[2] = config.readEntry(QString("Color Template Focused Editable Placeholder"),QColor(0x66,0xff,0x66));
    c.templateColors[3] = config.readEntry(QString("Color Template Not Editable Placeholder"),QColor(0xff,0xcc,0xcc));

    m_schemas[ newSchema ] = c;
  }

  ui->back->setColor(  m_schemas[ newSchema ].back);
  ui->selected->setColor(  m_schemas [ newSchema ].selected );
  ui->current->setColor(  m_schemas [ newSchema ].current );
  ui->bracket->setColor(  m_schemas [ newSchema ].bracket );
  ui->wwmarker->setColor(  m_schemas [ newSchema ].wwmarker );
  ui->tmarker->setColor(  m_schemas [ newSchema ].tmarker );
  ui->iconborder->setColor(  m_schemas [ newSchema ].iconborder );
  ui->linenumber->setColor(  m_schemas [ newSchema ].linenumber );
  ui->spellingmistakeline->setColor(  m_schemas [ newSchema ].spellingmistakeline );

  // map from 0..reservedMarkersCount()-1 - the same index as in markInterface
  for (int i = 0; i < KTextEditor::MarkInterface::reservedMarkersCount(); i++)
  {
    QPixmap pix(16, 16);
    pix.fill( m_schemas [ newSchema ].markerColors[i]);
    ui->combobox->setItemIcon(i, QIcon(pix));
  }
  for (int i = 0; i < 4; i++)
  {
    QPixmap pix(16, 16);
    pix.fill( m_schemas [ newSchema ].templateColors[i]);
    ui->combobox->setItemIcon(i+KTextEditor::MarkInterface::reservedMarkersCount(), QIcon(pix));
  }

  ui->markers->setColor(  m_schemas [ newSchema ].markerColors[ ui->combobox->currentIndex() ] );

  blockSignals(blocked);
}

void KateSchemaConfigColorTab::apply ()
{
  schemaChanged( m_schema );
  QMap<int,SchemaColors>::Iterator it;
  for ( it =  m_schemas.begin(); it !=  m_schemas.end(); ++it )
  {
    kDebug(13030)<<"APPLY scheme = "<<it.key();
    KConfigGroup config = KateGlobal::self()->schemaManager()->schema( it.key() );
    kDebug(13030)<<"Using config group "<<config.name();
    SchemaColors c = it.value();

    // TODO - don't save if using defaults, so that changing the color scheme
    // lets colors track the new scheme if they haven't been customized
    // Although, KColorScheme should handle this eventually...
    config.writeEntry("Color Background", c.back);
    config.writeEntry("Color Selection", c.selected);
    config.writeEntry("Color Highlighted Line", c.current);
    config.writeEntry("Color Highlighted Bracket", c.bracket);
    config.writeEntry("Color Word Wrap Marker", c.wwmarker);
    config.writeEntry("Color Tab Marker", c.tmarker);
    config.writeEntry("Color Icon Bar", c.iconborder);
    config.writeEntry("Color Line Number", c.linenumber);
    config.writeEntry("Color Spelling Mistake Line", c.spellingmistakeline);

    for (int i = 0; i < KTextEditor::MarkInterface::reservedMarkersCount(); i++)
    {
      config.writeEntry(QString("Color MarkType%1").arg(i + 1), c.markerColors[i]);
    }

    config.writeEntry(QString("Color Template Background"),c.templateColors[0]);
    config.writeEntry(QString("Color Template Editable Placeholder"),c.templateColors[1]);
    config.writeEntry(QString("Color Template Focused Editable Placeholder"),c.templateColors[2]);
    config.writeEntry(QString("Color Template Not Editable Placeholder"),c.templateColors[3]);

  }
}

void KateSchemaConfigColorTab::slotMarkerColorChanged( const QColor& color)
{
  int index = ui->combobox->currentIndex();
  if (index<7)
   m_schemas[ m_schema ].markerColors[ index ] = color;
  else
   m_schemas[m_schema].templateColors[index-7] = color;
  QPixmap pix(16, 16);
  pix.fill(color);
  ui->combobox->setItemIcon(index, QIcon(pix));

  emit changed();
}

void KateSchemaConfigColorTab::slotComboBoxChanged(int index)
{
  // temporarily block signals because setColor emits changed as well
  bool blocked = ui->markers->blockSignals(true);
  if (index<7)
    ui->markers->setColor( m_schemas[m_schema].markerColors[index] );
  else
    ui->markers->setColor( m_schemas[m_schema].templateColors[index-7] );
  ui->markers->blockSignals(blocked);
}

//END KateSchemaConfigColorTab

//BEGIN FontConfig -- 'Fonts' tab
KateSchemaConfigFontTab::KateSchemaConfigFontTab()
{
    // sizemanagment
  QGridLayout *grid = new QGridLayout( this );

  m_fontchooser = new KFontChooser ( this, KFontChooser::NoDisplayFlags );
  grid->addWidget( m_fontchooser, 0, 0);

  m_schema = -1;
}

KateSchemaConfigFontTab::~KateSchemaConfigFontTab()
{
}

void KateSchemaConfigFontTab::slotFontSelected( const QFont &font )
{
  if ( m_schema > -1 )
  {
    m_fonts[m_schema] = font;
    emit changed();
  }
}

void KateSchemaConfigFontTab::apply()
{
  FontMap::Iterator it;
  for ( it = m_fonts.begin(); it != m_fonts.end(); ++it )
  {
    KateGlobal::self()->schemaManager()->schema( it.key() ).writeEntry( "Font", it.value() );
  }
}

void KateSchemaConfigFontTab::schemaChanged( int newSchema )
{
  if ( m_schema > -1 )
    m_fonts[ m_schema ] = m_fontchooser->font();

  m_schema = newSchema;

  QFont f (KGlobalSettings::fixedFont());

  m_fontchooser->disconnect ( this );
  m_fontchooser->setFont ( KateGlobal::self()->schemaManager()->schema( newSchema ).readEntry("Font", f) );
  m_fonts[ newSchema ] = m_fontchooser->font();
  connect (m_fontchooser, SIGNAL (fontSelected(QFont)), this, SLOT (slotFontSelected(QFont)));
}
//END FontConfig

//BEGIN FontColorConfig -- 'Normal Text Styles' tab
KateSchemaConfigFontColorTab::KateSchemaConfigFontColorTab()
{
  // sizemanagment
  QGridLayout *grid = new QGridLayout( this );

  m_defaultStyles = new KateStyleTreeWidget( this );
  m_defaultStyles->setRootIsDecorated(false);
  connect(m_defaultStyles, SIGNAL(changed()), this, SIGNAL(changed()));
  grid->addWidget( m_defaultStyles, 0, 0);

  m_defaultStyles->setWhatsThis(i18n(
      "<p>This list displays the default styles for the current schema and "
      "offers the means to edit them. The style name reflects the current "
      "style settings.</p>"
      "<p>To edit the colors, click the colored squares, or select the color "
      "to edit from the popup menu.</p><p>You can unset the Background and Selected "
      "Background colors from the popup menu when appropriate.</p>") );
}

KateSchemaConfigFontColorTab::~KateSchemaConfigFontColorTab()
{
  qDeleteAll(m_defaultStyleLists);
}

KateAttributeList *KateSchemaConfigFontColorTab::attributeList (uint schema)
{
  if (!m_defaultStyleLists.contains(schema))
  {
    KateAttributeList *list = new KateAttributeList ();
    KateHlManager::self()->getDefaults(KateGlobal::self()->schemaManager()->name (schema), *list);

    m_defaultStyleLists.insert (schema, list);
  }

  return m_defaultStyleLists[schema];
}

void KateSchemaConfigFontColorTab::schemaChanged (uint schema)
{
  m_defaultStyles->clear ();

  KateAttributeList *l = attributeList (schema);

  // set colors
  QPalette p ( m_defaultStyles->palette() );
  KColorScheme s ( QPalette::Active, KColorScheme::View );
  QColor _c ( s.background().color() );
  p.setColor( QPalette::Base,
    KateGlobal::self()->schemaManager()->schema(schema).
      readEntry( "Color Background", _c ) );
  _c = KColorScheme(QPalette::Active, KColorScheme::Selection).background().color();
  p.setColor( QPalette::Highlight,
    KateGlobal::self()->schemaManager()->schema(schema).
      readEntry( "Color Selection", _c ) );
  _c = l->at(0)->foreground().color(); // not quite as much of an assumption ;)
  p.setColor( QPalette::Text, _c );
  m_defaultStyles->viewport()->setPalette( p );

  for ( uint i = 0; i < KateHlManager::self()->defaultStyles(); i++ )
  {
    m_defaultStyles->addItem( KateHlManager::self()->defaultStyleName(i, true), l->at( i ) );
  }
}

void KateSchemaConfigFontColorTab::reload ()
{
  m_defaultStyles->clear ();
  qDeleteAll(m_defaultStyleLists);
  m_defaultStyleLists.clear ();
}

void KateSchemaConfigFontColorTab::apply ()
{
  QHashIterator<int,KateAttributeList*> it = m_defaultStyleLists;
  while (it.hasNext()) {
    it.next();
    KateHlManager::self()->setDefaults(KateGlobal::self()->schemaManager()->name (it.key()), *it.value());
  }
}

void KateSchemaConfigFontColorTab::exportDefaults(int schema, KConfig *cfg) {
  KateHlManager::self()->setDefaults(KateGlobal::self()->schemaManager()->name (schema), *(m_defaultStyleLists[schema]),cfg);
}

void KateSchemaConfigFontColorTab::importDefaults(const QString& schemaName, int schema, KConfig *cfg) {
  KateHlManager::self()->getDefaults(schemaName, *(m_defaultStyleLists[schema]),cfg);
}

//END FontColorConfig

//BEGIN KateSchemaConfigHighlightTab -- 'Highlighting Text Styles' tab
KateSchemaConfigHighlightTab::KateSchemaConfigHighlightTab(KateSchemaConfigFontColorTab *page)
{
  m_defaults = page;

  m_schema = 0;
  m_hl = 0;

  QVBoxLayout *layout = new QVBoxLayout(this);

  // hl chooser
  KHBox *hbHl = new KHBox( this );
  layout->addWidget (hbHl);

  hbHl->setSpacing( -1 );
  QLabel *lHl = new QLabel( i18n("H&ighlight:"), hbHl );
  hlCombo = new KComboBox( hbHl );
  hlCombo->setEditable( false );
  lHl->setBuddy( hlCombo );
  connect( hlCombo, SIGNAL(activated(int)),
           this, SLOT(hlChanged(int)) );

  QPushButton *btnexport = new QPushButton( i18n("Export HlColors..."), hbHl );
  connect( btnexport,SIGNAL(clicked()),this,SLOT(exportHl()));
  
  QPushButton *btnimport = new QPushButton( i18n("Import HlColors..."), hbHl );
  connect( btnimport,SIGNAL(clicked()),this,SLOT(importHl()));
  
  for( int i = 0; i < KateHlManager::self()->highlights(); i++) {
    if (KateHlManager::self()->hlSection(i).length() > 0)
      hlCombo->addItem(KateHlManager::self()->hlSection(i) + QString ("/") + KateHlManager::self()->hlNameTranslated(i));
    else
      hlCombo->addItem(KateHlManager::self()->hlNameTranslated(i));
  }
  hlCombo->setCurrentIndex(0);

  // styles listview
  m_styles = new KateStyleTreeWidget( this, true );
  connect(m_styles, SIGNAL(changed()), this, SIGNAL(changed()));
  layout->addWidget (m_styles, 999);

  // get current highlighting from the host application
  int hl = 0;
  KTextEditor::MdiContainer *iface = qobject_cast<KTextEditor::MdiContainer*>(KateGlobal::self()->container());
  if (iface) {
    KateView *kv = qobject_cast<KateView*>(iface->activeView());
    if (kv) {
      const QString hlName = kv->doc()->highlight()->name();
      hl = KateHlManager::self()->nameFind(hlName);
    }
  }
  hlCombo->setCurrentIndex ( hl );
  hlChanged ( hl );

  m_styles->setWhatsThis(i18n(
    "<p>This list displays the contexts of the current syntax highlight mode and "
    "offers the means to edit them. The context name reflects the current "
    "style settings.</p><p>To edit using the keyboard, press "
    "<strong>&lt;SPACE&gt;</strong> and choose a property from the popup menu.</p>"
    "<p>To edit the colors, click the colored squares, or select the color "
    "to edit from the popup menu.</p><p>You can unset the Background and Selected "
    "Background colors from the context menu when appropriate.</p>") );
}

KateSchemaConfigHighlightTab::~KateSchemaConfigHighlightTab()
{
}

void KateSchemaConfigHighlightTab::hlChanged(int z)
{
  m_hl = z;

  schemaChanged (m_schema);
}

bool KateSchemaConfigHighlightTab::loadAllHlsForSchema(int schema) {
  QProgressDialog progress(i18n("Loading all highlightings for schema"),i18n("Cancel"),0,KateHlManager::self()->highlights(),this);
  progress.setWindowModality(Qt::WindowModal);
  for( int i = 0; i < KateHlManager::self()->highlights(); i++) {
    if (!m_hlDict[schema].contains(i))
    {
      kDebug(13030) << "NEW HL, create list";

      QList<KateExtendedAttribute::Ptr> list;
      KateHlManager::self()->getHl( i )->getKateExtendedAttributeListCopy(KateGlobal::self()->schemaManager()->name (schema), list);
      m_hlDict[schema].insert (i, list);
    }
    progress.setValue(progress.value()+1);
    if (progress.wasCanceled()) {
      progress.setValue(KateHlManager::self()->highlights());
      return false;
    }
  }
  progress.setValue(KateHlManager::self()->highlights());
  return true;
}

void KateSchemaConfigHighlightTab::schemaChanged (int schema)
{
  m_schema = schema;

  kDebug(13030) << "NEW SCHEMA: " << m_schema << " NEW HL: " << m_hl;

  m_styles->clear ();

  if (!m_hlDict.contains(m_schema))
  {
    kDebug(13030) << "NEW SCHEMA, create dict";

    m_hlDict.insert (schema, QHash<int, QList<KateExtendedAttribute::Ptr> >());
  }

  if (!m_hlDict[m_schema].contains(m_hl))
  {
    kDebug(13030) << "NEW HL, create list";

    QList<KateExtendedAttribute::Ptr> list;
    KateHlManager::self()->getHl( m_hl )->getKateExtendedAttributeListCopy(KateGlobal::self()->schemaManager()->name (m_schema), list);
    m_hlDict[m_schema].insert (m_hl, list);
  }

  KateAttributeList *l = m_defaults->attributeList (schema);

  // Set listview colors
  // We do that now, because we can now get the "normal text" color.
  // TODO this reads of the KConfig object, which should be changed when
  // the color tab is fixed.
  QPalette p ( m_styles->palette() );
  KColorScheme s ( QPalette::Active, KColorScheme::View );
  QColor _c ( s.background().color() );
  p.setColor( QPalette::Base,
    KateGlobal::self()->schemaManager()->schema(m_schema).
      readEntry( "Color Background", _c ) );
  _c = KColorScheme(QPalette::Active, KColorScheme::Selection).background().color();
  p.setColor( QPalette::Highlight,
    KateGlobal::self()->schemaManager()->schema(m_schema).
      readEntry( "Color Selection", _c ) );
  _c = l->at(0)->foreground().color(); // not quite as much of an assumption ;)
  p.setColor( QPalette::Text, _c );
  m_styles->viewport()->setPalette( p );

  QHash<QString, QTreeWidgetItem*> prefixes;
  QList<KateExtendedAttribute::Ptr>::ConstIterator it = m_hlDict[m_schema][m_hl].constBegin();
  while (it != m_hlDict[m_schema][m_hl].constEnd())
  {
    const KateExtendedAttribute::Ptr itemData = *it;
    Q_ASSERT(itemData);

    kDebug(13030) << "insert items " << itemData->name();

    // All stylenames have their language mode prefixed, e.g. HTML:Comment
    // split them and put them into nice substructures.
    int c = itemData->name().indexOf(':');
    if ( c > 0 ) {
      QString prefix = itemData->name().left(c);
      QString name   = itemData->name().mid(c+1);

      QTreeWidgetItem *parent = prefixes[prefix];
      if ( ! parent )
      {
        parent = new QTreeWidgetItem( m_styles, QStringList() << prefix );
        m_styles->expandItem(parent);
        prefixes.insert( prefix, parent );
      }
      m_styles->addItem( parent, name, l->at(itemData->defaultStyleIndex()), itemData );
    } else {
      m_styles->addItem( itemData->name(), l->at(itemData->defaultStyleIndex()), itemData );
    }
    ++it;
  }

  m_styles->resizeColumns();
}

void KateSchemaConfigHighlightTab::reload ()
{
  m_styles->clear ();

  m_hlDict.clear ();

  hlChanged (0);
}

void KateSchemaConfigHighlightTab::apply ()
{
  QMutableHashIterator<int, QHash<int, QList<KateExtendedAttribute::Ptr> > > it = m_hlDict;
  while (it.hasNext()) {
    it.next();
    QMutableHashIterator<int, QList<KateExtendedAttribute::Ptr> > it2 = it.value();
    while (it2.hasNext()) {
      it2.next();
      KateHlManager::self()->getHl( it2.key() )->setKateExtendedAttributeList (it.key(), it2.value());
    }
  }
}


QList<int> KateSchemaConfigHighlightTab::hlsForSchema(int schema) {
  return m_hlDict[schema].keys();
}


void KateSchemaConfigHighlightTab::importHl(const QString& fromSchemaName, int schema, int hl, KConfig *cfg) {
        QString schemaNameForLoading(fromSchemaName);
        QString hlName;
        bool doManage=(cfg==0);
        if (schema==-1) schema=m_schema;
        
        if (doManage) {
          QString srcName=KFileDialog::getOpenFileName( QString(KateHlManager::self()->getHl(hl)->name()+QString(".katehlcolor")),
                                  QString::fromLatin1("*.katehlcolor|%1").arg(i18n("Kate color schema")),
                                  this,
                                  i18n("Importing colors for single highlighting"));
          kDebug(13030)<<"hl file to open "<<srcName;
          if (srcName.isEmpty()) return;
          cfg=new KConfig(srcName,KConfig::SimpleConfig);
          KConfigGroup grp(cfg,"KateHLColors");
          hlName=grp.readEntry("highlight",QString());
          schemaNameForLoading=grp.readEntry("schema",QString());
          if ( (grp.readEntry("full schema","true").toUpper()!="FALSE") || hlName.isEmpty() || schemaNameForLoading.isEmpty()) {
            //ERROR - file format
            KMessageBox::information(
                    this,
                    i18n("File is not a single highlighting color file"),
                    i18n("Fileformat error"));
            hl=-1;
            schemaNameForLoading=QString();
          } else {
            hl = KateHlManager::self()->nameFind(hlName);
            if ( (hl==0) && (KateHlManager::self()->getHl(0)->name().toLower()!=hlName.toLower()))
              hl=-1;
            kDebug(13030)<<hlName<<"--->"<<hl;
            if (hl==-1) {
              //hl not found
              KMessageBox::information(
                      this,
                      i18n("The selected file contains colors for a non existing highlighting:%1",hlName),
                      i18n("Import failure"));
              hl=-1;
              schemaNameForLoading=QString();
            }
          }
        }
        
        if ( (hl!=-1) && (!schemaNameForLoading.isEmpty())) {
          
          QList<KateExtendedAttribute::Ptr> list;
          KateHlManager::self()->getHl( hl )->getKateExtendedAttributeListCopy(schemaNameForLoading, list, cfg);
          KateHlManager::self()->getHl( hl )->setKateExtendedAttributeList(schema, list);
          m_hlDict[schema].insert (hl, list);
        }
        
        if (cfg && doManage) {
          apply();
          delete cfg;
          cfg=0;
          if ( (hl!=-1) && (!schemaNameForLoading.isEmpty())) {
            hlChanged(m_hl);
            KMessageBox::information(
                      this,
                      i18n("Colors have been imported for highlighting: %1",hlName),
                      i18n("Import has finished"));
          }
        }
        
        
}


void KateSchemaConfigHighlightTab::exportHl(int schema, int hl, KConfig *cfg) {
  bool doManage=(cfg==0);
  if (schema==-1) schema=m_schema;
  if (hl==-1) hl=m_hl;
  
  QList<KateExtendedAttribute::Ptr> items=m_hlDict[schema][hl];
  if (doManage)  {
    QString destName=KFileDialog::getSaveFileName( QString(KateHlManager::self()->getHl(hl)->name()+".katehlcolor"),
                                    QString::fromLatin1("*.katehlcolor|%1").arg(i18n("Kate color schema")),
                                    this,
                                    i18n("Exporting colors for single highlighting: %1", KateHlManager::self()->getHl(hl)->name()),
                                    KFileDialog::ConfirmOverwrite );
  
    if (destName.isEmpty()) return;

    cfg=new KConfig(destName,KConfig::SimpleConfig);
    KConfigGroup grp(cfg,"KateHLColors");
    grp.writeEntry("highlight",KateHlManager::self()->getHl(hl)->name());
    grp.writeEntry("schema",KateGlobal::self()->schemaManager()->name(schema));
    grp.writeEntry("full schema","false");
  }
  KateHlManager::self()->getHl(hl)->setKateExtendedAttributeList(schema,items,cfg,doManage);

  if (doManage) {
    cfg->sync();
    delete cfg;
  }
  
}

//END KateSchemaConfigHighlightTab

//BEGIN KateSchemaConfigPage -- Main dialog page
KateSchemaConfigPage::KateSchemaConfigPage( QWidget *parent)
  : KateConfigPage( parent ),
    m_lastSchema (-1)
{
  QVBoxLayout *layout = new QVBoxLayout(this);
  layout->setMargin(0);

  KHBox *hbHl = new KHBox( this );
  layout->addWidget(hbHl);
  hbHl->setSpacing( -1 );
  QLabel *lHl = new QLabel( i18n("&Schema:"), hbHl );
  schemaCombo = new KComboBox( hbHl );
  schemaCombo->setEditable( false );
  lHl->setBuddy( schemaCombo );
  connect( schemaCombo, SIGNAL(activated(int)),
           this, SLOT(schemaChanged(int)) );

  QPushButton *btnnew = new QPushButton( i18n("&New..."), hbHl );
  connect( btnnew, SIGNAL(clicked()), this, SLOT(newSchema()) );

  btndel = new QPushButton( i18n("&Delete"), hbHl );
  connect( btndel, SIGNAL(clicked()), this, SLOT(deleteSchema()) );

  QPushButton *btnexport = new QPushButton( i18n("Export schema ..."), hbHl );
  connect(btnexport,SIGNAL(clicked()),this,SLOT(exportFullSchema()));
  QPushButton *btnimport = new QPushButton( i18n("Import schema ..."), hbHl );
  connect(btnimport,SIGNAL(clicked()),this,SLOT(importFullSchema()));
  
  qobject_cast<QBoxLayout *>(hbHl->layout())->addStretch();

  m_tabWidget = new KTabWidget ( this );
  layout->addWidget (m_tabWidget);

  m_colorTab = new KateSchemaConfigColorTab();
  m_tabWidget->addTab (m_colorTab, i18n("Colors"));
  connect(m_colorTab, SIGNAL(changed()), SLOT(slotChanged()));

  m_fontTab = new KateSchemaConfigFontTab();
  m_tabWidget->addTab (m_fontTab, i18n("Font"));
  connect(m_fontTab, SIGNAL(changed()), SLOT(slotChanged()));

  m_fontColorTab = new KateSchemaConfigFontColorTab();
  m_tabWidget->addTab (m_fontColorTab, i18n("Normal Text Styles"));
  connect(m_fontColorTab, SIGNAL(changed()), SLOT(slotChanged()));

  m_highlightTab = new KateSchemaConfigHighlightTab(m_fontColorTab);
  m_tabWidget->addTab(m_highlightTab, i18n("Highlighting Text Styles"));
  connect(m_highlightTab, SIGNAL(changed()), SLOT(slotChanged()));

  connect (m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT (newCurrentPage(int)));

  hbHl = new KHBox( this );
  layout->addWidget (hbHl);
  hbHl->setSpacing( -1 );
  lHl = new QLabel( i18n("&Default schema for %1:", KGlobal::mainComponent().aboutData()->programName ()), hbHl );
  defaultSchemaCombo = new KComboBox( hbHl );
  defaultSchemaCombo->setEditable( false );
  lHl->setBuddy( defaultSchemaCombo );

  m_defaultSchema = KateGlobal::self()->schemaManager()->number (KateRendererConfig::global()->schema());

  reload();

  connect( defaultSchemaCombo, SIGNAL(activated(int)),
           this, SLOT(slotChanged()) );
}

void KateSchemaConfigPage::exportFullSchema() {
  QString destName=KFileDialog::getSaveFileName( QString(KateGlobal::self()->schemaManager()->name(m_lastSchema)+".kateschema"),
                                    QString::fromLatin1("*.kateschema|%1").arg(i18n("Kate color schema")),
                                    this,
                                    i18n("Exporting color schema:%1", KateGlobal::self()->schemaManager()->name(m_lastSchema)),
                                    KFileDialog::ConfirmOverwrite );
  
  if (destName.isEmpty()) return;
  if (!m_highlightTab->loadAllHlsForSchema(m_lastSchema)) {
    //ABORT - MESSAGE
    return;
  }
  QStringList hlList;  
  QList<int> hls=m_highlightTab->hlsForSchema(m_lastSchema);
  KConfig cfg(destName,KConfig::SimpleConfig);
  m_fontColorTab->exportDefaults(m_lastSchema,&cfg);
  int cnt=0;
  QProgressDialog progress(i18n("Exporting schema"),i18n("Stop"),0,hls.count(),this);
  progress.setWindowModality(Qt::WindowModal);
  foreach(int hl,hls) {
    hlList<<KateHlManager::self()->getHl (hl)->name();
    m_highlightTab->exportHl(m_lastSchema,hl,&cfg);
    cnt++;
    progress.setValue(cnt);
    if (progress.wasCanceled()) break;
  }
  progress.setValue(hls.count());
  KConfigGroup grp(&cfg,"KateSchema");
  grp.writeEntry("full schema","true");
  grp.writeEntry("highlightings",hlList);
  grp.writeEntry("schema",KateGlobal::self()->schemaManager()->name(m_lastSchema));
  cfg.sync();

}

void KateSchemaConfigPage::importFullSchema() {
  QString srcName=KFileDialog::getOpenFileName( KUrl(),
                                    "*.kateschema|Kate color schema",
                                    this,
                                    i18n("Importing color schema")
                                    );

  if (srcName.isEmpty())  return;
  KConfig cfg(srcName,KConfig::SimpleConfig);
  KConfigGroup grp(&cfg,"KateSchema");
  if (grp.readEntry("full schema","false").toUpper()!="TRUE") {
    KMessageBox::information(
            this,
            i18n("File is not a full schema file"),
            i18n("Fileformat error"));
    return;
  }
  QStringList highlightings=grp.readEntry("highlightings",QStringList());
  QString schemaName=grp.readEntry("schema",i18n("Name unspecified"));
  QString fromSchemaName=schemaName;
  bool reask=true;
  do {
    KDialog howToImportDialog(this);
    Ui_KateHowToImportSchema howToImport;
    howToImport.setupUi(howToImportDialog.mainWidget());
    if (KateGlobal::self()->schemaManager()->list().contains(schemaName)) {
      howToImport.radioReplaceExisting->show();
      howToImport.radioReplaceExisting->setText(i18n("Replace existing schema %1",schemaName));
      howToImport.radioReplaceExisting->setChecked(true);
    } else {
      howToImport.radioReplaceExisting->hide();
      howToImport.newName->setText(schemaName);
    }
    if (howToImportDialog.exec()==KDialog::Cancel) {
      schemaName=QString();
      reask=false;
    } else {
      if (howToImport.radioReplaceExisting->isChecked()) {
        reask=false;
      } else if (howToImport.radioReplaceCurrent->isChecked()) {
        schemaName=KateGlobal::self()->schemaManager()->list()[m_lastSchema];
        reask=false;
      } else if (howToImport.radioAsNew->isChecked())  {
        schemaName=howToImport.newName->text();
        if (KateGlobal::self()->schemaManager()->list().contains(schemaName)) {
          reask=true;
        } else reask=false;
      } else reask=true;
    }
  } while (reask);
  if (!schemaName.isEmpty()) {
    kDebug(13030)<<"Importing schema:"<<schemaName;
    bool asNew=!KateGlobal::self()->schemaManager()->list().contains(schemaName);
    kDebug(13030)<<"schema exists?"<<(!asNew);
    int schemaId;
    if (asNew) {
      newSchema(schemaName);
      schemaId=m_lastSchema;
    } else {
      schemaId=KateGlobal::self()->schemaManager()->list().indexOf(schemaName);
    }
    schemaChanged(schemaId);
    m_fontColorTab->importDefaults(fromSchemaName,schemaId,&cfg);
    m_fontColorTab->apply();
    const int hlCount=KateHlManager::self()->highlights();
    QHash<QString,int> nameToId;
    for(int i=0;i<hlCount;i++) {
      nameToId.insert(KateHlManager::self()->hlName(i),i);
    }
    
    int cnt=0;
    QProgressDialog progress(i18n("Importing schema"),i18n("Stop"),0,highlightings.count(),this);
    progress.setWindowModality(Qt::WindowModal);
    foreach(const QString& hl,highlightings) {
      if (nameToId.contains(hl)) {
        int i=nameToId[hl];
        m_highlightTab->importHl(fromSchemaName,schemaId,i,&cfg);        
        kDebug(13030)<<"hl imported:"<<hl;
      } else {
        kDebug(13030)<<"could not import hl, hl unknown:"<<hl;
      }
      cnt++;
      progress.setValue(cnt);
      if (progress.wasCanceled()) break;
    }
    progress.setValue(highlightings.count());
    m_highlightTab->apply();
    schemaChanged(schemaId);
  }
}

KateSchemaConfigPage::~KateSchemaConfigPage ()
{
  // just reload config from disc
  KateGlobal::self()->schemaManager()->update ();
}

void KateSchemaConfigPage::apply()
{
  m_colorTab->apply();
  m_fontTab->apply();
  m_fontColorTab->apply ();
  m_highlightTab->apply ();

  // just sync the config
  KateGlobal::self()->schemaManager()->schema (0).sync();

  KateGlobal::self()->schemaManager()->update ();

  // clear all attributes
  for (int i = 0; i < KateHlManager::self()->highlights(); ++i)
    KateHlManager::self()->getHl (i)->clearAttributeArrays();

  // than reload the whole stuff
  KateRendererConfig::global()->setSchema (KateGlobal::self()->schemaManager()->name (defaultSchemaCombo->currentIndex()));
  KateRendererConfig::global()->reloadSchema();

  // sync the hl config for real
  KateHlManager::self()->getKConfig()->sync ();
}

void KateSchemaConfigPage::reload()
{
  // just reload the config from disc
  KateGlobal::self()->schemaManager()->update ();

  // special for the highlighting stuff
  m_fontColorTab->reload ();

  update ();

  defaultSchemaCombo->setCurrentIndex (KateGlobal::self()->schemaManager()->number (KateRendererConfig::global()->schema()));

  // initialize to the schema in the current document, or default schema
  schemaCombo->setCurrentIndex( m_defaultSchema );
  schemaChanged( m_defaultSchema );
}

void KateSchemaConfigPage::reset()
{
  reload ();
}

void KateSchemaConfigPage::defaults()
{
  reload ();
}

void KateSchemaConfigPage::update ()
{
  // soft update, no load from disk
  KateGlobal::self()->schemaManager()->update (false);

  schemaCombo->clear ();
  schemaCombo->addItems (KateGlobal::self()->schemaManager()->list ());

  defaultSchemaCombo->clear ();
  defaultSchemaCombo->addItems (KateGlobal::self()->schemaManager()->list ());

  schemaCombo->setCurrentIndex (0);
  schemaChanged (0);

  schemaCombo->setEnabled (schemaCombo->count() > 0);
}

void KateSchemaConfigPage::deleteSchema ()
{
  int t = schemaCombo->currentIndex ();

  KateGlobal::self()->schemaManager()->removeSchema (t);

  update ();
}

void KateSchemaConfigPage::newSchema (const QString& newName)
{
  QString t;
  if (newName.isEmpty())
    t = KInputDialog::getText (i18n("Name for New Schema"), i18n ("Name:"), i18n("New Schema"), 0, this);
  else
    t=newName;
  KateGlobal::self()->schemaManager()->addSchema (t);

  // soft update, no load from disk
  KateGlobal::self()->schemaManager()->update (false);
  int i = KateGlobal::self()->schemaManager()->list ().indexOf (t);

  update ();
  if (i > -1)
  {
    schemaCombo->setCurrentIndex (i);
    schemaChanged (i);
  }
}

void KateSchemaConfigPage::schemaChanged (int schema)
{
  btndel->setEnabled( schema > 1 );

  m_colorTab->schemaChanged( schema );
  m_fontTab->schemaChanged( schema );
  m_fontColorTab->schemaChanged (schema);
  m_highlightTab->schemaChanged (schema);

  m_lastSchema = schema;
}

void KateSchemaConfigPage::newCurrentPage (int index)
{
   QWidget *w = m_tabWidget->widget(index);
   if (w == m_highlightTab)
    m_highlightTab->schemaChanged (m_lastSchema);
}
//END KateSchemaConfigPage

//BEGIN SCHEMA ACTION -- the 'View->Schema' menu action
void KateViewSchemaAction::init()
{
  m_group=0;
  m_view = 0;
  last = 0;

  connect(menu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow()));
}

void KateViewSchemaAction::updateMenu (KateView *view)
{
  m_view = view;
}

void KateViewSchemaAction::slotAboutToShow()
{
  KateView *view=m_view;
  int count = KateGlobal::self()->schemaManager()->list().count();

  if (!m_group) {
   m_group=new QActionGroup(menu());
   m_group->setExclusive(true);

  }

  for (int z=0; z<count; z++)
  {
    QString hlName = KateGlobal::self()->schemaManager()->list().operator[](z);

    if (!names.contains(hlName))
    {
      names << hlName;
      QAction *a=menu()->addAction ( hlName, this, SLOT(setSchema()));
      a->setData(hlName);
      a->setCheckable(true);
      a->setActionGroup(m_group);
	//FIXME EXCLUSIVE
    }
  }

  if (!view) return;

  QString id=view->renderer()->config()->schema();
   foreach(QAction *a,menu()->actions()) {
	a->setChecked(a->data().toString()==id);

	}
//FIXME
#if 0
  popupMenu()->setItemChecked (last, false);
  popupMenu()->setItemChecked (view->renderer()->config()->schema()+1, true);

  last = view->renderer()->config()->schema()+1;
#endif
}

void KateViewSchemaAction::setSchema () {
  QAction *action = qobject_cast<QAction*>(sender());

  if (!action) return;
  QString mode=action->data().toString();

  KateView *view=m_view;

  if (view)
    view->renderer()->config()->setSchema (mode);
}
//END SCHEMA ACTION

// kate: space-indent on; indent-width 2; replace-tabs on;
