bzr branch
http://bzr.ed.am/gtk/eog-manage-raws
4
by edam
- added unkeep command |
1 |
# raw-tools.py |
2 |
# |
|
3 |
# Copyright (C) 2011 Tim Marston <edam@waxworlds.org> |
|
4 |
# |
|
5 |
# This file is part of Raw Tools (hereafter referred to as "this program"). |
|
6 |
# See http://www.waxworlds.org/edam/software/gtk/eog-raw-tools for more |
|
7 |
# information. |
|
8 |
# |
|
9 |
# This program is free software: you can redistribute it and/or modify |
|
10 |
# it under the terms of the GNU General Public License as published by |
|
11 |
# the Free Software Foundation, either version 3 of the License, or |
|
12 |
# (at your option) any later version. |
|
13 |
# |
|
14 |
# This program is distributed in the hope that it will be useful, |
|
15 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
17 |
# GNU General Public License for more details. |
|
18 |
# |
|
19 |
# You should have received a copy of the GNU General Public License |
|
20 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
21 |
||
22 |
||
23 |
# version 0.1 |
|
24 |
||
25 |
||
26 |
import eog, gtk, os, re, gio |
|
27 |
||
28 |
class RawToolsPlugin(eog.Plugin): |
|
1
by edam
initial comit |
29 |
|
30 |
raw_file_extensions = [ 'cr2', '3fr', 'ari', 'arw', 'srf', 'sr2', 'bay', |
|
31 |
'crw', 'cr2', 'cap', 'iiq', 'eip', 'dcs', 'dcr', 'drf', 'k25', 'kdc', |
|
32 |
'dng', 'erf', 'fff', 'mef', 'mos', 'mrw', 'nef', 'nrw', 'orf', 'ptx', |
|
33 |
'pef', 'pxn', 'r3d', 'raf', 'raw', 'rw2', 'rwl', 'rwz', 'x3f' ] |
|
34 |
||
35 |
def __init__( self ): |
|
36 |
eog.Plugin.__init__( self ) |
|
37 |
||
38 |
def activate( self, window ): |
|
39 |
self._window = window |
|
40 |
||
41 |
# insert menu item |
|
42 |
manager = window.get_ui_manager() |
|
2
by edam
- added status bar information |
43 |
self._action_group = gtk.ActionGroup( 'EogRawToolsPluginActions' ) |
44 |
self._action_group.add_actions( [ ( 'EogPluginRunKeepRaw', None, |
|
45 |
_( 'Keep Raw Image' ), 'K', |
|
46 |
_( "Move the accompanying raw file to a 'raw' subdirectory" ), |
|
1
by edam
initial comit |
47 |
self.on_keep_raw_image ) ] ) |
4
by edam
- added unkeep command |
48 |
self._action_group.add_actions( [ ( 'EogPluginRunUnkeepRaw', None, |
49 |
_( 'Unkeep Raw Image' ), 'U', |
|
50 |
_( "Move the accompanying raw file back to the image's directory" ), |
|
51 |
self.on_unkeep_raw_image ) ] ) |
|
2
by edam
- added status bar information |
52 |
self._action_group.add_actions( [ ( 'EogPluginRunDeleteRaw', None, |
53 |
_( 'Delete Unkept Raw Images' ), None, |
|
54 |
_( "Delete all raw files in the current image's directory (the unkept ones)" ), |
|
55 |
self.on_delete_raw_images ) ] ) |
|
1
by edam
initial comit |
56 |
manager.insert_action_group( self._action_group, -1 ) |
57 |
self._ui_id = manager.add_ui_from_string( """ |
|
58 |
<ui> |
|
59 |
<menubar name="MainMenu"> |
|
60 |
<menu name="ToolsMenu" action="Tools"> |
|
61 |
<separator /> |
|
2
by edam
- added status bar information |
62 |
<menuitem name="EogPluginRunKeepRaw" |
1
by edam
initial comit |
63 |
action="EogPluginRunKeepRaw" /> |
4
by edam
- added unkeep command |
64 |
<menuitem name="EogPluginRunUnkeepRaw" |
65 |
action="EogPluginRunUnkeepRaw" /> |
|
2
by edam
- added status bar information |
66 |
<menuitem name="EogPluginRunDeleteRaw" |
67 |
action="EogPluginRunDeleteRaw" /> |
|
1
by edam
initial comit |
68 |
<separator /> |
69 |
</menu> |
|
70 |
</menubar> |
|
71 |
<popup name="ViewPopup"> |
|
72 |
<separator /> |
|
73 |
<menuitem action="EogPluginRunKeepRaw" /> |
|
74 |
<separator /> |
|
75 |
</popup> |
|
76 |
</ui> |
|
77 |
""" ) |
|
78 |
||
2
by edam
- added status bar information |
79 |
# insert status bar |
80 |
self._statusbar = gtk.Statusbar() |
|
81 |
self._statusbar.set_has_resize_grip( False ) |
|
4
by edam
- added unkeep command |
82 |
self._statusbar.set_size_request( 80, 10 ) |
2
by edam
- added status bar information |
83 |
statusbar = window.get_statusbar() |
84 |
statusbar.pack_end( self._statusbar, False, False, 0 ); |
|
85 |
self._statusbar.show() |
|
86 |
||
1
by edam
initial comit |
87 |
# connect to selection change |
88 |
thumb_view = window.get_thumb_view() |
|
89 |
self._on_selection_change_id = thumb_view.connect_after( \ |
|
2
by edam
- added status bar information |
90 |
'selection_changed', self.on_selection_change, window ) |
1
by edam
initial comit |
91 |
|
92 |
# init ui state |
|
2
by edam
- added status bar information |
93 |
self.update_status( window ) |
1
by edam
initial comit |
94 |
|
95 |
def deactivate( self, window ): |
|
96 |
||
2
by edam
- added status bar information |
97 |
# disconnect handlers |
98 |
thumb_view = window.get_thumb_view() |
|
99 |
thumb_view.disconnect( self._on_selection_change_id ) |
|
100 |
||
1
by edam
initial comit |
101 |
# remove menu items |
102 |
manager = window.get_ui_manager() |
|
103 |
manager.remove_ui( self._ui_id ) |
|
104 |
manager.remove_action_group( self._action_group ) |
|
105 |
manager.ensure_update() |
|
106 |
||
2
by edam
- added status bar information |
107 |
# remove status bar entry |
108 |
statusbar = window.get_statusbar() |
|
109 |
statusbar.remove( self._statusbar ) |
|
1
by edam
initial comit |
110 |
|
111 |
def on_selection_change( self, view, data ): |
|
2
by edam
- added status bar information |
112 |
self.update_status( data ) |
113 |
||
114 |
def get_raw_filename_from_image( self, image ): |
|
1
by edam
initial comit |
115 |
fname = image.get_file().get_path() |
116 |
||
2
by edam
- added status bar information |
117 |
# get the base fileanme (with no extension), read for searching |
1
by edam
initial comit |
118 |
base_fname = image.get_file().get_path() |
119 |
pos = base_fname.rfind( '.' ) |
|
120 |
if( pos != -1 ): |
|
2
by edam
- added status bar information |
121 |
|
122 |
# check if the extension of the current image makes it a raw file |
|
123 |
for ext in self.raw_file_extensions + \ |
|
124 |
map( lambda x: x.upper(), self.raw_file_extensions ): |
|
125 |
if( base_fname[ pos : ] == ext ): |
|
126 |
return False; |
|
127 |
||
128 |
# remove extension from base filename |
|
1
by edam
initial comit |
129 |
base_fname = base_fname[ 0 : pos ] |
130 |
||
131 |
# check for stupidity |
|
132 |
if( base_fname[ -1 : None ] == '/' ): |
|
2
by edam
- added status bar information |
133 |
return False |
134 |
||
135 |
# loop through valid raw file extensions, uppercase and lowercase |
|
136 |
for ext in self.raw_file_extensions + \ |
|
137 |
map( lambda x: x.upper(), self.raw_file_extensions ): |
|
138 |
||
139 |
# if the raw file exists, we found it |
|
140 |
if( os.path.isfile( base_fname + '.' + ext ) ): |
|
141 |
return os.path.basename( base_fname + '.' + ext ); |
|
1
by edam
initial comit |
142 |
|
143 |
# path the raw images will be moved to |
|
144 |
raw_path = os.path.dirname( fname ) + '/raw'; |
|
145 |
||
2
by edam
- added status bar information |
146 |
# loop through valid raw file extensions, uppercase and lowercase |
1
by edam
initial comit |
147 |
for ext in self.raw_file_extensions + \ |
2
by edam
- added status bar information |
148 |
map( lambda x: x.upper(), self.raw_file_extensions ): |
149 |
||
150 |
# if the raw file exists, we found it |
|
151 |
if( os.path.isfile( os.path.dirname( fname ) + '/raw/' + \ |
|
152 |
os.path.basename( base_fname + '.' + ext ) ) ): |
|
153 |
return os.path.basename( base_fname + '.' + ext ); |
|
154 |
||
155 |
# not found |
|
156 |
return False; |
|
157 |
||
158 |
def update_status( self, window ): |
|
159 |
thumb_view = window.get_thumb_view() |
|
160 |
||
161 |
# do we have just the one selected image? we can't handle multiple |
|
162 |
# images because EogThumbView.get_selected_images() doesn't work. |
|
163 |
self._action_group.set_sensitive( \ |
|
164 |
thumb_view.get_n_selected() == 1 ) |
|
165 |
||
166 |
# update the status bar |
|
167 |
if( thumb_view.get_n_selected() > 0 ): |
|
168 |
image = thumb_view.get_first_selected_image() |
|
169 |
raw_fname = self.get_raw_filename_from_image( image ) |
|
170 |
path = os.path.dirname( image.get_file().get_path() ) |
|
171 |
self._statusbar.pop( 0 ) |
|
172 |
if( raw_fname is False ): |
|
173 |
self._statusbar.push( 0, _( 'raw: -' ) ) |
|
174 |
elif( os.path.isfile( path + '/' + raw_fname ) ): |
|
4
by edam
- added unkeep command |
175 |
self._statusbar.push( 0, _( 'raw: unkept' ) ) |
2
by edam
- added status bar information |
176 |
else: |
177 |
self._statusbar.push( 0, _( 'raw: keep' ) ) |
|
178 |
||
179 |
def on_keep_raw_image( self, action ): |
|
180 |
||
181 |
# do we have just the one selected image? we can't handle multiple |
|
182 |
# images because EogThumbView.get_selected_images() doesn't work. |
|
183 |
thumb_view = self._window.get_thumb_view() |
|
184 |
if( thumb_view.get_n_selected() == 1 ): |
|
185 |
||
186 |
# get the image |
|
187 |
image = thumb_view.get_first_selected_image() |
|
188 |
if( image != None ): |
|
189 |
self.keep_raw_image( image ) |
|
190 |
||
191 |
# update ui |
|
192 |
self.update_status( self._window ) |
|
193 |
||
4
by edam
- added unkeep command |
194 |
def on_unkeep_raw_image( self, action ): |
195 |
||
196 |
# do we have just the one selected image? we can't handle multiple |
|
197 |
# images because EogThumbView.get_selected_images() doesn't work. |
|
198 |
thumb_view = self._window.get_thumb_view() |
|
199 |
if( thumb_view.get_n_selected() == 1 ): |
|
200 |
||
201 |
# get the image |
|
202 |
image = thumb_view.get_first_selected_image() |
|
203 |
if( image != None ): |
|
204 |
self.unkeep_raw_image( image ) |
|
205 |
||
206 |
# update ui |
|
207 |
self.update_status( self._window ) |
|
208 |
||
2
by edam
- added status bar information |
209 |
def keep_raw_image( self, image ): |
210 |
||
211 |
raw_fname = self.get_raw_filename_from_image( image ) |
|
212 |
if( raw_fname is False ): |
|
213 |
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL, |
|
214 |
gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, |
|
215 |
_( 'Raw file not found!' ) ) |
|
216 |
dialog.format_secondary_text( _( "This image doesn't appear to " + |
|
217 |
"have an accompanying raw file." ) ) |
|
1
by edam
initial comit |
218 |
dialog.run() |
219 |
dialog.destroy() |
|
220 |
return |
|
2
by edam
- added status bar information |
221 |
|
222 |
# does raw file exist? |
|
223 |
path = os.path.dirname( image.get_file().get_path() ) |
|
224 |
if( os.path.isfile( path + '/' + raw_fname ) ): |
|
225 |
||
226 |
# create the raw directory, if it doesn't exist |
|
227 |
if( not os.path.isdir( path + '/raw' ) ): |
|
228 |
os.mkdir( path + '/raw' ); |
|
229 |
||
230 |
# move the raw file in to the raw directory |
|
231 |
os.rename( path + '/' + raw_fname, path + '/raw/' + raw_fname ) |
|
232 |
||
4
by edam
- added unkeep command |
233 |
def unkeep_raw_image( self, image ): |
234 |
||
235 |
raw_fname = self.get_raw_filename_from_image( image ) |
|
236 |
if( raw_fname is False ): |
|
237 |
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL, |
|
238 |
gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, |
|
239 |
_( 'Raw file not found!' ) ) |
|
240 |
dialog.format_secondary_text( _( "This image doesn't appear to " + |
|
241 |
"have an accompanying raw file." ) ) |
|
242 |
dialog.run() |
|
243 |
dialog.destroy() |
|
244 |
return |
|
245 |
||
246 |
# does raw file exist? |
|
247 |
path = os.path.dirname( image.get_file().get_path() ) |
|
248 |
if( os.path.isfile( path + '/raw/' + raw_fname ) ): |
|
249 |
||
250 |
# move the raw file back to the parent directory |
|
251 |
os.rename( path + '/raw/' + raw_fname, path + '/' + raw_fname ) |
|
252 |
||
253 |
# if the raw directory is empty, remove it |
|
254 |
if( len( os.listdir( path + '/raw' ) ) == 0 ): |
|
255 |
os.rmdir( path + '/raw' ) |
|
256 |
||
2
by edam
- added status bar information |
257 |
def on_delete_raw_images( self, action ): |
258 |
||
259 |
# get path to first selected image, if there is one |
|
260 |
thumb_view = self._window.get_thumb_view() |
|
261 |
if( thumb_view.get_n_selected() == 1 ): |
|
262 |
image = thumb_view.get_first_selected_image() |
|
263 |
path = os.path.dirname( image.get_file().get_path() ) |
|
264 |
||
265 |
# build a regex that will match raw filenames |
|
266 |
regex = re.compile( |
|
267 |
'.*\.(' + '|'.join( self.raw_file_extensions ) + ')', re.I ) |
|
268 |
||
269 |
# itterate through files in the dir |
|
270 |
files = set() |
|
271 |
for file in os.listdir( path ): |
|
272 |
if( regex.match( file ) ): |
|
273 |
files.add( file ) |
|
274 |
||
275 |
# do we have any files to delete? |
|
276 |
if( len( files ) > 0 ): |
|
277 |
||
278 |
# ask the user if they are sure |
|
279 |
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL, |
|
280 |
gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, |
|
281 |
_( 'Delete Raw Files?' ) ) |
|
282 |
if( len( files ) == 1 ): |
|
283 |
subject = _( ' remaining raw file' ) |
|
284 |
else: |
|
285 |
subject = _( ' remaining raw files' ) |
|
286 |
dialog.format_secondary_text( |
|
287 |
_( 'You are about to delete the ' ) + |
|
288 |
str( len( files ) ) + subject + |
|
289 |
_( " that you haven't specifically asked to keep from " + |
|
290 |
"the directory that the current image is in.\n\n" + |
|
291 |
"Do you want to continue?" ) ) |
|
292 |
result = dialog.run() |
|
293 |
dialog.destroy() |
|
294 |
if( result != gtk.RESPONSE_YES ): |
|
295 |
return |
|
296 |
||
297 |
# delete the files |
|
298 |
for file in files: |
|
4
by edam
- added unkeep command |
299 |
gio.file_parse_name( path + '/' + file ).trash() |
300 |
#os.unlink( path + '/' + file ) |
|
2
by edam
- added status bar information |
301 |
|
302 |
self.update_status( self._window ) |
|
303 |
||
304 |
# else, tell the user there aren't any raw files! |
|
305 |
else: |
|
306 |
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL, |
|
307 |
gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, |
|
308 |
_( 'No raw files to delete!' ) ) |
|
309 |
dialog.format_secondary_text( |
|
310 |
_( 'There are no raw files to delete!' ) ) |
|
311 |
dialog.run() |
|
312 |
dialog.destroy() |