gvcsfx 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,312 @@
1
+ # Copyright (C) 2020 Chris Liaw <chrisliaw@antrapol.com>
2
+ # Author: Chris Liaw <chrisliaw@antrapol.com>
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+
19
+ module GvcsFx
20
+ module TabBranches
21
+
22
+ class VcsStash < Hash
23
+
24
+ def to_s
25
+ end
26
+ end
27
+
28
+ class VcsBranch
29
+ include Antrapol::ToolRack::ExceptionUtils
30
+
31
+ attr_accessor :name, :stash, :current
32
+ def initialize
33
+ @name = ""
34
+ @stash = VcsStash.new
35
+ @current = false
36
+ end
37
+
38
+ def name=(val)
39
+ if not_empty?(val)
40
+ if val =~ /\*/
41
+ @current = true
42
+ @name = val.gsub("*","").strip
43
+ else
44
+ @name = val
45
+ end
46
+ end
47
+ end
48
+
49
+ def to_s
50
+ res = []
51
+ res << "#{(@current ? "* #{@name}" : @name)}"
52
+ if not_empty?(@stash)
53
+ res << "(#{@stash.length} stash(es) on this branch found)"
54
+ end
55
+ res.join(" ")
56
+ end
57
+ end # VcsBranch
58
+
59
+ def init_tab_branches
60
+
61
+ @lstBranches.add_event_handler(javafx.scene.input.MouseEvent::MOUSE_CLICKED, Proc.new do |evt|
62
+ if evt.button == javafx.scene.input.MouseButton::SECONDARY
63
+ # right click on item
64
+ branches_ctxmenu.show(@lstBranches, evt.screen_x, evt.screen_y)
65
+ #elsif evt.button == javafx.scene.input.MouseButton::PRIMARY and evt.click_count == 2
66
+ # # double click on item - view file
67
+ # sel = @tblChanges.selection_model.selected_items
68
+ # if sel.length > 0
69
+ # sel.each do |s|
70
+ # fullPath = File.join(@selWs.path,s.path.strip)
71
+ # if not File.directory?(fullPath)
72
+ # view_file(s.path)
73
+ # end
74
+ # end
75
+ # end
76
+
77
+ end
78
+ end)
79
+
80
+ end
81
+
82
+ def refresh_tab_branches
83
+
84
+ @lstBranches.items.clear
85
+
86
+ st, br = @selWs.local_branches
87
+ if st
88
+ sst, sinfo = @selWs.stash_list
89
+ if sst
90
+
91
+ bbr = { }
92
+ br.each do |b|
93
+ vb = VcsBranch.new
94
+ vb.name = b
95
+ bbr[vb.name] = vb
96
+ end
97
+
98
+ sinfo.each do |k,v|
99
+ if bbr.keys.include?(v[0])
100
+ bbr[v[0]].stash[k] = v
101
+ end
102
+ end
103
+
104
+ @lstBranches.items.add_all(bbr.values)
105
+
106
+ else
107
+ @lstBranches.items.add_all(br)
108
+ end
109
+ end
110
+
111
+ @txtNewBranchName.clear
112
+ end # refresh_tab_branches
113
+
114
+ def create_branch(evt)
115
+
116
+ bn = @txtNewBranchName.text
117
+ if is_empty?(bn)
118
+ fx_alert_error("Branch name cannot be empty","Empty Branch Name",main_stage)
119
+ else
120
+ st, res = @selWs.create_branch(bn)
121
+ if st
122
+ set_success_gmsg("New branch '#{bn}' successfully created.")
123
+ refresh_tab_branches
124
+ else
125
+ fx_alert_error(res.strip,"New Branch Creation Failed", main_stage)
126
+ end
127
+ end
128
+ end # create_branch
129
+
130
+ def branch_clicked(evt)
131
+ if evt.button == javafx.scene.input.MouseButton::PRIMARY and evt.click_count == 2
132
+ selBr = @lstBranches.selection_model.selected_item
133
+ if not_empty?(selBr)
134
+ if selBr.current #is_current_branch(selBr)
135
+ else
136
+ # switch branch
137
+ st, res = @selWs.switch_branch(selBr.name)
138
+ if st
139
+ set_info_gmsg("Workspace's branch switched to '#{selBr.name}'")
140
+ refresh_tab_branches
141
+ else
142
+ prompt_error("Failed to switch to branch '#{selBr.name}'. Error was :\n\n#{res}")
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ # hooked on text field of new branch
150
+ def new_branch_keypressed(evt)
151
+ if evt.code == javafx.scene.input.KeyCode::ENTER
152
+ create_branch(nil)
153
+ end
154
+ end
155
+
156
+ def show_stash_restore_win(options, stageTitle = "GVCS - Stash Restore")
157
+
158
+ #javafx.application.Platform.run_later do
159
+
160
+ stage = javafx.stage.Stage.new
161
+ stage.title = stageTitle
162
+ stage.initModality(javafx.stage.Modality::WINDOW_MODAL)
163
+ stage.initOwner(main_stage)
164
+ dlg = StashSelectController.load_into(stage)
165
+ dlg.options = options
166
+ stage.showAndWait
167
+
168
+ dlg.result
169
+ #end # run_later
170
+
171
+ end # show_options_win
172
+
173
+
174
+ def branches_ctxmenu
175
+
176
+ @selBranch = @lstBranches.selection_model.selected_items
177
+
178
+ @branchesCtxMenu = javafx.scene.control.ContextMenu.new
179
+
180
+ if @selBranch.length > 0
181
+
182
+ selBr = @selBranch.first
183
+ bst, currBranch = @selWs.current_branch
184
+
185
+
186
+ if not selBr.current #is_current_branch(selBr)
187
+
188
+
189
+ mergeMnuItm = javafx.scene.control.MenuItem.new("Merge with #{currBranch}")
190
+ mergeMnuItm.on_action do |evt|
191
+
192
+ res = fx_alert_confirmation("Merge changes in branch '#{selBr.name}' into '#{currBranch}'?", nil, "Confirmation to Merge Branches", main_stage)
193
+ if res == :ok
194
+ st,res = @selWs.merge_branch(selBr.name)
195
+ if st
196
+ set_success_gmsg("Branch '#{selBr.name}' merged into '#{currBranch}' successfully.")
197
+ else
198
+ log_error("Merge branch '#{selBr.name}' inito '#{currBranch}' failed. [#{res}]")
199
+ prompt_error("Merge branch '#{selBr.name}' inito '#{currBranch}' failed. [#{res}]")
200
+ end
201
+ end # if user answer ok to merge
202
+
203
+
204
+ end # on_action do .. end
205
+
206
+ @branchesCtxMenu.items.add(mergeMnuItm)
207
+
208
+
209
+ @branchesCtxMenu.items.add(javafx.scene.control.SeparatorMenuItem.new)
210
+
211
+ delMnuItm = javafx.scene.control.MenuItem.new("Delete branch")
212
+ delMnuItm.on_action do |evt|
213
+
214
+ res = fx_alert_confirmation("Delete branch '#{selBr.name}'?", nil, "Confirmation to Delete Branch", main_stage)
215
+ if res == :ok
216
+ st,res = @selWs.delete_branch(selBr.name)
217
+ if st
218
+ set_success_gmsg("Branch '#{selBr.name}' deleted successfully.")
219
+ refresh_tab_branches
220
+ else
221
+ log_error("Delete branch '#{selBr.name}' failed. [#{res}]")
222
+ prompt_error("Delete branch '#{selBr.name}' failed. [#{res}]")
223
+ end
224
+ end # if user answer ok to delete
225
+
226
+
227
+ end # on_action do .. end
228
+
229
+ @branchesCtxMenu.items.add(delMnuItm)
230
+
231
+ else
232
+ #@branchesCtxMenu.items.add(javafx.scene.control.SeparatorMenuItem.new) if @branchesCtxMenu.items.count > 0
233
+
234
+ #if not_empty?(selBr.stash)
235
+
236
+ # lsMnuItm = javafx.scene.control.MenuItem.new("Restore Stash to new branch")
237
+ # lsMnuItm.on_action do |evt|
238
+
239
+ # st, sel, branch = show_stash_restore_win(selBr.stash)
240
+ # if st
241
+ # if is_empty?(sel)
242
+ # prompt_error("Please select one of the Stash to restore.","Empty Stash Selection")
243
+ # elsif is_empty?(branch)
244
+ # prompt_error("Please provide a branch name.","Empty Branch Name")
245
+ # else
246
+ # sst, sres = @selWs.stash_to_new_branch(branch, sel.key)
247
+
248
+ # if sst
249
+ # set_success_gmsg(sres)
250
+ # else
251
+ # prompt_error("Failed to store the stash to #{currBranch}. Error was : #{sres}")
252
+ # end
253
+ # end
254
+ # end
255
+
256
+ # end # on_action do .. end
257
+
258
+ # @branchesCtxMenu.items.add(lsMnuItm)
259
+
260
+ #end
261
+
262
+ end # if selected branch is not current branch
263
+
264
+
265
+ if not_empty?(selBr.stash)
266
+
267
+ @branchesCtxMenu.items.add(javafx.scene.control.SeparatorMenuItem.new) if @branchesCtxMenu.items.count > 0
268
+
269
+ lsMnuItm = javafx.scene.control.MenuItem.new("Restore Stash to new branch")
270
+ lsMnuItm.on_action do |evt|
271
+
272
+ st, sel, branch = show_stash_restore_win(selBr.stash)
273
+ if st
274
+ if is_empty?(sel)
275
+ prompt_error("Please select one of the Stash to restore.","Empty Stash Selection")
276
+ elsif is_empty?(branch)
277
+ prompt_error("Please provide a branch name.","Empty Branch Name")
278
+ else
279
+ sst, sres = @selWs.stash_to_new_branch(branch, sel.key)
280
+
281
+ if sst
282
+ set_success_gmsg(sres)
283
+ refresh_tab_branches
284
+ else
285
+ prompt_error("Failed to restore the stash '#{sel.key}' to new branch #{branch}. Error was : #{sres}")
286
+ end
287
+ end
288
+ end
289
+
290
+ end # on_action do .. end
291
+
292
+ @branchesCtxMenu.items.add(lsMnuItm)
293
+
294
+ end
295
+
296
+
297
+ end
298
+
299
+ @branchesCtxMenu
300
+
301
+ end
302
+
303
+ def is_current_branch(br)
304
+ if is_empty?(br)
305
+ false
306
+ else
307
+ (br =~ /\*/) != nil
308
+ end
309
+ end
310
+
311
+ end
312
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (C) 2020 Chris Liaw <chrisliaw@antrapol.com>
2
+ # Author: Chris Liaw <chrisliaw@antrapol.com>
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+
19
+ module GvcsFx
20
+ module TabFiles
21
+
22
+ def refresh_files(*args)
23
+ puts "refresh files #{args}"
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright (C) 2020 Chris Liaw <chrisliaw@antrapol.com>
2
+ # Author: Chris Liaw <chrisliaw@antrapol.com>
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+
19
+ module GvcsFx
20
+ module TabIgnoreRules
21
+
22
+ def init_tab_ignore_rules
23
+ @txtIgnoreRules.prompt_text = "No ignore rules defined"
24
+ end
25
+
26
+ def refresh_tab_ignore_rules
27
+ @txtIgnoreRules.text = @selWs.ignore_rules
28
+ end
29
+
30
+ def on_save_ignore_rules(evt)
31
+ st,res = @selWs.update_ignore_rules(@txtIgnoreRules.text)
32
+ if st
33
+ set_success_gmsg(res)
34
+ else
35
+ prompt_error(res,"Save Ignore Rules Error")
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,222 @@
1
+ # Copyright (C) 2020 Chris Liaw <chrisliaw@antrapol.com>
2
+ # Author: Chris Liaw <chrisliaw@antrapol.com>
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ require 'date'
19
+
20
+ module GvcsFx
21
+ module TabLogs
22
+
23
+ class VcsLog
24
+ include Antrapol::ToolRack::ExceptionUtils
25
+ include javafx.beans.value.ObservableValue
26
+
27
+ attr_accessor :key, :date, :author_name, :author_email, :subject, :body, :notes
28
+ def reformatted_date
29
+ if not_empty?(@date)
30
+ dt = DateTime.strptime(@date,"%a %b %e %H:%M:%S %Y %z")
31
+ dt.strftime("%H:%M, %d.%b.%Y (%a)")
32
+ else
33
+ @date
34
+ end
35
+ end
36
+
37
+ def addListener(list)
38
+ end
39
+
40
+ def removeListener(list)
41
+ end
42
+
43
+ def value
44
+ self
45
+ end
46
+
47
+ end # VcsLog
48
+
49
+ class LogCellFactory < javafx.scene.control.TableCell
50
+ attr_accessor :tableColumn
51
+ def updateItem(itm,e)
52
+ super
53
+ if not itm.nil?
54
+ d = []
55
+ d << "Commit : #{itm.key}\n"
56
+ d << "#{itm.subject}"
57
+ lbl = javafx.scene.text.Text.new(d.join("\n"))
58
+ lbl.wrappingWidthProperty.bind(@tableColumn.widthProperty)
59
+ setGraphic(lbl)
60
+ else
61
+ setGraphic(nil)
62
+ end
63
+ end
64
+ end
65
+
66
+ def init_tab_logs
67
+
68
+ @tblLogs.placeholder = javafx.scene.control.Label.new("Log has no entries yet.")
69
+
70
+ @tblLogs.columns.clear
71
+ @tblLogs.column_resize_policy = javafx.scene.control.TableView::CONSTRAINED_RESIZE_POLICY
72
+
73
+ cols = []
74
+ colDate = TableColumn.new("Date")
75
+ colDate.cell_value_factory = Proc.new do |p|
76
+ SimpleStringProperty.new(p.value.reformatted_date)
77
+ end
78
+ colDate.sortable = false
79
+ cols << colDate
80
+
81
+ colSubj = TableColumn.new("Subject")
82
+ colSubj.cell_value_factory = Proc.new do |p|
83
+ p.value
84
+ end
85
+ colSubj.cell_factory = Proc.new do |pa|
86
+ cell = LogCellFactory.new
87
+ cell.tableColumn = pa
88
+ cell
89
+ end
90
+ colSubj.sortable = false
91
+ cols << colSubj
92
+
93
+ colAuthor = TableColumn.new("Committer")
94
+ colAuthor.cell_value_factory = Proc.new do |p|
95
+ SimpleStringProperty.new(p.value.author_name)
96
+ end
97
+ colAuthor.sortable = false
98
+ cols << colAuthor
99
+
100
+
101
+ @tblLogs.columns.add_all(cols)
102
+
103
+ # set column width
104
+ #colState.pref_width_property.bind(@tblChanges.width_property.multiply(0.1))
105
+ #colState.max_width_property.bind(colState.pref_width_property)
106
+ #colState.resizable = false
107
+ colDate.pref_width = 220.0
108
+ colDate.max_width = colDate.pref_width
109
+ colDate.min_width = colDate.pref_width
110
+
111
+ colAuthor.pref_width = 180.0
112
+ colAuthor.max_width = colAuthor.pref_width
113
+ colAuthor.min_width = colAuthor.pref_width
114
+
115
+ @tblLogs.selection_model.selection_mode = javafx.scene.control.SelectionMode::SINGLE
116
+
117
+ @tblLogs.add_event_handler(javafx.scene.input.MouseEvent::MOUSE_CLICKED, Proc.new do |evt|
118
+ if evt.button == javafx.scene.input.MouseButton::SECONDARY
119
+ # right click on item
120
+ logs_ctxmenu.show(@tblLogs, evt.screen_x, evt.screen_y)
121
+ elsif evt.button == javafx.scene.input.MouseButton::PRIMARY and evt.click_count == 2
122
+
123
+ sel = @tblLogs.selection_model.selected_item
124
+
125
+ if not sel.nil?
126
+
127
+ st, res = @selWs.show_log(sel.key)
128
+
129
+ if st
130
+ show_content_win("Log Detail", "Show Log Detail - #{sel.key}", res)
131
+ else
132
+ set_err_gmsg("Log detail for key '#{s.key}' failed. [#{res}]")
133
+ end
134
+
135
+ end
136
+
137
+ end
138
+
139
+ end)
140
+
141
+ @txtLogLimit.text = "50"
142
+
143
+ end # init_tab_logs
144
+
145
+ def refresh_tab_logs
146
+ limit = @txtLogLimit.text
147
+ st, res = @selWs.logs({ limit: limit })
148
+ if st
149
+
150
+ entries = []
151
+ res.each_line do |l|
152
+
153
+ #puts l
154
+
155
+ ll = l.split("|")
156
+
157
+ log = VcsLog.new
158
+ log.key = ll[0].strip
159
+ log.date = ll[1].strip
160
+ author = ll[2].nil? ? "" : ll[2].strip
161
+ if not_empty?(author)
162
+ aa = author.split(",")
163
+ log.author_name = aa[0].nil? ? "" : aa[0].strip
164
+ log.author_email = aa[1].nil? ? "" : aa[1].strip
165
+ end
166
+ log.subject = ll[3].strip
167
+ log.body = ll[4].nil? ? "" : ll[4].strip
168
+ log.notes = ll[5].nil? ? "" : ll[5].strip
169
+
170
+ entries << log
171
+ end
172
+
173
+ @tblLogs.items.clear
174
+ @tblLogs.items.add_all(entries)
175
+
176
+ else
177
+ @tblLogs.items.clear
178
+ end
179
+ end # refresh_tab_logs
180
+
181
+ def loglimit_keypressed(evt)
182
+ if (not evt.nil?) and evt.code == javafx.scene.input.KeyCode::ENTER
183
+ refresh_tab_logs
184
+ end
185
+ end
186
+
187
+ private
188
+ def logs_ctxmenu
189
+
190
+ @selLog = @tblLogs.selection_model.selected_items
191
+
192
+ @logsCtxMenu = javafx.scene.control.ContextMenu.new
193
+
194
+ if @selLog.length > 0
195
+
196
+ #
197
+ # Copy subject menu item
198
+ #
199
+ ccmMnuItm = javafx.scene.control.MenuItem.new("Copy Commit Message")
200
+ ccmMnuItm.on_action do |evt|
201
+
202
+ s = @selLog.first
203
+ cc = javafx.scene.input.ClipboardContent.new
204
+ cc.putString(s.subject)
205
+ javafx.scene.input.Clipboard.getSystemClipboard.setContent(cc)
206
+
207
+ set_info_gmsg("Commit message copied to system clipboard. Use Paste operation to paste it into destination.")
208
+
209
+ end
210
+ @logsCtxMenu.items.add(ccmMnuItm)
211
+ #
212
+ # end diff menu item
213
+ #
214
+
215
+ end
216
+
217
+ @logsCtxMenu
218
+
219
+ end
220
+
221
+ end
222
+ end