mireru 0.2.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +21 -0
- data/README.md +33 -17
- data/lib/mireru.rb +1 -1
- data/lib/mireru/command/mireru.rb +33 -55
- data/lib/mireru/navigator.rb +166 -0
- data/lib/mireru/version.rb +1 -1
- data/lib/mireru/widget.rb +18 -12
- data/lib/mireru/widget/binary.rb +16 -22
- data/lib/mireru/widget/image.rb +11 -7
- data/lib/mireru/widget/pdf.rb +38 -20
- data/lib/mireru/widget/svg.rb +20 -16
- data/lib/mireru/widget/text.rb +22 -24
- data/lib/mireru/widget/video.rb +35 -34
- data/lib/mireru/window.rb +149 -90
- data/mireru.gemspec +3 -2
- data/test/test-logger.rb +2 -1
- data/test/test-mireru.rb +4 -53
- data/test/test-window.rb +3 -16
- data/test/widget/test-binary.rb +3 -3
- data/test/widget/test-pdf.rb +3 -3
- data/test/widget/test-svg.rb +3 -3
- data/test/widget/test-text.rb +10 -6
- data/test/widget/test-video.rb +3 -3
- data/website/locales/en.yml +8 -7
- data/website/locales/ja.yml +5 -4
- data/website/source/localizable/index.haml +2 -2
- data/website/source/localizable/usage.html.erb +11 -10
- metadata +6 -11
- data/lib/mireru/container.rb +0 -38
- data/lib/mireru/widget/thumbnail.rb +0 -43
- data/test/test-container.rb +0 -52
- data/test/widget/test-thumbnail.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdbbb02cb56552275b740544a7156e7b155bd126
|
4
|
+
data.tar.gz: efb1f67b291ec5733cf9499f6ca71cb4969251cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d73f9d68826bb2dc43fa3a9719e1b1d053bfe119a33c194660c26dfbdb7223ebfd5a3b6a292239a6f30e4841066ec552313be858edc719d72e10dba6e09a970d
|
7
|
+
data.tar.gz: 55021cc099d4abef5652d11fef73e72cd170dd71c1b29291c90bfa7e1b0c9f0df4f406b3c174e9aa8f69089edb5e79734a0a216bed20523a2d479046622c02fa
|
data/NEWS.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# NEWS
|
2
2
|
|
3
|
+
## 0.9.0: 2014-07-13
|
4
|
+
|
5
|
+
Now we have TreeView, and many problems are resolved.
|
6
|
+
|
7
|
+
### Changes
|
8
|
+
|
9
|
+
* Improvements
|
10
|
+
* Improve scrolling movements.
|
11
|
+
* Save CPU and memory for distinction between text and binary.
|
12
|
+
* Improve help messages.
|
13
|
+
* Remove thumbnail function.
|
14
|
+
* pdf: Support multiple pages.
|
15
|
+
* Fit a parent widget (PDF, SVG and Video).
|
16
|
+
* Support music files.
|
17
|
+
* Add key bindings.
|
18
|
+
* Introduce Navigator as Gtk::TreeView.
|
19
|
+
|
20
|
+
* Fixes
|
21
|
+
* image: Enable animation for image files such as animated GIF.
|
22
|
+
* video: Fix a bug that destroyed object is called.
|
23
|
+
|
3
24
|
## 0.2.1: 2014-05-29
|
4
25
|
|
5
26
|
### Changes
|
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# Mireru [![Build Status](https://secure.travis-ci.org/myokoym/mireru.png?branch=master)](http://travis-ci.org/myokoym/mireru)
|
2
2
|
|
3
|
-
|
3
|
+
Mireru is a keyboard friendly file viewer by Ruby/GTK3.
|
4
4
|
|
5
|
-
|
5
|
+
It can handle a variety of file types (Picture, Text, PDF, Video and etc.).
|
6
6
|
|
7
7
|
## Requirements
|
8
8
|
|
9
|
-
* Ruby/GTK3, Ruby/GtkSourceView3, Ruby/ClutterGTK, Ruby/ClutterGStreamer
|
10
|
-
|
9
|
+
* Ruby/GTK3, Ruby/GtkSourceView3, Ruby/ClutterGTK, Ruby/ClutterGStreamer,
|
10
|
+
Ruby/Poppler and Ruby/RSVG2 in
|
11
11
|
[Ruby-GNOME2](http://ruby-gnome2.sourceforge.jp/)
|
12
12
|
* [hexdump](https://github.com/postmodern/hexdump)
|
13
13
|
|
@@ -19,28 +19,36 @@ A friend of a keyboard.
|
|
19
19
|
|
20
20
|
### Launch
|
21
21
|
|
22
|
-
$ mireru [OPTION]... [
|
22
|
+
$ mireru [OPTION]... [FILE_OR_DIRECTORY]...
|
23
23
|
|
24
|
-
If no argument, then
|
24
|
+
If no argument, then open the current directory.
|
25
25
|
|
26
26
|
### Options
|
27
27
|
|
28
|
-
-
|
29
|
-
|
28
|
+
-h, --help<br />
|
29
|
+
show this help message
|
30
30
|
|
31
31
|
-f, --font NAME<br />
|
32
|
-
set font such as "Monospace 16"
|
32
|
+
set a font such as "Monospace 16"
|
33
33
|
|
34
|
-
###
|
34
|
+
### Key bindings
|
35
35
|
|
36
36
|
#### Common
|
37
37
|
|
38
38
|
n: next<br />
|
39
39
|
p: prev<br />
|
40
|
+
e: expand/collpse<br />
|
40
41
|
r: reload<br />
|
41
|
-
e: expand path<br />
|
42
42
|
q: quit<br />
|
43
43
|
|
44
|
+
#### Control key mask
|
45
|
+
|
46
|
+
Ctrl+n: 10 tiles next<br />
|
47
|
+
Ctrl+p: 10 tiles prev<br />
|
48
|
+
Ctrl+e: expand all/collpse even if cursor on file<br />
|
49
|
+
Ctrl+h: move position of partition to left<br />
|
50
|
+
Ctrl+l: move position of partition to right<br />
|
51
|
+
|
44
52
|
#### Scroll
|
45
53
|
|
46
54
|
h: left<br />
|
@@ -48,19 +56,22 @@ j: down<br />
|
|
48
56
|
k: up<br />
|
49
57
|
l: right<br />
|
50
58
|
|
59
|
+
Shift+h: 100 times left<br />
|
60
|
+
Shift+j: 100 times down<br />
|
61
|
+
Shift+k: 100 times up<br />
|
62
|
+
Shift+l: 100 times right<br />
|
63
|
+
|
64
|
+
Shift+g: down to bottom<br />
|
65
|
+
|
51
66
|
#### Scale
|
52
67
|
|
53
68
|
+: larger<br />
|
54
69
|
-: smaller<br />
|
55
70
|
|
56
|
-
#### Special
|
57
|
-
|
58
|
-
T: thumbnail
|
59
|
-
|
60
71
|
#### Image
|
61
72
|
|
62
|
-
f:
|
63
|
-
o: original size<br />
|
73
|
+
f: fit window size<br />
|
74
|
+
o: scale to the original size<br />
|
64
75
|
|
65
76
|
#### Text
|
66
77
|
|
@@ -70,6 +81,11 @@ f: change font (at random)<br />
|
|
70
81
|
|
71
82
|
space: play/pause<br />
|
72
83
|
|
84
|
+
#### PDF
|
85
|
+
|
86
|
+
j: next page<br />
|
87
|
+
k: prev page<br />
|
88
|
+
|
73
89
|
## License
|
74
90
|
|
75
91
|
Copyright (c) 2013-2014 Masafumi Yokoyama <myokoym@gmail.com>
|
data/lib/mireru.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
require "gtk3"
|
2
1
|
require "mireru/logger"
|
3
2
|
require "mireru/window"
|
4
|
-
require "mireru/container"
|
5
3
|
require "mireru/version"
|
6
4
|
|
7
5
|
module Mireru
|
8
6
|
module Command
|
9
7
|
class Mireru
|
10
|
-
USAGE = "Usage: mireru [OPTION]... [
|
8
|
+
USAGE = "Usage: mireru [OPTION]... [FILE_OR_DIRECTORY]..."
|
11
9
|
|
12
10
|
class << self
|
13
11
|
def run(*arguments)
|
@@ -31,44 +29,17 @@ module Mireru
|
|
31
29
|
font = purge_option(arguments, /\A(-f|--font)\z/, true)
|
32
30
|
|
33
31
|
files = files_from_arguments(arguments)
|
34
|
-
file_container = ::Mireru::Container.new(files)
|
35
32
|
|
36
|
-
|
37
|
-
write_empty_message
|
38
|
-
exit(false)
|
39
|
-
end
|
40
|
-
|
41
|
-
window = ::Mireru::Window.new
|
33
|
+
window = ::Mireru::Window.new(files)
|
42
34
|
window.font = font if font
|
43
|
-
window.add_container(file_container)
|
44
35
|
|
45
|
-
|
36
|
+
window.run
|
46
37
|
end
|
47
38
|
|
48
39
|
private
|
49
40
|
def files_from_arguments(arguments)
|
50
41
|
if arguments.empty?
|
51
|
-
files = Dir.
|
52
|
-
elsif purge_option(arguments, /\A(-R|--recursive|-d|--deep)\z/)
|
53
|
-
if arguments.empty?
|
54
|
-
files = Dir.glob("**/*")
|
55
|
-
else
|
56
|
-
files = []
|
57
|
-
arguments.each do |f|
|
58
|
-
if File.directory?(f)
|
59
|
-
files << Dir.glob("#{f}/**/*")
|
60
|
-
else
|
61
|
-
files << f
|
62
|
-
end
|
63
|
-
end
|
64
|
-
files.flatten!
|
65
|
-
end
|
66
|
-
elsif arguments.all? {|v| File.directory?(v) }
|
67
|
-
files = []
|
68
|
-
arguments.each do |f|
|
69
|
-
files << Dir.glob("#{f}/*")
|
70
|
-
end
|
71
|
-
files.flatten!
|
42
|
+
files = [Dir.pwd]
|
72
43
|
else
|
73
44
|
files = arguments
|
74
45
|
end
|
@@ -89,38 +60,59 @@ module Mireru
|
|
89
60
|
def write_help_message
|
90
61
|
message = <<-EOM
|
91
62
|
#{USAGE}
|
92
|
-
If no argument, then
|
63
|
+
If no argument, then open the current directory.
|
64
|
+
|
93
65
|
Options:
|
94
|
-
-
|
95
|
-
|
66
|
+
-h, --help
|
67
|
+
show this help message
|
68
|
+
|
96
69
|
-f, --font NAME
|
97
|
-
set font such as "Monospace 16"
|
98
|
-
|
70
|
+
set a font such as "Monospace 16"
|
71
|
+
|
72
|
+
Key bindings:
|
99
73
|
n: next
|
100
74
|
p: prev
|
75
|
+
e: expand/collpse
|
101
76
|
r: reload
|
102
|
-
e: expand path
|
103
77
|
q: quit
|
104
78
|
|
79
|
+
Control key mask:
|
80
|
+
Ctrl+n: 10 tiles next
|
81
|
+
Ctrl+p: 10 tiles prev
|
82
|
+
Ctrl+e: expand all / collpse even if cursor on file
|
83
|
+
Ctrl+h: move position of partition to left
|
84
|
+
Ctrl+l: move position of partition to right
|
85
|
+
|
105
86
|
scroll:
|
106
87
|
h: left
|
107
88
|
j: down
|
108
89
|
k: up
|
109
90
|
l: right
|
110
91
|
|
92
|
+
Shift+h: 100 times left
|
93
|
+
Shift+j: 100 times down
|
94
|
+
Shift+k: 100 times up
|
95
|
+
Shift+l: 100 times right
|
96
|
+
|
97
|
+
Shift+g: down to bottom
|
98
|
+
|
111
99
|
scale:
|
112
100
|
+: larger
|
113
101
|
-: smaller
|
114
102
|
|
115
103
|
image:
|
116
|
-
f:
|
117
|
-
o: original size
|
104
|
+
f: fit window size
|
105
|
+
o: scale to the original size
|
118
106
|
|
119
107
|
text:
|
120
108
|
f: change font (at random)
|
121
109
|
|
122
110
|
video:
|
123
111
|
space: play/pause
|
112
|
+
|
113
|
+
PDF:
|
114
|
+
j: next page
|
115
|
+
k: prev page
|
124
116
|
EOM
|
125
117
|
@logger.info(message)
|
126
118
|
end
|
@@ -131,20 +123,6 @@ Keybind:
|
|
131
123
|
EOM
|
132
124
|
@logger.info(message)
|
133
125
|
end
|
134
|
-
|
135
|
-
def write_empty_message
|
136
|
-
message = <<-EOM
|
137
|
-
Warning: file not found.
|
138
|
-
#{USAGE}
|
139
|
-
If no argument, then search current directory.
|
140
|
-
Options:
|
141
|
-
-R, --recursive
|
142
|
-
recursive search as "**/*"
|
143
|
-
-f, --font NAME
|
144
|
-
set font such as "Monospace 16"
|
145
|
-
EOM
|
146
|
-
@logger.error(message)
|
147
|
-
end
|
148
126
|
end
|
149
127
|
end
|
150
128
|
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require "gtk3"
|
2
|
+
|
3
|
+
module Mireru
|
4
|
+
class Navigator < Gtk::ScrolledWindow
|
5
|
+
PATH_COLUMN, FILENAME_COLUMN, ICON_COLUMN = 0, 1, 2
|
6
|
+
|
7
|
+
def initialize(window, files)
|
8
|
+
super()
|
9
|
+
@window = window
|
10
|
+
@files = files
|
11
|
+
@dir_iters = {}
|
12
|
+
set_policy(:automatic, :automatic)
|
13
|
+
set_size_request(200, -1)
|
14
|
+
@model = Gtk::TreeStore.new(String, String, Gdk::Pixbuf)
|
15
|
+
@tree_view = create_tree(@model)
|
16
|
+
add(@tree_view)
|
17
|
+
end
|
18
|
+
|
19
|
+
def next
|
20
|
+
@tree_view.move_cursor(Gtk::MovementStep::DISPLAY_LINES, 1)
|
21
|
+
end
|
22
|
+
|
23
|
+
def prev
|
24
|
+
@tree_view.move_cursor(Gtk::MovementStep::DISPLAY_LINES, -1)
|
25
|
+
end
|
26
|
+
|
27
|
+
def expand_toggle(open_all=false)
|
28
|
+
path = selected_path
|
29
|
+
iter = @model.get_iter(path)
|
30
|
+
file_path = iter.get_value(PATH_COLUMN)
|
31
|
+
if open_all and File.file?(file_path)
|
32
|
+
parent = iter.parent
|
33
|
+
path = @model.get_path(parent)
|
34
|
+
@tree_view.collapse_row(path)
|
35
|
+
elsif @tree_view.row_expanded?(path)
|
36
|
+
@tree_view.collapse_row(path)
|
37
|
+
else
|
38
|
+
if open_all
|
39
|
+
return unless File.directory?(file_path)
|
40
|
+
Dir.glob("#{file_path}/*") do |dir|
|
41
|
+
next unless File.directory?(dir)
|
42
|
+
child_iter = @dir_iters[dir]
|
43
|
+
next unless child_iter
|
44
|
+
load_dir(@model, dir, child_iter, true)
|
45
|
+
@dir_iters.delete(dir)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@tree_view.expand_row(path, open_all)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def selected_path
|
53
|
+
selection = @tree_view.selection
|
54
|
+
selected = selection.selected
|
55
|
+
@model.get_path(selected)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def create_tree(model)
|
60
|
+
tree_view = Gtk::TreeView.new
|
61
|
+
tree_view.set_model(model)
|
62
|
+
tree_view.search_column = FILENAME_COLUMN
|
63
|
+
tree_view.enable_search = false
|
64
|
+
|
65
|
+
selection = tree_view.selection
|
66
|
+
selection.set_mode(:browse)
|
67
|
+
|
68
|
+
@files.each do |file|
|
69
|
+
load_file(model, file)
|
70
|
+
end
|
71
|
+
|
72
|
+
column = Gtk::TreeViewColumn.new
|
73
|
+
if @files.size == 1
|
74
|
+
column.title = File.dirname(@files.first)
|
75
|
+
else
|
76
|
+
column.title = "Selected Files"
|
77
|
+
end
|
78
|
+
tree_view.append_column(column)
|
79
|
+
|
80
|
+
renderer = Gtk::CellRendererPixbuf.new
|
81
|
+
renderer.set_fixed_size(*Gtk::IconSize.lookup(:menu))
|
82
|
+
column.pack_start(renderer, :expand => false)
|
83
|
+
column.add_attribute(renderer, :pixbuf, ICON_COLUMN)
|
84
|
+
|
85
|
+
renderer = Gtk::CellRendererText.new
|
86
|
+
column.pack_start(renderer, :expand => false)
|
87
|
+
column.add_attribute(renderer, :text, FILENAME_COLUMN)
|
88
|
+
|
89
|
+
selection.signal_connect("changed") do |selection|
|
90
|
+
apply_changed(selection)
|
91
|
+
end
|
92
|
+
|
93
|
+
tree_view.expand_all
|
94
|
+
tree_view
|
95
|
+
end
|
96
|
+
|
97
|
+
def apply_changed(selection)
|
98
|
+
iter = selection.selected
|
99
|
+
return unless iter
|
100
|
+
path = iter.get_value(PATH_COLUMN)
|
101
|
+
if File.directory?(path)
|
102
|
+
if @dir_iters[path]
|
103
|
+
load_dir(@model, path, @dir_iters[path])
|
104
|
+
end
|
105
|
+
@dir_iters.delete(path)
|
106
|
+
end
|
107
|
+
return unless File.file?(path)
|
108
|
+
@window.title = path
|
109
|
+
@window.file = path
|
110
|
+
begin
|
111
|
+
GLib::Timeout.add(100) do
|
112
|
+
if @window.file == path
|
113
|
+
begin
|
114
|
+
@window.add_from_file(path)
|
115
|
+
rescue => e
|
116
|
+
$stderr.puts("#{e.class}: #{e.message}")
|
117
|
+
$stderr.puts(e.backtrace)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
false
|
121
|
+
end
|
122
|
+
rescue
|
123
|
+
stock = Gtk::Stock::MISSING_IMAGE
|
124
|
+
size = :dialog
|
125
|
+
pixbuf = Gtk::Image.new.render_icon_pixbuf(stock, size)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def load_dir(model, dir, parent=nil, recursive=false)
|
130
|
+
Dir.glob("#{File.expand_path(dir)}/*") do |child|
|
131
|
+
load_file(model, child, parent, recursive)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def load_file(model, file, parent=nil, recursive=false)
|
136
|
+
iter = model.append(parent)
|
137
|
+
iter.set_value(PATH_COLUMN, file)
|
138
|
+
iter.set_value(FILENAME_COLUMN, File.basename(file))
|
139
|
+
if File.directory?(file)
|
140
|
+
@dir_iters[file] = iter unless recursive
|
141
|
+
dir_icon = self.render_icon_pixbuf(Gtk::Stock::DIRECTORY, :menu)
|
142
|
+
iter.set_value(ICON_COLUMN, dir_icon)
|
143
|
+
load_dir(model, file, iter, recursive) if recursive
|
144
|
+
else
|
145
|
+
file_icon = select_icon(file)
|
146
|
+
iter.set_value(ICON_COLUMN, file_icon)
|
147
|
+
end
|
148
|
+
# TODO: too slow...
|
149
|
+
#icon_width, icon_height = Gtk::IconSize.lookup(:menu)
|
150
|
+
#begin
|
151
|
+
# pixbuf = Gdk::Pixbuf.new(file_path, icon_width, icon_height)
|
152
|
+
#rescue Gdk::PixbufError
|
153
|
+
# pixbuf = file_icon
|
154
|
+
#end
|
155
|
+
#iter.set_value(ICON_COLUMN, pixbuf)
|
156
|
+
end
|
157
|
+
|
158
|
+
def select_icon(file)
|
159
|
+
if Widget.video?(file) or Widget.music?(file)
|
160
|
+
self.render_icon_pixbuf(Gtk::Stock::CDROM, :menu)
|
161
|
+
else
|
162
|
+
self.render_icon_pixbuf(Gtk::Stock::FILE, :menu)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|