~ubuntu-branches/ubuntu/trusty/pitivi/trusty

« back to all changes in this revision

Viewing changes to pitivi/ui/sourcelist.py

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2011-07-07 13:43:47 UTC
  • mto: (6.1.9 sid) (1.2.12)
  • mto: This revision was merged to the branch mainline in revision 32.
  • Revision ID: james.westby@ubuntu.com-20110707134347-cari9kxjiakzej9z
Tags: upstream-0.14.1
ImportĀ upstreamĀ versionĀ 0.14.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
#
17
17
# You should have received a copy of the GNU Lesser General Public
18
18
# License along with this program; if not, write to the
19
 
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
 
# Boston, MA 02111-1307, USA.
 
19
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 
20
# Boston, MA 02110-1301, USA.
21
21
 
22
22
import gobject
23
23
import gst
85
85
            <placeholder name="SourceList" >
86
86
                <menuitem action="ImportSources" />
87
87
                <menuitem action="ImportSourcesFolder" />
 
88
                <separator />
 
89
                <menuitem action="SelectUnusedSources" />
88
90
                <menuitem action="RemoveSources" />
89
91
                <separator />
90
92
                <menuitem action="InsertEnd" />
102
104
INVISIBLE = gtk.gdk.pixbuf_new_from_file(os.path.join(get_pixmap_dir(),
103
105
    "invisible.png"))
104
106
 
 
107
 
105
108
class SourceList(gtk.VBox, Loggable):
106
109
    """ Widget for listing sources """
107
110
 
134
137
 
135
138
        # Popup Menu
136
139
        self.popup = gtk.Menu()
137
 
        self.popup_importitem = gtk.ImageMenuItem(_("Import clips..."))
 
140
        self.popup_importitem = gtk.ImageMenuItem(_("Import Files..."))
138
141
        image = gtk.Image()
139
142
        image.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_MENU)
140
143
        self.popup_importitem.set_image(image)
237
240
        txtlabel.set_line_wrap(True)
238
241
        txtlabel.set_line_wrap_mode(pango.WRAP_WORD)
239
242
        txtlabel.set_justify(gtk.JUSTIFY_CENTER)
240
 
        txtlabel.set_markup(
241
 
            _("<span>Import your clips by dragging them here or "
242
 
              "by using the buttons above.</span>"))
 
243
        txtlabel.set_text(
 
244
            _('Add media to your project by dragging files and folders here or '
 
245
              'by using the "Import Files..." button.'))
243
246
        self.infobar.add(txtlabel)
244
247
        self.txtlabel = txtlabel
245
248
 
256
259
        self._hide_infobar_btn = gtk.Button()
257
260
        self._hide_infobar_btn.set_label(_("Hide"))
258
261
        self._view_error_btn.connect("clicked", self._viewErrorsButtonClickedCb)
259
 
        self._hide_infobar_btn.connect("clicked",
260
 
                                        self._hideInfoBarClickedCb)
 
262
        self._hide_infobar_btn.connect("clicked", self._hideInfoBarClickedCb)
261
263
        content_area.add(self._warning_label)
262
264
        actions_area.add(self._view_error_btn)
263
265
        actions_area.add(self._hide_infobar_btn)
268
270
        # Connect to project.  We must remove and reset the callbacks when
269
271
        # changing project.
270
272
        self.project_signals = SignalGroup()
271
 
        self.app.connect("new-project-created",
272
 
            self._newProjectCreatedCb)
273
 
        self.app.connect("new-project-loaded",
274
 
            self._newProjectLoadedCb)
275
 
        self.app.connect("new-project-failed",
276
 
            self._newProjectFailedCb)
 
273
        self.app.connect("new-project-created", self._newProjectCreatedCb)
 
274
        self.app.connect("new-project-loaded", self._newProjectLoadedCb)
 
275
        self.app.connect("new-project-failed", self._newProjectFailedCb)
277
276
 
278
277
        # default pixbufs
