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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/Gemfile +24 -0
- data/README.md +71 -0
- data/bin/gvcsfx +13 -0
- data/bin/gvcsfx.rb +97 -0
- data/config/warble.rb +212 -0
- data/fx/add_workspace.fxml +90 -0
- data/fx/diff.fxml +51 -0
- data/fx/float.fxml +29 -0
- data/fx/main.fxml +637 -0
- data/fx/show_text.fxml +50 -0
- data/fx/stash_select.fxml +59 -0
- data/gvcs_fx.rb +85 -0
- data/handlers/add_workspace_controller.rb +88 -0
- data/handlers/event_handler.rb +58 -0
- data/handlers/float_win_controller.rb +68 -0
- data/handlers/fx_alert.rb +120 -0
- data/handlers/listener.rb +59 -0
- data/handlers/main_win_controller.rb +191 -0
- data/handlers/notification.rb +113 -0
- data/handlers/show_text_controller.rb +38 -0
- data/handlers/stash_select_controller.rb +86 -0
- data/handlers/tab_branches.rb +312 -0
- data/handlers/tab_files.rb +27 -0
- data/handlers/tab_ignore_rules.rb +40 -0
- data/handlers/tab_logs.rb +222 -0
- data/handlers/tab_repos.rb +277 -0
- data/handlers/tab_state.rb +571 -0
- data/handlers/tab_tags.rb +224 -0
- data/handlers/tray.rb +128 -0
- data/handlers/workspace.rb +547 -0
- data/javafx_test.rb +81 -0
- data/lib/global.rb +56 -0
- data/lib/log_helper.rb +40 -0
- data/lib/store.rb +152 -0
- data/lib/version.rb +21 -0
- data/res/accept.png +0 -0
- data/res/cross.png +0 -0
- data/res/tick.png +0 -0
- data/res/version-control.png +0 -0
- data/res/warn.png +0 -0
- data/res/world.png +0 -0
- metadata +156 -0
@@ -0,0 +1,277 @@
|
|
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 TabRepos
|
21
|
+
|
22
|
+
class GvcsFxRepository
|
23
|
+
include javafx.beans.value.ObservableValue
|
24
|
+
attr_reader :repos, :branch
|
25
|
+
def initialize(repos,branch)
|
26
|
+
@repos = repos
|
27
|
+
@branch = branch
|
28
|
+
end
|
29
|
+
|
30
|
+
def addListener(list)
|
31
|
+
end
|
32
|
+
|
33
|
+
def removeListener(list)
|
34
|
+
end
|
35
|
+
|
36
|
+
def value
|
37
|
+
self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class URLTableCell < javafx.scene.control.TableCell
|
42
|
+
def updateItem(itm, isEmpty)
|
43
|
+
super
|
44
|
+
if item.nil?
|
45
|
+
setGraphic(nil)
|
46
|
+
else
|
47
|
+
repos = itm.repos
|
48
|
+
br = itm.branch
|
49
|
+
#st = []
|
50
|
+
#st << repos.url
|
51
|
+
#st << "Push to / Pull from current branch : #{br}"
|
52
|
+
#lbl = javafx.scene.control.Label.new(st.join("\n"))
|
53
|
+
lbl = javafx.scene.control.Label.new(repos.url)
|
54
|
+
setGraphic(lbl)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def init_tab_repos
|
60
|
+
|
61
|
+
@tblRepos.placeholder = javafx.scene.control.Label.new("No remote repository configured")
|
62
|
+
|
63
|
+
@tblRepos.columns.clear
|
64
|
+
@tblRepos.column_resize_policy = javafx.scene.control.TableView::CONSTRAINED_RESIZE_POLICY
|
65
|
+
|
66
|
+
cols = []
|
67
|
+
colName = TableColumn.new("Name")
|
68
|
+
colName.cell_value_factory = Proc.new do |c|
|
69
|
+
SimpleStringProperty.new(c.value.repos.name)
|
70
|
+
end
|
71
|
+
cols << colName
|
72
|
+
|
73
|
+
colUrl = TableColumn.new("URL")
|
74
|
+
colUrl.cell_value_factory = Proc.new do |c|
|
75
|
+
c.value
|
76
|
+
end
|
77
|
+
colUrl.cell_factory = Proc.new do |tc|
|
78
|
+
URLTableCell.new
|
79
|
+
end
|
80
|
+
cols << colUrl
|
81
|
+
|
82
|
+
#@cmbRepoBranches = javafx.scene.control.ComboBox.new
|
83
|
+
#colBranches = TableColumn.new("Branch")
|
84
|
+
#colBranches.cell_factory = Proc.new do |tc|
|
85
|
+
# @tblCelReposBranch = ReposBranchTableCell.new
|
86
|
+
# @tblCelReposBranch
|
87
|
+
#end
|
88
|
+
#colBranches.cell_value_factory = Proc.new do |p|
|
89
|
+
# p.value.branches
|
90
|
+
#end
|
91
|
+
#colBranches.cell_value_factory = Proc.new do |p|
|
92
|
+
# SimpleStringProperty.new(p.value.url)
|
93
|
+
#end
|
94
|
+
#cols << colBranches
|
95
|
+
|
96
|
+
@tblRepos.columns.add_all(cols)
|
97
|
+
|
98
|
+
colName.pref_width = 180.0
|
99
|
+
colName.max_width = 280.0
|
100
|
+
colName.min_width = 160.0
|
101
|
+
|
102
|
+
#colBranches.pref_width = 180.0
|
103
|
+
#colBranches.max_width = 220.0
|
104
|
+
#colBranches.min_width = 168.0
|
105
|
+
|
106
|
+
@tblRepos.selection_model.selection_mode = javafx.scene.control.SelectionMode::SINGLE
|
107
|
+
|
108
|
+
#@tblRepos.add_event_handler(javafx.scene.input.MouseEvent::MOUSE_CLICKED, Proc.new do |evt|
|
109
|
+
# if evt.button == javafx.scene.input.MouseButton::SECONDARY
|
110
|
+
# # right click on item
|
111
|
+
# changes_ctxmenu.show(@tblChanges, evt.screen_x, evt.screen_y)
|
112
|
+
# elsif evt.button == javafx.scene.input.MouseButton::PRIMARY and evt.click_count == 2
|
113
|
+
# # double click on item - view file
|
114
|
+
# sel = @tblChanges.selection_model.selected_items
|
115
|
+
# if sel.length > 0
|
116
|
+
# sel.each do |s|
|
117
|
+
# view_file(s.path)
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
|
121
|
+
# end
|
122
|
+
#end)
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
def refresh_tab_repos
|
127
|
+
|
128
|
+
@txtReposName.clear
|
129
|
+
@txtReposUrl.clear
|
130
|
+
|
131
|
+
st, @currBr = @selWs.current_branch
|
132
|
+
@currBr = "<unknown>" if not st
|
133
|
+
|
134
|
+
@lblReposMessage.text = "Operation push & pull always based on current branch [Current branch is '#{@currBr}'].\nIf you want to push / pull to different branch, change it at the 'Branches' tab before come here."
|
135
|
+
|
136
|
+
refresh_repos_list
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
def refresh_repos_list
|
141
|
+
|
142
|
+
@tblRepos.items.clear
|
143
|
+
|
144
|
+
st, res = @selWs.remote_config
|
145
|
+
if st
|
146
|
+
rp = []
|
147
|
+
res.each do |k,v|
|
148
|
+
#repos = Gvcs::Repository.new(k,v)
|
149
|
+
repos = Gvcs::Repository.new(k,v)
|
150
|
+
rp << GvcsFxRepository.new(repos,"")
|
151
|
+
#st, br = @selWs.current_branch
|
152
|
+
#if st
|
153
|
+
# rp << GvcsFxRepository.new(repos,br)
|
154
|
+
#else
|
155
|
+
# rp << GvcsFxRepository.new(repos,"<unknown>")
|
156
|
+
#end
|
157
|
+
#rp << repos
|
158
|
+
end
|
159
|
+
|
160
|
+
@tblRepos.items.add_all(rp)
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
def repos_key_released(evt)
|
167
|
+
|
168
|
+
if evt.code == javafx.scene.input.KeyCode::DELETE
|
169
|
+
sel = @tblRepos.selection_model.selected_items.to_a
|
170
|
+
if sel.length > 0
|
171
|
+
nm = sel.first.repos.name
|
172
|
+
pa = sel.first.repos.url
|
173
|
+
res = fx_alert_confirmation("Delete Repository '#{nm} - #{pa}' from system?", nil, "Remove Repository?", main_stage)
|
174
|
+
if res == :ok
|
175
|
+
st, rres = @selWs.remove_remote(nm)
|
176
|
+
if st
|
177
|
+
refresh_repos_list
|
178
|
+
log_debug "Remote repository '#{nm} - #{pa}' removed from workspace"
|
179
|
+
set_success_gmsg("Remote repository '#{nm} - #{pa}' removed from workspace")
|
180
|
+
else
|
181
|
+
fx_alert_error(rres,"Remove Repository Exception",main_stage)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
def add_repository(evt)
|
191
|
+
|
192
|
+
nm = @txtReposName.text
|
193
|
+
pa = @txtReposUrl.text
|
194
|
+
|
195
|
+
if is_empty?(nm)
|
196
|
+
fx_alert_error("Repository name cannot be empty","Repository Name Empty",main_stage)
|
197
|
+
elsif is_empty?(pa)
|
198
|
+
fx_alert_error("Repository URL cannot be empty","Repository URL Empty",main_stage)
|
199
|
+
else
|
200
|
+
st, res = @selWs.add_remote(nm,pa)
|
201
|
+
if st
|
202
|
+
|
203
|
+
@txtReposName.clear
|
204
|
+
@txtReposUrl.clear
|
205
|
+
|
206
|
+
refresh_repos_list
|
207
|
+
else
|
208
|
+
fx_alert_error(res.strip, "Add Repository Exception", main_stage)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
def txtReposUrl_key_released(evt)
|
215
|
+
|
216
|
+
if evt.code == javafx.scene.input.KeyCode::ENTER
|
217
|
+
add_repository(nil)
|
218
|
+
evt.consume
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
def butRepositoryOpen_onAction(evt)
|
224
|
+
dc = javafx.stage.DirectoryChooser.new
|
225
|
+
dc.title = "Select Local Repository"
|
226
|
+
wsDir = dc.showDialog(main_stage)
|
227
|
+
|
228
|
+
@txtReposUrl.text = wsDir.absolute_path if not_empty?(wsDir)
|
229
|
+
end
|
230
|
+
|
231
|
+
def repos_pull(evt)
|
232
|
+
sel = @tblRepos.selection_model.selected_items.to_a
|
233
|
+
if sel.length > 0
|
234
|
+
selRepos = sel.first
|
235
|
+
|
236
|
+
repos = selRepos.repos.name
|
237
|
+
@selWs.add_repos(selRepos.repos)
|
238
|
+
ret, msg = @selWs.pull(repos, @currBr)
|
239
|
+
if ret
|
240
|
+
set_success_gmsg(msg)
|
241
|
+
else
|
242
|
+
fx_alert_error(msg, "GVCS Repository Pull Exception", main_stage)
|
243
|
+
end
|
244
|
+
|
245
|
+
else
|
246
|
+
fx_alert_error("No repository selected. Please select one repository to pull.", "No Repository Selected", main_stage)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def repos_push(evt)
|
251
|
+
sel = @tblRepos.selection_model.selected_items.to_a
|
252
|
+
if sel.length > 0
|
253
|
+
|
254
|
+
selRepos = sel.first
|
255
|
+
withTag = @chkPushWithTag.isSelected
|
256
|
+
|
257
|
+
repos = selRepos.repos.name
|
258
|
+
@selWs.add_repos(selRepos.repos)
|
259
|
+
if withTag
|
260
|
+
ret, msg = @selWs.push_changes_with_tags(repos, @currBr)
|
261
|
+
else
|
262
|
+
ret, msg = @selWs.push_changes(repos, @currBr)
|
263
|
+
end
|
264
|
+
|
265
|
+
if ret
|
266
|
+
set_success_gmsg(msg)
|
267
|
+
else
|
268
|
+
fx_alert_error(msg, "GVCS Repository Push Exception", main_stage)
|
269
|
+
end
|
270
|
+
|
271
|
+
else
|
272
|
+
fx_alert_error("No repository selected. Please select one repository to push.", "No Repository Selected", main_stage)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,571 @@
|
|
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
|
+
java_import javafx.scene.control.TableColumn
|
19
|
+
|
20
|
+
require_relative 'show_text_controller'
|
21
|
+
|
22
|
+
module GvcsFx
|
23
|
+
module TabState
|
24
|
+
|
25
|
+
###########
|
26
|
+
class VcsElement
|
27
|
+
attr_accessor :ctype, :path, :ftype
|
28
|
+
def initialize(ctype, path, ftype)
|
29
|
+
@ctype = ctype
|
30
|
+
@path = path
|
31
|
+
@ftype = ftype
|
32
|
+
end
|
33
|
+
end
|
34
|
+
class ModifiedFile < VcsElement
|
35
|
+
def initialize(path, ftype)
|
36
|
+
super("M",path, ftype)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
class ConflictedFile < VcsElement
|
40
|
+
def initialize(path, ftype)
|
41
|
+
super("C",path, ftype)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
class NewFile < VcsElement
|
45
|
+
def initialize(path, ftype)
|
46
|
+
super("N",path, ftype)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
class DeletedFile < VcsElement
|
50
|
+
def initialize(path, ftype)
|
51
|
+
super("D",path, ftype)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
#############
|
55
|
+
|
56
|
+
def init_tab_state
|
57
|
+
@tblChanges.placeholder = javafx.scene.control.Label.new("Changeset is empty. Please select a workspace or the selected workspace has no changes ")
|
58
|
+
|
59
|
+
@tblChanges.columns.clear
|
60
|
+
@tblChanges.column_resize_policy = javafx.scene.control.TableView::CONSTRAINED_RESIZE_POLICY
|
61
|
+
|
62
|
+
cols = []
|
63
|
+
colState = TableColumn.new("State")
|
64
|
+
colState.cell_value_factory = Proc.new do |p|
|
65
|
+
SimpleStringProperty.new(p.value.ctype)
|
66
|
+
end
|
67
|
+
cols << colState
|
68
|
+
|
69
|
+
colUrl = TableColumn.new("Path")
|
70
|
+
colUrl.cell_value_factory = Proc.new do |p|
|
71
|
+
SimpleStringProperty.new(p.value.path)
|
72
|
+
end
|
73
|
+
cols << colUrl
|
74
|
+
|
75
|
+
@tblChanges.columns.add_all(cols)
|
76
|
+
|
77
|
+
# set column width
|
78
|
+
#colState.pref_width_property.bind(@tblChanges.width_property.multiply(0.1))
|
79
|
+
#colState.max_width_property.bind(colState.pref_width_property)
|
80
|
+
#colState.resizable = false
|
81
|
+
colState.pref_width = 80.0
|
82
|
+
colState.max_width = 100.0
|
83
|
+
colState.min_width = 60.0
|
84
|
+
|
85
|
+
@tblChanges.selection_model.selection_mode = javafx.scene.control.SelectionMode::MULTIPLE
|
86
|
+
|
87
|
+
# mouse event
|
88
|
+
@tblChanges.add_event_handler(javafx.scene.input.MouseEvent::MOUSE_CLICKED, Proc.new do |evt|
|
89
|
+
if evt.button == javafx.scene.input.MouseButton::SECONDARY
|
90
|
+
# right click on item
|
91
|
+
changes_ctxmenu.show(@tblChanges, evt.screen_x, evt.screen_y)
|
92
|
+
elsif evt.button == javafx.scene.input.MouseButton::PRIMARY and evt.click_count == 2
|
93
|
+
# double click on item - diff file
|
94
|
+
sel = @tblChanges.selection_model.selected_items
|
95
|
+
if sel.length > 0
|
96
|
+
sel.each do |s|
|
97
|
+
st, res = @selWs.diff_file(s.path)
|
98
|
+
if st
|
99
|
+
|
100
|
+
show_content_win("Diff Output", "Diff Result - #{s.path}", res)
|
101
|
+
|
102
|
+
else
|
103
|
+
set_err_gmsg("Diff for '#{s.path}' failed. [#{res}]")
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end) # end mouse event
|
111
|
+
|
112
|
+
@msgHistory = []
|
113
|
+
@cmbCommitMsg.items.clear
|
114
|
+
end
|
115
|
+
|
116
|
+
# hooked to but Commit on action
|
117
|
+
def vcs_commit(evt)
|
118
|
+
sel = @tblChanges.selection_model.selected_items
|
119
|
+
msg = @cmbCommitMsg.value
|
120
|
+
if sel.length == 0
|
121
|
+
fx_alert_error "Cannot commit on empty changes selection. Please select at least a file from the table above.", "No Files Selected", main_stage
|
122
|
+
elsif (msg.nil? or msg.empty?)
|
123
|
+
fx_alert_error "Commit message must be present.", "Empty Commit Message", main_stage
|
124
|
+
else
|
125
|
+
commit_changes(sel, msg)
|
126
|
+
if not @msgHistory.include?(msg)
|
127
|
+
@cmbCommitMsg.items.add(msg)
|
128
|
+
@msgHistory << msg
|
129
|
+
end
|
130
|
+
refresh_tab_state
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# hooked to but Refresh on action
|
135
|
+
def refresh_vcs_status(evt = nil)
|
136
|
+
|
137
|
+
if not (@selWs.nil?)
|
138
|
+
|
139
|
+
mst, mods_dirs, mods_files = @selWs.modified_files
|
140
|
+
cst, cflt_dirs, cflt_files = @selWs.conflicted_files
|
141
|
+
nst, news_dirs, news_files = @selWs.new_files
|
142
|
+
dst, dels_dirs, dels_files = @selWs.deleted_files
|
143
|
+
|
144
|
+
data = []
|
145
|
+
mods_dirs.each do |f|
|
146
|
+
data << ModifiedFile.new(f,:dir)
|
147
|
+
end
|
148
|
+
mods_files.each do |f|
|
149
|
+
data << ModifiedFile.new(f,:file)
|
150
|
+
end
|
151
|
+
|
152
|
+
cflt_dirs.each do |f|
|
153
|
+
data << ConflictedFile.new(f,:dir)
|
154
|
+
end
|
155
|
+
cflt_files.each do |f|
|
156
|
+
data << ConflictedFile.new(f,:file)
|
157
|
+
end
|
158
|
+
|
159
|
+
news_dirs.each do |f|
|
160
|
+
data << NewFile.new(f,:dir)
|
161
|
+
end
|
162
|
+
news_files.each do |f|
|
163
|
+
data << NewFile.new(f,:file)
|
164
|
+
end
|
165
|
+
dels_dirs.each do |f|
|
166
|
+
data << DeletedFile.new(f,:dir)
|
167
|
+
end
|
168
|
+
dels_files.each do |f|
|
169
|
+
data << DeletedFile.new(f,:file)
|
170
|
+
end
|
171
|
+
|
172
|
+
bst, currBranch = @selWs.current_branch
|
173
|
+
if bst
|
174
|
+
@lblCurrBranch.text = currBranch
|
175
|
+
else
|
176
|
+
@lblCurrBranch.text = "<Exception while reading branch [#{currBranch}]>"
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
@tblChanges.items.clear
|
181
|
+
@tblChanges.items.add_all(data)
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
def refresh_tab_state
|
187
|
+
refresh_vcs_status(nil)
|
188
|
+
@cmbCommitMsg.selection_model.clear_selection
|
189
|
+
@cmbCommitMsg.value = nil
|
190
|
+
end
|
191
|
+
|
192
|
+
# hooked to on_key_typed
|
193
|
+
def is_cmbCommit_enter(evt)
|
194
|
+
if (not evt.nil?) and evt.code == javafx.scene.input.KeyCode::ENTER
|
195
|
+
vcs_commit(nil)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# hooked to the button "not ready to commit just yet..."
|
200
|
+
def stash_changes(evt)
|
201
|
+
mst, mods_dirs, mods_files = @selWs.modified_files
|
202
|
+
cst, cflt_dirs, cflt_files = @selWs.conflicted_files
|
203
|
+
nst, news_dirs, news_files = @selWs.new_files
|
204
|
+
dst, dels_dirs, dels_files = @selWs.deleted_files
|
205
|
+
|
206
|
+
if mods_dirs.length > 0 or mods_files.length > 0 \
|
207
|
+
or cflt_dirs.length > 0 or cflt_files.length > 0 \
|
208
|
+
or news_dirs.length > 0 or news_files.length > 0 \
|
209
|
+
or dels_dirs.length > 0 or dels_files.length > 0
|
210
|
+
|
211
|
+
msg = []
|
212
|
+
msg << "System detected there are existing uncommitted changes in the current workspace:\n"
|
213
|
+
msg << "\tModified folder(s) : \t\t#{mods_dirs.length}\n"
|
214
|
+
msg << "\tModified file(s) : \t\t#{mods_files.length}\n"
|
215
|
+
msg << "\tConflicted folder(s) : \t#{cflt_dirs.length}\n"
|
216
|
+
msg << "\tConflicted file(s) : \t\t#{cflt_files.length}\n"
|
217
|
+
msg << "\tDeleted folder(s) : \t\t#{dels_dirs.length}\n"
|
218
|
+
msg << "\tDeleted file(s) : \t\t#{dels_files.length}\n"
|
219
|
+
msg << "\tNew folder(s) : \t\t#{news_dirs.length}\n"
|
220
|
+
msg << "\tNew file(s) : \t\t\t#{news_files.length}\n"
|
221
|
+
|
222
|
+
st, name = fx_alert_input("Temporary Save Changes To Branch",msg.join, "Please give a descriptive name of this temporary changes.\nIt is recommended but not mandatory")
|
223
|
+
if st
|
224
|
+
# this means user click ok, but the text can still be empty
|
225
|
+
sst, res = @selWs.stash_changes(name)
|
226
|
+
if sst
|
227
|
+
set_info_gmsg(res)
|
228
|
+
refresh_vcs_status
|
229
|
+
else
|
230
|
+
prompt_error("Failed to stash the changes. Error was : #{res}")
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
else
|
235
|
+
fx_alert_info("Workspace is clean. No uncommitted changes found")
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
def commit_changes(selected, msg)
|
241
|
+
raise_if_empty(selected, "No file given to commit", GvcsFxException)
|
242
|
+
raise_if_empty(msg, "No message given to commit", GvcsFxException)
|
243
|
+
|
244
|
+
@emptyDirCommit = []
|
245
|
+
@processed = []
|
246
|
+
selected.each do |f|
|
247
|
+
begin
|
248
|
+
fullPath = File.join(@selWs.path,f.path.strip)
|
249
|
+
if File.directory?(fullPath)
|
250
|
+
# check if the directory is empty...
|
251
|
+
if Dir.entries(fullPath).length == 2
|
252
|
+
# empty!
|
253
|
+
keepPath = File.join(fullPath,".keep")
|
254
|
+
FileUtils.touch keepPath
|
255
|
+
|
256
|
+
@selWs.add(keepPath)
|
257
|
+
@emptyDirCommit << File.join(f.path.strip,".keep")
|
258
|
+
else
|
259
|
+
@selWs.add(f.path)
|
260
|
+
@processed << f.path.strip
|
261
|
+
end
|
262
|
+
else
|
263
|
+
@selWs.add(f.path)
|
264
|
+
@processed << f.path.strip
|
265
|
+
end
|
266
|
+
rescue Exception => ex
|
267
|
+
log_error "Error while GVCS add to staging operation:"
|
268
|
+
log_error ex.message
|
269
|
+
log_error ex.backtrace.join("\n")
|
270
|
+
reset_add_commit_error(@processed,@emptyDirCommit)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
begin
|
275
|
+
cst, res = @selWs.commit(msg)
|
276
|
+
if cst
|
277
|
+
@cmbCommitMsg.items.add(msg)
|
278
|
+
else
|
279
|
+
reset_add_commit_error(@processed,@emptyDirCommit)
|
280
|
+
log_error("Commit failed. Error was : #{res.strip}")
|
281
|
+
prompt_error("Error while committing changes. Error was:\n#{res.strip}", "Commit Error", GvcsFxException)
|
282
|
+
#set_err_gmsg("Error while committing changes. Error was:\n#{res.strip}")
|
283
|
+
end
|
284
|
+
rescue Exception => ex
|
285
|
+
reset_add_commit_error(@processed,@emptyDirCommit)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def reset_add_commit_error(files, emptyFolders = [])
|
290
|
+
|
291
|
+
if not_empty?(files)
|
292
|
+
files.each do |f|
|
293
|
+
begin
|
294
|
+
@selWs.remove_from_staging(f)
|
295
|
+
rescue Exception => ex
|
296
|
+
log_error "Exception while removing file from staging. Error was: "
|
297
|
+
log_error ex.message
|
298
|
+
log_error ex.backtrace[0..5].join("\n")
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
if not_empty?(emptyFolders)
|
304
|
+
emptyFolders.each do |f|
|
305
|
+
@selWs.remove_from_staging(f)
|
306
|
+
# not removing the created .keep file because it is an exception case
|
307
|
+
# Exception case doesn't mean the intention to check in the directory is incorrect.
|
308
|
+
# the intention to check in still there therefore the .keep file shall remain
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
end # reset_add_commit_error
|
313
|
+
|
314
|
+
def view_file(path)
|
315
|
+
|
316
|
+
javafx.application.Platform.run_later do
|
317
|
+
stage = javafx.stage.Stage.new
|
318
|
+
stage.title = "View Content"
|
319
|
+
stage.initModality(javafx.stage.Modality::WINDOW_MODAL)
|
320
|
+
#stage.initOwner(main_stage)
|
321
|
+
dlg = ShowTextController.load_into(stage)
|
322
|
+
dlg.set_title("File Content - #{path}")
|
323
|
+
File.open(File.join(@selWs.path,path),"r") do |f|
|
324
|
+
@cont = f.read
|
325
|
+
end
|
326
|
+
dlg.set_content(@cont)
|
327
|
+
stage.showAndWait
|
328
|
+
end
|
329
|
+
|
330
|
+
end
|
331
|
+
|
332
|
+
def changes_ctxmenu
|
333
|
+
|
334
|
+
@selChanges = @tblChanges.selection_model.selected_items
|
335
|
+
|
336
|
+
|
337
|
+
@changesCtxMenu = javafx.scene.control.ContextMenu.new
|
338
|
+
|
339
|
+
if @selChanges.length > 0
|
340
|
+
|
341
|
+
#
|
342
|
+
# View file menu item
|
343
|
+
#
|
344
|
+
diffMnuItm = javafx.scene.control.MenuItem.new("Diff")
|
345
|
+
diffMnuItm.on_action do |evt|
|
346
|
+
|
347
|
+
@selChanges.each do |s|
|
348
|
+
|
349
|
+
st, res = @selWs.diff_file(s.path)
|
350
|
+
if st
|
351
|
+
show_content_win("Diff Output", "Diff Result - #{s.path}", res)
|
352
|
+
else
|
353
|
+
prompt_error("Diff for '#{s.path}' failed. [#{res}]")
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
359
|
+
@changesCtxMenu.items.add(diffMnuItm)
|
360
|
+
#
|
361
|
+
# end diff menu item
|
362
|
+
#
|
363
|
+
|
364
|
+
#
|
365
|
+
# View file menu item
|
366
|
+
#
|
367
|
+
vfMnuItm = javafx.scene.control.MenuItem.new("View file")
|
368
|
+
vfMnuItm.on_action do |evt|
|
369
|
+
|
370
|
+
@selChanges.each do |s|
|
371
|
+
|
372
|
+
fullPath = File.join(@selWs.path,s.path.strip)
|
373
|
+
if not File.directory?(fullPath)
|
374
|
+
view_file(s.path)
|
375
|
+
end
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
@changesCtxMenu.items.add(vfMnuItm)
|
381
|
+
#
|
382
|
+
# end diff menu item
|
383
|
+
#
|
384
|
+
|
385
|
+
#
|
386
|
+
# Remove from VCS
|
387
|
+
#
|
388
|
+
@changesCtxMenu.items.add(javafx.scene.control.SeparatorMenuItem.new)
|
389
|
+
|
390
|
+
rmvVcsMnuItm = javafx.scene.control.MenuItem.new("Remove from VCS")
|
391
|
+
rmvVcsMnuItm.on_action do |evt|
|
392
|
+
|
393
|
+
@selChanges.each do |s|
|
394
|
+
@selWs.remove_from_vcs(s.path)
|
395
|
+
@selWs.ignore(s.path)
|
396
|
+
|
397
|
+
set_info_gmsg("File '#{s.path}' removed from VCS")
|
398
|
+
end
|
399
|
+
|
400
|
+
refresh_vcs_status(nil)
|
401
|
+
|
402
|
+
end
|
403
|
+
@changesCtxMenu.items.add(rmvVcsMnuItm)
|
404
|
+
#
|
405
|
+
# end remove from VCS
|
406
|
+
#
|
407
|
+
|
408
|
+
#delMnuItm = javafx.scene.control.MenuItem.new("Delete physical file")
|
409
|
+
#delMnuItm.on_action do |evt|
|
410
|
+
# puts "Del physical file"
|
411
|
+
#end
|
412
|
+
#@changesCtxMenu.items.add(delMnuItm)
|
413
|
+
|
414
|
+
@changesCtxMenu.items.add(javafx.scene.control.SeparatorMenuItem.new)
|
415
|
+
|
416
|
+
#
|
417
|
+
# Add to ignore list
|
418
|
+
#
|
419
|
+
ignMnuItm = javafx.scene.control.MenuItem.new("Add to ignore list")
|
420
|
+
ignMnuItm.on_action do |evt|
|
421
|
+
|
422
|
+
igPat = []
|
423
|
+
@selChanges.each do |s|
|
424
|
+
fullPath = File.join(@selWs.path, s.path)
|
425
|
+
if File.directory?(fullPath)
|
426
|
+
|
427
|
+
res = fx_alert_confirmation("Add folder '#{s.path}' to ignore list?\nAll changes under this folder shall be ignored if done so.", nil, "Confirmation to Ignore Directory", main_stage)
|
428
|
+
if res == :ok
|
429
|
+
# is the folder already in version control?
|
430
|
+
if s.is_a?(NewFile)
|
431
|
+
igPat << s.path
|
432
|
+
elsif s.is_a?(DeletedFile)
|
433
|
+
fx_alert_info("Folder '#{s.path}' is marked deleted but not yet committed.\nFolder shall be put inside ignore rules but shall only reflect after you've committed the changes.")
|
434
|
+
igPat << s.path
|
435
|
+
elsif s.is_a?(ModifiedFile)
|
436
|
+
res = fx_alert_confirmation("Folder being ignored is already tracked under the VCS.\nRemove folder from VCS and put it under ignore rule?", nil, "Confirmation to Ignore Tracked Folder", main_stage)
|
437
|
+
if res == :ok
|
438
|
+
@selWs.remove_from_vcs(s.path)
|
439
|
+
igPat << s.path
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
cnt = igPat.join("\n")
|
444
|
+
st, res = @selWs.ignore(cnt)
|
445
|
+
|
446
|
+
if st
|
447
|
+
set_success_gmsg(res)
|
448
|
+
refresh_vcs_status(nil)
|
449
|
+
else
|
450
|
+
set_err_gmsg("Add to ignore list for '#{igPat.join(",")}' failed. [#{res}]")
|
451
|
+
end
|
452
|
+
|
453
|
+
end # res == :0k
|
454
|
+
|
455
|
+
else
|
456
|
+
# is the file already in version control?
|
457
|
+
if s.is_a?(NewFile)
|
458
|
+
igPat << s.path
|
459
|
+
elsif s.is_a?(DeletedFile)
|
460
|
+
fx_alert_info("File '#{s.path}' is marked deleted but not yet committed.\nFile shall be put inside ignore rules but shall only reflect after you've committed the changes.")
|
461
|
+
igPat << s.path
|
462
|
+
elsif s.is_a?(ModifiedFile)
|
463
|
+
res = fx_alert_confirmation("File being ignored is already tracked under the VCS.\nRemove file from VCS and put it under ignore rule?", nil, "Confirmation to Ignore Tracked File", main_stage)
|
464
|
+
if res == :ok
|
465
|
+
@selWs.remove_from_vcs(s.path)
|
466
|
+
igPat << s.path
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
cnt = igPat.join("\n")
|
471
|
+
st, res = @selWs.ignore(cnt)
|
472
|
+
|
473
|
+
if st
|
474
|
+
set_success_gmsg(res)
|
475
|
+
refresh_vcs_status(nil)
|
476
|
+
else
|
477
|
+
set_err_gmsg("Add to ignore list for '#{igPat.join(",")}' failed. [#{res}]")
|
478
|
+
end
|
479
|
+
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
#cnt = igPat.join("\n")
|
484
|
+
#st, res = @selWs.ignore(cnt)
|
485
|
+
|
486
|
+
#if st
|
487
|
+
# refresh_vcs_status(nil)
|
488
|
+
#else
|
489
|
+
# set_err_gmsg("Add to ignore list for '#{igPat.join(",")}' failed. [#{res}]")
|
490
|
+
#end
|
491
|
+
|
492
|
+
end
|
493
|
+
@changesCtxMenu.items.add(ignMnuItm)
|
494
|
+
#
|
495
|
+
# end Add to ignore list
|
496
|
+
#
|
497
|
+
|
498
|
+
#
|
499
|
+
# Add extension to ignore list
|
500
|
+
#
|
501
|
+
ignExtMnuItm = javafx.scene.control.MenuItem.new("Add extension to ignore list")
|
502
|
+
ignExtMnuItm.on_action do |evt|
|
503
|
+
|
504
|
+
igPat = []
|
505
|
+
@selChanges.each do |s|
|
506
|
+
fullPath = File.join(@selWs.path, s.path)
|
507
|
+
if File.directory?(fullPath)
|
508
|
+
fx_alert_warning("Given file '#{s.path}' to add extension to ignore list is a folder.\nPlease use 'Add to ignore list' option if indeed that is the intention.","Folder has no extension",main_stage)
|
509
|
+
else
|
510
|
+
igPat << "*#{File.extname(s.path)}"
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
cnt = igPat.join("\n")
|
515
|
+
st, res = @selWs.ignore(cnt)
|
516
|
+
|
517
|
+
if st
|
518
|
+
refresh_vcs_status(nil)
|
519
|
+
else
|
520
|
+
set_err_gmsg("Add extension '#{igPat.join(",")}' to ignore list failed. [#{res}]")
|
521
|
+
end
|
522
|
+
|
523
|
+
end
|
524
|
+
@changesCtxMenu.items.add(ignExtMnuItm)
|
525
|
+
#
|
526
|
+
# end Add extension to ignore list
|
527
|
+
#
|
528
|
+
|
529
|
+
@changesCtxMenu.items.add(javafx.scene.control.SeparatorMenuItem.new)
|
530
|
+
|
531
|
+
#
|
532
|
+
# Revert changes
|
533
|
+
#
|
534
|
+
revertExtMnuItm = javafx.scene.control.MenuItem.new("Revert Changes")
|
535
|
+
revertExtMnuItm.on_action do |evt|
|
536
|
+
|
537
|
+
igPat = []
|
538
|
+
@selChanges.each do |s|
|
539
|
+
res = fx_alert_confirmation("Revert '#{s.path}' to version from last commit?\nAll changes made to the fill will be discarded!.", nil, "Confirmation to Revert Changes", main_stage)
|
540
|
+
if res == :ok
|
541
|
+
igPat << s.path
|
542
|
+
end
|
543
|
+
|
544
|
+
end
|
545
|
+
|
546
|
+
cnt = igPat.join("\n")
|
547
|
+
st, res = @selWs.reset_file_changes(cnt)
|
548
|
+
|
549
|
+
if st
|
550
|
+
set_info_gmsg(res)
|
551
|
+
refresh_vcs_status(nil)
|
552
|
+
else
|
553
|
+
set_err_gmsg("Add extension '#{igPat.join(",")}' to ignore list failed. [#{res}]")
|
554
|
+
end
|
555
|
+
|
556
|
+
end
|
557
|
+
@changesCtxMenu.items.add(revertExtMnuItm)
|
558
|
+
#
|
559
|
+
# end Add extension to ignore list
|
560
|
+
#
|
561
|
+
|
562
|
+
|
563
|
+
end
|
564
|
+
|
565
|
+
|
566
|
+
@changesCtxMenu
|
567
|
+
|
568
|
+
end
|
569
|
+
|
570
|
+
end
|
571
|
+
end
|