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.
85
85
<placeholder name="SourceList" >
86
86
<menuitem action="ImportSources" />
87
87
<menuitem action="ImportSourcesFolder" />
89
<menuitem action="SelectUnusedSources" />
88
90
<menuitem action="RemoveSources" />
90
92
<menuitem action="InsertEnd" />
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)
241
_("<span>Import your clips by dragging them here or "
242
"by using the buttons above.</span>"))
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
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)
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)
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)
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",
307
306
# always available
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),
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),
384
388
def _removeSourcesCb(self, unused_action):
385
389
self._removeSources()
391
def _selectUnusedSourcesCb(self, widget):
392
self._selectUnusedSources()
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()
400
def searchEntryChangedCb (self, entry):
407
def searchEntryChangedCb(self, entry):
401
408
self.modelFilter.refilter()
403
def searchEntryIconClickedCb (self, entry, unused, unsed1):
410
def searchEntryIconClickedCb(self, entry, unused, unsed1):
404
411
entry.set_text("")
406
413
def searchEntryDeactivateCb(self, entry, event):
417
424
text = data.get_text().lower()
419
return True # Avoid silly warnings
426
return True # Avoid silly warnings
421
428
return text in model.get_value(iter, COL_INFOTEXT).lower()
453
460
self.project_signals.connect(
454
461
project.sources, "starting", None, self._sourcesStartedImportingCb)
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
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")
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)
533
538
self._importDialog.connect('close', self._dialogBoxCloseCb)
534
539
self._importDialog.show()
536
def addUris(self, files):
537
""" Add files to the list """
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)
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()
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"))
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"))
661
658
self._import_warning_infobar.show_all()
663
660
## Error Dialog Box callbacks
665
662
def _errorDialogBoxCloseCb(self, unused_dialog):
666
self._error_dialogbox.destroy()
663
self._error_dialogbox.window.destroy()
667
664
self._error_dialogbox = None
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
673
670
## Import Sources Dialog Box callbacks
712
709
self.app.current.sources.removeUri(uri)
713
710
self.app.action_log.commit()
712
def _selectUnusedSources(self):
714
Select, in the media library, unused sources in the project.
716
sources = self.app.current.sources.getSources()
717
unused_sources_uris = []
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)
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()
733
if row[COL_URI] not in unused_sources_uris:
734
if self.clip_view == SHOW_TREEVIEW:
735
selection.unselect_iter(row.iter)
737
self.iconview.unselect_path(row.path)
715
739
## UI Button callbacks
717
741
def _importButtonClickedCb(self, unused_widget=None):
735
759
self.emit('play', factory)
737
761
def _hideInfoBarClickedCb(self, unused_button):
762
self._resetErrorList()
764
def _resetErrorList(self):
738
765
self._errors = []
739
766
self._import_warning_infobar.hide()
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()
760
787
def _treeViewMenuItemToggledCb(self, unused_widget):
761
788
if self.treeview_menuitem.get_active():
974
1001
def _newProjectCreatedCb(self, app, project):
975
# clear the storemodel
1002
self._resetErrorList()
976
1003
self.storemodel.clear()
977
1004
self._connectToProject(project)
979
1006
def _newProjectLoadedCb(self, unused_pitivi, project):
982
def _newProjectFailedCb(self, unused_pitivi, unused_reason,
1009
def _newProjectFailedCb(self, unused_pitivi, unused_reason, unused_uri):
984
1010
self.storemodel.clear()
985
1011
self.project_signals.disconnectAll()
988
1013
## Drag and Drop
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
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
1033
self.addUris([quote_uri(uri) for uri in filenames])
1034
except SourceListError:
1035
# filenames already present in the sourcelist
1055
uris = [quote_uri(uri) for uri in filenames]
1056
self.app.current.sources.addUris(uris)
1038
1058
#used with TreeView and IconView
1039
1059
def _dndDragBeginCb(self, view, context):