Merge lp:~dcaro/clicompanion/fix-909893 into lp:clicompanion

Proposed by David Caro
Status: Merged
Approved by: Marek Bardoński
Approved revision: 97
Merged at revision: 98
Proposed branch: lp:~dcaro/clicompanion/fix-909893
Merge into: lp:clicompanion
Diff against target: 234 lines (+127/-12)
2 files modified
clicompanionlib/controller.py (+15/-4)
clicompanionlib/view.py (+112/-8)
To merge this branch: bzr merge lp:~dcaro/clicompanion/fix-909893
Reviewer Review Type Date Requested Status
Marek Bardoński Approve
Review via email: mp+87131@code.launchpad.net

Description of the change

Now the drag and drop feature works properly and allows you to:
  - reorder list
  - add commands from external source (on for each line)
  - saves all the changes made so they are not lost
  - when dropping also removes duplicates (practically they seem moved from the previous position to the new)

To post a comment you must log in.
lp:~dcaro/clicompanion/fix-909893 updated
97. By David Caro "<email address hidden>"

Duplicated TARGETS declaration

Revision history for this message
Marek Bardoński (bdfhjk) wrote :

All work correctly, our program need this.

Thank you.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'clicompanion' (properties changed: -x to +x)
2=== modified file 'clicompanionlib/controller.py'
3--- clicompanionlib/controller.py 2011-11-18 23:56:17 +0000
4+++ clicompanionlib/controller.py 2011-12-30 12:25:27 +0000
5@@ -141,7 +141,13 @@
6 ## cancel button
7 dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
8 ## some secondary text
9- dialog.format_secondary_markup(_("When entering a command use question marks(?) as placeholders if user input is required when the command runs. Example: ls /any/directory would be entered as, ls ? .For each question mark(?) in your command, if any, use the User Input field to provide a hint for each variable. Using our example ls ? you could put directory as the User Input. Lastly provide a brief Description."))
10+ dialog.format_secondary_markup(_('When entering a command use question '
11+ 'marks(?) as placeholders if user input is required when the '
12+ 'command runs. Example: ls /any/directory would be entered as, '
13+ 'ls ? .For each question mark(?) in your command, if any, use '
14+ 'the User Input field to provide a hint for each variable. '
15+ 'Using our example ls ? you could put directory as the User '
16+ 'Input. Lastly provide a brief Description.'))
17
18 ## add it and show it
19 dialog.vbox.pack_end(hbox2, True, True, 0)
20@@ -283,7 +289,6 @@
21
22 ## Remove command from command file and GUI
23 def remove_command(self, widget, liststore):
24-
25 row_int_x = int(view.ROW[0][0])
26 row_int = 0
27 ## TODO: Not implemented with filted yet
28@@ -353,8 +358,7 @@
29 #clear CMNDS list then populate it with the filteredlist of commands
30 view.CMNDS = []
31 for line in modelfilter:
32- linelist = line
33- filteredcommandplus = linelist[0], linelist[1], linelist[2]
34+ filteredcommandplus = tuple(line[0:2])
35 view.CMNDS.append(filteredcommandplus)
36
37
38@@ -369,6 +373,7 @@
39 pagenum = notebook.get_current_page()
40 widget = notebook.get_nth_page(pagenum)
41 page_widget = widget.get_child()
42+
43 ## view.CMNDS is where commands are stored
44 cmnd = view.CMNDS[row_int][0]
45
46@@ -687,4 +692,10 @@
47 ## The destroy method must be called otherwise the 'Close' button will
48 ## not work.
49 dialog.destroy()
50+
51+ def save_cmnds(self):
52+ with open(CHEATSHEET, "w") as cheatfile:
53+ for command in view.CMNDS:
54+ cheatfile.write('\t'.join(command)+'\n')
55+
56
57
58=== modified file 'clicompanionlib/view.py'
59--- clicompanionlib/view.py 2011-11-20 16:51:59 +0000
60+++ clicompanionlib/view.py 2011-12-30 12:25:27 +0000
61@@ -323,23 +323,23 @@
62 ## instantiate tabs
63 tabs = clicompanionlib.tabs.Tabs()
64 ## instantiate controller.Actions, where all the button actions are
65- actions = clicompanionlib.controller.Actions()
66+ self.actions = clicompanionlib.controller.Actions()
67 ## instantiate 'File' and 'Help' Drop Down Menu [menus_buttons.py]
68 bar = clicompanionlib.menus_buttons.FileMenu()
69- menu_bar = bar.the_menu(actions, self.notebook, self.liststore)
70+ menu_bar = bar.the_menu(self.actions, self.notebook, self.liststore)
71
72
73 ## get row of a selection
74 def mark_selected(self, treeselection):
75 global ROW
76- (model, pathlist)=treeselection.get_selected_rows()
77+ (model, pathlist) = treeselection.get_selected_rows()
78 ROW = pathlist
79
80
81 ## double click to run a command
82 def treeview_clicked(widget, event):
83 if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
84- actions.run_command(self, self.notebook, self.liststore)
85+ self.actions.run_command(self, self.notebook, self.liststore)
86
87 ## press enter to run a command
88 def treeview_button(widget, event):
89@@ -347,7 +347,7 @@
90 #print keyname ##debug
91 if event.type == gtk.gdk.KEY_PRESS:
92 if keyname == 'RETURN':
93- actions.run_command(self, self.notebook, self.liststore)
94+ self.actions.run_command(self, self.notebook, self.liststore)
95
96
97
98@@ -367,7 +367,7 @@
99 search_label = gtk.Label(_("Search:"))
100 search_label.set_alignment(xalign=-1, yalign=0)
101 self.search_box = gtk.Entry()
102- self.search_box.connect("changed", actions._filter_commands, self.liststore, self.treeview)
103+ self.search_box.connect("changed", self.actions._filter_commands, self.liststore, self.treeview)
104 ## search box tooltip
105 self.search_box.set_tooltip_text(_("Search your list of commands"))
106 ## Set the search box sensitive OFF at program start, because
107@@ -405,7 +405,7 @@
108
109 global button_box
110 ## buttons at bottom of main window [menus_buttons.py]
111- button_box = bar.buttons(actions, 10, gtk.BUTTONBOX_END, self.notebook, self.liststore)
112+ button_box = bar.buttons(self.actions, 10, gtk.BUTTONBOX_END, self.notebook, self.liststore)
113
114 ## vbox for search, notebook, buttonbar
115 vbox = gtk.VBox()
116@@ -423,13 +423,117 @@
117 self.window.connect("key-press-event", self.key_clicked)
118 add_tab_button.connect("clicked", tabs.add_tab, self.notebook)
119 ## right click menu event capture
120- self.treeview.connect ("button_press_event", bar.right_click, actions, self.treeview, self.notebook, self.liststore)
121+ self.treeview.connect ("button_press_event", bar.right_click, self.actions, self.treeview, self.notebook, self.liststore)
122+
123+ # Allow enable drag and drop of rows including row move
124+ self.treeview.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
125+ TARGETS,
126+ gtk.gdk.ACTION_DEFAULT |
127+ gtk.gdk.ACTION_COPY)
128+ self.treeview.enable_model_drag_dest(TARGETS,
129+ gtk.gdk.ACTION_DEFAULT)
130+
131+ self.treeview.connect ("drag_data_get", self.drag_data_get_event)
132+ self.treeview.connect ("drag_data_received", self.drag_data_received_event)
133
134
135 #self.vte.grab_focus()
136 self.window.show_all()
137 return
138
139+ def drag_data_get_event(self, treeview, context, selection, target_id,
140+ etime):
141+ """
142+ Executed on dragging
143+ """
144+ treeselection = treeview.get_selection()
145+ model, iter = treeselection.get_selected()
146+ data = model.get(iter, 0, 1, 2)
147+ selection.set(selection.target, 8, '\t'.join(data))
148+
149+ def drag_data_received_event(self, treeview, context, x, y, selection, info,
150+ etime):
151+ """
152+ Executed when dropping.
153+ """
154+ global CMNDS
155+ model = treeview.get_model()
156+ for data in selection.data.split('\n'):
157+ # if we got an empty line skip it
158+ if not data.replace('\r',''): continue
159+ # format the incoming string
160+ orig = data.replace('\r','').split('\t',2)
161+ orig = tuple([ fld.strip() for fld in orig ])
162+ # fill the empty fields
163+ if len(orig) < 3: orig = orig + ('',)*(3-len(orig))
164+ # if the element already exists delete it (dragged from clicompanion)
165+ olditer = self.find_iter_by_tuple(orig, model)
166+ if olditer: del model[olditer]
167+
168+ drop_info = treeview.get_dest_row_at_pos(x, y)
169+ if drop_info:
170+ path, position = drop_info
171+ iter = model.get_iter(path)
172+ dest = tuple(model.get(iter, 0, 1, 2))
173+ if (position == gtk.TREE_VIEW_DROP_BEFORE
174+ or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
175+ model.insert_before(iter, orig)
176+ self.drag_cmnd(orig, dest, before=True)
177+ else:
178+ model.insert_after(iter, orig)
179+ self.drag_cmnd(orig, dest, before=False)
180+ else:
181+ if len(model) > 0:
182+ iter = model[-1].iter
183+ model.insert_after(iter, orig)
184+ else:
185+ model.insert(0, orig)
186+ return
187+ dest = tuple(model.get(iter, 0, 1, 2))
188+ self.drag_cmnd(orig, dest, before=False)
189+ if context.action == gtk.gdk.ACTION_MOVE:
190+ context.finish(True, True, etime)
191+ self.actions.save_cmnds()
192+
193+ def find_iter_by_tuple(self, data, model):
194+ for row in model:
195+ if tuple(model.get(row.iter, 0, 1, 2)) == data:
196+ return row.iter
197+ return None
198+
199+ def drag_cmnd(self, orig, dest, before=True):
200+ """
201+ Sync the CMNDS array with the drag and drop of the treeview.
202+ """
203+ global CMNDS
204+ i = j = None
205+ pos = 0
206+ for cmnd in CMNDS:
207+ if cmnd == orig:
208+ i = pos
209+ elif cmnd == dest:
210+ j = pos
211+ pos += 1
212+ ## both from clicompanion
213+ if i != None and j != None:
214+ cmnd = CMNDS.pop(i)
215+ if before and i<=j:
216+ CMNDS.insert(j-1, cmnd)
217+ elif before and i>j:
218+ CMNDS.insert(j, cmnd)
219+ elif i<=j:
220+ CMNDS.insert(j, cmnd)
221+ else:
222+ CMNDS.insert(j+1, cmnd)
223+ ## origin unknown
224+ elif j != None:
225+ cmnd = orig
226+ if before:
227+ CMNDS.insert(j, cmnd)
228+ else:
229+ CMNDS.insert(j+1, cmnd)
230+
231+
232 def main(self):
233 try:
234 gtk.main()

Subscribers

People subscribed via source and target branches