vimmate 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +10 -0
- data/CHANGELOG +108 -0
- data/COPYING +20 -0
- data/README +221 -0
- data/Rakefile +31 -0
- data/TODO +21 -0
- data/bin/vimmate +105 -0
- data/config/environment.rb +35 -0
- data/controllers/file_filter_controller.rb +101 -0
- data/controllers/file_popup_menu_controller.rb +40 -0
- data/controllers/vim_controller.rb +28 -0
- data/controllers/vim_mate_controller.rb +76 -0
- data/images/file.png +0 -0
- data/images/file_green.png +0 -0
- data/images/file_orange.png +0 -0
- data/images/file_red.png +0 -0
- data/images/folder.png +0 -0
- data/images/folder_green.png +0 -0
- data/images/folder_orange.png +0 -0
- data/images/folder_red.png +0 -0
- data/images/processing.png +0 -0
- data/images/svn_added.png +0 -0
- data/images/svn_conflict.png +0 -0
- data/images/svn_deleted.png +0 -0
- data/images/svn_locked.png +0 -0
- data/images/svn_modified.png +0 -0
- data/images/svn_normal.png +0 -0
- data/images/svn_readonly.png +0 -0
- data/images/vimmate16.png +0 -0
- data/images/vimmate32.png +0 -0
- data/images/vimmate48.png +0 -0
- data/lib/active_window/active_column.rb +218 -0
- data/lib/active_window/active_tree_store/columns.rb +88 -0
- data/lib/active_window/active_tree_store/extentions.rb +81 -0
- data/lib/active_window/active_tree_store/index.rb +53 -0
- data/lib/active_window/active_tree_store.rb +26 -0
- data/lib/active_window/application.rb +137 -0
- data/lib/active_window/controller.rb +58 -0
- data/lib/active_window/dot_file.rb +29 -0
- data/lib/active_window/filtered_active_tree_store.rb +113 -0
- data/lib/active_window/listed_item.rb +127 -0
- data/lib/active_window/signal.rb +46 -0
- data/lib/active_window.rb +8 -0
- data/lib/config_window.rb +90 -0
- data/lib/file_tree_store.rb +74 -0
- data/lib/filtered_file_tree_store.rb +34 -0
- data/lib/gtk_thread_helper.rb +73 -0
- data/lib/listed_directory.rb +45 -0
- data/lib/listed_file.rb +67 -0
- data/lib/try.rb +9 -0
- data/lib/vim/buffers.rb +18 -0
- data/lib/vim/integration.rb +38 -0
- data/lib/vim/netbeans.rb +154 -0
- data/lib/vim/source.vim +18 -0
- data/lib/vim_mate/config.rb +132 -0
- data/lib/vim_mate/dummy_window.rb +14 -0
- data/lib/vim_mate/files_menu.rb +110 -0
- data/lib/vim_mate/icons.rb +156 -0
- data/lib/vim_mate/nice_singleton.rb +53 -0
- data/lib/vim_mate/plugins/inotify/init.rb +4 -0
- data/lib/vim_mate/plugins/inotify/lib/INotify.rb +208 -0
- data/lib/vim_mate/plugins/inotify/lib/directory.rb +58 -0
- data/lib/vim_mate/plugins/subversion/init.rb +7 -0
- data/lib/vim_mate/plugins/subversion/lib/file.rb +59 -0
- data/lib/vim_mate/plugins/subversion/lib/menu.rb +96 -0
- data/lib/vim_mate/plugins/subversion/lib/subversion.rb +157 -0
- data/lib/vim_mate/plugins.rb +6 -0
- data/lib/vim_mate/requirer.rb +68 -0
- data/lib/vim_mate/search_window.rb +227 -0
- data/lib/vim_mate/tags_window.rb +167 -0
- data/lib/vim_mate/terminals_window.rb +163 -0
- data/lib/vim_mate/version.rb +29 -0
- data/lib/vim_mate/vim_widget.rb +143 -0
- data/spec/active_window/active_column_spec.rb +41 -0
- data/spec/active_window/active_tree_store_spec.rb +312 -0
- data/spec/active_window/controller_spec.rb +6 -0
- data/spec/lib/file_tree_store_spec.rb +40 -0
- data/spec/lib/listed_directory_spec.rb +26 -0
- data/spec/lib/listed_file_spec.rb +53 -0
- data/spec/nice_singleton_spec.rb +23 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +10 -0
- data/views/vim_mate.glade +500 -0
- data/vimmate.gemspec +138 -0
- metadata +146 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
module VimMate
|
2
|
+
module Plugin
|
3
|
+
module SubversionMenu
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
include InstanceMethods
|
7
|
+
alias_method :initialize_without_svn, :initialize
|
8
|
+
alias_method :initialize, :initialize_with_svn
|
9
|
+
end
|
10
|
+
end
|
11
|
+
module InstanceMethods
|
12
|
+
def initialize_with_svn(*args)
|
13
|
+
initialize_without_svn(*args)
|
14
|
+
svn_sub_menu = Gtk::Menu.new
|
15
|
+
|
16
|
+
svn_sub_menu.append(svn_add = Gtk::ImageMenuItem.new(Gtk::Stock::ADD))
|
17
|
+
svn_add.signal_connect("activate") do
|
18
|
+
menu_svn_add
|
19
|
+
end
|
20
|
+
|
21
|
+
svn_sub_menu.append(svn_rename = Gtk::MenuItem.new("R_ename"))
|
22
|
+
svn_rename.signal_connect("activate") do
|
23
|
+
menu_svn_rename
|
24
|
+
end
|
25
|
+
|
26
|
+
svn_sub_menu.append(svn_delete = Gtk::ImageMenuItem.new(Gtk::Stock::DELETE))
|
27
|
+
svn_delete.signal_connect("activate") do
|
28
|
+
menu_svn_delete
|
29
|
+
end
|
30
|
+
|
31
|
+
svn_sub_menu.append(svn_revert = Gtk::ImageMenuItem.new(Gtk::Stock::REVERT_TO_SAVED))
|
32
|
+
svn_revert.signal_connect("activate") do
|
33
|
+
menu_svn_revert
|
34
|
+
end
|
35
|
+
|
36
|
+
@gtk_menu.append(subversion = Gtk::MenuItem.new("S_ubversion"))
|
37
|
+
subversion.submenu = svn_sub_menu
|
38
|
+
@gtk_menu.show_all
|
39
|
+
end
|
40
|
+
# Add the selected file to subversion
|
41
|
+
def menu_svn_add
|
42
|
+
Subversion.add(@last_path)
|
43
|
+
menu_refresh
|
44
|
+
end
|
45
|
+
|
46
|
+
# Rename the selected file with subversion
|
47
|
+
def menu_svn_rename
|
48
|
+
dialog = Gtk::FileChooserDialog.new("Rename #{File.basename(@last_path)}",
|
49
|
+
@parent_window.gtk_window,
|
50
|
+
Gtk::FileChooser::ACTION_SAVE,
|
51
|
+
nil,
|
52
|
+
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
|
53
|
+
[Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
|
54
|
+
dialog.set_icon_list(Icons.window_icons)
|
55
|
+
dialog.current_folder = File.dirname(@last_path)
|
56
|
+
if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
|
57
|
+
Subversion.move(@last_path, dialog.filename)
|
58
|
+
end
|
59
|
+
dialog.destroy
|
60
|
+
menu_refresh
|
61
|
+
end
|
62
|
+
|
63
|
+
# Revert the selected file in subversion
|
64
|
+
def menu_svn_revert
|
65
|
+
dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
|
66
|
+
Gtk::MessageDialog::Flags::MODAL,
|
67
|
+
Gtk::MessageDialog::Type::QUESTION,
|
68
|
+
Gtk::MessageDialog::ButtonsType::YES_NO,
|
69
|
+
"Do a Subversion Revert on #{File.basename(@last_path)} ?")
|
70
|
+
dialog.set_icon_list(Icons.window_icons)
|
71
|
+
if dialog.run == Gtk::Dialog::RESPONSE_YES
|
72
|
+
Subversion.revert(@last_path)
|
73
|
+
end
|
74
|
+
dialog.destroy
|
75
|
+
menu_refresh
|
76
|
+
end
|
77
|
+
|
78
|
+
# Delete the selected file from subversion
|
79
|
+
def menu_svn_delete
|
80
|
+
dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
|
81
|
+
Gtk::MessageDialog::Flags::MODAL,
|
82
|
+
Gtk::MessageDialog::Type::QUESTION,
|
83
|
+
Gtk::MessageDialog::ButtonsType::YES_NO,
|
84
|
+
"Do a Subversion Delete on #{File.basename(@last_path)} ?")
|
85
|
+
dialog.set_icon_list(Icons.window_icons)
|
86
|
+
if dialog.run == Gtk::Dialog::RESPONSE_YES
|
87
|
+
Subversion.remove(@last_path)
|
88
|
+
end
|
89
|
+
dialog.destroy
|
90
|
+
menu_refresh
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,157 @@
|
|
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 'svn/core'
|
25
|
+
require 'svn/client'
|
26
|
+
require 'svn/wc'
|
27
|
+
require 'svn/repos'
|
28
|
+
require 'vimmatelib/nice_singleton'
|
29
|
+
require 'vimmatelib/requirer'
|
30
|
+
|
31
|
+
module VimMate
|
32
|
+
|
33
|
+
# Do not load Subversion if it's disabled
|
34
|
+
Requirer.raise_load_error_if do
|
35
|
+
not Config[:subversion_enabled]
|
36
|
+
end
|
37
|
+
|
38
|
+
# This class helps the integration of the Subversion version control system
|
39
|
+
class Subversion
|
40
|
+
include NiceSingleton
|
41
|
+
|
42
|
+
UNKNOWN = -1
|
43
|
+
NONE = 1
|
44
|
+
UNVERSIONED = 2
|
45
|
+
NORMAL = 3
|
46
|
+
ADDED = 4
|
47
|
+
MISSING = 5
|
48
|
+
DELETED = 6
|
49
|
+
REPLACED = 7
|
50
|
+
MODIFIED = 8
|
51
|
+
MERGED = 9
|
52
|
+
CONFLICTED = 10
|
53
|
+
IGNORED = 11
|
54
|
+
OBSTRUCTED = 12
|
55
|
+
EXTERNAL = 13
|
56
|
+
INCOMPLETE = 14
|
57
|
+
|
58
|
+
STATUS_TEXT = {
|
59
|
+
UNKNOWN => "",
|
60
|
+
NONE => "None",
|
61
|
+
UNVERSIONED => "Unversioned",
|
62
|
+
NORMAL => "Normal",
|
63
|
+
ADDED => "Added",
|
64
|
+
MISSING => "Missing",
|
65
|
+
DELETED => "Deleted",
|
66
|
+
REPLACED => "Replaced",
|
67
|
+
MODIFIED => "Modified",
|
68
|
+
MERGED => "Merged",
|
69
|
+
CONFLICTED => "Conflicted",
|
70
|
+
IGNORED => "Ignored",
|
71
|
+
OBSTRUCTED => "Obstructed",
|
72
|
+
EXTERNAL => "External",
|
73
|
+
INCOMPLETE => "Incomplete",
|
74
|
+
}.freeze
|
75
|
+
|
76
|
+
# Create the Subversion class. Cannot be called directly
|
77
|
+
def initialize
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get the status of the specified file. The file must be a full path.
|
81
|
+
def status(path)
|
82
|
+
ret_status = UNKNOWN
|
83
|
+
begin
|
84
|
+
# Arguments: File, Revision, Recursive, Any files, Update
|
85
|
+
new_client.status(path, "HEAD", true, true, false) do |path, status|
|
86
|
+
ret_status = status.text_status if status.text_status > ret_status
|
87
|
+
end
|
88
|
+
rescue Svn::Error::WC_NOT_DIRECTORY
|
89
|
+
rescue Svn::Error::WC_NOT_LOCKED
|
90
|
+
end
|
91
|
+
ret_status
|
92
|
+
end
|
93
|
+
|
94
|
+
# Get the text that represents the status of the file
|
95
|
+
def status_text(path)
|
96
|
+
STATUS_TEXT[status(path)]
|
97
|
+
end
|
98
|
+
|
99
|
+
# Add the specified file (full path) to Subversion
|
100
|
+
def add(path)
|
101
|
+
cleanup(path)
|
102
|
+
new_client.add(path)
|
103
|
+
rescue
|
104
|
+
false
|
105
|
+
else
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
# Remove the specified file (full path) from Subversion's control
|
110
|
+
def remove(path)
|
111
|
+
cleanup(path)
|
112
|
+
new_client.remove(path)
|
113
|
+
rescue
|
114
|
+
false
|
115
|
+
else
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
# Revert the specified file (full path) to what it was before the local
|
120
|
+
# modifications
|
121
|
+
def revert(path)
|
122
|
+
cleanup(path)
|
123
|
+
new_client.revert(path)
|
124
|
+
rescue
|
125
|
+
false
|
126
|
+
else
|
127
|
+
true
|
128
|
+
end
|
129
|
+
|
130
|
+
# Move the specified file (full path) to a new file name
|
131
|
+
def move(path, new_path)
|
132
|
+
cleanup(path)
|
133
|
+
new_client.move(path, new_path)
|
134
|
+
rescue
|
135
|
+
false
|
136
|
+
else
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
# Cleanup the subversion path when something is locked
|
141
|
+
def cleanup(path)
|
142
|
+
new_client.cleanup(File.directory?(path) ? path : File.dirname(path))
|
143
|
+
rescue
|
144
|
+
false
|
145
|
+
else
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
# Create a new subversion client
|
152
|
+
def new_client
|
153
|
+
Svn::Client::Context.new
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,68 @@
|
|
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
|
+
module VimMate
|
25
|
+
|
26
|
+
# This module contains methods to help when requiring files that
|
27
|
+
# could not be installed on the user computer.
|
28
|
+
module Requirer
|
29
|
+
|
30
|
+
# Runs the provided block if the file can be required. If it can't,
|
31
|
+
# return the value of to_return_on_error
|
32
|
+
def self.require_if(file, to_return_on_error = false)
|
33
|
+
begin
|
34
|
+
require file
|
35
|
+
rescue LoadError
|
36
|
+
to_return_on_error
|
37
|
+
else
|
38
|
+
yield
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Runs the provided block if the file cannot be required. If it can,
|
43
|
+
# return the value of to_return_on_success
|
44
|
+
def self.require_not_if(file, to_return_on_success = false)
|
45
|
+
begin
|
46
|
+
require file
|
47
|
+
rescue LoadError
|
48
|
+
yield
|
49
|
+
else
|
50
|
+
to_return_on_success
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Exit the program with a nice message if the specified file cannot
|
55
|
+
# be required
|
56
|
+
def self.require_exit(file)
|
57
|
+
require file
|
58
|
+
rescue LoadError
|
59
|
+
puts "Module #{file} is required to run this program"
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
# Raise a LoadError if the provided block returns true
|
64
|
+
def self.raise_load_error_if
|
65
|
+
raise LoadError, "Requirer cannot continue" if yield
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,227 @@
|
|
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 'set'
|
26
|
+
|
27
|
+
module VimMate
|
28
|
+
|
29
|
+
# A window that can be used to search for files
|
30
|
+
class SearchWindow
|
31
|
+
|
32
|
+
# Column for the file name
|
33
|
+
NAME = 0
|
34
|
+
# Column for the full path of the file
|
35
|
+
PATH = 1
|
36
|
+
|
37
|
+
# Create the SearchWindow
|
38
|
+
def initialize(file_tree)
|
39
|
+
@open_signal = Set.new
|
40
|
+
@menu_signal = Set.new
|
41
|
+
@file_tree = file_tree
|
42
|
+
@filter = /.*/
|
43
|
+
|
44
|
+
# File name, Path
|
45
|
+
@gtk_list_model = Gtk::ListStore.new(String, String)
|
46
|
+
@gtk_list_model.set_sort_column_id(PATH)
|
47
|
+
@gtk_filtered_list_model = Gtk::TreeModelFilter.new(@gtk_list_model)
|
48
|
+
@gtk_filtered_list_model.set_visible_func do |model, iter|
|
49
|
+
if iter[NAME] =~ @filter
|
50
|
+
true
|
51
|
+
else
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@gtk_list_view = Gtk::TreeView.new(@gtk_filtered_list_model)
|
57
|
+
@gtk_list_view.selection.mode = Gtk::SELECTION_SINGLE
|
58
|
+
@gtk_list_view.headers_visible = false
|
59
|
+
|
60
|
+
# Double-click, Enter, Space: Signal to open the file
|
61
|
+
@gtk_list_view.signal_connect("row-activated") do |view, path, column|
|
62
|
+
path = @gtk_filtered_list_model.get_iter(path)[PATH]
|
63
|
+
@open_signal.each do |signal|
|
64
|
+
signal.call(path,
|
65
|
+
Config[:files_default_open_in_tabs] ? :tab_open : :open)
|
66
|
+
end
|
67
|
+
@gtk_entry.text = ""
|
68
|
+
end
|
69
|
+
|
70
|
+
# Left-click: Select and Signal to open the menu
|
71
|
+
@gtk_list_view.signal_connect("button_press_event") do |widget, event|
|
72
|
+
if event.kind_of? Gdk::EventButton and event.button == 3
|
73
|
+
path = @gtk_list_view.get_path_at_pos(event.x, event.y)
|
74
|
+
@gtk_list_view.selection.select_path(path[NAME]) if path
|
75
|
+
|
76
|
+
selected = @gtk_list_view.selection.selected
|
77
|
+
if selected
|
78
|
+
@menu_signal.each do |signal|
|
79
|
+
signal.call(selected[PATH])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Same thing as Left-click, but with the keyboard
|
86
|
+
@gtk_list_view.signal_connect("popup_menu") do
|
87
|
+
selected = @gtk_list_view.selection.selected
|
88
|
+
if selected
|
89
|
+
@menu_signal.each do |signal|
|
90
|
+
signal.call(selected[PATH])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Add the columns
|
96
|
+
column = Gtk::TreeViewColumn.new
|
97
|
+
column.title = "Files"
|
98
|
+
|
99
|
+
# File name
|
100
|
+
text_cell_renderer = Gtk::CellRendererText.new
|
101
|
+
if Config[:files_use_ellipsis]
|
102
|
+
text_cell_renderer.ellipsize = Pango::Layout::EllipsizeMode::MIDDLE
|
103
|
+
end
|
104
|
+
column.pack_start(text_cell_renderer, true)
|
105
|
+
column.set_attributes(text_cell_renderer, :text => NAME)
|
106
|
+
|
107
|
+
@gtk_list_view.append_column(column)
|
108
|
+
|
109
|
+
# Put the tree view in a scroll window
|
110
|
+
@gtk_scrolled_window = Gtk::ScrolledWindow.new
|
111
|
+
@gtk_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC,
|
112
|
+
Gtk::POLICY_AUTOMATIC)
|
113
|
+
@gtk_scrolled_window.add(@gtk_list_view)
|
114
|
+
|
115
|
+
# Create a label to show the path of the file
|
116
|
+
gtk_label = Gtk::Label.new
|
117
|
+
gtk_label.ellipsize = Pango::Layout::EllipsizeMode::START
|
118
|
+
|
119
|
+
# When a selection is changed in the list view, we change the label
|
120
|
+
# to show the path of the file and which characters matches in the
|
121
|
+
# file name
|
122
|
+
@gtk_list_view.selection.signal_connect("changed") do
|
123
|
+
gtk_label.markup = ""
|
124
|
+
# Nothing to do if there are no selections or if the entry
|
125
|
+
# is empty
|
126
|
+
next if (selected_row = @gtk_list_view.selection.selected).nil?
|
127
|
+
next if @gtk_entry.text.empty?
|
128
|
+
# Build a regexp to add markup information on the file name
|
129
|
+
match = []
|
130
|
+
Regexp.escape(@gtk_entry.text).gsub(/\\.|./) {|c| match << c}
|
131
|
+
match_regexp = Regexp.new(match.join("|"), Config[:files_search_ignore_case])
|
132
|
+
file_name_markup = selected_row[NAME].gsub(match_regexp) do |c|
|
133
|
+
"<b><i>#{c}</i></b>"
|
134
|
+
end
|
135
|
+
# Join the path and the file name with the markup
|
136
|
+
gtk_label.markup = File.join(File.dirname(selected_row[PATH]), file_name_markup)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Build a box to contain the entry for the filter
|
140
|
+
gtk_filter_box = Gtk::HBox.new
|
141
|
+
gtk_filter_box.spacing = 10
|
142
|
+
gtk_filter_box.border_width = 10
|
143
|
+
gtk_filter_box.add(@gtk_entry = Gtk::Entry.new)
|
144
|
+
|
145
|
+
# When the filter changes, create a new regex to filter the file names
|
146
|
+
@gtk_entry.signal_connect("changed") do
|
147
|
+
@filter = Regexp.new(".*" + Regexp.escape(@gtk_entry.text).gsub(/\\.|./) {|c| "#{c}.*"},
|
148
|
+
Config[:files_search_ignore_case])
|
149
|
+
# Unselect everything, filter and reselect the first row
|
150
|
+
@gtk_list_view.selection.unselect_all
|
151
|
+
@gtk_filtered_list_model.refilter
|
152
|
+
if first_row = @gtk_filtered_list_model.iter_first
|
153
|
+
@gtk_list_view.selection.select_iter(first_row)
|
154
|
+
end
|
155
|
+
# Scroll at the top
|
156
|
+
@gtk_scrolled_window.vscrollbar.value = @gtk_scrolled_window.vscrollbar.adjustment.lower
|
157
|
+
end
|
158
|
+
|
159
|
+
# When we press Enter in the entry, open the first file of the list
|
160
|
+
@gtk_entry.signal_connect("activate") do
|
161
|
+
next if (first_row = @gtk_filtered_list_model.iter_first).nil?
|
162
|
+
@open_signal.each do |signal|
|
163
|
+
signal.call(first_row[PATH],
|
164
|
+
Config[:files_default_open_in_tabs] ? :tab_open : :open)
|
165
|
+
end
|
166
|
+
@gtk_entry.text = ""
|
167
|
+
end
|
168
|
+
|
169
|
+
# Add the components in a box
|
170
|
+
@gtk_container_box = Gtk::VBox.new
|
171
|
+
@gtk_container_box.pack_start(gtk_filter_box, false, false)
|
172
|
+
@gtk_container_box.pack_start(@gtk_scrolled_window, true, true)
|
173
|
+
@gtk_container_box.pack_start(gtk_label, false, false)
|
174
|
+
|
175
|
+
|
176
|
+
# TODO put this into file_tree_controller
|
177
|
+
# Process file tree event
|
178
|
+
#@file_tree.add_refresh_signal do |method, file|
|
179
|
+
# next if file.instance_of? ListedDirectory
|
180
|
+
# case method
|
181
|
+
# when :add
|
182
|
+
# # Add the new file
|
183
|
+
# new_row = @gtk_list_model.append
|
184
|
+
# new_row[NAME] = file.name
|
185
|
+
# new_row[PATH] = file.path
|
186
|
+
# when :remove
|
187
|
+
# # A file is removed. Find it and remove it
|
188
|
+
# to_remove = []
|
189
|
+
# @gtk_list_model.each do |model,path,iter|
|
190
|
+
# if iter[PATH] == file.path
|
191
|
+
# to_remove << Gtk::TreeRowReference.new(model, path)
|
192
|
+
# break
|
193
|
+
# end
|
194
|
+
# end
|
195
|
+
# to_remove.each do |element|
|
196
|
+
# @gtk_list_model.remove(@gtk_list_model.get_iter(element.path))
|
197
|
+
# end
|
198
|
+
# end
|
199
|
+
#end
|
200
|
+
end
|
201
|
+
|
202
|
+
# The "window" for this object
|
203
|
+
def gtk_window
|
204
|
+
@gtk_container_box
|
205
|
+
end
|
206
|
+
|
207
|
+
# Set the focus to the entry field in the file search list
|
208
|
+
def focus_file_search
|
209
|
+
@gtk_entry.has_focus = true if @gtk_entry
|
210
|
+
end
|
211
|
+
|
212
|
+
# Add a block that will be called when the user choose to open a file
|
213
|
+
# The block take two argument: the path to the file to open, and a
|
214
|
+
# symbol to indicate the kind: :open, :split_open, :tab_open
|
215
|
+
def add_open_signal(&block)
|
216
|
+
@open_signal << block
|
217
|
+
end
|
218
|
+
|
219
|
+
# Add a block that will be called when the user choose to open the
|
220
|
+
# menu. The block takes one argument: the path to the file to open.
|
221
|
+
def add_menu_signal(&block)
|
222
|
+
@menu_signal << block
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|