/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 raw-tools.py

  • Committer: edam
  • Date: 2011-04-05 17:16:57 UTC
  • Revision ID: edam@waxworlds.org-20110405171657-uqvfkft9zvr7it6p
initial comit

Show diffs side-by-side

added added

removed removed

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
import eog, gtk, os
 
2
 
 
3
class HelloWorldPlugin(eog.Plugin):
29
4
 
30
5
    raw_file_extensions = [ 'cr2', '3fr', 'ari', 'arw', 'srf', 'sr2', 'bay',
31
6
        'crw', 'cr2', 'cap', 'iiq', 'eip', 'dcs', 'dcr', 'drf', 'k25', 'kdc',
40
15
 
41
16
        # insert menu item
42
17
        manager = window.get_ui_manager()
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" ),
 
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" ),
47
22
            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 ) ] )
56
23
        manager.insert_action_group( self._action_group, -1 )
57
24
        self._ui_id = manager.add_ui_from_string( """
58
25
            <ui>
59
26
                <menubar name="MainMenu">
60
27
                    <menu name="ToolsMenu" action="Tools">
61
28
                        <separator />
62
 
                        <menuitem name="EogPluginRunKeepRaw"
 
29
                        <menuitem name="EogPluginRawTools"
63
30
                            action="EogPluginRunKeepRaw" />
64
 
                        <menuitem name="EogPluginRunUnkeepRaw"
65
 
                            action="EogPluginRunUnkeepRaw" />
66
 
                        <menuitem name="EogPluginRunDeleteRaw"
67
 
                            action="EogPluginRunDeleteRaw" />
68
31
                        <separator />
69
32
                    </menu>
70
33
                </menubar>
76
39
            </ui>
77
40
        """ )
78
41
 
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
 
 
87
42
        # connect to selection change
88
43
        thumb_view = window.get_thumb_view()
89
44
        self._on_selection_change_id = thumb_view.connect_after( \
90
 
            'selection_changed', self.on_selection_change, window )
 
45
            "selection_changed", self.on_selection_change, window )
91
46
 
92
47
        # init ui state
93
 
        self.update_status( window )
 
48
        self.update_action_group_sensitivity( window )
94
49
 
95
50
    def deactivate( self, window ):
96
51
 
97
 
        # disconnect handlers
98
 
        thumb_view = window.get_thumb_view()
99
 
        thumb_view.disconnect( self._on_selection_change_id )
100
 
 
101
52
        # remove menu items
102
53
        manager = window.get_ui_manager()
103
54
        manager.remove_ui( self._ui_id )
104
55
        manager.remove_action_group( self._action_group )
105
56
        manager.ensure_update()
106
57
 
107
 
        # remove status bar entry
108
 
        statusbar = window.get_statusbar()
109
 
        statusbar.remove( self._statusbar )
 
58
        # disconnect handlers
 
59
        thumb_view = window.get_thumb_view()
 
60
        thumb_view.disconnect( self._on_selection_change_id )
110
61
 
111
62
    def on_selection_change( self, view, data ):
112
 
        self.update_status( data )
113
 
 
114
 
    def get_raw_filename_from_image( self, image ):
 
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
 
115
87
        fname = image.get_file().get_path()
116
88
 
117
 
        # get the base fileanme (with no extension), read for searching
 
89
        # strip the file extension off, ready to search for raw files
118
90
        base_fname = image.get_file().get_path()
119
91
        pos = base_fname.rfind( '.' )
120
92
        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
129
93
            base_fname = base_fname[ 0 : pos ]
130
94
        
131
95
        # check for stupidity
132
96
        if( base_fname[ -1 : None ] == '/' ):
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 );
 
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
142
102
 
143
103
        # path the raw images will be moved to
144
104
        raw_path = os.path.dirname( fname ) + '/raw';
145
105
 
146
 
        # loop through valid raw file extensions, uppercase and lowercase
 
106
        # loop through valid raw file extensions
 
107
        found = False;
147
108
        for ext in self.raw_file_extensions + \
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()
 
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