summaryrefslogtreecommitdiffstats
path: root/src/gui/editors/guitar/GuitarChordSelectorDialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/editors/guitar/GuitarChordSelectorDialog.cpp')
-rw-r--r--src/gui/editors/guitar/GuitarChordSelectorDialog.cpp475
1 files changed, 475 insertions, 0 deletions
diff --git a/src/gui/editors/guitar/GuitarChordSelectorDialog.cpp b/src/gui/editors/guitar/GuitarChordSelectorDialog.cpp
new file mode 100644
index 0000000..bd62c1f
--- /dev/null
+++ b/src/gui/editors/guitar/GuitarChordSelectorDialog.cpp
@@ -0,0 +1,475 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ 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 "GuitarChordSelectorDialog.h"
+#include "GuitarChordEditorDialog.h"
+#include "ChordXmlHandler.h"
+#include "FingeringBox.h"
+#include "FingeringListBoxItem.h"
+
+#include "misc/Debug.h"
+#include <qlistbox.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstddirs.h>
+
+namespace Rosegarden
+{
+
+GuitarChordSelectorDialog::GuitarChordSelectorDialog(QWidget *parent)
+ : KDialogBase(parent, "GuitarChordSelector", true, i18n("Guitar Chord Selector"), Ok|Cancel)
+{
+ QWidget *page = new QWidget(this);
+ setMainWidget(page);
+ QGridLayout *topLayout = new QGridLayout(page, 3, 4, spacingHint());
+
+ topLayout->addWidget(new QLabel(i18n("Root"), page), 0, 0);
+ m_rootNotesList = new QListBox(page);
+ topLayout->addWidget(m_rootNotesList, 1, 0);
+
+ topLayout->addWidget(new QLabel(i18n("Extension"), page), 0, 1);
+ m_chordExtList = new QListBox(page);
+ topLayout->addWidget(m_chordExtList, 1, 1);
+
+ m_newFingeringButton = new QPushButton(i18n("New"), page);
+ m_deleteFingeringButton = new QPushButton(i18n("Delete"), page);
+ m_editFingeringButton = new QPushButton(i18n("Edit"), page);
+
+ m_chordComplexityCombo = new QComboBox(page);
+ m_chordComplexityCombo->insertItem(i18n("beginner"));
+ m_chordComplexityCombo->insertItem(i18n("common"));
+ m_chordComplexityCombo->insertItem(i18n("all"));
+
+ connect(m_chordComplexityCombo, SIGNAL(activated(int)),
+ this, SLOT(slotComplexityChanged(int)));
+
+ QVBoxLayout* vboxLayout = new QVBoxLayout(page, 5);
+ topLayout->addMultiCellLayout(vboxLayout, 1, 3, 2, 2);
+ vboxLayout->addWidget(m_chordComplexityCombo);
+ vboxLayout->addStretch(10);
+ vboxLayout->addWidget(m_newFingeringButton);
+ vboxLayout->addWidget(m_deleteFingeringButton);
+ vboxLayout->addWidget(m_editFingeringButton);
+
+ connect(m_newFingeringButton, SIGNAL(clicked()),
+ this, SLOT(slotNewFingering()));
+ connect(m_deleteFingeringButton, SIGNAL(clicked()),
+ this, SLOT(slotDeleteFingering()));
+ connect(m_editFingeringButton, SIGNAL(clicked()),
+ this, SLOT(slotEditFingering()));
+
+ topLayout->addWidget(new QLabel(i18n("Fingerings"), page), 0, 3);
+ m_fingeringsList = new QListBox(page);
+ topLayout->addMultiCellWidget(m_fingeringsList, 1, 2, 3, 3);
+
+ m_fingeringBox = new FingeringBox(false, page);
+ topLayout->addMultiCellWidget(m_fingeringBox, 2, 2, 0, 1);
+
+ connect(m_rootNotesList, SIGNAL(highlighted(int)),
+ this, SLOT(slotRootHighlighted(int)));
+ connect(m_chordExtList, SIGNAL(highlighted(int)),
+ this, SLOT(slotChordExtHighlighted(int)));
+ connect(m_fingeringsList, SIGNAL(highlighted(QListBoxItem*)),
+ this, SLOT(slotFingeringHighlighted(QListBoxItem*)));
+}
+
+void
+GuitarChordSelectorDialog::init()
+{
+ // populate the listboxes
+ //
+ std::vector<QString> chordFiles = getAvailableChordFiles();
+
+ parseChordFiles(chordFiles);
+
+// m_chordMap.debugDump();
+
+ populate();
+}
+
+void
+GuitarChordSelectorDialog::populate()
+{
+ QStringList rootList = m_chordMap.getRootList();
+ if (rootList.count() > 0) {
+ m_rootNotesList->insertStringList(rootList);
+
+ QStringList extList = m_chordMap.getExtList(rootList.first());
+ populateExtensions(extList);
+
+ Guitar::ChordMap::chordarray chords = m_chordMap.getChords(rootList.first(), extList.first());
+ populateFingerings(chords);
+
+ m_chord.setRoot(rootList.first());
+ m_chord.setExt(extList.first());
+ }
+
+ m_rootNotesList->sort();
+
+ m_rootNotesList->setCurrentItem(0);
+}
+
+void
+GuitarChordSelectorDialog::clear()
+{
+ m_rootNotesList->clear();
+ m_chordExtList->clear();
+ m_fingeringsList->clear();
+}
+
+void
+GuitarChordSelectorDialog::refresh()
+{
+ clear();
+ populate();
+}
+
+void
+GuitarChordSelectorDialog::slotRootHighlighted(int i)
+{
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::slotRootHighlighted " << i << endl;
+
+ m_chord.setRoot(m_rootNotesList->text(i));
+
+ QStringList extList = m_chordMap.getExtList(m_chord.getRoot());
+ populateExtensions(extList);
+ if (m_chordExtList->count() > 0)
+ m_chordExtList->setCurrentItem(0);
+ else
+ m_fingeringsList->clear(); // clear any previous fingerings
+}
+
+void
+GuitarChordSelectorDialog::slotChordExtHighlighted(int i)
+{
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::slotChordExtHighlighted " << i << endl;
+
+ Guitar::ChordMap::chordarray chords = m_chordMap.getChords(m_chord.getRoot(), m_chordExtList->text(i));
+ populateFingerings(chords);
+
+ m_fingeringsList->setCurrentItem(0);
+}
+
+void
+GuitarChordSelectorDialog::slotFingeringHighlighted(QListBoxItem* listBoxItem)
+{
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::slotFingeringHighlighted\n";
+
+ FingeringListBoxItem* fingeringItem = dynamic_cast<FingeringListBoxItem*>(listBoxItem);
+ if (fingeringItem) {
+ m_chord = fingeringItem->getChord();
+ m_fingeringBox->setFingering(m_chord.getFingering());
+ setEditionEnabled(m_chord.isUserChord());
+ }
+}
+
+void
+GuitarChordSelectorDialog::slotComplexityChanged(int)
+{
+ // simply repopulate the extension list box
+ //
+ QStringList extList = m_chordMap.getExtList(m_chord.getRoot());
+ populateExtensions(extList);
+ if (m_chordExtList->count() > 0)
+ m_chordExtList->setCurrentItem(0);
+ else
+ m_fingeringsList->clear(); // clear any previous fingerings
+}
+
+void
+GuitarChordSelectorDialog::slotNewFingering()
+{
+ Guitar::Chord newChord;
+ newChord.setRoot(m_chord.getRoot());
+ newChord.setExt(m_chord.getExt());
+
+ GuitarChordEditorDialog* chordEditorDialog = new GuitarChordEditorDialog(newChord, m_chordMap, this);
+
+ if (chordEditorDialog->exec() == QDialog::Accepted) {
+ m_chordMap.insert(newChord);
+ // populate lists
+ //
+ if (!m_rootNotesList->findItem(newChord.getRoot(), Qt::ExactMatch)) {
+ m_rootNotesList->insertItem(newChord.getRoot());
+ m_rootNotesList->sort();
+ }
+
+ if (!m_chordExtList->findItem(newChord.getExt(), Qt::ExactMatch)) {
+ m_chordExtList->insertItem(newChord.getExt());
+ m_chordExtList->sort();
+ }
+ }
+
+ delete chordEditorDialog;
+
+ refresh();
+}
+
+void
+GuitarChordSelectorDialog::slotDeleteFingering()
+{
+ if (m_chord.isUserChord()) {
+ m_chordMap.remove(m_chord);
+ delete m_fingeringsList->selectedItem();
+ }
+}
+
+void
+GuitarChordSelectorDialog::slotEditFingering()
+{
+ Guitar::Chord newChord = m_chord;
+ GuitarChordEditorDialog* chordEditorDialog = new GuitarChordEditorDialog(newChord, m_chordMap, this);
+
+ if (chordEditorDialog->exec() == QDialog::Accepted) {
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::slotEditFingering() - current map state :\n";
+ m_chordMap.debugDump();
+ m_chordMap.substitute(m_chord, newChord);
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::slotEditFingering() - new map state :\n";
+ m_chordMap.debugDump();
+ setChord(newChord);
+ }
+
+ delete chordEditorDialog;
+
+ refresh();
+}
+
+void
+GuitarChordSelectorDialog::slotOk()
+{
+ if (m_chordMap.needSave()) {
+ saveUserChordMap();
+ m_chordMap.clearNeedSave();
+ }
+
+ KDialogBase::slotOk();
+}
+
+void
+GuitarChordSelectorDialog::setChord(const Guitar::Chord& chord)
+{
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::setChord " << chord << endl;
+
+ m_chord = chord;
+
+ // select the chord's root
+ //
+ m_rootNotesList->setCurrentItem(0);
+ QListBoxItem* correspondingRoot = m_rootNotesList->findItem(chord.getRoot(), Qt::ExactMatch);
+ if (correspondingRoot)
+ m_rootNotesList->setSelected(correspondingRoot, true);
+
+ // update the dialog's complexity setting if needed, then populate the extension list
+ //
+ QString chordExt = chord.getExt();
+ int complexityLevel = m_chordComplexityCombo->currentItem();
+ int chordComplexity = evaluateChordComplexity(chordExt);
+
+ if (chordComplexity > complexityLevel) {
+ m_chordComplexityCombo->setCurrentItem(chordComplexity);
+ }
+
+ QStringList extList = m_chordMap.getExtList(chord.getRoot());
+ populateExtensions(extList);
+
+ // select the chord's extension
+ //
+ if (chordExt.isEmpty()) {
+ chordExt = "";
+ m_chordExtList->setSelected(0, true);
+ } else {
+ QListBoxItem* correspondingExt = m_chordExtList->findItem(chordExt, Qt::ExactMatch);
+ if (correspondingExt)
+ m_chordExtList->setSelected(correspondingExt, true);
+ }
+
+ // populate fingerings and pass the current chord's fingering so it is selected
+ //
+ Guitar::ChordMap::chordarray similarChords = m_chordMap.getChords(chord.getRoot(), chord.getExt());
+ populateFingerings(similarChords, chord.getFingering());
+}
+
+void
+GuitarChordSelectorDialog::populateFingerings(const Guitar::ChordMap::chordarray& chords, const Guitar::Fingering& refFingering)
+{
+ m_fingeringsList->clear();
+
+ for(Guitar::ChordMap::chordarray::const_iterator i = chords.begin(); i != chords.end(); ++i) {
+ const Guitar::Chord& chord = *i;
+ QString fingeringString = chord.getFingering().toString();
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::populateFingerings " << chord << endl;
+ QPixmap fingeringPixmap = getFingeringPixmap(chord.getFingering());
+ FingeringListBoxItem *item = new FingeringListBoxItem(chord, m_fingeringsList, fingeringPixmap, fingeringString);
+ if (refFingering == chord.getFingering()) {
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::populateFingerings - fingering found " << fingeringString << endl;
+ m_fingeringsList->setSelected(item, true);
+ }
+ }
+
+}
+
+
+QPixmap
+GuitarChordSelectorDialog::getFingeringPixmap(const Guitar::Fingering& fingering) const
+{
+ QPixmap pixmap(FINGERING_PIXMAP_WIDTH, FINGERING_PIXMAP_HEIGHT);
+ pixmap.fill();
+
+ QPainter pp(&pixmap);
+ QPainter *p = &pp;
+
+ p->setViewport(FINGERING_PIXMAP_H_MARGIN, FINGERING_PIXMAP_W_MARGIN,
+ FINGERING_PIXMAP_WIDTH - FINGERING_PIXMAP_W_MARGIN,
+ FINGERING_PIXMAP_HEIGHT - FINGERING_PIXMAP_H_MARGIN);
+
+ Guitar::NoteSymbols::drawFingeringPixmap(fingering, m_fingeringBox->getNoteSymbols(), p);
+
+ return pixmap;
+}
+
+void
+GuitarChordSelectorDialog::populateExtensions(const QStringList& extList)
+{
+ m_chordExtList->clear();
+
+ if (m_chordComplexityCombo->currentItem() != COMPLEXITY_ALL) {
+ // some filtering needs to be done
+ int complexityLevel = m_chordComplexityCombo->currentItem();
+
+ QStringList filteredList;
+ for(QStringList::const_iterator i = extList.constBegin(); i != extList.constEnd(); ++i) {
+ if (evaluateChordComplexity((*i).lower().stripWhiteSpace()) <= complexityLevel) {
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::populateExtensions - adding '" << *i << "'\n";
+ filteredList.append(*i);
+ }
+ }
+
+ m_chordExtList->insertStringList(filteredList);
+
+ } else {
+ m_chordExtList->insertStringList(extList);
+ }
+}
+
+int
+GuitarChordSelectorDialog::evaluateChordComplexity(const QString& ext)
+{
+ if (ext.isEmpty() ||
+ ext == "7" ||
+ ext == "m" ||
+ ext == "5")
+ return COMPLEXITY_BEGINNER;
+
+ if (ext == "dim" ||
+ ext == "dim7" ||
+ ext == "aug" ||
+ ext == "sus2" ||
+ ext == "sus4" ||
+ ext == "maj7" ||
+ ext == "m7" ||
+ ext == "mmaj7" ||
+ ext == "m7b5" ||
+ ext == "7sus4")
+
+ return COMPLEXITY_COMMON;
+
+ return COMPLEXITY_ALL;
+}
+
+void
+GuitarChordSelectorDialog::parseChordFiles(const std::vector<QString>& chordFiles)
+{
+ for(std::vector<QString>::const_iterator i = chordFiles.begin(); i != chordFiles.end(); ++i) {
+ parseChordFile(*i);
+ }
+}
+
+void
+GuitarChordSelectorDialog::parseChordFile(const QString& chordFileName)
+{
+ ChordXmlHandler handler(m_chordMap);
+ QFile chordFile(chordFileName);
+ bool ok = chordFile.open(IO_ReadOnly);
+ if (!ok)
+ KMessageBox::error(0, i18n("couldn't open file '%1'").arg(handler.errorString()));
+
+ QXmlInputSource source(chordFile);
+ QXmlSimpleReader reader;
+ reader.setContentHandler(&handler);
+ reader.setErrorHandler(&handler);
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::parseChordFile() parsing " << chordFileName << endl;
+ reader.parse(source);
+ if (!ok)
+ KMessageBox::error(0, i18n("couldn't parse chord dictionnary : %1").arg(handler.errorString()));
+
+}
+
+void
+GuitarChordSelectorDialog::setEditionEnabled(bool enabled)
+{
+ m_deleteFingeringButton->setEnabled(enabled);
+ m_editFingeringButton->setEnabled(enabled);
+}
+
+std::vector<QString>
+GuitarChordSelectorDialog::getAvailableChordFiles()
+{
+ std::vector<QString> names;
+
+ // Read config for default directory
+ QStringList chordDictFiles = KGlobal::dirs()->findAllResources("appdata", "chords/*.xml");
+
+ for(QStringList::iterator i = chordDictFiles.begin(); i != chordDictFiles.end(); ++i) {
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::getAvailableChordFiles : adding file " << *i << endl;
+ names.push_back(*i);
+ }
+
+ return names;
+}
+
+bool
+GuitarChordSelectorDialog::saveUserChordMap()
+{
+ // Read config for user directory
+ QString userDir = KGlobal::dirs()->saveLocation("appdata", "chords/");
+
+ QString userChordDictPath = userDir + "/user_chords.xml";
+
+ NOTATION_DEBUG << "GuitarChordSelectorDialog::saveUserChordMap() : saving user chord map to " << userChordDictPath << endl;
+ QString errMsg;
+
+ m_chordMap.saveDocument(userChordDictPath, true, errMsg);
+
+ return errMsg.isEmpty();
+}
+
+
+}
+
+
+#include "GuitarChordSelectorDialog.moc"