gvcsfx 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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