internal static bool ConfirmUserAction(int tracks_to_remove) { string header = String.Format( Catalog.GetPluralString( // singular form unused b/c we know it's > 1, but we still need GetPlural "The sync operation will remove one track from your device.", "The sync operation will remove {0} tracks from your device.", tracks_to_remove), tracks_to_remove); string message = Catalog.GetString("Are you sure you want to continue?"); var md = new HigMessageDialog( ServiceManager.Get <GtkElementsService> ().PrimaryWindow, DialogFlags.DestroyWithParent, MessageType.Warning, ButtonsType.None, header, message ); md.AddButton("gtk-cancel", ResponseType.No, true); md.AddButton(Catalog.GetString("Remove tracks"), ResponseType.Yes, false); bool remove_tracks = false; ThreadAssist.BlockingProxyToMain(() => { try { if (md.Run() == (int)ResponseType.Yes) { remove_tracks = true; } } finally { md.Destroy(); } }); return(remove_tracks); }
public static bool ConfirmRemove(string header) { string message = Catalog.GetString("Are you sure you want to continue?"); bool remove_tracks = false; ThreadAssist.BlockingProxyToMain(() => { var md = new HigMessageDialog( ServiceManager.Get <GtkElementsService> ().PrimaryWindow, DialogFlags.DestroyWithParent, MessageType.Warning, ButtonsType.None, header, message ); md.AddButton("gtk-cancel", ResponseType.No, true); md.AddButton(Catalog.GetString("Remove tracks"), ResponseType.Yes, false); try { if (md.Run() == (int)ResponseType.Yes) { remove_tracks = true; } } finally { md.Destroy(); } }); return(remove_tracks); }
protected void Initialize(bool active) { base.Initialize(); ThreadAssist.BlockingProxyToMain(() => { if (!active) { ClearChildSources(); Properties.Set <ISourceContents> ("Nereid.SourceContents", new InactiveDapContent(this)); } DapContent.UpdateActions(); }); }
private void OnSourceUpdated(object o, EventArgs args) { ThreadAssist.BlockingProxyToMain(delegate { try { if (source == null || source.Sync.Syncing) { return; } UpdateUsage(); } catch (Exception e) { Log.Error(e); } }); }
public void PasswordProvider(PdfPasswordProviderArgs args) { // This method is called from some random thread, but we need // to do the dialog on the GUI thread; use the reset_event // to block this thread until the user is done with the dialog. ThreadAssist.BlockingProxyToMain(delegate { Log.Debug("Password requested to open document"); var dialog = new Hyena.Widgets.HigMessageDialog( Window, DialogFlags.Modal, MessageType.Question, ButtonsType.None, Catalog.GetString("Document is Encrypted"), Catalog.GetString("Enter the document's password to open it:") ); dialog.Image = Gtk.IconTheme.Default.LoadIcon("dialog-password", 48, 0); var password_entry = new Entry() { Visibility = false }; password_entry.Show(); dialog.LabelVBox.PackStart(password_entry, false, false, 12); dialog.AddButton(Stock.Cancel, ResponseType.Cancel, false); dialog.AddButton(Stock.Ok, ResponseType.Ok, true); var response = (ResponseType)dialog.Run(); string password = password_entry.Text; dialog.Destroy(); if (response == ResponseType.Ok) { args.Password = Document.Password = password; } else { Log.Information("Password dialog cancelled"); args.Abort = true; } }); }
public override void LoadPath(string path, string suggestedFilename, System.Action finishedCallback) { lock (this) { // One document per window if (loading || Document != null) { new Client().LoadPath(path, suggestedFilename); return; } loading = true; } if (!path.StartsWith("file://")) { path = System.IO.Path.GetFullPath(path); } Configuration.LastOpenFolder = System.IO.Path.GetDirectoryName(suggestedFilename ?? path); status_label.Text = Catalog.GetString("Loading document..."); ThreadAssist.SpawnFromMain(delegate { try { Document = new Document(); Document.Load(path, PasswordProvider, suggestedFilename != null); if (suggestedFilename != null) { Document.SuggestedSavePath = suggestedFilename; } ThreadAssist.BlockingProxyToMain(delegate { IconView.SetDocument(Document); BookmarkView.SetDocument(Document); RecentManager.Default.AddItem(Document.Uri); Document.Changed += UpdateForDocument; UpdateForDocument(); OnDocumentLoaded(); }); } catch (Exception e) { Document = null; ThreadAssist.BlockingProxyToMain(delegate { status_label.Text = ""; if (e is System.IO.FileNotFoundException) { try { RecentManager.Default.RemoveItem(new Uri(path).AbsoluteUri); } catch {} } }); Hyena.Log.Exception(e); Hyena.Log.Error( Catalog.GetString("Error Loading Document"), String.Format(Catalog.GetString("There was an error loading {0}"), GLib.Markup.EscapeText(path ?? "")), true ); } finally { lock (this) { loading = false; } if (finishedCallback != null) { finishedCallback(); } } }); }
protected override void AddTrackToDevice(DatabaseTrackInfo track, SafeUri fromUri) { if (track.PrimarySourceId == DbId) { return; } lock (mtp_device) { Track mtp_track = TrackInfoToMtpTrack(track, fromUri); bool video = track.HasAttribute(TrackMediaAttributes.VideoStream); Folder folder = GetFolderForTrack(track); mtp_device.UploadTrack(fromUri.LocalPath, mtp_track, folder, OnUploadProgress); // Add/update album art if (!video) { string key = MakeAlbumKey(track); if (!album_cache.ContainsKey(key)) { // LIBMTP 1.0.3 BUG WORKAROUND // In libmtp.c the 'LIBMTP_Create_New_Album' function invokes 'create_new_abstract_list'. // The latter calls strlen on the 'name' parameter without null checking. If AlbumTitle is // null, this causes a sigsegv. Lets be safe and always pass non-null values. Album album = new Album(mtp_device, track.AlbumTitle ?? "", track.AlbumArtist ?? "", track.Genre ?? "", track.Composer ?? ""); album.AddTrack(mtp_track); if (supports_jpegs && can_sync_albumart) { ArtworkManager art = ServiceManager.Get <ArtworkManager> (); Exception ex = null; Gdk.Pixbuf pic = null; byte[] bytes = null; uint width = 0, height = 0; ThreadAssist.BlockingProxyToMain(() => { try { pic = art.LookupScalePixbuf(track.ArtworkId, thumb_width); if (pic != null) { bytes = pic.SaveToBuffer("jpeg"); width = (uint)pic.Width; height = (uint)pic.Height; } } catch (Exception e) { ex = e; } }); try { if (ex != null) { throw ex; } if (bytes != null) { ArtworkManager.DisposePixbuf(pic); album.Save(bytes, width, height); album_cache [key] = Tuple.Create(album, folder); } } catch (Exception e) { Log.Debug("Failed to create MTP Album", e.Message); } } else { album.Save(); album_cache[key] = Tuple.Create(album, folder); } } else { Album album = album_cache[key].Item1; album.AddTrack(mtp_track); album.Save(); } } MtpTrackInfo new_track = new MtpTrackInfo(mtp_device, mtp_track); new_track.PrimarySource = this; new_track.Save(false); track_map[new_track.TrackId] = mtp_track; } }
private void RateLimitedSync() { syncing = true; bool sync_playlists = false; if (dap.SupportsPlaylists) { foreach (DapLibrarySync library_sync in library_syncs) { if (library_sync.Library.SupportsPlaylists) { sync_playlists = true; break; } } } if (sync_playlists) { dap.RemovePlaylists(); } foreach (DapLibrarySync library_sync in library_syncs) { try { library_sync.Sync(); } catch (DapLibrarySync.PossibleUserErrorException e) { string header = String.Format( Catalog.GetPluralString( // singular form unused b/c we know it's > 1, but we still need GetPlural "The sync operation will remove one track from your device.", "The sync operation will remove {0} tracks from your device.", e.TracksToRemove), e.TracksToRemove); string message = Catalog.GetString("Are you sure you want to continue?"); HigMessageDialog md = new HigMessageDialog( ServiceManager.Get <GtkElementsService> ().PrimaryWindow, DialogFlags.DestroyWithParent, MessageType.Warning, ButtonsType.None, header, message ); md.AddButton("gtk-cancel", ResponseType.No, true); md.AddButton(Catalog.GetString("Remove tracks"), ResponseType.Yes, false); bool remove_tracks = false; ThreadAssist.BlockingProxyToMain(() => { try { if (md.Run() == (int)ResponseType.Yes) { remove_tracks = true; } } finally { md.Destroy(); } }); if (remove_tracks) { library_sync.Sync(true); } } } if (sync_playlists) { dap.SyncPlaylists(); } syncing = false; }
protected override void Initialize() { PurgeTemporaryPlaylists(); base.Initialize(); Expanded = true; Properties.SetStringList("Icon.Name", GetIconNames()); Properties.Set <string> ("SourcePropertiesActionLabel", Catalog.GetString("Device Properties")); Properties.Set <OpenPropertiesDelegate> ("SourceProperties.GuiHandler", delegate { new DapPropertiesDialog(this).RunDialog(); }); Properties.Set <bool> ("Nereid.SourceContents.HeaderVisible", false); Properties.Set <bool> ("Nereid.SourceContents.FooterVisible", false); Properties.Set <System.Reflection.Assembly> ("ActiveSourceUIResource.Assembly", System.Reflection.Assembly.GetExecutingAssembly()); Properties.SetString("ActiveSourceUIResource", "ActiveSourceUI.xml"); sync = new DapSync(this); if (String.IsNullOrEmpty(GenericName)) { GenericName = Catalog.GetString("Media Player"); } if (String.IsNullOrEmpty(Name)) { Name = device.Name; } AddDapProperty(Catalog.GetString("Product"), device.Product); AddDapProperty(Catalog.GetString("Vendor"), device.Vendor); if (acceptable_mimetypes == null) { acceptable_mimetypes = HasMediaCapabilities ? MediaCapabilities.PlaybackMimeTypes : null; if (acceptable_mimetypes == null || acceptable_mimetypes.Length == 0) { acceptable_mimetypes = new string [] { "taglib/mp3" }; } } AddChildSource(music_group_source = new MusicGroupSource(this)); // We want the group sources to be on top of the list, with Music first music_group_source.Order = -30; if (SupportsVideo) { video_group_source = new VideoGroupSource(this); video_group_source.Order = -20; } if (SupportsPodcasts) { podcast_group_source = new PodcastGroupSource(this); podcast_group_source.Order = -10; } BuildPreferences(); ThreadAssist.BlockingProxyToMain(delegate { Properties.Set <Gtk.Widget> ("Nereid.SourceContents.FooterWidget", dap_info_bar = new DapInfoBar(this)); Properties.Set <Banshee.Sources.Gui.ISourceContents> ("Nereid.SourceContents", dap_properties_display = new DapContent(this)); }); }
private void UpdateForQuery(Feed <Video> video_feed) { int result_display_count = 0; var tiles = new List <YouTubeTileData> (); bool cleanup; if (video_feed.TotalResults > 0) { cleanup = !showing_results; foreach (Video entry in video_feed.Entries) { // Don't include videos that are not live if (entry.IsDraft) { continue; } else if (result_display_count++ < max_results_display) { tiles.Add(new YouTubeTileData(entry)); } } showing_results = true; } else { Log.Debug("YouTube: No videos found"); cleanup = showing_results; showing_results = false; } ThreadAssist.BlockingProxyToMain(delegate { results_tv.ClearWidgets(); if (showing_results) { if (cleanup) { Remove(no_results_label); Add(results_tv); ShowAll(); } foreach (YouTubeTileData tile in tiles) { results_tv.AddWidget(new YouTubeTile(tile)); } results_tv.ShowAll(); } else if (cleanup) { Remove(results_tv); Add(no_results_label); ShowAll(); } ready = true; refreshing = false; yt_context_page.SetState(Banshee.ContextPane.ContextState.Loaded); }); }
protected override void AddTrackToDevice(DatabaseTrackInfo track, SafeUri fromUri) { if (track.PrimarySourceId == DbId) { return; } SafeUri new_uri = new SafeUri(GetTrackPath(track, System.IO.Path.GetExtension(fromUri))); // If it already is on the device but it's out of date, remove it //if (File.Exists(new_uri) && File.GetLastWriteTime(track.Uri.LocalPath) > File.GetLastWriteTime(new_uri)) //RemoveTrack(new MassStorageTrackInfo(new SafeUri(new_uri))); if (!File.Exists(new_uri)) { Directory.Create(System.IO.Path.GetDirectoryName(new_uri.LocalPath)); File.Copy(fromUri, new_uri, false); DatabaseTrackInfo copied_track = new DatabaseTrackInfo(track); copied_track.PrimarySource = this; copied_track.Uri = new_uri; // Write the metadata in db to the file on the DAP if it has changed since file was modified // to ensure that when we load it next time, it's data will match what's in the database // and the MetadataHash will actually match. We do this by comparing the time // stamps on files for last update of the db metadata vs the sync to file. // The equals on the inequality below is necessary for podcasts who often have a sync and // update time that are the same to the second, even though the album metadata has changed in the // DB to the feedname instead of what is in the file. It should be noted that writing the metadata // is a small fraction of the total copy time anyway. if (track.LastSyncedStamp >= Hyena.DateTimeUtil.ToDateTime(track.FileModifiedStamp)) { Log.DebugFormat("Copying Metadata to File Since Sync time >= Updated Time"); bool write_metadata = Metadata.SaveTrackMetadataService.WriteMetadataEnabled.Value; bool write_ratings = Metadata.SaveTrackMetadataService.WriteRatingsEnabled.Value; bool write_playcounts = Metadata.SaveTrackMetadataService.WritePlayCountsEnabled.Value; Banshee.Streaming.StreamTagger.SaveToFile(copied_track, write_metadata, write_ratings, write_playcounts); } copied_track.Save(false); } if (CoverArtSize > -1 && !String.IsNullOrEmpty(CoverArtFileType) && !String.IsNullOrEmpty(CoverArtFileName) && (FolderDepth == -1 || FolderDepth > 0)) { SafeUri cover_uri = new SafeUri(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(new_uri.LocalPath), CoverArtFileName)); string coverart_id = track.ArtworkId; if (!File.Exists(cover_uri) && CoverArtSpec.CoverExists(coverart_id)) { if (CoverArtFileType == "jpg" || CoverArtFileType == "jpeg") { SafeUri local_cover_uri = new SafeUri(Banshee.Base.CoverArtSpec.GetPath(coverart_id)); Banshee.IO.File.Copy(local_cover_uri, cover_uri, false); } else { Gdk.Pixbuf pic = null; try { byte[] bytes = null; ThreadAssist.BlockingProxyToMain(() => { pic = artwork_manager.LookupScalePixbuf(coverart_id, CoverArtSize); bytes = pic.SaveToBuffer(CoverArtFileType); }); if (bytes != null) { System.IO.Stream cover_art_file = File.OpenWrite(cover_uri, true); cover_art_file.Write(bytes, 0, bytes.Length); cover_art_file.Close(); } else { Log.Error("Cover art {0} had no bytes", coverart_id); } } catch (GLib.GException) { Log.DebugFormat("Could not convert cover art to {0}, unsupported filetype?", CoverArtFileType); } finally { Banshee.Collection.Gui.ArtworkManager.DisposePixbuf(pic); } } } } }