summaryrefslogtreecommitdiff
path: root/muse2/muse/functions.cpp
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2011-05-29 12:43:17 +0000
committerFlorian Jung <flo@windfisch.org>2011-05-29 12:43:17 +0000
commit25a43d58dead31caf482fc8ada4f231d2f1269d9 (patch)
treec39631efc11ab7099520e9b2f861a86674db1251 /muse2/muse/functions.cpp
parent55a6fa75d70dbcd38e4b434420c970475448d1a7 (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.cpp157
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)