3
# Copyright (C) 2011 Tim Marston <edam@waxworlds.org>
5
# This file is part of Manage Raws (hereafter referred to as "this
6
# program"). See http://ed.am/dev/gtk/eog-manage-raws for more
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.
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.
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/>.
25
from gi.repository import GObject, Gtk, Eog, Gio
28
class ManageRawsPlugin( GObject.Object, Eog.WindowActivatable ):
30
# Override EogWindowActivatable's window property
31
window = GObject.property( type = Eog.Window )
33
# list of file extension to recognise as RAW files
3
class HelloWorldPlugin(eog.Plugin):
34
5
raw_file_extensions = [ 'cr2', '3fr', 'ari', 'arw', 'srf', 'sr2', 'bay',
35
6
'crw', 'cr2', 'cap', 'iiq', 'eip', 'dcs', 'dcr', 'drf', 'k25', 'kdc',
36
7
'dng', 'erf', 'fff', 'mef', 'mos', 'mrw', 'nef', 'nrw', 'orf', 'ptx',
37
8
'pef', 'pxn', 'r3d', 'raf', 'raw', 'rw2', 'rwl', 'rwz', 'x3f' ]
39
10
def __init__( self ):
40
GObject.Object.__init__( self )
11
eog.Plugin.__init__( self )
42
def do_activate( self ):
13
def activate( self, window ):
45
ui_manager = self.window.get_ui_manager()
46
self.action_group = Gtk.ActionGroup( 'EogManageRawsPluginActions' )
47
self.action_group.add_actions( [ ( 'EogPluginRunKeepRaw', None,
48
_( 'Keep Raw File' ), 'K',
49
_( "Move the accompanying raw file to a 'raw' subdirectory" ),
50
self.do_keep_raw_file ) ], self.window )
51
self.action_group.add_actions( [ ( 'EogPluginRunUnkeepRaw', None,
52
_( 'Unkeep Raw File' ), 'U',
53
_( "Move the accompanying raw file back to the image's directory" ),
54
self.do_unkeep_raw_file ) ], self.window )
55
self.action_group.add_actions( [ ( 'EogPluginRunDeleteRaw', None,
56
_( 'Delete Unkept Raw Files' ), None,
57
_( "Delete all raw files in the current image's directory (the unkept ones)" ),
58
self.do_delete_raw_files ) ], self.window )
59
ui_manager.insert_action_group( self.action_group, -1 )
60
self.ui_id = ui_manager.add_ui_from_string( """
17
manager = window.get_ui_manager()
18
self._action_group = gtk.ActionGroup( "EogRawToolsPluginActions" )
19
self._action_group.add_actions( [ ( "EogPluginRunKeepRaw", None,
20
_( "Keep Raw Image" ), "K",
21
_( "Keep accompanying raw image" ),
22
self.on_keep_raw_image ) ] )
23
manager.insert_action_group( self._action_group, -1 )
24
self._ui_id = manager.add_ui_from_string( """
62
26
<menubar name="MainMenu">
63
27
<menu name="ToolsMenu" action="Tools">
65
<menuitem name="EogPluginRunKeepRaw"
29
<menuitem name="EogPluginRawTools"
66
30
action="EogPluginRunKeepRaw" />
67
<menuitem name="EogPluginRunUnkeepRaw"
68
action="EogPluginRunUnkeepRaw" />
69
<menuitem name="EogPluginRunDeleteRaw"
70
action="EogPluginRunDeleteRaw" />
83
self.statusbar = Gtk.Statusbar()
84
#self.statusbar.set_size_request( 100, 10 )
85
statusbar = self.window.get_statusbar()
86
statusbar.pack_end( self.statusbar, False, False, 0 );
89
42
# connect to selection change
90
thumb_view = self.window.get_thumb_view()
91
self.on_selection_change_id = thumb_view.connect_after( \
92
'selection_changed', self.on_selection_change, self.window )
43
thumb_view = window.get_thumb_view()
44
self._on_selection_change_id = thumb_view.connect_after( \
45
"selection_changed", self.on_selection_change, window )
95
self.update_status( self.window )
48
self.update_action_group_sensitivity( window )
97
def do_deactivate( self ):
50
def deactivate( self, window ):
99
52
# remove menu items
100
ui_manager = self.window.get_ui_manager()
101
ui_manager.remove_ui( self.ui_id )
103
ui_manager.remove_action_group( self.action_group )
104
self.action_group = None
105
ui_manager.ensure_update()
53
manager = window.get_ui_manager()
54
manager.remove_ui( self._ui_id )
55
manager.remove_action_group( self._action_group )
56
manager.ensure_update()
107
58
# disconnect handlers
108
thumb_view = self.window.get_thumb_view()
109
thumb_view.disconnect( self.on_selection_change_id )
111
# remove status bar entry
112
statusbar = self.window.get_statusbar()
113
Gtk.Container.remove( statusbar, self.statusbar )
59
thumb_view = window.get_thumb_view()
60
thumb_view.disconnect( self._on_selection_change_id )
115
62
def on_selection_change( self, view, data ):
116
self.update_status( data )
118
def get_raw_filename_from_image( self, image ):
63
self.update_action_group_sensitivity( data )
65
def update_action_group_sensitivity( self, window ):
67
# do we have just the one selected image? we can't handle multiple
68
# images because EogThumbView.get_selected_images() doesn't work.
69
thumb_view = window.get_thumb_view()
70
self._action_group.set_sensitive( \
71
thumb_view.get_n_selected() == 1 )
73
def on_keep_raw_image( self, action ):
75
# do we have just the one selected image? we can't handle multiple
76
# images because EogThumbView.get_selected_images() doesn't work.
77
thumb_view = self._window.get_thumb_view()
78
if( thumb_view.get_n_selected() == 1 ):
81
image = thumb_view.get_first_selected_image()
83
self.keep_raw_image( image )
85
def keep_raw_image( self, image ):
119
87
fname = image.get_file().get_path()
121
# get the base fileanme (with no extension), read for searching
89
# strip the file extension off, ready to search for raw files
122
90
base_fname = image.get_file().get_path()
123
91
pos = base_fname.rfind( '.' )
126
# check if the extension of the current image makes it a raw file
127
for ext in self.raw_file_extensions + \
128
map( lambda x: x.upper(), self.raw_file_extensions ):
129
if( base_fname[ pos : ] == ext ):
132
# remove extension from base filename
133
93
base_fname = base_fname[ 0 : pos ]
135
95
# check for stupidity
136
96
if( base_fname[ -1 : None ] == '/' ):
139
# loop through valid raw file extensions, uppercase and lowercase
140
for ext in self.raw_file_extensions + \
141
map( lambda x: x.upper(), self.raw_file_extensions ):
143
# if the raw file exists, we found it
144
if( os.path.isfile( base_fname + '.' + ext ) ):
145
return os.path.basename( base_fname + '.' + ext );
147
# path the raw files will be moved to
97
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
98
gtk.BUTTONS_CLOSE, "Image is invalid!" )
103
# path the raw images will be moved to
148
104
raw_path = os.path.dirname( fname ) + '/raw';
150
# loop through valid raw file extensions, uppercase and lowercase
106
# loop through valid raw file extensions
151
108
for ext in self.raw_file_extensions + \
152
map( lambda x: x.upper(), self.raw_file_extensions ):
154
# if the raw file exists, we found it
155
if( os.path.isfile( os.path.dirname( fname ) + '/raw/' + \
156
os.path.basename( base_fname + '.' + ext ) ) ):
157
return os.path.basename( base_fname + '.' + ext );
162
def update_status( self, window ):
163
thumb_view = window.get_thumb_view()
165
# do we have just the one selected image? we can't handle multiple
166
# images because EogThumbView.get_selected_images() doesn't work.
167
self.action_group.set_sensitive( \
168
thumb_view.get_n_selected() == 1 )
170
# update the status bar
171
if( thumb_view.get_n_selected() > 0 ):
172
image = thumb_view.get_first_selected_image()
173
raw_fname = self.get_raw_filename_from_image( image )
174
path = os.path.dirname( image.get_file().get_path() )
175
self.statusbar.pop( 0 )
176
if( raw_fname is False ):
177
self.statusbar.push( 0, " " + _( 'raw: -' ) )
178
elif( os.path.isfile( path + '/' + raw_fname ) ):
179
self.statusbar.push( 0, " " + _( 'raw: unkept' ) )
181
self.statusbar.push( 0, " " + _( 'raw: keep' ) )
183
def do_keep_raw_file( self, action, window ):
185
# do we have just the one selected image? we can't handle multiple
186
# images because EogThumbView.get_selected_images() doesn't work.
187
thumb_view = window.get_thumb_view()
188
if( thumb_view.get_n_selected() == 1 ):
191
image = thumb_view.get_first_selected_image()
193
self.keep_raw_file( image )
196
self.update_status( window )
198
def do_unkeep_raw_file( self, action, window ):
200
# do we have just the one selected image? we can't handle multiple
201
# images because EogThumbView.get_selected_images() doesn't work.
202
thumb_view = window.get_thumb_view()
203
if( thumb_view.get_n_selected() == 1 ):
206
image = thumb_view.get_first_selected_image()
208
self.unkeep_raw_file( image )
211
self.update_status( window )
213
def keep_raw_file( self, image ):
215
raw_fname = self.get_raw_filename_from_image( image )
216
if( raw_fname is False ):
217
dialog = Gtk.MessageDialog( None, Gtk.DialogFlags.MODAL,
218
Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
219
_( 'Raw file not found!' ) )
220
dialog.format_secondary_text( _( "This image doesn't appear to " +
221
"have an accompanying raw file." ) )
226
# does raw file exist?
227
path = os.path.dirname( image.get_file().get_path() )
228
if( os.path.isfile( path + '/' + raw_fname ) ):
230
# create the raw directory, if it doesn't exist
231
if( not os.path.isdir( path + '/raw' ) ):
232
os.mkdir( path + '/raw' );
234
# move the raw file in to the raw directory
235
os.rename( path + '/' + raw_fname, path + '/raw/' + raw_fname )
237
def unkeep_raw_file( self, image ):
239
raw_fname = self.get_raw_filename_from_image( image )
240
if( raw_fname is False ):
241
dialog = Gtk.MessageDialog( None, Gtk.DialogFlags.MODAL,
242
Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
243
_( 'Raw file not found!' ) )
244
dialog.format_secondary_text( _( "This image doesn't appear to " +
245
"have an accompanying raw file." ) )
250
# does raw file exist?
251
path = os.path.dirname( image.get_file().get_path() )
252
if( os.path.isfile( path + '/raw/' + raw_fname ) ):
254
# move the raw file back to the parent directory
255
os.rename( path + '/raw/' + raw_fname, path + '/' + raw_fname )
257
# if the raw directory is empty, remove it
258
if( len( os.listdir( path + '/raw' ) ) == 0 ):
259
os.rmdir( path + '/raw' )
261
def do_delete_raw_files( self, action, window ):
263
# get path to first selected image, if there is one
264
thumb_view = window.get_thumb_view()
265
if( thumb_view.get_n_selected() == 1 ):
266
image = thumb_view.get_first_selected_image()
267
path = os.path.dirname( image.get_file().get_path() )
269
# build a regex that will match raw filenames
271
'.*\.(' + '|'.join( self.raw_file_extensions ) + ')', re.I )
273
# itterate through files in the dir
275
for file in os.listdir( path ):
276
if( regex.match( file ) ):
279
# do we have any files to delete?
280
if( len( files ) > 0 ):
282
# ask the user if they are sure
283
dialog = Gtk.MessageDialog( None, Gtk.DialogFlags.MODAL,
284
Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO,
285
_( 'Delete Raw Files?' ) )
286
if( len( files ) == 1 ):
287
subject = _( ' remaining raw file' )
289
subject = _( ' remaining raw files' )
290
dialog.format_secondary_text(
291
_( 'You are about to delete the ' ) +
292
str( len( files ) ) + subject +
293
_( " that you haven't specifically asked to keep from " +
294
"the directory that the current image is in.\n\n" +
295
"Do you want to continue?" ) )
296
result = dialog.run()
298
if( result != Gtk.ResponseType.YES ):
303
Gio.file_parse_name( path + '/' + file ).trash( None )
304
#os.unlink( path + '/' + file )
306
self.update_status( window )
308
# else, tell the user there aren't any raw files!
310
dialog = Gtk.MessageDialog( None, Gtk.DialogFlags.MODAL,
311
Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
312
_( 'No raw files to delete!' ) )
313
dialog.format_secondary_text(
314
_( 'There are no raw files to delete!' ) )
109
map( lambda x: x.upper(), self.raw_file_extensions ):
111
# calculate the name of the raw file and where we would move it to
112
src_fname = base_fname + '.' + ext
113
dst_fname = raw_path + '/' + os.path.basename( src_fname )
115
# look for existing files
116
if( os.path.isfile( src_fname ) ):
119
# create the raw directory, if it doesn't exist
120
if( not os.path.isdir( raw_path ) ):
121
os.mkdir( raw_path );
123
# move the raw file in to the raw directory
124
os.rename( src_fname, dst_fname )
126
# check for already-moved raw files
127
elif( os.path.isfile( dst_fname ) ):
130
# check we found the raw file
132
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
133
gtk.BUTTONS_CLOSE, "Raw file not found!" )
134
dialog.format_secondary_text( "This image doesn't appear to have an accompanying raw file." )