Check-in [8c7de37e5e]
Overview
Comment: | Implement basic exporting and conversion for drag-and-drop. Needs to buffer implicit playlist file, because data_get() gets called excessively. Still support direct M3U/PLS/XSPF transfers (should any other application ever understand it), and direct URL transmission. No import functionality yet, but internal JSON format prepared as target type. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8c7de37e5ee837f7e11dd169067f03b0 |
User & Date: | mario on 2015-04-19 16:36:22 |
Other Links: | manifest | tags |
Context
2015-04-19
| ||
19:35 | Add plugin defaults. check-in: 6a17061df0 user: mario tags: trunk | |
16:36 | Implement basic exporting and conversion for drag-and-drop. Needs to buffer implicit playlist file, because data_get() gets called excessively. Still support direct M3U/PLS/XSPF transfers (should any other application ever understand it), and direct URL transmission. No import functionality yet, but internal JSON format prepared as target type. check-in: 8c7de37e5e user: mario tags: trunk | |
16:33 | Semi-fix for brand-new initialization. Set default category from existing categories[] list. Setting the displayed path as well doesn't work yet. (It's just half-way selected after the next restart.) check-in: 1cfacd1296 user: mario tags: trunk | |
Changes
Modified channels/dnd.py from [fc493ef928] to [2bdcd36106].
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # Implements Gtk/X11 drag and drop support for station lists. # Should allow to export either just stream URLs, or complete # PLS, XSPF collections. # # Also used by the bookmarks tab to move favourites around. from config import * from uikit import * # Drag and Drop support class dnd(object): module = "dnd" meta = plugin_meta() # Keeps selected row on starting DND event | > > | > > > > < | | < > > > > > > > > > | | | | | > > > | | > > | < | | | | > | > > > | | | > > > | > > > > > > > > > > > > > > > > > > > > | > > > > > > > | > > > > | | | | > > | | | > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | # Implements Gtk/X11 drag and drop support for station lists. # Should allow to export either just stream URLs, or complete # PLS, XSPF collections. # # Also used by the bookmarks tab to move favourites around. import copy from config import * from uikit import * import action # Drag and Drop support class dnd(object): module = "dnd" meta = plugin_meta() # Keeps selected row on starting DND event row = None # Buffer converted types buf = {} # Supported type map drag_types = [ ("json/vnd.streamtuner2.station", 0, 51), ("audio/x-mpegurl", 0, 20), ("application/x-scpls", 0, 21), ("application/xspf+xml", 0, 22), ("FILE_NAME", 0, 3), ("text/uri-list", 0, 4), ("STRING", 0, 5), ("text/plain", 0, 5), ] cnv_types = { 20: "m3u", 21: "pls", 22: "xspf", 4: "temp", 5: "srv", 51: "json", } # Hook to main, and extend channel tabs def __init__(self, parent): self.parent = parent parent.hooks["init"].append(self.add_dnd) # Attach drag and drop handlers to each channelsĀ“ station TreeView def add_dnd(self, parent): # visit each module for cn,module in parent.channels.items(): w = module.gtk_list # bind SOURCE events w.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.drag_types, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE) w.connect('drag-begin', self.begin) w.connect('drag-data-get', self.data_get) # bind DESTINATION events w.enable_model_drag_dest(self.drag_types, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_COPY) w.connect('drag-drop', self.drop)#self.drag_types w.connect('drag-data-received', self.data_received) # -- SOURCE, drag'n'drop from ST2 to elsewhere -- # Starting to drag a row def begin(self, widget, context): __print__(dbg.UI, "dndāsource: begin-drag, store current row") self.row = self.treelist_row() self.buf = {} #context.set_icon_stock("gtk-add", 2, 2) return "url" in self.row # Keep currently selected row when source dragging starts def treelist_row(self): cn = self.parent.channel() row = copy.copy(cn.row()) row.setdefault("format", cn.audioformat) row.setdefault("listformat", cn.listformat) return row # Target window/app requests data for offered drop def data_get(self, widget, context, selection, info, time): __print__(dbg.UI, "dndāsource: data-get, send and convert to requested target type", info) # Start new converter if not buffered (because `data_get` gets called mercilessly along the dragging path) if not info in self.buf: r = self.row cnv = action.save_playlist(source=r["listformat"], multiply=False) # Pass M3U/PLS/XSPF as direct content, or internal JSON even if info >= 20: buf = 'set_text', cnv.export(urls=[r["url"]], row=r, dest=self.cnv_types[info]) # Create temporary PLS file, because "text/uri-list" is widely misunderstood and just implemented for file:// IRLs elif info <= 4: fn = "{}/{}.pls".format(conf.tmp, re.sub("[^\w-]+", " ", r["title"])) cnv.file(rows=[r], dest="pls", fn=fn) if info == 4: fn = ["file://localhost{}".format(fn)] buf = 'set_uris', fn # Text sources are assumed to understand the literal URL, or expect a description else: buf = 'set_text', "{url}\n# Title: {title}\n# Homepage: {homepage}".format(**r) # Buffer self.buf[info] = buf # Return prepared data func, data = self.buf[info] if func in ('set_text'): selection.set_text(data) else: selection.set_uris(data) return True # -- DESTINATION, when playlist/url gets dragged in from other app -- # Just a notification for incoming drop def drop(self, widget, context, x, y, time): __print__(dbg.UI, "dndādest: drop-probing", context.targets, x, y, time, context.drag_get_selection()) widget.drag_get_data(context, context.targets[0], time) return True # Actual data is being passed, # now has to be converted and patched into stream rows and channel liststore def data_received(self, widget, context, x, y, selection, info, time): __print__(dbg.UI, "dndādest: data-receival", x,y,selection, info, time, selection.get_uris(), selection.get_text()) context.finish(True, False, time) return True |