Check-in [38812e4bbf]
Overview
Comment: | Implement in-application row copying per JSON (info=51, mime=json/vnd.streamtuner2.station). Fixed set_text() bug by using set("STRING",..) atom instead. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
38812e4bbf19fa780e3b285be9f68838 |
User & Date: | mario on 2015-04-19 22:17:04 |
Other Links: | manifest | tags |
Context
2015-04-20
| ||
16:21 | Remove some obsolete comments/code snippets. check-in: dd605f1352 user: mario tags: trunk | |
2015-04-19
| ||
22:17 | Implement in-application row copying per JSON (info=51, mime=json/vnd.streamtuner2.station). Fixed set_text() bug by using set("STRING",..) atom instead. check-in: 38812e4bbf user: mario tags: trunk | |
19:35 | Experiment with a few more target types. Works with a few text editors on STRING. Most just want a uri-list, but can't handle it. check-in: e0e28edba2 user: mario tags: trunk | |
Changes
Modified channels/dnd.py from [3ecc3ca6e1] to [25fd725420].
︙ | ︙ | |||
40 41 42 43 44 45 46 | row = None # Buffer converted types buf = {} # Supported type map drag_types = [ # internal | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | row = None # Buffer converted types buf = {} # Supported type map drag_types = [ # internal ("json/vnd.streamtuner2.station", gtk.TARGET_SAME_APP, 51), # literal exports ("audio/x-mpegurl", 0, 20), ("application/x-scpls", 0, 21), ("application/xspf+xml", 0, 22), ("application/smil", 0, 23), ("text/html", 0, 23), ("text/richtext", 0, 23), |
︙ | ︙ | |||
89 90 91 92 93 94 95 | # 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 | | > | < > | 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 | # 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) 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) 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 = {} # uikit.do(context.set_icon_default) uikit.do(context.set_icon_stock, gtk.STOCK_ADD, 16, 16) 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) row.setdefault("url", row.get("homepage")) 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, selection.get_target()) # 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) # internal JSON row if info >= 51: buf = 'text', json.dumps(r) print buf # Pass M3U/PLS/XSPF as literal payload elif info >= 20: buf = 'text', cnv.export(urls=[r["url"]], row=r, dest=self.cnv_types[info]) # Direct server URL elif info >= 10: urls = action.convert_playlist(r["url"], r["listformat"], "srv", False, r) #buf = 'uris', urls |
︙ | ︙ | |||
154 155 156 157 158 159 160 | # Keep in type request buffer self.buf[info] = buf # Return prepared data func, data = self.buf[info] if func.find("text") >= 0: | > | < | < | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | # Keep in type request buffer self.buf[info] = buf # Return prepared data func, data = self.buf[info] if func.find("text") >= 0: # Yay for trial and error. Nay for docs. PyGtks selection.set_text() doesn't actually work unless the requested target type is an Atom. selection.set("STRING", 8, data) if func.find("uris") >= 0: 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, possible targets:", context.targets) # context.drop_reply(True, time) #"STRING" return widget.drag_get_data(context, context.targets[0], time) or 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", info, selection.get_text(), selection.get_uris()) # print selection.get_length() # print selection.get_format() # print selection.get_targets() # print selection.get_target() # incoming data data = selection.get_text() urls = selection.get_uris() if not data and not urls: context.drop_finish(False, time) context.drag_abort(time) print "ABORT DROP" return # internal target dicts cn = self.parent.channel() # direct/internal row import if info >= 51: print "ADD ROW" cn.streams[cn.current].append(json.loads(data)) # convertible formats elif info >= 10: pass elif info >= 5: pass else: pass #self.parent.streamedit() # finish drop context.drop_finish(True, time) context.finish(True, False, time) return True |