/*
    Rosegarden
    A MIDI and audio sequencer and musical notation editor.
 
    This program is Copyright 2000-2008
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <richard.bown@ferventsoftware.com>
 
    The moral rights of Guillaume Laurent, Chris Cannam, and Richard
    Bown to claim authorship of this work have been asserted.
 
    Other copyrights also apply to some parts of this work.  Please
    see the AUTHORS file and individual file headers for details.
 
    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.  See the file
    COPYING included with this distribution for more information.
*/


#include "TextEventDialog.h"
#include <tdeapplication.h>

#include <tdelocale.h>
#include "misc/Strings.h"
#include "document/ConfigGroups.h"
#include "base/NotationTypes.h"
#include "gui/editors/notation/NotePixmapFactory.h"
#include <kcombobox.h>
#include <tdeconfig.h>
#include <kdialogbase.h>
#include <tqbitmap.h>
#include <tqgrid.h>
#include <tqgroupbox.h>
#include <tqlabel.h>
#include <tqlineedit.h>
#include <tqobject.h>
#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqstring.h>
#include <tqvbox.h>
#include <tqwidget.h>
#include <tqspinbox.h>

namespace Rosegarden
{

TextEventDialog::TextEventDialog(TQWidget *parent,
                                 NotePixmapFactory *npf,
                                 Text defaultText,
                                 int maxLength) :
        KDialogBase(parent, 0, true, i18n("Text"), Ok | Cancel | Help),
        m_notePixmapFactory(npf),
        m_styles(Text::getUserStyles()) /*,
            //m_directives(Text::getLilyPondDirectives()) */
{
    setHelp("nv-text");
    TQVBox *vbox = makeVBoxMainWidget();

    TQGroupBox *entryBox = new TQGroupBox
                          (1, TQt::Horizontal, i18n("Specification"), vbox);
    TQGroupBox *exampleBox = new TQGroupBox
                            (1, TQt::Horizontal, i18n("Preview"), vbox);

    TQGrid *entryGrid = new TQGrid(2, TQt::Horizontal, entryBox);

    new TQLabel(i18n("Text:  "), entryGrid);
    m_text = new TQLineEdit(entryGrid);
    m_text->setText(strtoqstr(defaultText.getText()));
    if (maxLength > 0)
        m_text->setMaxLength(maxLength);

    // style combo
    new TQLabel(i18n("Style:  "), entryGrid);
    m_typeCombo = new KComboBox(entryGrid);

    for (unsigned int i = 0; i < m_styles.size(); ++i)
    {

        std::string style = m_styles[i];

        // if the style is in this list, we can i18n it (kludgy):

        if (style == Text::Dynamic) {                           // index //
            m_typeCombo->insertItem(i18n("Dynamic"));           // 0

        } else if (style == Text::Direction) {
            m_typeCombo->insertItem(i18n("Direction"));         // 1

        } else if (style == Text::LocalDirection) {
            m_typeCombo->insertItem(i18n("Local Direction"));   // 2

        } else if (style == Text::Tempo) {
            m_typeCombo->insertItem(i18n("Tempo"));             // 3

        } else if (style == Text::LocalTempo) {
            m_typeCombo->insertItem(i18n("Local Tempo"));       // 4

        } else if (style == Text::Lyric) {
            m_typeCombo->insertItem(i18n("Lyric"));             // 5

        } else if (style == Text::Chord) {
            m_typeCombo->insertItem(i18n("Chord"));             // 6

        } else if (style == Text::Annotation) {
            m_typeCombo->insertItem(i18n("Annotation"));        // 7

        } else if (style == Text::LilyPondDirective) {
            m_typeCombo->insertItem(i18n("LilyPond Directive")); // 8

        } else {
            // not i18n()-able

            std::string styleName;
            styleName += (char)toupper(style[0]);
            styleName += style.substr(1);

            int uindex = styleName.find('_');
            if (uindex > 0) {
                styleName =
                    styleName.substr(0, uindex) + " " +
                    styleName.substr(uindex + 1);
            }

            m_typeCombo->insertItem(strtoqstr(styleName));
        }

        if (style == defaultText.getTextType()) {
            m_typeCombo->setCurrentItem(m_typeCombo->count() - 1);
        }
    }

    m_verseLabel = new TQLabel(i18n("Verse:  "), entryGrid);
    m_verseLabel->hide();
    m_verseSpin = new TQSpinBox(entryGrid);
    m_verseSpin->setMinValue(1);
    m_verseSpin->setMaxValue(12);
    m_verseSpin->setLineStep(1);
    m_verseSpin->setValue(defaultText.getVerse() + 1);
    m_verseSpin->hide();

    // dynamic shortcuts combo
    m_dynamicShortcutLabel = new TQLabel(i18n("Dynamic:  "), entryGrid);
    m_dynamicShortcutLabel->hide();

    m_dynamicShortcutCombo = new KComboBox(entryGrid);
    m_dynamicShortcutCombo->insertItem(i18n("ppp"));
    m_dynamicShortcutCombo->insertItem(i18n("pp"));
    m_dynamicShortcutCombo->insertItem(i18n("p"));
    m_dynamicShortcutCombo->insertItem(i18n("mp"));
    m_dynamicShortcutCombo->insertItem(i18n("mf"));
    m_dynamicShortcutCombo->insertItem(i18n("f"));
    m_dynamicShortcutCombo->insertItem(i18n("ff"));
    m_dynamicShortcutCombo->insertItem(i18n("fff"));
    m_dynamicShortcutCombo->insertItem(i18n("rfz"));
    m_dynamicShortcutCombo->insertItem(i18n("sf"));
    m_dynamicShortcutCombo->hide();

    // direction shortcuts combo
    m_directionShortcutLabel = new TQLabel(i18n("Direction:  "), entryGrid);
    m_directionShortcutLabel->hide();

    m_directionShortcutCombo = new KComboBox(entryGrid);
    // note, the "  ," is a breath mark; the extra spaces are a cheap hack to
    // try to improve the probability of Rosegarden drawing the blasted thing
    // where it's supposed to go, without the need to micro-diddle each and
    // every bliffin' one.  (Micro-diddling is not exportable to LilyPond
    // either, is it?  I rather doubt it.)
    m_directionShortcutCombo->insertItem(i18n("  ,"));
    m_directionShortcutCombo->insertItem(i18n("D.C. al Fine"));
    m_directionShortcutCombo->insertItem(i18n("D.S. al Fine"));
    m_directionShortcutCombo->insertItem(i18n("Fine"));
    m_directionShortcutCombo->insertItem(i18n("D.S. al Coda"));
    m_directionShortcutCombo->insertItem(i18n("to Coda"));
    m_directionShortcutCombo->insertItem(i18n("Coda"));
    m_directionShortcutCombo->hide();

    // local direction shortcuts combo
    m_localDirectionShortcutLabel = new TQLabel(i18n("Local Direction:  "), entryGrid);
    m_localDirectionShortcutLabel->hide();

    m_localDirectionShortcutCombo = new KComboBox(entryGrid);
    m_localDirectionShortcutCombo->insertItem(i18n("accel."));
    m_localDirectionShortcutCombo->insertItem(i18n("ritard."));
    m_localDirectionShortcutCombo->insertItem(i18n("ralletando"));
    m_localDirectionShortcutCombo->insertItem(i18n("a tempo"));
    m_localDirectionShortcutCombo->insertItem(i18n("legato"));
    m_localDirectionShortcutCombo->insertItem(i18n("simile"));
    m_localDirectionShortcutCombo->insertItem(i18n("pizz."));
    m_localDirectionShortcutCombo->insertItem(i18n("arco"));
    m_localDirectionShortcutCombo->insertItem(i18n("non vib."));
    m_localDirectionShortcutCombo->insertItem(i18n("sul pont."));
    m_localDirectionShortcutCombo->insertItem(i18n("sul tasto"));
    m_localDirectionShortcutCombo->insertItem(i18n("con legno"));
    m_localDirectionShortcutCombo->insertItem(i18n("sul tasto"));
    m_localDirectionShortcutCombo->insertItem(i18n("sul G"));
    m_localDirectionShortcutCombo->insertItem(i18n("ordinario"));
    m_localDirectionShortcutCombo->insertItem(i18n("Muta in "));
    m_localDirectionShortcutCombo->insertItem(i18n("volti subito "));
    m_localDirectionShortcutCombo->insertItem(i18n("soli"));
    m_localDirectionShortcutCombo->insertItem(i18n("div."));
    m_localDirectionShortcutCombo->hide();

    // tempo shortcuts combo
    m_tempoShortcutLabel = new TQLabel(i18n("Tempo:  "), entryGrid);
    m_tempoShortcutLabel->hide();

    m_tempoShortcutCombo = new KComboBox(entryGrid);
    m_tempoShortcutCombo->insertItem(i18n("Grave"));
    m_tempoShortcutCombo->insertItem(i18n("Adagio"));
    m_tempoShortcutCombo->insertItem(i18n("Largo"));
    m_tempoShortcutCombo->insertItem(i18n("Lento"));
    m_tempoShortcutCombo->insertItem(i18n("Andante"));
    m_tempoShortcutCombo->insertItem(i18n("Moderato"));
    m_tempoShortcutCombo->insertItem(i18n("Allegretto"));
    m_tempoShortcutCombo->insertItem(i18n("Allegro"));
    m_tempoShortcutCombo->insertItem(i18n("Vivace"));
    m_tempoShortcutCombo->insertItem(i18n("Presto"));
    m_tempoShortcutCombo->insertItem(i18n("Prestissimo"));
    m_tempoShortcutCombo->insertItem(i18n("Maestoso"));
    m_tempoShortcutCombo->insertItem(i18n("Sostenuto"));
    m_tempoShortcutCombo->insertItem(i18n("Tempo Primo"));
    m_tempoShortcutCombo->hide();

    // local tempo shortcuts combo (duplicates the non-local version, because
    // nobody is actually sure what is supposed to distinguish Tempo from
    // Local Tempo, or what this text style is supposed to be good for in the
    // way of standard notation)
    m_localTempoShortcutLabel = new TQLabel(i18n("Local Tempo:  "), entryGrid);
    m_localTempoShortcutLabel->hide();

    m_localTempoShortcutCombo = new KComboBox(entryGrid);
    m_localTempoShortcutCombo->insertItem(i18n("Grave"));
    m_localTempoShortcutCombo->insertItem(i18n("Adagio"));
    m_localTempoShortcutCombo->insertItem(i18n("Largo"));
    m_localTempoShortcutCombo->insertItem(i18n("Lento"));
    m_localTempoShortcutCombo->insertItem(i18n("Andante"));
    m_localTempoShortcutCombo->insertItem(i18n("Moderato"));
    m_localTempoShortcutCombo->insertItem(i18n("Allegretto"));
    m_localTempoShortcutCombo->insertItem(i18n("Allegro"));
    m_localTempoShortcutCombo->insertItem(i18n("Vivace"));
    m_localTempoShortcutCombo->insertItem(i18n("Presto"));
    m_localTempoShortcutCombo->insertItem(i18n("Prestissimo"));
    m_localTempoShortcutCombo->insertItem(i18n("Maestoso"));
    m_localTempoShortcutCombo->insertItem(i18n("Sostenuto"));
    m_localTempoShortcutCombo->insertItem(i18n("Tempo Primo"));
    m_localTempoShortcutCombo->hide();

    // LilyPond directive combo
    m_directiveLabel = new TQLabel(i18n("Directive:  "), entryGrid);
    m_directiveLabel->hide();

    m_lilyPondDirectiveCombo = new KComboBox(entryGrid);
    m_lilyPondDirectiveCombo->hide();

    // not i18nable, because the directive exporter currently depends on the
    // textual contents of these strings, not some more abstract associated
    // type label
    m_lilyPondDirectiveCombo->insertItem(Text::Segno.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::Coda.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::Alternate1.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::Alternate2.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::BarDouble.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::BarEnd.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::BarDot.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::Gliss.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::Arpeggio.c_str());
    //    m_lilyPondDirectiveCombo->insertItem(Text::ArpeggioUp.c_str());
    //    m_lilyPondDirectiveCombo->insertItem(Text::ArpeggioDn.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::Tiny.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::Small.c_str());
    m_lilyPondDirectiveCombo->insertItem(Text::NormalSize.c_str());

    TQVBox *exampleVBox = new TQVBox(exampleBox);

    int ls = m_notePixmapFactory->getLineSpacing();

    int mapWidth = 200;
    TQPixmap map(mapWidth, ls * 5 + 1);
    TQBitmap mask(mapWidth, ls * 5 + 1);

    map.fill();
    mask.fill(TQt::color0);

    TQPainter p, pm;

    p.begin(&map);
    pm.begin(&mask);

    p.setPen(TQt::black);
    pm.setPen(TQt::white);

    for (int i = 0; i < 5; ++i)
    {
        p.drawLine(0, ls * i, mapWidth - 1, ls * i);
        pm.drawLine(0, ls * i, mapWidth - 1, ls * i);
    }

    p.end();
    pm.end();

    map.setMask(mask);

    m_staffAboveLabel = new TQLabel("staff", exampleVBox);
    m_staffAboveLabel->setPixmap(map);

    m_textExampleLabel = new TQLabel(i18n("Example"), exampleVBox);

    m_staffBelowLabel = new TQLabel("staff", exampleVBox);
    m_staffBelowLabel->setPixmap(map);

    // restore last setting for shortcut combos
    TDEConfig *config = kapp->config();
    config->setGroup(NotationViewConfigGroup);

    m_dynamicShortcutCombo->setCurrentItem(config->readNumEntry("dynamic_shortcut", 0));
    m_directionShortcutCombo->setCurrentItem(config->readNumEntry("direction_shortcut", 0));
    m_localDirectionShortcutCombo->setCurrentItem(config->readNumEntry("local_direction_shortcut", 0));
    m_tempoShortcutCombo->setCurrentItem(config->readNumEntry("tempo_shortcut", 0));
    m_localTempoShortcutCombo->setCurrentItem(config->readNumEntry("local_tempo_shortcut", 0));
    m_lilyPondDirectiveCombo->setCurrentItem(config->readNumEntry("lilyPond_directive_combo", 0));

    m_prevChord = config->readEntry("previous_chord", "");
    m_prevLyric = config->readEntry("previous_lyric", "");
    m_prevAnnotation = config->readEntry("previous_annotation", "");

    TQObject::connect(m_text, TQ_SIGNAL(textChanged(const TQString &)),
                     this, TQ_SLOT(slotTextChanged(const TQString &)));
    TQObject::connect(m_typeCombo, TQ_SIGNAL(activated(const TQString &)),
                     this, TQ_SLOT(slotTypeChanged(const TQString &)));
    TQObject::connect(this, TQ_SIGNAL(okClicked()), this, TQ_SLOT(slotOK()));
    TQObject::connect(m_dynamicShortcutCombo, TQ_SIGNAL(activated(const TQString &)),
                     this, TQ_SLOT(slotDynamicShortcutChanged(const TQString &)));
    TQObject::connect(m_directionShortcutCombo, TQ_SIGNAL(activated(const TQString &)),
                     this, TQ_SLOT(slotDirectionShortcutChanged(const TQString &)));
    TQObject::connect(m_localDirectionShortcutCombo, TQ_SIGNAL(activated(const TQString &)),
                     this, TQ_SLOT(slotLocalDirectionShortcutChanged(const TQString &)));
    TQObject::connect(m_tempoShortcutCombo, TQ_SIGNAL(activated(const TQString &)),
                     this, TQ_SLOT(slotTempoShortcutChanged(const TQString &)));
    TQObject::connect(m_localTempoShortcutCombo, TQ_SIGNAL(activated(const TQString &)),
                     this, TQ_SLOT(slotLocalTempoShortcutChanged(const TQString &)));
    TQObject::connect(m_lilyPondDirectiveCombo, TQ_SIGNAL(activated(const TQString &)),
                     this, TQ_SLOT(slotLilyPondDirectiveChanged(const TQString &)));

    m_text->setFocus();
    slotTypeChanged(strtoqstr(getTextType()));

    // a hacky little fix for #1512143, to restore the capability to edit
    // existing annotations and other whatnots
    //!!! tacking another one of these on the bottom strikes me as lame in the
    // extreme, but it works, and it costs little, and other solutions I can
    // imagine would cost so much more.
    m_text->setText(strtoqstr(defaultText.getText()));
}

Text
TextEventDialog::getText() const
{
    Text text(getTextString(), getTextType());
    text.setVerse(m_verseSpin->value() - 1);
    return text;
}

std::string
TextEventDialog::getTextType() const
{
    return m_styles[m_typeCombo->currentItem()];
}

std::string
TextEventDialog::getTextString() const
{
    return std::string(qstrtostr(m_text->text()));
}

void
TextEventDialog::slotTextChanged(const TQString &qtext)
{
    std::string type(getTextType());

    TQString qtrunc(qtext);
    if (qtrunc.length() > 20)
        qtrunc = qtrunc.left(20) + "...";
    std::string text(qstrtostr(qtrunc));
    if (text == "")
        text = "Sample";

    Text rtext(text, type);
    m_textExampleLabel->setPixmap
    (NotePixmapFactory::toTQPixmap(m_notePixmapFactory->makeTextPixmap(rtext)));
}

void
TextEventDialog::slotTypeChanged(const TQString &)
{
    std::string type(getTextType());

    TQString qtrunc(m_text->text());
    if (qtrunc.length() > 20)
        qtrunc = qtrunc.left(20) + "...";
    std::string text(qstrtostr(qtrunc));
    if (text == "")
        text = "Sample";

    Text rtext(text, type);
    m_textExampleLabel->setPixmap
    (NotePixmapFactory::toTQPixmap(m_notePixmapFactory->makeTextPixmap(rtext)));

    //
    // swap widgets in and out, depending on the current text type
    //
    if (type == Text::Dynamic) {
        m_dynamicShortcutLabel->show();
        m_dynamicShortcutCombo->show();
        slotDynamicShortcutChanged(text.c_str());
    } else {
        m_dynamicShortcutLabel->hide();
        m_dynamicShortcutCombo->hide();
    }

    if (type == Text::Direction) {
        m_directionShortcutLabel->show();
        m_directionShortcutCombo->show();
        slotDirectionShortcutChanged(text.c_str());
    } else {
        m_directionShortcutLabel->hide();
        m_directionShortcutCombo->hide();
    }

    if (type == Text::LocalDirection) {
        m_localDirectionShortcutLabel->show();
        m_localDirectionShortcutCombo->show();
        slotLocalDirectionShortcutChanged(text.c_str());
    } else {
        m_localDirectionShortcutLabel->hide();
        m_localDirectionShortcutCombo->hide();
    }

    if (type == Text::Tempo) {
        m_tempoShortcutLabel->show();
        m_tempoShortcutCombo->show();
        slotTempoShortcutChanged(text.c_str());
    } else {
        m_tempoShortcutLabel->hide();
        m_tempoShortcutCombo->hide();
    }

    if (type == Text::LocalTempo) {
        m_localTempoShortcutLabel->show();
        m_localTempoShortcutCombo->show();
        slotLocalTempoShortcutChanged(text.c_str());
    } else {
        m_localTempoShortcutLabel->hide();
        m_localTempoShortcutCombo->hide();
    }

    // restore previous text of appropriate type
    if (type == Text::Lyric)
        m_text->setText(m_prevLyric);
    else if (type == Text::Chord)
        m_text->setText(m_prevChord);
    else if (type == Text::Annotation)
        m_text->setText(m_prevAnnotation);

    //
    // LilyPond directives only taking temporary residence here; will move out
    // into some new class eventually
    //
    if (type == Text::LilyPondDirective) {
        m_lilyPondDirectiveCombo->show();
        m_directiveLabel->show();
        m_staffAboveLabel->hide();
        m_staffBelowLabel->show();
        m_text->setReadOnly(true);
        m_text->setEnabled(false);
        slotLilyPondDirectiveChanged(text.c_str());
    } else {
        m_lilyPondDirectiveCombo->hide();
        m_directiveLabel->hide();
        m_text->setReadOnly(false);
        m_text->setEnabled(true);

        if (type == Text::Dynamic ||
            type == Text::LocalDirection ||
            type == Text::UnspecifiedType ||
            type == Text::Lyric ||
            type == Text::Annotation) {

            m_staffAboveLabel->show();
            m_staffBelowLabel->hide();

        } else {
            m_staffAboveLabel->hide();
            m_staffBelowLabel->show();

        }

        if (type == Text::Lyric) {
            m_verseLabel->show();
            m_verseSpin->show();
        }
    }
}

void
TextEventDialog::slotOK()
{
    // store last setting for shortcut combos
    TDEConfig *config = kapp->config();
    config->setGroup(NotationViewConfigGroup);

    config->writeEntry("dynamic_shortcut", m_dynamicShortcutCombo->currentItem());
    config->writeEntry("direction_shortcut", m_directionShortcutCombo->currentItem());
    config->writeEntry("local_direction_shortcut", m_localDirectionShortcutCombo->currentItem());
    config->writeEntry("tempo_shortcut", m_tempoShortcutCombo->currentItem());
    config->writeEntry("local_tempo_shortcut", m_localTempoShortcutCombo->currentItem());
    // temporary home:
    config->writeEntry("lilyPond_directive_combo", m_lilyPondDirectiveCombo->currentItem());

    // store  last chord, lyric, annotation, depending on what's currently in
    // the text entry widget
    int index = m_typeCombo->currentItem();
    if (index == 5)
        config->writeEntry("previous_chord", m_text->text());
    else if (index == 6)
        config->writeEntry("previous_lyric", m_text->text());
    else if (index == 7)
        config->writeEntry("previous_annotation", m_text->text());
}

void
TextEventDialog::slotDynamicShortcutChanged(const TQString &text)
{
    if (text == "" || text == "Sample") {
        m_text->setText((m_dynamicShortcutCombo->currentText()));
    } else {
        m_text->setText(text);
    }
}

void
TextEventDialog::slotDirectionShortcutChanged(const TQString &text)
{
    if (text == "" || text == "Sample") {
        m_text->setText((m_directionShortcutCombo->currentText()));
    } else {
        m_text->setText(text);
    }
}

void
TextEventDialog::slotLocalDirectionShortcutChanged(const TQString &text)
{
    if (text == "" || text == "Sample") {
        m_text->setText((m_localDirectionShortcutCombo->currentText()));
    } else {
        m_text->setText(text);
    }
}

void
TextEventDialog::slotTempoShortcutChanged(const TQString &text)
{
    if (text == "" || text == "Sample") {
        m_text->setText((m_tempoShortcutCombo->currentText()));
    } else {
        m_text->setText(text);
    }
}

void
TextEventDialog::slotLocalTempoShortcutChanged(const TQString &text)
{
    if (text == "" || text == "Sample") {
        m_text->setText((m_localTempoShortcutCombo->currentText()));
    } else {
        m_text->setText(text);
    }
}

void
TextEventDialog::slotLilyPondDirectiveChanged(const TQString &)
{
    m_text->setText((m_lilyPondDirectiveCombo->currentText()));
}

}
#include "TextEventDialog.moc"
