diff options
author | Florian Jung <flo@windfisch.org> | 2011-05-29 12:43:17 +0000 |
---|---|---|
committer | Florian Jung <flo@windfisch.org> | 2011-05-29 12:43:17 +0000 |
commit | 25a43d58dead31caf482fc8ada4f231d2f1269d9 (patch) | |
tree | c39631efc11ab7099520e9b2f861a86674db1251 /muse2/muse/functions.cpp | |
parent | 55a6fa75d70dbcd38e4b434420c970475448d1a7 (diff) |
- moved cut,copy'n'paste to functions.cpp, removed unneccessary
duplication
- changed behaviour of paste: now the pasted, not the original
notes are selected
Diffstat (limited to 'muse2/muse/functions.cpp')
-rw-r--r-- | muse2/muse/functions.cpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index 5677bcfd..94b7a52d 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -14,8 +14,18 @@ #include <values.h> #include <iostream> +#include <errno.h> +#include <values.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <QMimeData> +#include <QByteArray> +#include <QDrag> #include <QMessageBox> +#include <QClipboard> + using namespace std; @@ -604,6 +614,153 @@ void legato(const set<Part*>& parts, int range, int min_len, bool dont_shorten) +void copy_notes(const set<Part*>& parts, int range) +{ + QMimeData* drag = selected_events_to_mime(parts,range); + + if (drag) + QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard); +} + +void paste_notes(Part* dest_part) +{ + QString tmp="x-muse-eventlist"; // QClipboard::text() expects a QString&, not a QString :( + QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard); // TODO CHECK Tim. + paste_at(dest_part, s, song->cpos()); +} + +QMimeData* selected_events_to_mime(const set<Part*>& parts, int range) +{ + map<Event*, Part*> events=get_events(parts,range); + + //--------------------------------------------------- + // generate event list from selected events + //--------------------------------------------------- + + EventList el; + unsigned startTick = MAXINT; //will be the tick of the first event or MAXINT if no events are there + + for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) + { + Event& e = *it->first; + + if (e.tick() < startTick) + startTick = e.tick(); + + el.add(e); + } + + //--------------------------------------------------- + // write events as XML into tmp file + //--------------------------------------------------- + + FILE* tmp = tmpfile(); + if (tmp == 0) + { + fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n", strerror(errno)); + return 0; + } + + Xml xml(tmp); + int level = 0; + + xml.tag(level++, "eventlist"); + for (ciEvent e = el.begin(); e != el.end(); ++e) + e->second.write(level, xml, -startTick); + xml.etag(--level, "eventlist"); + + //--------------------------------------------------- + // read tmp file into drag Object + //--------------------------------------------------- + + fflush(tmp); + struct stat f_stat; + if (fstat(fileno(tmp), &f_stat) == -1) + { + fprintf(stderr, "PianoCanvas::copy() fstat failed:<%s>\n", + strerror(errno)); + fclose(tmp); + return 0; + } + int n = f_stat.st_size; + char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fileno(tmp), 0); + fbuf[n] = 0; + + QByteArray data(fbuf); + QMimeData* md = new QMimeData(); + + md->setData("text/x-muse-eventlist", data); + + munmap(fbuf, n); + fclose(tmp); + + return md; +} + +void paste_at(Part* dest_part, const QString& pt, int pos) +{ + Xml xml(pt.toLatin1().constData()); + for (;;) + { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) + { + case Xml::Error: + case Xml::End: + return; + + case Xml::TagStart: + if (tag == "eventlist") + { + song->startUndo(); + EventList el; + el.read(xml, "eventlist", true); + int modified = SC_EVENT_INSERTED; + for (iEvent i = el.begin(); i != el.end(); ++i) + { + Event e = i->second; + int tick = e.tick() + pos - dest_part->tick(); + if (tick<0) + { + printf("ERROR: trying to add event before current part!\n"); + song->endUndo(SC_EVENT_INSERTED); + return; + } + + e.setTick(tick); + e.setSelected(true); + int diff = e.endTick()-dest_part->lenTick(); + if (diff > 0) // too short part? extend it + { + Part* newPart = dest_part->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + audio->msgChangePart(dest_part, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + dest_part = newPart; // reassign TODO FINDME does this work, or has dest_part to be a nonconst reference? + } + // Indicate no undo, and do not do port controller values and clone parts. + audio->msgAddEvent(e, dest_part, false, false, false); + } + song->endUndo(modified); + return; + } + else + xml.unknown("pasteAt"); + break; + + case Xml::Attribut: + case Xml::TagEnd: + default: + break; + } + } +} + + + void read_function_dialog_config(Xml& xml) { if (erase_dialog==NULL) |