void
LyricEditDialog::unparse()
{
    // This and SetLyricsCommand::execute() are opposites that will
    // need to be kept in sync with any changes in one another.  (They
    // should really both be in a common lyric management class.)

    countVerses();

    Composition *comp = m_segment->getComposition();

    bool firstNote = true;
    timeT lastTime = m_segment->getStartTime();
    int lastBarNo = comp->getBarNumber(lastTime);
    std::map<int, bool> haveLyric;

    QString fragment = QString("[%1] ").arg(lastBarNo + 1);

    m_skeleton = fragment;
    m_texts.clear();
    for (int v = 0; v < m_verseCount; ++v) {
        m_texts.push_back(fragment);
        haveLyric[v] = false;
    }

    for (Segment::iterator i = m_segment->begin();
         m_segment->isBeforeEndMarker(i); ++i) {

        bool isNote = (*i)->isa(Note::EventType);
        bool isLyric = false;

        if (!isNote) {
            if ((*i)->isa(Text::EventType)) {
                std::string textType;
                if ((*i)->get<String>(Text::TextTypePropertyName, textType) &&
                    textType == Text::Lyric) {
                    isLyric = true;
                }
            }
        } else {
            if ((*i)->has(BaseProperties::TIED_BACKWARD) &&
                (*i)->get<Bool>(BaseProperties::TIED_BACKWARD)) {
                continue;
            }
        }

        if (!isNote && !isLyric) continue;

        timeT myTime = (*i)->getNotationAbsoluteTime();
        int myBarNo = comp->getBarNumber(myTime);

        if (myBarNo > lastBarNo) {

            fragment = "";

            while (myBarNo > lastBarNo) {
                fragment += " /";
                ++lastBarNo;
            }

            fragment += QString("\n[%1] ").arg(myBarNo + 1);

            m_skeleton += fragment;
            for (int v = 0; v < m_verseCount; ++v) m_texts[v] += fragment;
        }

        if (isNote) {
            if ((myTime > lastTime) || firstNote) {
                m_skeleton += " .";
                for (int v = 0; v < m_verseCount; ++v) {
                    if (!haveLyric[v]) m_texts[v] += " .";
                    haveLyric[v] = false;
                }
                lastTime = myTime;
                firstNote = false;
            }
        }

        if (isLyric) {

            std::string ssyllable;
            (*i)->get<String>(Text::TextPropertyName, ssyllable);

            long verse = 0;
            (*i)->get<Int>(Text::LyricVersePropertyName, verse);

            QString syllable(strtoqstr(ssyllable));
            syllable.replace(QRegExp("\\s+"), "~");

            m_texts[verse] += " " + syllable;
            haveLyric[verse] = true;
        }
    }

    if (!m_texts.empty()) {
        m_textEdit->setPlainText(m_texts[0]);
    } else {
        m_texts.push_back(m_skeleton);
    }
}
void
SetLyricsCommand::execute()
{
    // This and LyricEditDialog::unparse() are opposites that will
    // need to be kept in sync with any changes to one another.  (They
    // should really both be in a common lyric management class.)

    // first remove old lyric events

    Segment::iterator i = m_segment->begin();

    while (i != m_segment->end()) {

        Segment::iterator j = i;
        ++j;

        if ((*i)->isa(Text::EventType)) {
            std::string textType;
            if ((*i)->get<String>(Text::TextTypePropertyName, textType) &&
                textType == Text::Lyric) {
                long verse = 0;
                (*i)->get<Int>(Text::LyricVersePropertyName, verse);
                if (verse == m_verse) {
                    m_oldLyricEvents.push_back(new Event(**i));
                    m_segment->erase(i);
                }
            }
        }

        i = j;
    }

    // now parse the new string

    QStringList barStrings =
        m_newLyricData.split("/", QString::KeepEmptyParts); // empties ok

    Composition *comp = m_segment->getComposition();
    int barNo = comp->getBarNumber(m_segment->getStartTime());

    QStringList::Iterator bsi = barStrings.begin();
    while ( bsi != barStrings.end() ) {
        NOTATION_DEBUG << "Parsing lyrics for bar number " << barNo << ": \"" << *bsi << "\"" << endl;

        std::pair<timeT, timeT> barRange = comp->getBarRange(barNo++);
        QString syllables = *bsi;
        syllables.replace(QRegExp("\\[\\d+\\] "), " ");
        syllables.replace(QRegExp("\n"), " ");
        QStringList syllableList = syllables.split(" ", QString::SkipEmptyParts); // no empties

        i = m_segment->findTime(barRange.first);
        timeT laterThan = barRange.first - 1;

	++bsi; // update here in order to check whether we are in the last bar string
        bool isLastBSI = (bsi == barStrings.end());

        for (QStringList::Iterator ssi = syllableList.begin();
                ssi != syllableList.end(); ++ssi) {

	    // As a rule, syllables belong to a certain bar. However, from the
	    // last barString list syllables may flow to the following bars.
	    // As a result, one may copy&paste the full syllable list of a verse.
            while (m_segment->isBeforeEndMarker(i) &&
                    (isLastBSI || (*i)->getAbsoluteTime() < barRange.second) &&
                    (!(*i)->isa(Note::EventType) ||
                     (*i)->getNotationAbsoluteTime() <= laterThan ||
                     ((*i)->has(TIED_BACKWARD) &&
                      (*i)->get
                      <Bool>(TIED_BACKWARD)))) ++i;

            timeT time = m_segment->getEndMarkerTime();
            timeT notationTime = time;
            if (m_segment->isBeforeEndMarker(i)) {
                time = (*i)->getAbsoluteTime();
                notationTime = (*i)->getNotationAbsoluteTime();
            }

            QString syllable = *ssi;
            syllable.replace(QRegExp("~"), " ");
            syllable = syllable.simplified();
            if (syllable == "")
                continue;
            laterThan = notationTime + 1;
            if (syllable == ".")
                continue;

            NOTATION_DEBUG << "Syllable \"" << syllable << "\" at time " << time << endl;

            Text text(qstrtostr(syllable), Text::Lyric);
            Event *event = text.getAsEvent(time);
            event->set<Int>(Text::LyricVersePropertyName, m_verse);
            m_segment->insert(event);
        }
    }
}