/gtk/eog-manage-raws

To get this branch, use:
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()