279
278
        self.audiofilepixbuf = self._getIcon("audio-x-generic", "pitivi-sound.png")
285
284
                           gtk.gdk.ACTION_COPY)
286
285
        self.connect("drag_data_received", self._dndDataReceivedCb)
287
286
 
288
 
        self.treeview.drag_source_set(0,[], gtk.gdk.ACTION_COPY)
 
287
        self.treeview.drag_source_set(0, [], gtk.gdk.ACTION_COPY)
289
288
        self.treeview.connect("motion-notify-event",
290
289
            self._treeViewMotionNotifyEventCb)
291
290
        self.treeview.connect("button-release-event",
293
292
        self.treeview.connect("drag_begin", self._dndDragBeginCb)
294
293
        self.treeview.connect("drag_data_get", self._dndDataGetCb)
295
294
 
296
 
        self.iconview.drag_source_set(0,[], gtk.gdk.ACTION_COPY)
 
295
        self.iconview.drag_source_set(0, [], gtk.gdk.ACTION_COPY)
297
296
        self.iconview.connect("motion-notify-event",
298
297
            self._iconViewMotionNotifyEventCb)
299
298
        self.iconview.connect("button-release-event",
306
305
 
307
306
        # always available
308
307
        actions = (
309
 
            ("ImportSources", gtk.STOCK_ADD, _("_Import clips..."),
310
 
                None, _("Import clips to use"), self._importSourcesCb),
 
308
            ("ImportSources", gtk.STOCK_ADD, _("_Import Files..."),
 
309
                None, _("Add media files to your project"),
 
310
                self._importSourcesCb),
311
311
            ("ImportSourcesFolder", gtk.STOCK_ADD,
312
 
                _("Import _folder of clips..."), None,
313
 
                _("Import folder of clips to use"), self._importSourcesFolderCb),
 
312
                _("Import _Folders..."), None,
 
313
                _("Add the contents of a folder as clips in your project"),
 
314
                self._importSourcesFolderCb),
 
315
            ("SelectUnusedSources", None, _("Select Unused Media"), None,
 
316
                _("Select clips that have not been used in the project"),
 
317
                self._selectUnusedSourcesCb),
314
318
        )
315
319
 
316
320
        # only available when selection is non-empty
317
321
        selection_actions = (
318
322
            ("RemoveSources", gtk.STOCK_DELETE,
319
 
                _("_Remove from project"), "<Control>Delete", None,
 
323
                _("_Remove from Project"), "<Control>Delete", None,
320
324
                self._removeSourcesCb),
321
325
            ("InsertEnd", gtk.STOCK_COPY,
322
 
                _("Insert at _end of timeline"), "Insert", None,
 
326
                _("Insert at _End of Timeline"), "Insert", None,
323
327
                self._insertEndCb),
324
328
        )
325
329
 
384
388
    def _removeSourcesCb(self, unused_action):
385
389
        self._removeSources()
386
390
 
 
391
    def _selectUnusedSourcesCb(self, widget):
 
392
        self._selectUnusedSources()
 
393
 
387
394
    def _insertEndCb(self, unused_action):
388
395
        self.app.action_log.begin("add clip")
389
396
        timeline = self.app.current.timeline
397
404
            start += source.duration
398
405
        self.app.action_log.commit()
399
406
 
400
 
    def searchEntryChangedCb (self, entry):
 
407
    def searchEntryChangedCb(self, entry):
401
408
        self.modelFilter.refilter()
402
409
 
403
 
    def searchEntryIconClickedCb (self, entry, unused, unsed1):
 
410
    def searchEntryIconClickedCb(self, entry, unused, unsed1):
404
411
        entry.set_text("")
405
412
 
406
413
    def searchEntryDeactivateCb(self, entry, event):
416
423
        """
417
424
        text = data.get_text().lower()
418
425
        if text == "":
419
 
            return True # Avoid silly warnings
 
426
            return True  # Avoid silly warnings
420
427
        else:
421
428
            return text in model.get_value(iter, COL_INFOTEXT).lower()
422
429
 
453
460
        self.project_signals.connect(
454
461
            project.sources, "starting", None, self._sourcesStartedImportingCb)
455
462
 
456
 
 
457
 
 
458
463
    def _setClipView(self, show):
459
464
        """ Set which clip view to use when sourcelist is showing clips. If
460
465
        none is given, the current one is used. Show: one of SHOW_TREEVIEW or
507
512
 
508
513
        if select_folders:
509
514
            chooser_action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER
510
 
            dialogtitle = _("Import a folder")
 
515
            dialogtitle = _("Select One or More Folders")
511
516
        else:
512
517
            chooser_action = gtk.FILE_CHOOSER_ACTION_OPEN
513
 
            dialogtitle = _("Import a clip")
 
518
            dialogtitle = _("Select One or More Files")
514
519
        close_after = gtk.CheckButton(_("Close after importing files"))
515
520
        close_after.set_active(self.app.settings.closeImportDialog)
516
521
 
533
538
        self._importDialog.connect('close', self._dialogBoxCloseCb)
534
539
        self._importDialog.show()
535
540
 
536
 
    def addUris(self, files):
537
 
        """ Add files to the list """
538
 
        try:
539
 
            self.app.current.sources.addUris(files)
540
 
        except SourceListError as error:
541
 
            disclaimer, uri = error.args
542
 
            self.error("'%s' is already present in the source list." + uri)
543
 
 
544
541
    def addFolders(self, folders):
545
542
        """ walks the trees of the folders in the list and adds the files it finds """
546
543
        self.app.threads.addThread(PathWalker, folders, self.app.current.sources.addUris)
652
649
        self._progressbar.hide()
653
650
        if self._errors:
654
651
            if len(self._errors) > 1:
655
 
                self._warning_label.set_text(_("Errors occured while importing."))
 
652
                self._warning_label.set_text(_("Errors occurred while importing."))
656
653
                self._view_error_btn.set_label(_("View errors"))
657
654
            else:
658
 
                self._warning_label.set_text(_("An error occured while importing."))
 
655
                self._warning_label.set_text(_("An error occurred while importing."))
659
656
                self._view_error_btn.set_label(_("View error"))
660
657
 
661
658
            self._import_warning_infobar.show_all()
663
660
    ## Error Dialog Box callbacks
664
661
 
665
662
    def _errorDialogBoxCloseCb(self, unused_dialog):
666
 
        self._error_dialogbox.destroy()
 
663
        self._error_dialogbox.window.destroy()
667
664
        self._error_dialogbox = None
668
665
 
669
666
    def _errorDialogBoxResponseCb(self, unused_dialog, unused_response):
670
 
        self._error_dialogbox.destroy()
 
667
        self._error_dialogbox.window.destroy()
671
668
        self._error_dialogbox = None
672
669
 
673
670
    ## Import Sources Dialog Box callbacks
683
680
            if select_folders:
684
681
                self.addFolders(filenames)
685
682
            else:
686
 
                self.addUris(filenames)
 
683
                self.app.current.sources.addUris(filenames)
687
684
            if self.app.settings.closeImportDialog:
688
685
                dialogbox.destroy()
689
686
                self._importDialog = None
712
709
            self.app.current.sources.removeUri(uri)
713
710
        self.app.action_log.commit()
714
711
 
 
712
    def _selectUnusedSources(self):
 
713
        """
 
714
        Select, in the media library, unused sources in the project.
 
715
        """
 
716
        sources = self.app.current.sources.getSources()
 
717
        unused_sources_uris = []
 
718
 
 
719
        model = self.storemodel
 
720
        selection = self.treeview.get_selection()
 
721
        for source in sources:
 
722
            if not self.app.current.timeline.usesFactory(source):
 
723
                unused_sources_uris.append(source.uri)
 
724
 
 
725
        # Hack around the fact that making selections (in a treeview/iconview)
 
726
        # deselects what was previously selected
 
727
        if self.clip_view == SHOW_TREEVIEW:
 
728
            self.treeview.get_selection().select_all()
 
729
        elif self.clip_view == SHOW_ICONVIEW:
 
730
            self.iconview.select_all()
 
731
 
 
732
        for row in model:
 
733
            if row[COL_URI] not in unused_sources_uris:
 
734
                if self.clip_view == SHOW_TREEVIEW:
 
735
                    selection.unselect_iter(row.iter)
 
736
                else:
 
737
                    self.iconview.unselect_path(row.path)
 
738
 
715
739
    ## UI Button callbacks
716
740
 
717
741
    def _importButtonClickedCb(self, unused_widget=None):
735
759
        self.emit('play', factory)
736
760
 
737
761
    def _hideInfoBarClickedCb(self, unused_button):
 
762
        self._resetErrorList()
 
763
 
 
764
    def _resetErrorList(self):
738
765
        self._errors = []
739
766
        self._import_warning_infobar.hide()
740
767
 
753
780
        self._error_dialogbox.connect("response", self._errorDialogBoxResponseCb)
754
781
        for uri, reason, extra in self._errors:
755
782
            self._error_dialogbox.addFailedFile(uri, reason, extra)
756
 
        self._error_dialogbox.show()
757
 
        self._errors = []  # Reset the error list (since the user has read them)
758
 
        self._import_warning_infobar.hide()
 
783
        self._error_dialogbox.window.show()
 
784
        # Reset the error list, since the user has read them.
 
785
        self._resetErrorList()
759
786
 
760
787
    def _treeViewMenuItemToggledCb(self, unused_widget):
761
788
        if self.treeview_menuitem.get_active():
972
999
        return False
973
1000
 
974
1001
    def _newProjectCreatedCb(self, app, project):
975
 
        # clear the storemodel
 
1002
        self._resetErrorList()
976
1003
        self.storemodel.clear()
977
1004
        self._connectToProject(project)
978
1005
 
979
1006
    def _newProjectLoadedCb(self, unused_pitivi, project):
980
1007
        pass
981
1008
 
982
 
    def _newProjectFailedCb(self, unused_pitivi, unused_reason,
983
 
        unused_uri):
 
1009
    def _newProjectFailedCb(self, unused_pitivi, unused_reason, unused_uri):
984
1010
        self.storemodel.clear()
985
1011
        self.project_signals.disconnectAll()
986
1012
 
987
 
 
988
1013
    ## Drag and Drop
989
 
 
990
1014
    def _dndDataReceivedCb(self, unused_widget, unused_context, unused_x,
991
1015
                           unused_y, selection, targettype, unused_time):
992
1016
        def get_file_type(path):
994
1018
                if os.path.isfile(path[7:]):
995
1019
                    return LOCAL_FILE
996
1020
                return LOCAL_DIR
997
 
            elif "://" in path: #we concider it is a remote file
 
1021
            elif "://" in path:  # we concider it is a remote file
998
1022
                return REMOTE_FILE
999
1023
            return NOT_A_FILE
1000
1024
 
1001
 
 
1002
1025
        self.debug("targettype:%d, selection.data:%r", targettype, selection.data)
1003
1026
        directories = []
1004
1027
        if targettype == dnd.TYPE_URI_LIST:
1029
1052
            #TODO waiting for remote files downloader support to be implemented
1030
1053
            pass
1031
1054
 
1032
 
        try:
1033
 
            self.addUris([quote_uri(uri) for uri in filenames])
1034
 
        except SourceListError:
1035
 
            # filenames already present in the sourcelist
1036
 
            pass
 
1055
        uris = [quote_uri(uri) for uri in filenames]
 
1056
        self.app.current.sources.addUris(uris)
1037
1057
 
1038
1058
    #used with TreeView and IconView
1039
1059
    def _dndDragBeginCb(self, view, context):