rkumar-rbcurse 0.1.0
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.
- data/CHANGELOG +1577 -0
- data/README.txt +310 -0
- data/examples/qdfilechooser.rb +68 -0
- data/examples/rfe.rb +853 -0
- data/examples/rfe_renderer.rb +69 -0
- data/examples/test1.rb +242 -0
- data/examples/test2.rb +498 -0
- data/examples/testcombo.rb +95 -0
- data/examples/testkeypress.rb +61 -0
- data/examples/testmenu.rb +105 -0
- data/examples/testtable.rb +266 -0
- data/examples/testtabp.rb +106 -0
- data/examples/testtodo.rb +532 -0
- data/examples/viewtodo.rb +512 -0
- data/lib/rbcurse.rb +7 -0
- data/lib/rbcurse/action.rb +31 -0
- data/lib/rbcurse/applicationheader.rb +57 -0
- data/lib/rbcurse/celleditor.rb +120 -0
- data/lib/rbcurse/checkboxcellrenderer.rb +69 -0
- data/lib/rbcurse/colormap.rb +133 -0
- data/lib/rbcurse/comboboxcellrenderer.rb +45 -0
- data/lib/rbcurse/defaultlistselectionmodel.rb +49 -0
- data/lib/rbcurse/keylabelprinter.rb +143 -0
- data/lib/rbcurse/listcellrenderer.rb +99 -0
- data/lib/rbcurse/listkeys.rb +33 -0
- data/lib/rbcurse/listscrollable.rb +216 -0
- data/lib/rbcurse/listselectable.rb +67 -0
- data/lib/rbcurse/mapper.rb +108 -0
- data/lib/rbcurse/orderedhash.rb +77 -0
- data/lib/rbcurse/rcombo.rb +243 -0
- data/lib/rbcurse/rdialogs.rb +183 -0
- data/lib/rbcurse/rform.rb +845 -0
- data/lib/rbcurse/rinputdataevent.rb +36 -0
- data/lib/rbcurse/rlistbox.rb +804 -0
- data/lib/rbcurse/rmenu.rb +666 -0
- data/lib/rbcurse/rmessagebox.rb +325 -0
- data/lib/rbcurse/rpopupmenu.rb +754 -0
- data/lib/rbcurse/rtabbedpane.rb +259 -0
- data/lib/rbcurse/rtable.rb +1296 -0
- data/lib/rbcurse/rtextarea.rb +673 -0
- data/lib/rbcurse/rtextview.rb +335 -0
- data/lib/rbcurse/rwidget.rb +1731 -0
- data/lib/rbcurse/scrollable.rb +301 -0
- data/lib/rbcurse/selectable.rb +94 -0
- data/lib/rbcurse/table/tablecellrenderer.rb +85 -0
- data/lib/rbcurse/table/tabledatecellrenderer.rb +102 -0
- data/lib/ver/keyboard.rb +150 -0
- data/lib/ver/keyboard2.rb +170 -0
- data/lib/ver/ncurses.rb +102 -0
- data/lib/ver/window.rb +369 -0
- data/test/test_rbcurse.rb +0 -0
- metadata +117 -0
data/README.txt
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
= rbcurse
|
2
|
+
|
3
|
+
* http://totalrecall.wordpress.com << CORRECTED !!!
|
4
|
+
|
5
|
+
* rbcurse on rubyforge: http://rbcurse.rubyforge.org/
|
6
|
+
|
7
|
+
* See latest changes on http://github.com/rkumar/rbcurse/tree/master/CHANGELOG
|
8
|
+
|
9
|
+
* Many working demos in examples folder, such as:
|
10
|
+
|
11
|
+
* test2.rb (exit with F1, Or Cancel button/Alt-C) contains various
|
12
|
+
widgets. F2 for menubar toggling
|
13
|
+
|
14
|
+
* rfe.rb is a ruby file explorer
|
15
|
+
|
16
|
+
* testtodo.rb is a test TODO application
|
17
|
+
|
18
|
+
* Screenshots on http://github.com/rkumar/rbcurse/wikis/screenshots
|
19
|
+
(OLD)
|
20
|
+
and http://www.benegal.org/files/screen/?M=D (new)
|
21
|
+
and on blog, http://totalrecall.wordpress.com
|
22
|
+
|
23
|
+
|
24
|
+
== DESCRIPTION:
|
25
|
+
|
26
|
+
A small but comprehensive widget library written in ruby for creating ncurses
|
27
|
+
applications.
|
28
|
+
|
29
|
+
== FEATURES
|
30
|
+
|
31
|
+
* entry fields in ruby
|
32
|
+
* scrollable list box (new, editable with Field, checkbox and combos)
|
33
|
+
* multi-line editable area
|
34
|
+
* togglebutton, radio and check buttons (with mnemonics)
|
35
|
+
* message box
|
36
|
+
* menubar - with submenu and CheckBoxMenuItem
|
37
|
+
* popup list
|
38
|
+
* tabbedpane (multiple forms using tabbed metaphor)
|
39
|
+
* combobox
|
40
|
+
* labels with mnemonics (hotkeys)
|
41
|
+
* multi-column table - with cell selection and editing
|
42
|
+
|
43
|
+
Above may be created using DSL like syntax, or hashes.
|
44
|
+
|
45
|
+
== Sample programs:
|
46
|
+
|
47
|
+
* rfe : file explorer or Finder like app
|
48
|
+
* testtodo.rb : a todo app based on a yaml file
|
49
|
+
* test2.rb most widgets (including menus)
|
50
|
+
* test1.rb various kinds of messageboxes (input, list, custom)
|
51
|
+
* testtabp.rb tabbed pane
|
52
|
+
* testcombo.rb combos with various insert policies and vertical
|
53
|
+
alignments
|
54
|
+
|
55
|
+
== PROBLEMS, ISSUES
|
56
|
+
TextArea not bug free. Some situations wrapping errors could exist.
|
57
|
+
|
58
|
+
== Terminal related issues.
|
59
|
+
|
60
|
+
* Some terminals may not show underlines (e.g screen).
|
61
|
+
|
62
|
+
* Some terminals (xterm-color) do not process Function keys, avoid declaring F1 etc if
|
63
|
+
unsure of client terminals. I have put in fixes for xterm-color F1 and
|
64
|
+
backtab.
|
65
|
+
|
66
|
+
* To use ALT/META keys on a Mac OS X, in Terminal preferences, under
|
67
|
+
Keyboard, select
|
68
|
+
"use Option as Meta key". All hotkeys are automatically, ALT combinations.
|
69
|
+
|
70
|
+
* Some screens do not display window background color under spaces.
|
71
|
+
This is okay under "screen" and "xterm-color" but not under "xterm". You will notice
|
72
|
+
this in the message box samples.
|
73
|
+
|
74
|
+
I am developing and testing under "screen" under OS X Leopard.
|
75
|
+
|
76
|
+
== SYNOPSIS:
|
77
|
+
|
78
|
+
See lib/rbcurse/rwidgets.rb.
|
79
|
+
For test programs, see test1, test2, testcombo etc in examples folder.
|
80
|
+
|
81
|
+
This depends only on "window" provided by ncurses. Does not use forms
|
82
|
+
and fields. Minor changes and improvements may have happened to sample
|
83
|
+
code below. See test programs for latest, working code.
|
84
|
+
|
85
|
+
=== create a window and a form based on window
|
86
|
+
|
87
|
+
@layout = { :height => 0, :width => 0, :top => 0, :left => 0 }
|
88
|
+
@win = VER::Window.new(@layout)
|
89
|
+
|
90
|
+
@form = Form.new @win
|
91
|
+
|
92
|
+
|
93
|
+
=== create a bunch of fields with dependent labels
|
94
|
+
|
95
|
+
r = 1; c = 22;
|
96
|
+
%w[ name age company].each do |w|
|
97
|
+
field = Field.new @form do
|
98
|
+
name w
|
99
|
+
row r
|
100
|
+
col c
|
101
|
+
display_length 30
|
102
|
+
set_buffer "abcd #{w}"
|
103
|
+
set_label Label.new @form, {'text' => w}
|
104
|
+
end
|
105
|
+
r += 1
|
106
|
+
end
|
107
|
+
|
108
|
+
=== create a variable (like TkVariable) and tie a label to it.
|
109
|
+
|
110
|
+
$results = Variable.new
|
111
|
+
$results.value = "A variable"
|
112
|
+
var = RubyCurses::Label.new @form, {'text_variable' => $results, "row" => r, "col" => 22}
|
113
|
+
r += 1
|
114
|
+
|
115
|
+
=== create a list and a list box based on the list.
|
116
|
+
|
117
|
+
mylist = []
|
118
|
+
0.upto(100) { |v| mylist << "#{v} scrollable data" }
|
119
|
+
|
120
|
+
field = Listbox.new @form do
|
121
|
+
name "mylist"
|
122
|
+
row r
|
123
|
+
col 1
|
124
|
+
width 40
|
125
|
+
height 10
|
126
|
+
list mylist
|
127
|
+
end
|
128
|
+
field.insert 5, "hello ruby", "so long python", "farewell java", "RIP .Net"
|
129
|
+
|
130
|
+
=== create a textarea for entry (this can be buggy at present)
|
131
|
+
|
132
|
+
texta = TextArea.new @form do
|
133
|
+
name "mytext"
|
134
|
+
row 1
|
135
|
+
col 52
|
136
|
+
width 40
|
137
|
+
height 20
|
138
|
+
end
|
139
|
+
texta << "hello there" << "we are testing deletes in this application"
|
140
|
+
texta << "HELLO there" << "WE ARE testing deletes in this application"
|
141
|
+
|
142
|
+
=== create a check box, updates a Variable
|
143
|
+
|
144
|
+
checkbutton = CheckBox.new @form do
|
145
|
+
text_variable $results
|
146
|
+
#value = true
|
147
|
+
onvalue "selected cb"
|
148
|
+
offvalue "UNselected cb"
|
149
|
+
text "Please click me"
|
150
|
+
row 17
|
151
|
+
col 22
|
152
|
+
end
|
153
|
+
|
154
|
+
=== change field properties at any time by referring to them by name
|
155
|
+
|
156
|
+
@form.by_name["age"].display_length = 3
|
157
|
+
@form.by_name["age"].maxlen = 3
|
158
|
+
@form.by_name["age"].set_buffer "24"
|
159
|
+
@form.by_name["name"].set_buffer "Not focusable"
|
160
|
+
@form.by_name["age"].chars_allowed = /\d/
|
161
|
+
@form.by_name["company"].type(:ALPHA)
|
162
|
+
@form.by_name["name"].set_focusable(false)
|
163
|
+
|
164
|
+
@form.by_name["password"].color 'red'
|
165
|
+
@form.by_name["password"].bgcolor 'blue'
|
166
|
+
|
167
|
+
# restrict entry to some values
|
168
|
+
password.values(%w[ scotty tiger secret qwerty])
|
169
|
+
|
170
|
+
# validation using ruby's regular expressions
|
171
|
+
|
172
|
+
field.valid_regex(/^[A-Z]\d+/)
|
173
|
+
|
174
|
+
=== bind events to forms, and fields
|
175
|
+
|
176
|
+
@form.bind(:ENTER) { |f| f.label.bgcolor = $promptcolor if f.instance_of? RubyCurses::Field}
|
177
|
+
@form.bind(:LEAVE) { |f| f.label.bgcolor = $datacolor if f.instance_of? RubyCurses::Field}
|
178
|
+
|
179
|
+
=== create buttons
|
180
|
+
|
181
|
+
ok_button = Button.new @form do
|
182
|
+
text "OK"
|
183
|
+
name "OK"
|
184
|
+
row 18
|
185
|
+
col 22
|
186
|
+
end
|
187
|
+
ok_button.command { |form| $results.value = "OK PRESS:";form.printstr(@window, 23,45, "OK CALLED") }
|
188
|
+
#text "Cancel"
|
189
|
+
cancel_button = Button.new @form do
|
190
|
+
text_variable $results
|
191
|
+
row 18
|
192
|
+
col 28
|
193
|
+
end
|
194
|
+
cancel_button.command { |form| form.printstr(@window, 23,45, "Cancel CALLED"); throw(:close); }
|
195
|
+
|
196
|
+
=== create radio buttons
|
197
|
+
|
198
|
+
colorlabel = Label.new @form, {'text' => "Select a color:", "row" => 20,
|
199
|
+
"col" => 22, "color"=> "cyan"}
|
200
|
+
$radio = Variable.new
|
201
|
+
radio1 = RadioButton.new @form do
|
202
|
+
text_variable $radio
|
203
|
+
text "red"
|
204
|
+
value "red"
|
205
|
+
color "red"
|
206
|
+
row 21
|
207
|
+
col 22
|
208
|
+
end
|
209
|
+
radio2 = RadioButton.new @form do
|
210
|
+
text_variable $radio
|
211
|
+
text "green"
|
212
|
+
value "green"
|
213
|
+
color "green"
|
214
|
+
row 22
|
215
|
+
col 22
|
216
|
+
end
|
217
|
+
|
218
|
+
=== create a messagebox
|
219
|
+
|
220
|
+
@mb = RubyCurses::MessageBox.new do
|
221
|
+
title "Enter your name"
|
222
|
+
message "Enter your name"
|
223
|
+
type :input
|
224
|
+
default_value "rahul"
|
225
|
+
default_button 0
|
226
|
+
end
|
227
|
+
#title "Color selector"
|
228
|
+
#type :custom
|
229
|
+
#buttons %w[red green blue yellow]
|
230
|
+
#underlines [0,0,0,0]
|
231
|
+
|
232
|
+
$log.debug "MBOX : #{@mb.selected_index} "
|
233
|
+
$log.debug "MBOX : #{@mb.input_value} "
|
234
|
+
|
235
|
+
=== create a read-only scrollable view of data
|
236
|
+
|
237
|
+
@textview = TextView.new @form do
|
238
|
+
name "myView"
|
239
|
+
row 16
|
240
|
+
col 52
|
241
|
+
width 40
|
242
|
+
height 7
|
243
|
+
end
|
244
|
+
content = File.open("../../README.txt","r").readlines
|
245
|
+
@textview.set_content content
|
246
|
+
|
247
|
+
## set it to point to row 21
|
248
|
+
@textview.top_row 21
|
249
|
+
|
250
|
+
|
251
|
+
# lets scroll the text view as we scroll the listbox
|
252
|
+
|
253
|
+
listb.bind(:ENTER_ROW, @textview) { |arow, tview| tview.top_row arow }
|
254
|
+
|
255
|
+
# lets scroll the text view to the line you enter in the numeric
|
256
|
+
# field
|
257
|
+
@form.by_name["line"].bind(:LEAVE, @textview) { |fld, tv| tv.top_row(fld.getvalue.to_i) }
|
258
|
+
|
259
|
+
# lets scroll the text view to the first match of the regex you
|
260
|
+
# enter
|
261
|
+
@form.by_name["regex"].bind(:LEAVE, @textview) { |fld, tv| tv.top_row(tv.find_first_match(fld.getvalue)) }
|
262
|
+
|
263
|
+
# change the value of colorlabel to the selected radiobutton
|
264
|
+
# (red or green)
|
265
|
+
|
266
|
+
$radio.update_command(colorlabel) {|tv, label| label.color tv.value}
|
267
|
+
|
268
|
+
# change the attribute of colorlabel to bold or normal
|
269
|
+
|
270
|
+
$results.update_command(colorlabel,checkbutton) {|tv, label, cb|
|
271
|
+
attrs = cb.value ? 'bold' : nil; label.attrs(attrs)}
|
272
|
+
|
273
|
+
# during menu creation, create a checkboxmenuitem
|
274
|
+
|
275
|
+
item = RubyCurses::CheckBoxMenuItem.new "CheckMe"
|
276
|
+
|
277
|
+
# when selected, make colorlabel attribute reverse.
|
278
|
+
|
279
|
+
item.command(colorlabel){|it, label| att = it.getvalue ? 'reverse' :
|
280
|
+
nil; label.attrs(att); label.repaint}
|
281
|
+
|
282
|
+
== REQUIREMENTS:
|
283
|
+
|
284
|
+
* ruby 1.8.7 (not compatible with 1.9)
|
285
|
+
|
286
|
+
* ncurses-ruby
|
287
|
+
|
288
|
+
(following is provided with source)
|
289
|
+
|
290
|
+
* uses the window class created by "manveru" (michael) - this can be
|
291
|
+
removed if not needed. (lib/ver/window)
|
292
|
+
It is provided with this package, and has some alterations from the
|
293
|
+
original. I have added a method getchar() which traps and returns
|
294
|
+
ALT/META, META+CTRL, META+SHIFT+CONTROL, ALT+Fn etc.
|
295
|
+
|
296
|
+
So basically do not remove it unless you have very different
|
297
|
+
requirements.
|
298
|
+
|
299
|
+
== INSTALL:
|
300
|
+
|
301
|
+
* currently, just unzip/untar in a folder. Please change the path in
|
302
|
+
the top line of the test programs.
|
303
|
+
|
304
|
+
(Please advice me how i can improve installation procedure)
|
305
|
+
|
306
|
+
== LICENSE:
|
307
|
+
|
308
|
+
Copyright (c) 2008 rkumar
|
309
|
+
|
310
|
+
Same as ruby license.
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# this is a test program, tests out messageboxes. type F1 to exit
|
2
|
+
# a quick dirty file chooser in 2 lines of code.
|
3
|
+
#$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
|
4
|
+
require 'rubygems'
|
5
|
+
require 'ncurses'
|
6
|
+
require 'logger'
|
7
|
+
require 'ver/ncurses'
|
8
|
+
require 'ver/window'
|
9
|
+
require 'rbcurse/rwidget'
|
10
|
+
|
11
|
+
##
|
12
|
+
# a quick dirty file chooser - only temporary till we make something better.
|
13
|
+
class QDFileChooser
|
14
|
+
attr_accessor :show_folders # bool
|
15
|
+
attr_accessor :traverse_folders # bool
|
16
|
+
attr_accessor :default_pattern # e.g. "*.*"
|
17
|
+
attr_accessor :dialog_title # File Chooser
|
18
|
+
def initialize
|
19
|
+
|
20
|
+
end
|
21
|
+
def show_open_dialog
|
22
|
+
@form = RubyCurses::Form.new nil
|
23
|
+
label = RubyCurses::Label.new @form, {'text' => 'File', 'row'=>3, 'col'=>4, 'color'=>'black', 'bgcolor'=>'white', 'mnemonic'=>'F'}
|
24
|
+
field = RubyCurses::Field.new @form do
|
25
|
+
name "file"
|
26
|
+
row 3
|
27
|
+
col 10
|
28
|
+
display_length 40
|
29
|
+
set_label label
|
30
|
+
end
|
31
|
+
default_pattern ||= "*.*"
|
32
|
+
flist = Dir.glob(default_pattern)
|
33
|
+
@listb = RubyCurses::Listbox.new @form do
|
34
|
+
name "mylist"
|
35
|
+
row 5
|
36
|
+
col 10
|
37
|
+
width 40
|
38
|
+
height 10
|
39
|
+
list flist
|
40
|
+
title "File list"
|
41
|
+
title_attrib 'bold'
|
42
|
+
end
|
43
|
+
#@listb.list.bind(:ENTER_ROW) { field.set_buffer @listb.selected_item }
|
44
|
+
listb = @listb
|
45
|
+
field.bind(:CHANGE) do |f|
|
46
|
+
flist = Dir.glob(f.getvalue+"*")
|
47
|
+
l = listb.list
|
48
|
+
l.remove_all
|
49
|
+
l.insert 0, *flist
|
50
|
+
end
|
51
|
+
atitle = @dialog_title || "Quick Dirty(TM) File Chooser"
|
52
|
+
@mb = RubyCurses::MessageBox.new @form do
|
53
|
+
title atitle
|
54
|
+
type :override
|
55
|
+
height 20
|
56
|
+
width 60
|
57
|
+
top 5
|
58
|
+
left 20
|
59
|
+
default_button 0
|
60
|
+
button_type :ok_cancel
|
61
|
+
end
|
62
|
+
return @mb.selected_index == 0 ? :OK : :CANCEL
|
63
|
+
$log.debug "MBOX :selected #{@listb.selected_item}"
|
64
|
+
end
|
65
|
+
def get_selected_file
|
66
|
+
return @mb.selected_index == 0 ? @listb.selected_item : nil
|
67
|
+
end
|
68
|
+
end
|
data/examples/rfe.rb
ADDED
@@ -0,0 +1,853 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ncurses'
|
3
|
+
require 'logger'
|
4
|
+
require 'rbcurse'
|
5
|
+
require 'rbcurse/rcombo'
|
6
|
+
require 'rbcurse/rlistbox'
|
7
|
+
require 'rfe_renderer'
|
8
|
+
#require 'lib/rbcurse/table/tablecellrenderer'
|
9
|
+
require 'rbcurse/keylabelprinter'
|
10
|
+
require 'rbcurse/applicationheader'
|
11
|
+
require 'rbcurse/action'
|
12
|
+
require 'fileutils'
|
13
|
+
#$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
|
14
|
+
|
15
|
+
# TODO
|
16
|
+
# operations on selected files: move, delete, zip
|
17
|
+
# This class represents the finder pane. There are 2
|
18
|
+
# on this sample app
|
19
|
+
class FileExplorer
|
20
|
+
include FileUtils
|
21
|
+
attr_reader :wdir
|
22
|
+
attr_reader :list # listbox
|
23
|
+
attr_reader :dir
|
24
|
+
attr_reader :prev_dirs
|
25
|
+
attr_reader :other_list # the opposite list
|
26
|
+
attr_reader :entries # avoid, can be outdated
|
27
|
+
attr_accessor :filter_pattern
|
28
|
+
|
29
|
+
def initialize form, rfe, row, col, height, width
|
30
|
+
@form = form
|
31
|
+
@rfe = rfe
|
32
|
+
@row, @col, @ht, @wid = row, col, height, width
|
33
|
+
@dir = Dir.new(Dir.getwd)
|
34
|
+
@wdir = @dir.path
|
35
|
+
@filter_pattern = '*'
|
36
|
+
@prev_dirs=[]
|
37
|
+
end
|
38
|
+
def title str
|
39
|
+
@list.title = str
|
40
|
+
end
|
41
|
+
def selected_color
|
42
|
+
@list.selected_color
|
43
|
+
end
|
44
|
+
def selected_bgcolor
|
45
|
+
@list.selected_bgcolor
|
46
|
+
end
|
47
|
+
|
48
|
+
# changes to given dir
|
49
|
+
# ensure that path is provided since other list
|
50
|
+
# may have cd'd elsewhere
|
51
|
+
def change_dir adir
|
52
|
+
list = @list
|
53
|
+
begin
|
54
|
+
#dir = File.expand_path dir
|
55
|
+
#cd "#{@dir.path}/#{adir}"
|
56
|
+
cd adir
|
57
|
+
list.title = pwd()
|
58
|
+
@dir = Dir.new(Dir.getwd)
|
59
|
+
@wdir = @dir.path
|
60
|
+
@prev_dirs << @wdir
|
61
|
+
rescan
|
62
|
+
rescue => err
|
63
|
+
@rfe.status_row.text = err.to_s
|
64
|
+
end
|
65
|
+
end
|
66
|
+
def goto_previous_dir
|
67
|
+
d = @prev_dirs.pop
|
68
|
+
if !d.nil? and d == @wdir
|
69
|
+
d = @prev_dirs.pop
|
70
|
+
end
|
71
|
+
change_dir d unless d.nil?
|
72
|
+
end
|
73
|
+
def filter list
|
74
|
+
list.delete_if { |f|
|
75
|
+
!File.directory? @wdir +"/"+ f and !File.fnmatch?(@filter_pattern, f)
|
76
|
+
}
|
77
|
+
#$log.debug " FILTER CALLED AFTER #{list.size}, #{list.entries}"
|
78
|
+
end
|
79
|
+
def rescan
|
80
|
+
flist = @dir.entries
|
81
|
+
flist.shift
|
82
|
+
#populate @entries
|
83
|
+
populate flist
|
84
|
+
end
|
85
|
+
def populate flist
|
86
|
+
#fl << format_string("..", nil)
|
87
|
+
#fl = []
|
88
|
+
#flist.each {|f| ff = "#{@wdir}/#{f}"; stat = File.stat(ff)
|
89
|
+
# fl << format_string(f, stat)
|
90
|
+
#}
|
91
|
+
filter(flist) if @filter_pattern != '*'
|
92
|
+
@entries = flist
|
93
|
+
list.list_data_model.remove_all
|
94
|
+
#list.list_data_model.insert 0, *fl
|
95
|
+
list.list_data_model.insert 0, *flist
|
96
|
+
end
|
97
|
+
def sort key, reverse=false
|
98
|
+
# remove parent before sorting, keep at top
|
99
|
+
first = @entries.delete_at(0) if @entries[0]==".."
|
100
|
+
key ||= @sort_key
|
101
|
+
cdir=cur_dir()+"/"
|
102
|
+
case key
|
103
|
+
when :size
|
104
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
105
|
+
if reverse
|
106
|
+
xs.size <=> ys.size
|
107
|
+
else
|
108
|
+
ys.size <=> xs.size
|
109
|
+
end
|
110
|
+
}
|
111
|
+
when :mtime
|
112
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
113
|
+
if reverse
|
114
|
+
xs.mtime <=> ys.mtime
|
115
|
+
else
|
116
|
+
ys.mtime <=> xs.mtime
|
117
|
+
end
|
118
|
+
}
|
119
|
+
when :atime
|
120
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
121
|
+
if reverse
|
122
|
+
xs.atime <=> ys.atime
|
123
|
+
else
|
124
|
+
ys.atime <=> xs.atime
|
125
|
+
end
|
126
|
+
}
|
127
|
+
when :name
|
128
|
+
@entries.sort! {|x,y| x <=> y
|
129
|
+
if reverse
|
130
|
+
x <=> y
|
131
|
+
else
|
132
|
+
y <=> x
|
133
|
+
end
|
134
|
+
}
|
135
|
+
when :ext
|
136
|
+
@entries.sort! {|x,y|
|
137
|
+
if reverse
|
138
|
+
File.extname(cdir+x) <=> File.extname(cdir+y)
|
139
|
+
else
|
140
|
+
File.extname(cdir+y) <=> File.extname(cdir+x)
|
141
|
+
end
|
142
|
+
}
|
143
|
+
end
|
144
|
+
@sort_key = key
|
145
|
+
@entries.insert 0, first unless first.nil? # keep parent on top
|
146
|
+
populate @entries
|
147
|
+
end
|
148
|
+
GIGA_SIZE = 1073741824.0
|
149
|
+
MEGA_SIZE = 1048576.0
|
150
|
+
KILO_SIZE = 1024.0
|
151
|
+
|
152
|
+
# Return the file size with a readable style.
|
153
|
+
def readable_file_size(size, precision)
|
154
|
+
case
|
155
|
+
#when size == 1 : "1 B"
|
156
|
+
when size < KILO_SIZE : "%d B" % size
|
157
|
+
when size < MEGA_SIZE : "%.#{precision}f K" % (size / KILO_SIZE)
|
158
|
+
when size < GIGA_SIZE : "%.#{precision}f M" % (size / MEGA_SIZE)
|
159
|
+
else "%.#{precision}f G" % (size / GIGA_SIZE)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
def date_format t
|
163
|
+
t.strftime "%Y/%m/%d"
|
164
|
+
end
|
165
|
+
def oldformat_string fn, stat
|
166
|
+
max_len = 30
|
167
|
+
f = fn.dup
|
168
|
+
if File.directory? f
|
169
|
+
#"%-*s\t(dir)" % [max_len,f]
|
170
|
+
#f = "/"+f # disallows search on keypress
|
171
|
+
f = f + "/ "
|
172
|
+
end
|
173
|
+
if f.size > max_len
|
174
|
+
f = f[0..max_len-1]
|
175
|
+
end
|
176
|
+
"%-*s\t%10s\t%s" % [max_len,f, readable_file_size(stat.size,1), date_format(stat.mtime)]
|
177
|
+
end
|
178
|
+
def cur_dir
|
179
|
+
@dir.path
|
180
|
+
end
|
181
|
+
alias :current_dir :cur_dir
|
182
|
+
def draw_screen dir=nil
|
183
|
+
cd dir unless dir.nil?
|
184
|
+
wdir = FileUtils.pwd
|
185
|
+
@prev_dirs << wdir
|
186
|
+
@dir = Dir.new(Dir.getwd)
|
187
|
+
@wdir = @dir.path
|
188
|
+
r = @row
|
189
|
+
c = @col
|
190
|
+
#cola = 1
|
191
|
+
#colb = Ncurses.COLS/2
|
192
|
+
ht = @ht
|
193
|
+
wid = @wid
|
194
|
+
#fl = Dir.glob(default_pattern)
|
195
|
+
#flist << format_string("..", nil)
|
196
|
+
fl = @dir.entries
|
197
|
+
fl.shift
|
198
|
+
filter(fl)
|
199
|
+
#flist = []
|
200
|
+
#fl.each {|f| stat = File.stat(f)
|
201
|
+
# flist << format_string(f, stat)
|
202
|
+
#}
|
203
|
+
@entries = fl
|
204
|
+
title = pwd()
|
205
|
+
@wdir = title
|
206
|
+
rfe = self
|
207
|
+
|
208
|
+
lista = Listbox.new @form do
|
209
|
+
name "lista"
|
210
|
+
row r
|
211
|
+
col c
|
212
|
+
width wid
|
213
|
+
height ht
|
214
|
+
#list flist
|
215
|
+
list fl
|
216
|
+
title wdir
|
217
|
+
#title_attrib 'reverse'
|
218
|
+
cell_renderer RfeRenderer.new "", {"color"=>@color, "bgcolor"=>@bgcolor, "parent" => rfe, "display_length"=> wid-2}
|
219
|
+
end
|
220
|
+
@list = lista
|
221
|
+
lista.bind(:ENTER) {|l| @rfe.current_list(self); l.title_attrib 'reverse'; }
|
222
|
+
lista.bind(:LEAVE) {|l| l.title_attrib 'normal'; }
|
223
|
+
|
224
|
+
|
225
|
+
#row_cmd = lambda {|list| file = list.list_data_model[list.current_index].split(/\t/)[0].strip; @rfe.status_row.text = File.stat("#{cur_dir()}/#{file}").inspect }
|
226
|
+
row_cmd = lambda {|lb, list| file = list.entries[lb.current_index]; @rfe.status_row.text = file; # File.stat("#{cur_dir()}/#{file}").inspect
|
227
|
+
}
|
228
|
+
lista.bind(:ENTER_ROW, self) {|lb,list| row_cmd.call(lb,list) }
|
229
|
+
|
230
|
+
end
|
231
|
+
def list_data
|
232
|
+
@list.list_data_model
|
233
|
+
end
|
234
|
+
def current_index
|
235
|
+
@list.current_index
|
236
|
+
end
|
237
|
+
def filename
|
238
|
+
#@entries[@list.current_index]
|
239
|
+
list_data()[current_index()]
|
240
|
+
end
|
241
|
+
def filepath
|
242
|
+
f = filename()
|
243
|
+
if f[0,1]=='/'
|
244
|
+
f
|
245
|
+
else
|
246
|
+
cur_dir() + "/" + filename()
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
class RFe
|
252
|
+
attr_reader :status_row
|
253
|
+
def initialize
|
254
|
+
@window = VER::Window.root_window
|
255
|
+
@form = Form.new @window
|
256
|
+
status_row = RubyCurses::Label.new @form, {'text' => "", :row => Ncurses.LINES-4, :col => 0, :display_length=>Ncurses.COLS-2}
|
257
|
+
@status_row = status_row
|
258
|
+
colb = Ncurses.COLS/2
|
259
|
+
ht = Ncurses.LINES - 7
|
260
|
+
wid = Ncurses.COLS/2 - 0
|
261
|
+
@lista = FileExplorer.new @form, self, row=2, col=1, ht, wid
|
262
|
+
@listb = FileExplorer.new @form, self, row=2, col=colb, ht, wid
|
263
|
+
|
264
|
+
init_vars
|
265
|
+
end
|
266
|
+
def init_vars
|
267
|
+
@bookmarks=[]
|
268
|
+
@config_name = File.expand_path("~/.rfe.yml")
|
269
|
+
if File.exist? @config_name
|
270
|
+
@config = YAML::load( File.open(@config_name));
|
271
|
+
if !@config.nil?
|
272
|
+
@bookmarks = @config["bookmarks"]||[]
|
273
|
+
@last_dirs = @config["last_dirs"]
|
274
|
+
end
|
275
|
+
end
|
276
|
+
@config ||={}
|
277
|
+
end
|
278
|
+
def save_config
|
279
|
+
@config["last_dirs"]=[@lista.current_dir(),@listb.current_dir()]
|
280
|
+
File.open(@config_name, "w") { | f | YAML.dump( @config, f )}
|
281
|
+
end
|
282
|
+
def move
|
283
|
+
fp = @current_list.filepath
|
284
|
+
fn = @current_list.filename
|
285
|
+
$log.debug " FP #{fp}"
|
286
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
287
|
+
other_dir = other_list.cur_dir
|
288
|
+
$log.debug " OL #{other_list.cur_dir}"
|
289
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
290
|
+
$log.debug " MOVE #{fp}"
|
291
|
+
#confirm "#{str}"
|
292
|
+
mb = RubyCurses::MessageBox.new do
|
293
|
+
title "Move"
|
294
|
+
message "Move #{fn} to"
|
295
|
+
type :input
|
296
|
+
width 60
|
297
|
+
default_value other_dir
|
298
|
+
button_type :ok_cancel
|
299
|
+
default_button 0
|
300
|
+
end
|
301
|
+
#confirm "selected :#{mb.input_value}, #{mb.selected_index}"
|
302
|
+
if mb.selected_index == 0
|
303
|
+
# need to redraw directories
|
304
|
+
FileUtils.move(fp, mb.input_value)
|
305
|
+
@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
306
|
+
other_list.rescan
|
307
|
+
end
|
308
|
+
end
|
309
|
+
def copy
|
310
|
+
fp = @current_list.filepath
|
311
|
+
fn = @current_list.filename
|
312
|
+
$log.debug " FP #{fp}"
|
313
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
314
|
+
other_dir = other_list.cur_dir
|
315
|
+
$log.debug " OL #{other_list.cur_dir}"
|
316
|
+
str= "copy #{fn} to #{other_list.cur_dir}"
|
317
|
+
$log.debug " copy #{fp}"
|
318
|
+
#confirm "#{str}"
|
319
|
+
mb = RubyCurses::MessageBox.new do
|
320
|
+
title "Copy"
|
321
|
+
message "Copy #{fn} to"
|
322
|
+
type :input
|
323
|
+
width 60
|
324
|
+
default_value other_dir
|
325
|
+
button_type :ok_cancel
|
326
|
+
default_button 0
|
327
|
+
end
|
328
|
+
#confirm "selected :#{mb.input_value}, #{mb.selected_index}"
|
329
|
+
if mb.selected_index == 0
|
330
|
+
# need to redraw directories
|
331
|
+
FileUtils.copy(fp, mb.input_value)
|
332
|
+
other_list.rescan
|
333
|
+
end
|
334
|
+
end
|
335
|
+
## TODO : make this separate and callable with its own keylabels
|
336
|
+
def view content=nil
|
337
|
+
require 'rbcurse/rtextview'
|
338
|
+
wt = 0
|
339
|
+
wl = 0
|
340
|
+
wh = Ncurses.LINES-wt
|
341
|
+
ww = Ncurses.COLS-wl
|
342
|
+
if content.nil?
|
343
|
+
fp = @current_list.filepath
|
344
|
+
content = get_contents(fp)
|
345
|
+
else
|
346
|
+
fp=""
|
347
|
+
end
|
348
|
+
@layout = { :height => wh, :width => ww, :top => wt, :left => wl }
|
349
|
+
@v_window = VER::Window.new(@layout)
|
350
|
+
@v_form = RubyCurses::Form.new @v_window
|
351
|
+
@textview = TextView.new @v_form do
|
352
|
+
name "myView"
|
353
|
+
row 0
|
354
|
+
col 0
|
355
|
+
width ww
|
356
|
+
height wh-2
|
357
|
+
title fp
|
358
|
+
title_attrib 'bold'
|
359
|
+
print_footer true
|
360
|
+
footer_attrib 'bold'
|
361
|
+
end
|
362
|
+
#content = File.open(fp,"r").readlines
|
363
|
+
@textview.set_content content #, :WRAP_WORD
|
364
|
+
@v_form.repaint
|
365
|
+
@v_window.wrefresh
|
366
|
+
Ncurses::Panel.update_panels
|
367
|
+
begin
|
368
|
+
while((ch = @v_window.getchar()) != ?\C-q )
|
369
|
+
break if ch == KEY_F3
|
370
|
+
@v_form.handle_key ch
|
371
|
+
@v_form.repaint
|
372
|
+
##@v_window.wrefresh
|
373
|
+
end
|
374
|
+
ensure
|
375
|
+
@v_window.destroy if !@v_window.nil?
|
376
|
+
end
|
377
|
+
end
|
378
|
+
def get_contents fp
|
379
|
+
return nil unless File.readable? fp
|
380
|
+
return Dir.new(fp).entries if File.directory? fp
|
381
|
+
case File.extname(fp)
|
382
|
+
when '.tgz','.gz'
|
383
|
+
cmd = "tar -ztvf #{fp}"
|
384
|
+
content = %x[#{cmd}]
|
385
|
+
else
|
386
|
+
content = File.open(fp,"r").readlines
|
387
|
+
end
|
388
|
+
end
|
389
|
+
def opt_file c
|
390
|
+
fp = @current_list.filepath
|
391
|
+
fn = @current_list.filename
|
392
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
393
|
+
case c
|
394
|
+
when 'c'
|
395
|
+
# str= "copy #{fn} to #{other_list.cur_dir}"
|
396
|
+
copy
|
397
|
+
when 'm'
|
398
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
399
|
+
move
|
400
|
+
#if confirm("#{str}")==:YES
|
401
|
+
#$log.debug " MOVE #{str}"
|
402
|
+
#end
|
403
|
+
when 'd'
|
404
|
+
str= "delete #{fn} "
|
405
|
+
if confirm("#{str}")==:YES
|
406
|
+
$log.debug " delete #{fp}"
|
407
|
+
FileUtils.rm fp
|
408
|
+
ret=@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
409
|
+
$log.debug " DEL RET #{ret},#{@current_list.list.current_index}"
|
410
|
+
end
|
411
|
+
when 'u'
|
412
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
413
|
+
if confirm("#{str}")==:YES
|
414
|
+
$log.debug " MOVE #{str}"
|
415
|
+
end
|
416
|
+
when 'v'
|
417
|
+
str= "view #{fp}"
|
418
|
+
#if confirm("#{str}")==:YES
|
419
|
+
$log.debug " VIEW #{fp}"
|
420
|
+
view
|
421
|
+
#end
|
422
|
+
when 'r'
|
423
|
+
str= "ruby #{fn}"
|
424
|
+
if confirm("#{str}")=='y'
|
425
|
+
$log.debug " #{str} "
|
426
|
+
end
|
427
|
+
when 'e'
|
428
|
+
str= "edit #{fp}"
|
429
|
+
#if confirm("#{str}")==:YES
|
430
|
+
edit fp
|
431
|
+
when 'x'
|
432
|
+
str= "exec #{fp}"
|
433
|
+
exec_popup fp
|
434
|
+
end
|
435
|
+
end
|
436
|
+
def opt_dir c
|
437
|
+
fp = @current_list.filepath
|
438
|
+
fn = @current_list.filename
|
439
|
+
case c
|
440
|
+
when 'O'
|
441
|
+
# str= "copy #{fn} to #{other_list.cur_dir}"
|
442
|
+
if File.directory? @current_list.filepath
|
443
|
+
@current_list.change_dir fp
|
444
|
+
end
|
445
|
+
when 'o'
|
446
|
+
if File.directory? @current_list.filepath
|
447
|
+
@other_list.change_dir fp
|
448
|
+
end
|
449
|
+
@open_in_other = true # ???basically keep opening in other
|
450
|
+
when 'd'
|
451
|
+
str= "delete #{fn} "
|
452
|
+
if confirm("#{str}")==:YES
|
453
|
+
$log.debug " delete #{fp}"
|
454
|
+
FileUtils.rm fp
|
455
|
+
ret=@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
456
|
+
$log.debug " DEL RET #{ret},#{@current_list.list.current_index}"
|
457
|
+
end
|
458
|
+
when 'u'
|
459
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
460
|
+
if confirm("#{str}")==:YES
|
461
|
+
$log.debug " MOVE #{str}"
|
462
|
+
end
|
463
|
+
when 'b'
|
464
|
+
dd = @current_list.wdir
|
465
|
+
@bookmarks << dd unless @bookmarks.include? dd
|
466
|
+
when 'u'
|
467
|
+
dd = @current_list.wdir
|
468
|
+
@bookmarks.delete dd
|
469
|
+
when 'l'
|
470
|
+
@current_list.populate @bookmarks
|
471
|
+
when 's'
|
472
|
+
@config["bookmarks"] = @bookmarks
|
473
|
+
save_config
|
474
|
+
when 'e'
|
475
|
+
str= "edit #{fp}"
|
476
|
+
#if confirm("#{str}")==:YES
|
477
|
+
edit fp
|
478
|
+
when 'x'
|
479
|
+
str= "exec #{fp}"
|
480
|
+
exec_popup fp
|
481
|
+
end
|
482
|
+
end
|
483
|
+
def exec_popup fp
|
484
|
+
last_exec_def1 = @last_exec_def1 || ""
|
485
|
+
last_exec_def2 = @last_exec_def2 || false
|
486
|
+
|
487
|
+
sel, inp, hash = get_string_with_options("Enter a command to execute on #{fp}", 30, last_exec_def1, {"checkboxes" => ["view result"], "checkbox_defaults"=>[last_exec_def2]})
|
488
|
+
if sel == 0
|
489
|
+
@last_exec_def1 = inp
|
490
|
+
@last_exec_def2 = hash["view result"]
|
491
|
+
cmd = "#{inp} #{fp}"
|
492
|
+
filestr = %x[ #{cmd} 2>/dev/null ]
|
493
|
+
if hash["view result"]==true
|
494
|
+
view filestr
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
def edit fp=@current_list.filepath
|
499
|
+
$log.debug " edit #{fp}"
|
500
|
+
shell_out "/opt/local/bin/vim #{fp}"
|
501
|
+
end
|
502
|
+
def draw_screens
|
503
|
+
lasta = lastb = nil
|
504
|
+
if !@config["last_dirs"].nil?
|
505
|
+
lasta = @config["last_dirs"][0]
|
506
|
+
lastb = @config["last_dirs"][1]
|
507
|
+
end
|
508
|
+
@lista.draw_screen lasta
|
509
|
+
@listb.draw_screen lastb
|
510
|
+
|
511
|
+
@form.bind_key(?@){
|
512
|
+
@current_list.change_dir File.expand_path("~/")
|
513
|
+
}
|
514
|
+
@form.bind_key(?^){
|
515
|
+
@current_list.change_dir @current_list.prev_dirs[0] unless @current_list.prev_dirs.empty?
|
516
|
+
}
|
517
|
+
@form.bind_key(?\C-f){
|
518
|
+
@klp.mode :file
|
519
|
+
@klp.repaint
|
520
|
+
## FIXME chr could fail !!
|
521
|
+
while((ch = @window.getchar()) != ?\C-c )
|
522
|
+
if "cmdsuvrex".index(ch.chr) == nil
|
523
|
+
Ncurses.beep
|
524
|
+
else
|
525
|
+
opt_file ch.chr
|
526
|
+
break
|
527
|
+
end
|
528
|
+
end
|
529
|
+
@klp.mode :normal
|
530
|
+
}
|
531
|
+
@form.bind_key(?\C-d){
|
532
|
+
@klp.mode :dir
|
533
|
+
@klp.repaint
|
534
|
+
keys = @klp.get_current_keys
|
535
|
+
## FIXME chr could fail !!
|
536
|
+
while((ch = @window.getchar()) != ?\C-c )
|
537
|
+
if !keys.include?(ch.chr)
|
538
|
+
Ncurses.beep
|
539
|
+
else
|
540
|
+
opt_dir ch.chr
|
541
|
+
break
|
542
|
+
end
|
543
|
+
end
|
544
|
+
@klp.mode :normal
|
545
|
+
}
|
546
|
+
# backspace
|
547
|
+
@form.bind_key(127){
|
548
|
+
@current_list.goto_previous_dir
|
549
|
+
}
|
550
|
+
@form.bind_key(32){
|
551
|
+
begin
|
552
|
+
cmd="qlmanage -p #{@current_list.filepath} 2>/dev/null"
|
553
|
+
%x[#{cmd}]
|
554
|
+
rescue Interrupt
|
555
|
+
end
|
556
|
+
}
|
557
|
+
@form.bind_key(KEY_F3){
|
558
|
+
view()
|
559
|
+
}
|
560
|
+
@form.bind_key(KEY_F4){
|
561
|
+
edit()
|
562
|
+
}
|
563
|
+
@form.bind_key(KEY_F6){
|
564
|
+
selected_index, sort_key, reverse, case_sensitive = sort_popup
|
565
|
+
if selected_index == 0
|
566
|
+
@current_list.sort(sort_key, reverse)
|
567
|
+
end
|
568
|
+
}
|
569
|
+
@form.bind_key(KEY_F5){
|
570
|
+
filter()
|
571
|
+
}
|
572
|
+
@form.bind_key(KEY_F7){
|
573
|
+
grep_popup()
|
574
|
+
}
|
575
|
+
@form.bind_key(KEY_F8){
|
576
|
+
system_popup()
|
577
|
+
}
|
578
|
+
@form.bind_key(?\C-m){
|
579
|
+
dir = @current_list.filepath
|
580
|
+
if File.directory? @current_list.filepath
|
581
|
+
@current_list.change_dir dir
|
582
|
+
end
|
583
|
+
}
|
584
|
+
@klp = RubyCurses::KeyLabelPrinter.new @form, get_key_labels
|
585
|
+
@klp.set_key_labels get_key_labels(:file), :file
|
586
|
+
@klp.set_key_labels get_key_labels(:view), :view
|
587
|
+
@klp.set_key_labels get_key_labels(:dir), :dir
|
588
|
+
@form.repaint
|
589
|
+
@window.wrefresh
|
590
|
+
Ncurses::Panel.update_panels
|
591
|
+
begin
|
592
|
+
while((ch = @window.getchar()) != ?\C-q )
|
593
|
+
s = keycode_tos ch
|
594
|
+
status_row.text = "Pressed #{ch} , #{s}"
|
595
|
+
@form.handle_key(ch)
|
596
|
+
|
597
|
+
@form.repaint
|
598
|
+
@window.wrefresh
|
599
|
+
end
|
600
|
+
ensure
|
601
|
+
@window.destroy if !@window.nil?
|
602
|
+
save_config
|
603
|
+
end
|
604
|
+
|
605
|
+
end
|
606
|
+
# TODO
|
607
|
+
#
|
608
|
+
#
|
609
|
+
#
|
610
|
+
|
611
|
+
# current_list
|
612
|
+
##
|
613
|
+
# getter and setter for current_list
|
614
|
+
def current_list(*val)
|
615
|
+
if val.empty?
|
616
|
+
@current_list
|
617
|
+
else
|
618
|
+
@current_list = val[0]
|
619
|
+
@other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
620
|
+
end
|
621
|
+
end
|
622
|
+
def get_key_labels categ=nil
|
623
|
+
if categ.nil?
|
624
|
+
key_labels = [
|
625
|
+
['C-q', 'Exit'], ['C-v', 'View'],
|
626
|
+
['C-f', 'File'], ['C-d', 'Dir'],
|
627
|
+
['C-x','Select'], nil,
|
628
|
+
['F3', 'View'], ['F4', 'Edit'],
|
629
|
+
['F5', 'Filter'], ['F6', 'Sort'],
|
630
|
+
['F7', 'Grep'], ['F8', 'System'],
|
631
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
632
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn']
|
633
|
+
]
|
634
|
+
elsif categ == :file
|
635
|
+
key_labels = [
|
636
|
+
['c', 'Copy'], ['m', 'Move'],
|
637
|
+
['d', 'Delete'], ['v', 'View'],
|
638
|
+
['s', 'Select'], ['u', 'Unselect'],
|
639
|
+
['p', 'Page'], ['x', 'Exec Cmd'],
|
640
|
+
['r', 'ruby'], ['e', "Edit"],
|
641
|
+
['C-c', 'Cancel']
|
642
|
+
]
|
643
|
+
elsif categ == :view
|
644
|
+
key_labels = [
|
645
|
+
['c', 'Date'], ['m', 'Size'],
|
646
|
+
['d', 'Delete'], ['v', 'View'],
|
647
|
+
['C-c', 'Cancel']
|
648
|
+
]
|
649
|
+
elsif categ == :dir
|
650
|
+
key_labels = [
|
651
|
+
['o', 'open'], ['O', 'Open in right'],
|
652
|
+
['d', 'Delete'], ['R', 'Del Recurse'],
|
653
|
+
['t', 'tree'], ['p', 'Previous'],
|
654
|
+
['b', 'Bookmark'], ['u', 'Unbookmark'],
|
655
|
+
['l', 'List'], ['s', 'Save'],
|
656
|
+
['C-c', 'Cancel']
|
657
|
+
]
|
658
|
+
end
|
659
|
+
return key_labels
|
660
|
+
end
|
661
|
+
def get_key_labels_table
|
662
|
+
key_labels = [
|
663
|
+
['M-n','NewRow'], ['M-d','DelRow'],
|
664
|
+
['C-x','Select'], nil,
|
665
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
666
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn'],
|
667
|
+
['M-Tab','Nxt Fld'], ['Tab','Nxt Col'],
|
668
|
+
['+','Widen'], ['-','Narrow']
|
669
|
+
]
|
670
|
+
return key_labels
|
671
|
+
end
|
672
|
+
def sort_popup
|
673
|
+
mform = RubyCurses::Form.new nil
|
674
|
+
field_list = []
|
675
|
+
r = 4
|
676
|
+
$radio = RubyCurses::Variable.new
|
677
|
+
rtextvalue = [:name, :ext, :size, :mtime, :atime]
|
678
|
+
["Name", "Extension", "Size", "Modify Time", "Access Time" ].each_with_index do |rtext,ix|
|
679
|
+
field = RubyCurses::RadioButton.new mform do
|
680
|
+
variable $radio
|
681
|
+
text rtext
|
682
|
+
value rtextvalue[ix]
|
683
|
+
color 'black'
|
684
|
+
bgcolor 'white'
|
685
|
+
row r
|
686
|
+
col 5
|
687
|
+
end
|
688
|
+
field_list << field
|
689
|
+
r += 1
|
690
|
+
end
|
691
|
+
r = 4
|
692
|
+
["Reverse", "case sensitive"].each do |cbtext|
|
693
|
+
field = RubyCurses::CheckBox.new mform do
|
694
|
+
text cbtext
|
695
|
+
name cbtext
|
696
|
+
color 'black'
|
697
|
+
bgcolor 'white'
|
698
|
+
row r
|
699
|
+
col 30
|
700
|
+
end
|
701
|
+
field_list << field
|
702
|
+
r += 1
|
703
|
+
end
|
704
|
+
mb = RubyCurses::MessageBox.new mform do
|
705
|
+
title "Sort Options"
|
706
|
+
button_type :ok_cancel
|
707
|
+
default_button 0
|
708
|
+
end
|
709
|
+
if mb.selected_index == 0
|
710
|
+
$log.debug " SORT POPUP #{$radio.value}"
|
711
|
+
#$log.debug " SORT POPUP #{mb.inspect}"
|
712
|
+
$log.debug " SORT POPUP #{mform.by_name["Reverse"].value}"
|
713
|
+
$log.debug " SORT POPUP #{mform.by_name["case sensitive"].value}"
|
714
|
+
end
|
715
|
+
return mb.selected_index, $radio.value, mform.by_name["Reverse"].value, mform.by_name["case sensitive"].value
|
716
|
+
end
|
717
|
+
def filter
|
718
|
+
f = get_string("Enter a filter pattern", 20, "*")
|
719
|
+
f = "*" if f.nil? or f == ""
|
720
|
+
@current_list.filter_pattern = f
|
721
|
+
@current_list.rescan
|
722
|
+
end
|
723
|
+
def grep_popup
|
724
|
+
last_regex = @last_regex || ""
|
725
|
+
last_pattern = @last_pattern || "*"
|
726
|
+
mform = RubyCurses::Form.new nil
|
727
|
+
r = 4
|
728
|
+
field = RubyCurses::Field.new mform do
|
729
|
+
name "regex"
|
730
|
+
row r
|
731
|
+
col 30
|
732
|
+
set_buffer last_regex
|
733
|
+
set_label Label.new @form, {'text' => 'Regex', 'col'=>5, :color=>'black',:bgcolor=>'white','mnemonic'=> 'R'}
|
734
|
+
end
|
735
|
+
r += 1
|
736
|
+
field = RubyCurses::Field.new mform do
|
737
|
+
name "filepattern"
|
738
|
+
row r
|
739
|
+
col 30
|
740
|
+
set_buffer last_pattern
|
741
|
+
set_label Label.new @form, {'text' => 'File Pattern','col'=>5, :color=>'black',:bgcolor=>'white','mnemonic'=> 'F'}
|
742
|
+
end
|
743
|
+
r += 1
|
744
|
+
["Recurse", "case insensitive"].each do |cbtext|
|
745
|
+
field = RubyCurses::CheckBox.new mform do
|
746
|
+
text cbtext
|
747
|
+
name cbtext
|
748
|
+
color 'black'
|
749
|
+
bgcolor 'white'
|
750
|
+
row r
|
751
|
+
col 5
|
752
|
+
end
|
753
|
+
r += 1
|
754
|
+
end
|
755
|
+
mb = RubyCurses::MessageBox.new mform do
|
756
|
+
title "Grep Options"
|
757
|
+
button_type :ok_cancel
|
758
|
+
default_button 0
|
759
|
+
end
|
760
|
+
if mb.selected_index == 0
|
761
|
+
return if mform.by_name["regex"].getvalue()==""
|
762
|
+
@last_regex = mform.by_name["regex"].getvalue
|
763
|
+
inp = mform.by_name["regex"].getvalue
|
764
|
+
fp = mform.by_name["filepattern"].getvalue
|
765
|
+
@last_pattern = fp
|
766
|
+
flags=""
|
767
|
+
flags << " -i " if mform.by_name["case insensitive"].value==true
|
768
|
+
flags << " -R " if mform.by_name["Recurse"].value==true
|
769
|
+
cmd = "cd #{@current_list.cur_dir()};grep -l #{flags} #{inp} #{fp}"
|
770
|
+
filestr = %x[ #{cmd} ]
|
771
|
+
files = nil
|
772
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
773
|
+
#view filestr
|
774
|
+
@current_list.title "grep #{inp}"
|
775
|
+
@current_list.populate files
|
776
|
+
end
|
777
|
+
return mb.selected_index, mform.by_name["regex"].getvalue, mform.by_name["filepattern"].getvalue, mform.by_name["Recurse"].value, mform.by_name["case insensitive"].value
|
778
|
+
end
|
779
|
+
def system_popup
|
780
|
+
deflt = @last_system || ""
|
781
|
+
options=["run in shell","view output","file explorer"]
|
782
|
+
#inp = get_string("Enter a system command", 30, deflt)
|
783
|
+
sel, inp, hash = get_string_with_options("Enter a system command", 40, deflt, {"radiobuttons" => options, "radio_default"=>@last_system_radio || options[0]})
|
784
|
+
if sel == 0
|
785
|
+
if !inp.nil?
|
786
|
+
@last_system = inp
|
787
|
+
@last_system_radio = hash["radio"]
|
788
|
+
case hash["radio"]
|
789
|
+
when options[0]
|
790
|
+
shell_out inp
|
791
|
+
when options[1]
|
792
|
+
filestr = %x[ #{inp} ]
|
793
|
+
view filestr
|
794
|
+
when options[2]
|
795
|
+
filestr = %x[ #{inp} ]
|
796
|
+
files = nil
|
797
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
798
|
+
@current_list.title inp
|
799
|
+
@current_list.populate files
|
800
|
+
$log.debug " SYSTEM got #{files.size}, #{files.inspect}"
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|
804
|
+
end
|
805
|
+
def popup
|
806
|
+
deflt = @last_regexp || ""
|
807
|
+
#sel, inp, hash = get_string_with_options("Enter a filter pattern", 20, "*", {"checkboxes" => ["case sensitive","reverse"], "checkbox_defaults"=>[true, false]})
|
808
|
+
sel, inp, hash = get_string_with_options("Enter a grep pattern", 20, deflt, {"checkboxes" => ["case insensitive","not-including"]})
|
809
|
+
if sel == 0
|
810
|
+
@last_regexp = inp
|
811
|
+
flags=""
|
812
|
+
flags << " -i " if hash["case insensitive"]==true
|
813
|
+
flags << " -v " if hash["not-including"]==true
|
814
|
+
cmd = "grep -l #{flags} #{inp} *"
|
815
|
+
filestr = %x[ #{cmd} ]
|
816
|
+
files = nil
|
817
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
818
|
+
view filestr
|
819
|
+
end
|
820
|
+
$log.debug " POPUP: #{sel}: #{inp}, #{hash['case sensitive']}, #{hash['reverse']}"
|
821
|
+
end
|
822
|
+
def shell_out command
|
823
|
+
@window.hide
|
824
|
+
Ncurses.endwin
|
825
|
+
system command
|
826
|
+
Ncurses.refresh
|
827
|
+
#Ncurses.curs_set 0 # why ?
|
828
|
+
@window.show
|
829
|
+
end
|
830
|
+
end
|
831
|
+
if $0 == __FILE__
|
832
|
+
include RubyCurses
|
833
|
+
include RubyCurses::Utils
|
834
|
+
|
835
|
+
begin
|
836
|
+
# Initialize curses
|
837
|
+
VER::start_ncurses # this is initializing colors via ColorMap.setup
|
838
|
+
$log = Logger.new("view.log")
|
839
|
+
$log.level = Logger::DEBUG
|
840
|
+
|
841
|
+
catch(:close) do
|
842
|
+
t = RFe.new
|
843
|
+
t.draw_screens
|
844
|
+
end
|
845
|
+
rescue => ex
|
846
|
+
ensure
|
847
|
+
VER::stop_ncurses
|
848
|
+
p ex if ex
|
849
|
+
p(ex.backtrace.join("\n")) if ex
|
850
|
+
$log.debug( ex) if ex
|
851
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
852
|
+
end
|
853
|
+
end
|