VimMate 0.6.2

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,124 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ require 'yaml'
25
+ require 'vimmatelib/nice_singleton'
26
+
27
+ module VimMate
28
+
29
+ # Holds the configurations for VimMate. Also read and write this
30
+ # configuration so the user can change it.
31
+ class Config
32
+ include NiceSingleton
33
+
34
+ BASE_FILENAME = '.vimmaterc'
35
+ DEFAULT_CONFIG = {
36
+ :window_title => 'VimMate',
37
+ :window_width => 950,
38
+ :window_height => 600,
39
+ :layout_big_terminals => false,
40
+ :files_opened_width => 250,
41
+ :files_closed_width => 25,
42
+ :files_expanded => true,
43
+ :file_headers_visible => false,
44
+ :file_hover_selection => false,
45
+ :file_directory_separator => true,
46
+ :files_filter_active => true,
47
+ :files_refresh_interval => 10,
48
+ :files_default_open_in_tabs => true,
49
+ :files_use_ellipsis => true,
50
+ :files_use_search => true,
51
+ :files_search_ignore_case => true,
52
+ :files_search_separator_position => 400,
53
+ :terminals_enabled => true,
54
+ :terminals_height => 50,
55
+ :terminals_font => "10",
56
+ :terminals_foreground_color => "#000000",
57
+ :terminals_background_color => "#FFFFDD",
58
+ :terminals_audible_bell => false,
59
+ :terminals_visible_bell => false,
60
+ :terminals_autoexec => "",
61
+ :subversion_enabled => true,
62
+ }.freeze
63
+
64
+ # Create the Config class. Cannot be called directly
65
+ def initialize
66
+ # Set the full path to the configuration file. In the user's
67
+ # HOME or the current directory
68
+ if ENV['HOME']
69
+ self.class.const_set(:FILENAME, File.join(ENV['HOME'], BASE_FILENAME))
70
+ else
71
+ self.class.const_set(:FILENAME, BASE_FILENAME)
72
+ end
73
+ @config = DEFAULT_CONFIG.dup
74
+ end
75
+
76
+ # Access the configuration hash
77
+ def config
78
+ read_config
79
+ @config.freeze
80
+ # Once read, we only need a simple reader
81
+ self.class.send(:attr_reader, :config)
82
+ config
83
+ end
84
+
85
+ # Easy access to the configuration hash
86
+ def [](symbol)
87
+ config[symbol.to_sym]
88
+ end
89
+
90
+ # Get the lib path
91
+ def lib_path
92
+ File.dirname(File.expand_path(__FILE__))
93
+ end
94
+
95
+ private
96
+
97
+ # Read the configuration file
98
+ def read_config
99
+ # Write the default if it doesn't exist
100
+ unless File.exist? FILENAME
101
+ write_config
102
+ return
103
+ end
104
+ # Read the configuration file and merge it with the default
105
+ # so if the user doesn't specify an option, it's set to the default
106
+ @config.merge!(YAML.load_file(FILENAME))
107
+ write_config
108
+ rescue StandardError => e
109
+ $stderr.puts e.to_s
110
+ $stderr.puts "Problem reading config file #{FILENAME}, using default"
111
+ end
112
+
113
+ # Write the configuration file
114
+ def write_config
115
+ File.open(FILENAME, 'w') do |file|
116
+ YAML.dump(@config, file)
117
+ end
118
+ rescue StandardError => e
119
+ $stderr.puts e.to_s
120
+ $stderr.puts "Problem writing config file #{FILENAME}"
121
+ end
122
+ end
123
+ end
124
+
@@ -0,0 +1,39 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ require 'gtk2'
25
+
26
+ module VimMate
27
+
28
+ # Represents a dummy window used when a feature is missing
29
+ class DummyWindow
30
+
31
+ attr_reader :gtk_window
32
+
33
+ # Create a DummyWindow
34
+ def initialize
35
+ @gtk_window = Gtk::EventBox.new
36
+ end
37
+ end
38
+ end
39
+
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,230 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ require 'set'
25
+ require 'vimmatelib/icons'
26
+ require 'vimmatelib/requirer'
27
+
28
+ module VimMate
29
+
30
+ # A file within the tree
31
+ class ListedFile
32
+ attr_reader :name, :path, :parent
33
+
34
+ # Create a ListedFile from a path and an optional parent. A block
35
+ # must be passed so it can be called to signal changes.
36
+ def initialize(path, parent = nil, &block)
37
+ @path = path
38
+ @name = File.basename(path)
39
+ @parent = parent
40
+ @tree_signal = block
41
+ @tree_signal.call(:add, self)
42
+ @last_status = nil
43
+ end
44
+
45
+ # Refresh the file. Doesn't do anything since it's the directory
46
+ # that does the job.
47
+ def refresh
48
+ self
49
+ end
50
+
51
+ # Returns the icon for this file
52
+ def icon
53
+ Icons.file_icon
54
+ end
55
+
56
+ # Returns the status text for this file
57
+ def status_text
58
+ ""
59
+ end
60
+
61
+ # If subversion can be required, change the definition of some functions
62
+ Requirer.require_if('vimmatelib/subversion') do
63
+ # Refresh the file. If the file status has changed, send a refresh
64
+ # signal
65
+ def refresh
66
+ status = Subversion.status(@path)
67
+ if @last_status != status
68
+ @last_status = status
69
+ @tree_signal.call(:refresh, self)
70
+ end
71
+ self
72
+ end
73
+
74
+ # Return the icon for this file depending on the file status
75
+ def icon
76
+ status = Subversion.status(@path)
77
+ if @last_status != status
78
+ @last_status = status
79
+ end
80
+ case status
81
+ when Subversion::UNVERSIONED, Subversion::EXTERNAL,
82
+ Subversion::IGNORED, Subversion::UNKNOWN
83
+ Icons.send("#{icon_type}_icon")
84
+ when Subversion::NONE, Subversion::NORMAL
85
+ Icons.send("#{icon_type}_green_icon")
86
+ when Subversion::ADDED, Subversion::DELETED,
87
+ Subversion::REPLACED, Subversion::MODIFIED
88
+ Icons.send("#{icon_type}_orange_icon")
89
+ when Subversion::MISSING, Subversion::MERGED,
90
+ Subversion::CONFLICTED, Subversion::OBSTRUCTED,
91
+ Subversion::INCOMPLETE
92
+ Icons.send("#{icon_type}_red_icon")
93
+ end
94
+ end
95
+
96
+ # Return the status text for this file depending on the file status
97
+ def status_text
98
+ Subversion.status_text(@path)
99
+ end
100
+ end
101
+
102
+ # The type of icon to use
103
+ def icon_type
104
+ :file
105
+ end
106
+ end
107
+
108
+ # A directory within the tree. Can contain files and other directories.
109
+ class ListedDirectory < ListedFile
110
+ include Enumerable
111
+
112
+ # Create a ListedDirectory from a path and an optional parent. A block
113
+ # must be passed so it can be called to signal changes.
114
+ def initialize(path, exclude_file_list, parent = nil, &block)
115
+ super(path, parent, &block)
116
+ @files = Set.new
117
+ @exclude_file_list = exclude_file_list
118
+ refresh
119
+ end
120
+
121
+ # Yield each files and directory within this directory
122
+ def each(&block)
123
+ @files.each(&block)
124
+ self
125
+ end
126
+
127
+ # Refresh the files from this directory. If it doesn't exist, the
128
+ # file is removed. If it didn't exist before, the file is added.
129
+ def refresh
130
+ super
131
+ # Find files to remove
132
+ files_to_remove = Set.new
133
+ all_paths = Set.new
134
+ each do |file|
135
+ file.refresh
136
+ if File.exist? file.path
137
+ all_paths << file.path
138
+ else
139
+ files_to_remove << file
140
+ @tree_signal.call(:remove, file)
141
+ end
142
+ end
143
+ @files -= files_to_remove
144
+
145
+ # Find files to add
146
+ begin
147
+ Dir.foreach(@path) do |file|
148
+ # Skip hidden files
149
+ next if file =~ /^\./
150
+ path = File.join(@path, file)
151
+ next if @exclude_file_list.any? {|f| path[-(f.size+1)..-1] == "/#{f}" }
152
+ # Skip files that we already have
153
+ next if all_paths.include? path
154
+ # Add the new file
155
+ @files << if File.directory? path
156
+ ListedDirectory.new(path, @exclude_file_list, self, &@tree_signal)
157
+ else
158
+ ListedFile.new(path, self, &@tree_signal)
159
+ end
160
+ end
161
+ rescue Errno::ENOENT
162
+ end
163
+ self
164
+ end
165
+
166
+ # The type of icon to use
167
+ def icon_type
168
+ :folder
169
+ end
170
+ end
171
+
172
+ # A tree of files and directory. Can signal added and removed files.
173
+ class ListedTree
174
+ include Enumerable
175
+
176
+ # Create a ListedTree which contains ListedFile and ListedDirectory
177
+ def initialize(exclude_file_list = [])
178
+ @paths = Set.new
179
+ @refresh_signal = Set.new
180
+ @signal_method = method(:signal)
181
+ @exclude_file_list = exclude_file_list
182
+ end
183
+
184
+ # Yield each files and directory at the root of the tree
185
+ def each(&block)
186
+ @paths.each(&block)
187
+ self
188
+ end
189
+
190
+ # Add a path: a file or a directory. If it's a directory, all files
191
+ # within this directory are also added
192
+ def add_path(path)
193
+ return unless File.exist? path
194
+ return if @exclude_file_list.any? {|f| path[-(f.size+1)..-1] == "/#{f}" }
195
+ @paths << if File.directory? path
196
+ ListedDirectory.new(path, @exclude_file_list, &@signal_method)
197
+ else
198
+ ListedFile.new(path, &@signal_method)
199
+ end
200
+ self
201
+ end
202
+
203
+ # Refresh the files from the tree. Inexistent files are removed and
204
+ # new files are added
205
+ def refresh
206
+ each do |path|
207
+ path.refresh
208
+ end
209
+ self
210
+ end
211
+
212
+ # Add a block that will be called when a file is added or removed.
213
+ # The block take 2 arguments: method and file:
214
+ # method: :add, :remove or :refresh
215
+ # file: the ListedFile or ListedDirectory that is affected
216
+ def add_refresh_signal(&block)
217
+ @refresh_signal << block
218
+ end
219
+
220
+ private
221
+
222
+ # Signal that a file has been added or removed.
223
+ def signal(method, file)
224
+ @refresh_signal.each do |block|
225
+ block.call(method, file)
226
+ end
227
+ end
228
+ end
229
+ end
230
+
@@ -0,0 +1,325 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ require 'gtk2'
25
+ require 'fileutils'
26
+ require 'set'
27
+ require 'vimmatelib/config'
28
+ require 'vimmatelib/requirer'
29
+
30
+ module VimMate
31
+
32
+ # The pop-up menu used in the file tree
33
+ class FilesMenu
34
+
35
+ # Create a FilesMenu
36
+ def initialize(parent_window)
37
+ @parent_window = parent_window
38
+ @open_signals = Set.new
39
+ @refresh_signals = Set.new
40
+
41
+ # The last path is the path of the file that was used when
42
+ # the menu was opened
43
+ @last_path = nil
44
+
45
+ # Build the menu items
46
+ @gtk_menu = Gtk::Menu.new
47
+
48
+ @gtk_menu.append(open = Gtk::ImageMenuItem.new(Gtk::Stock::OPEN))
49
+ open.signal_connect("activate") do
50
+ menu_open
51
+ end
52
+
53
+ @gtk_menu.append(split_open = Gtk::MenuItem.new("_Split Open"))
54
+ split_open.signal_connect("activate") do
55
+ menu_split_open
56
+ end
57
+
58
+ @gtk_menu.append(tab_open = Gtk::MenuItem.new("_Tab Open"))
59
+ tab_open.signal_connect("activate") do
60
+ menu_tab_open
61
+ end
62
+
63
+ @gtk_menu.append(Gtk::SeparatorMenuItem.new)
64
+
65
+ @gtk_menu.append(new = Gtk::ImageMenuItem.new(Gtk::Stock::NEW))
66
+ new.signal_connect("activate") do
67
+ menu_new
68
+ end
69
+
70
+ @gtk_menu.append(new_folder = Gtk::MenuItem.new("New _Folder"))
71
+ new_folder.signal_connect("activate") do
72
+ menu_new_folder
73
+ end
74
+
75
+ @gtk_menu.append(Gtk::SeparatorMenuItem.new)
76
+
77
+ @gtk_menu.append(rename = Gtk::MenuItem.new("R_ename"))
78
+ rename.signal_connect("activate") do
79
+ menu_rename
80
+ end
81
+
82
+ @gtk_menu.append(delete = Gtk::ImageMenuItem.new(Gtk::Stock::DELETE))
83
+ delete.signal_connect("activate") do
84
+ menu_delete
85
+ end
86
+
87
+ @gtk_menu.append(Gtk::SeparatorMenuItem.new)
88
+
89
+ Requirer.require_if('vimmatelib/subversion') do
90
+ svn_sub_menu = Gtk::Menu.new
91
+
92
+ svn_sub_menu.append(svn_add = Gtk::ImageMenuItem.new(Gtk::Stock::ADD))
93
+ svn_add.signal_connect("activate") do
94
+ menu_svn_add
95
+ end
96
+
97
+ svn_sub_menu.append(svn_rename = Gtk::MenuItem.new("R_ename"))
98
+ svn_rename.signal_connect("activate") do
99
+ menu_svn_rename
100
+ end
101
+
102
+ svn_sub_menu.append(svn_delete = Gtk::ImageMenuItem.new(Gtk::Stock::DELETE))
103
+ svn_delete.signal_connect("activate") do
104
+ menu_svn_delete
105
+ end
106
+
107
+ svn_sub_menu.append(svn_revert = Gtk::ImageMenuItem.new(Gtk::Stock::REVERT_TO_SAVED))
108
+ svn_revert.signal_connect("activate") do
109
+ menu_svn_revert
110
+ end
111
+
112
+ @gtk_menu.append(subversion = Gtk::MenuItem.new("S_ubversion"))
113
+ subversion.submenu = svn_sub_menu
114
+ end
115
+
116
+ @gtk_menu.append(refresh = Gtk::ImageMenuItem.new(Gtk::Stock::REFRESH))
117
+ refresh.signal_connect("activate") do
118
+ menu_refresh
119
+ end
120
+
121
+ @gtk_menu.show_all
122
+ end
123
+
124
+ # Open the menu. Specify a path to show where the menu was opened.
125
+ def open(path)
126
+ @last_path = path
127
+ @gtk_menu.popup(nil, nil, 0, 0)
128
+ end
129
+
130
+ # Add a block that will be called when the user choose to open a file
131
+ # The block take two argument: the path to the file to open, and a
132
+ # symbol to indicate the kind: :open, :split_open, :tab_open
133
+ def add_open_signal(&block)
134
+ @open_signals << block
135
+ end
136
+
137
+ # Add a block that will be called when the user choose to refresh the
138
+ # file tree. The block doesn't take an argument.
139
+ def add_refresh_signal(&block)
140
+ @refresh_signals << block
141
+ end
142
+
143
+ private
144
+
145
+ # Signals that a file must be opened
146
+ def menu_open
147
+ @open_signals.each do |signal|
148
+ signal.call(@last_path, :open)
149
+ end
150
+ end
151
+
152
+ def menu_split_open
153
+ @open_signals.each do |signal|
154
+ signal.call(@last_path, :split_open)
155
+ end
156
+ end
157
+
158
+ def menu_tab_open
159
+ @open_signals.each do |signal|
160
+ signal.call(@last_path, :tab_open)
161
+ end
162
+ end
163
+
164
+ # Open a dialog to enter a new file name to create
165
+ def menu_new
166
+ dialog = Gtk::FileChooserDialog.new("New file",
167
+ @parent_window.gtk_window,
168
+ Gtk::FileChooser::ACTION_SAVE,
169
+ nil,
170
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
171
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
172
+ dialog.set_icon_list(Icons.window_icons)
173
+ dialog.current_folder = if File.directory? @last_path
174
+ @last_path
175
+ else
176
+ File.dirname(@last_path)
177
+ end
178
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
179
+ begin
180
+ FileUtils.touch(dialog.filename)
181
+ rescue
182
+ $stderr.puts "Cannot touch #{dialog.filename}"
183
+ end
184
+ end
185
+ dialog.destroy
186
+ menu_refresh
187
+ end
188
+
189
+ # Open a dialog to enter a new folder name to create
190
+ def menu_new_folder
191
+ dialog = Gtk::FileChooserDialog.new("New folder",
192
+ @parent_window.gtk_window,
193
+ Gtk::FileChooser::ACTION_CREATE_FOLDER,
194
+ nil,
195
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
196
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
197
+ dialog.set_icon_list(Icons.window_icons)
198
+ dialog.current_folder = if File.directory? @last_path
199
+ @last_path
200
+ else
201
+ File.dirname(@last_path)
202
+ end
203
+ dialog.run
204
+ dialog.destroy
205
+ menu_refresh
206
+ end
207
+
208
+ # Open a dialog to enter a new name for a file or directory
209
+ def menu_rename
210
+ dialog = Gtk::FileChooserDialog.new("Rename #{File.basename(@last_path)}",
211
+ @parent_window.gtk_window,
212
+ Gtk::FileChooser::ACTION_SAVE,
213
+ nil,
214
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
215
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
216
+ dialog.set_icon_list(Icons.window_icons)
217
+ dialog.current_folder = File.dirname(@last_path)
218
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
219
+ begin
220
+ File.rename(@last_path, dialog.filename)
221
+ rescue SystemCallError
222
+ $stderr.puts "Cannot rename from #{@last_path} to #{dialog.filename}"
223
+ end
224
+ end
225
+ dialog.destroy
226
+ menu_refresh
227
+ end
228
+
229
+ # Open a dialog and ask the user if he really wants to delete the target
230
+ # file or directory. Note that for safety, directories can only be removed
231
+ # if they are empty.
232
+ def menu_delete
233
+ name = File.basename(@last_path)
234
+ dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
235
+ Gtk::MessageDialog::Flags::MODAL,
236
+ Gtk::MessageDialog::Type::QUESTION,
237
+ Gtk::MessageDialog::ButtonsType::YES_NO,
238
+ if File.directory? @last_path
239
+ "Delete directory #{name} ?"
240
+ else
241
+ "Delete file #{name} ?"
242
+ end)
243
+ dialog.set_icon_list(Icons.window_icons)
244
+ if dialog.run == Gtk::Dialog::RESPONSE_YES
245
+ begin
246
+ if File.directory? @last_path
247
+ FileUtils.rmdir(@last_path)
248
+ else
249
+ FileUtils.rm(@last_path)
250
+ end
251
+ rescue
252
+ $stderr.puts "Cannot remove #{@last_path}"
253
+ end
254
+ end
255
+ dialog.destroy
256
+ menu_refresh
257
+ end
258
+
259
+ # Only define the Subversion methods if subversion is available
260
+ Requirer.require_if('vimmatelib/subversion') do
261
+
262
+ # Add the selected file to subversion
263
+ def menu_svn_add
264
+ Subversion.add(@last_path)
265
+ menu_refresh
266
+ end
267
+
268
+ # Rename the selected file with subversion
269
+ def menu_svn_rename
270
+ dialog = Gtk::FileChooserDialog.new("Rename #{File.basename(@last_path)}",
271
+ @parent_window.gtk_window,
272
+ Gtk::FileChooser::ACTION_SAVE,
273
+ nil,
274
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
275
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
276
+ dialog.set_icon_list(Icons.window_icons)
277
+ dialog.current_folder = File.dirname(@last_path)
278
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
279
+ Subversion.move(@last_path, dialog.filename)
280
+ end
281
+ dialog.destroy
282
+ menu_refresh
283
+ end
284
+
285
+ # Revert the selected file in subversion
286
+ def menu_svn_revert
287
+ dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
288
+ Gtk::MessageDialog::Flags::MODAL,
289
+ Gtk::MessageDialog::Type::QUESTION,
290
+ Gtk::MessageDialog::ButtonsType::YES_NO,
291
+ "Do a Subversion Revert on #{File.basename(@last_path)} ?")
292
+ dialog.set_icon_list(Icons.window_icons)
293
+ if dialog.run == Gtk::Dialog::RESPONSE_YES
294
+ Subversion.revert(@last_path)
295
+ end
296
+ dialog.destroy
297
+ menu_refresh
298
+ end
299
+
300
+ # Delete the selected file from subversion
301
+ def menu_svn_delete
302
+ dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
303
+ Gtk::MessageDialog::Flags::MODAL,
304
+ Gtk::MessageDialog::Type::QUESTION,
305
+ Gtk::MessageDialog::ButtonsType::YES_NO,
306
+ "Do a Subversion Delete on #{File.basename(@last_path)} ?")
307
+ dialog.set_icon_list(Icons.window_icons)
308
+ if dialog.run == Gtk::Dialog::RESPONSE_YES
309
+ Subversion.remove(@last_path)
310
+ end
311
+ dialog.destroy
312
+ menu_refresh
313
+ end
314
+ end
315
+
316
+ # Signals that the file tree must be refreshed
317
+ def menu_refresh
318
+ @refresh_signals.each do |signal|
319
+ signal.call
320
+ end
321
+ end
322
+
323
+ end
324
+ end
325
+