/gtk/eog-manage-raws

To get this branch, use:
bzr branch http://bzr.ed.am/gtk/eog-manage-raws

« back to all changes in this revision

Viewing changes to src/raw-tools.py

  • Committer: edam
  • Date: 2011-09-22 21:53:20 UTC
  • Revision ID: edam@waxworlds.org-20110922215320-4by9fw8fvmiul2wp
- added some files required for release

Show diffs side-by-side

added added

removed removed

1
 
import eog, gtk, os
2
 
 
3
 
class HelloWorldPlugin(eog.Plugin):
 
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):
4
29
 
5
30
    raw_file_extensions = [ 'cr2', '3fr', 'ari', 'arw', 'srf', 'sr2', 'bay',
6
31
        'crw', 'cr2', 'cap', 'iiq', 'eip', 'dcs', 'dcr', 'drf', 'k25', 'kdc',
15
40
 
16
41
        # insert menu item
17
42
        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" ),
 
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" ),
22
47
            self.on_keep_raw_image ) ] )
 
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 ) ] )
 
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 ) ] )
23
56
        manager.insert_action_group( self._action_group, -1 )
24
57
        self._ui_id = manager.add_ui_from_string( """
25
58
            <ui>
26
59
                <menubar name="MainMenu">
27
60
                    <menu name="ToolsMenu" action="Tools">
28
61
                        <separator />
29
 
                        <menuitem name="EogPluginRawTools"
 
62
                        <menuitem name="EogPluginRunKeepRaw"
30
63
                            action="EogPluginRunKeepRaw" />
 
64
                        <menuitem name="EogPluginRunUnkeepRaw"
 
65
                            action="EogPluginRunUnkeepRaw" />
 
66
                        <menuitem name="EogPluginRunDeleteRaw"
 
67
                            action="EogPluginRunDeleteRaw" />
31
68
                        <separator />
32
69
                    </menu>
33
70
                </menubar>
39
76
            </ui>
40
77
        """ )
41
78
 
 
79
        # insert status bar
 
80
        self._statusbar = gtk.Statusbar()
 
81
        self._statusbar.set_has_resize_grip( False )
 
82
        self._statusbar.set_size_request( 80, 10 )
 
83
        statusbar = window.get_statusbar()
 
84
        statusbar.pack_end( self._statusbar, False, False, 0 );
 
85
        self._statusbar.show()
 
86
 
42
87
        # connect to selection change
43
88
        thumb_view = window.get_thumb_view()
44
89
        self._on_selection_change_id = thumb_view.connect_after( \
45
 
            "selection_changed", self.on_selection_change, window )
 
90
            'selection_changed', self.on_selection_change, window )
46
91
 
47
92
        # init ui state
48
 
        self.update_action_group_sensitivity( window )
 
93
        self.update_status( window )
49
94
 
50
95
    def deactivate( self, window ):
51
96
 
 
97
        # disconnect handlers
 
98
        thumb_view = window.get_thumb_view()
 
99
        thumb_view.disconnect( self._on_selection_change_id )
 
100
 
52
101
        # remove menu items
53
102
        manager = window.get_ui_manager()
54
103
        manager.remove_ui( self._ui_id )
55
104
        manager.remove_action_group( self._action_group )
56
105
        manager.ensure_update()
57
106
 
58
 
        # disconnect handlers
59
 
        thumb_view = window.get_thumb_view()
60
 
        thumb_view.disconnect( self._on_selection_change_id )
 
107
        # remove status bar entry
 
108
        statusbar = window.get_statusbar()
 
109
        statusbar.remove( self._statusbar )
61
110
 
62
111
    def on_selection_change( self, view, data ):
63
 
        self.update_action_group_sensitivity( data )
64
 
 
65
 
    def update_action_group_sensitivity( self, window ):
66
 
 
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 )
72
 
 
73
 
    def on_keep_raw_image( self, action ):
74
 
 
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 ):
79
 
 
80
 
            # get the image
81
 
            image = thumb_view.get_first_selected_image()
82
 
            if( image != None ):
83
 
                self.keep_raw_image( image )
84
 
 
85
 
    def keep_raw_image( self, image ):
86
 
 
 
112
        self.update_status( data )
 
113
 
 
114
    def get_raw_filename_from_image( self, image ):
87
115
        fname = image.get_file().get_path()
88
116
 
89
 
        # strip the file extension off, ready to search for raw files
 
117
        # get the base fileanme (with no extension), read for searching
90
118
        base_fname = image.get_file().get_path()
91
119
        pos = base_fname.rfind( '.' )
92
120
        if( pos != -1 ):
 
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
93
129
            base_fname = base_fname[ 0 : pos ]
94
130
        
95
131
        # check for stupidity
96
132
        if( base_fname[ -1 : None ] == '/' ):
97
 
            dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
98
 
                gtk.BUTTONS_CLOSE, "Image is invalid!" )
99
 
            dialog.run()
100
 
            dialog.destroy()
101
 
            return
 
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 );
102
142
 
103
143
        # path the raw images will be moved to
104
144
        raw_path = os.path.dirname( fname ) + '/raw';
105
145
 
106
 
        # loop through valid raw file extensions
107
 
        found = False;
 
146
        # loop through valid raw file extensions, uppercase and lowercase
108
147
        for ext in self.raw_file_extensions + \
109
 
             map( lambda x: x.upper(), self.raw_file_extensions ):
110
 
 
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 )
114
 
 
115
 
            # look for existing files
116
 
            if( os.path.isfile( src_fname ) ):
117
 
                found = True;
118
 
 
119
 
                # create the raw directory, if it doesn't exist
120
 
                if( not os.path.isdir( raw_path ) ):
121
 
                    os.mkdir( raw_path );
122
 
 
123
 
                # move the raw file in to the raw directory
124
 
                os.rename( src_fname, dst_fname )
125
 
 
126
 
            # check for already-moved raw files
127
 
            elif( os.path.isfile( dst_fname ) ):
128
 
                found = True;
129
 
 
130
 
        # check we found the raw file
131
 
        if( not found ):
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." )
135
 
            dialog.run()
136
 
            dialog.destroy()
137
 
            return
 
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 ) ):
 
175
                self._statusbar.push( 0, _( 'raw: unkept' ) )
 
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
 
 
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
 
 
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." ) )
 
218
            dialog.run()
 
219
            dialog.destroy()
 
220
            return
 
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
 
 
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
 
 
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:
 
299
                    gio.file_parse_name( path + '/' + file ).trash()
 
300
                    #os.unlink( path + '/' + file )
 
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()