Restructure to be more MVC like
This commit is contained in:
parent
db6393fa55
commit
9516f53b70
|
@ -24,6 +24,7 @@ namespace SparkleLib {
|
||||||
public const string LOCALE_DIR = "@prefix@/share/locale";
|
public const string LOCALE_DIR = "@prefix@/share/locale";
|
||||||
public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@";
|
public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@";
|
||||||
public const string PREFIX = "@prefix@";
|
public const string PREFIX = "@prefix@";
|
||||||
|
public const string OPEN_COMMAND = "xdg-open";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,15 +42,15 @@ namespace SparkleLib {
|
||||||
public string Author;
|
public string Author;
|
||||||
public string Email;
|
public string Email;
|
||||||
public string Message;
|
public string Message;
|
||||||
public string RepositoryName;
|
public string RepositoryPath;
|
||||||
|
|
||||||
public NewCommitArgs (string author, string email, string message, string repository_name)
|
public NewCommitArgs (string author, string email, string message, string repository_path)
|
||||||
{
|
{
|
||||||
|
|
||||||
Author = author;
|
Author = author;
|
||||||
Email = email;
|
Email = email;
|
||||||
Message = message;
|
Message = message;
|
||||||
RepositoryName = repository_name;
|
RepositoryPath = repository_path;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -789,7 +789,7 @@ namespace SparkleLib {
|
||||||
Commit commit = Head.CurrentCommit;
|
Commit commit = Head.CurrentCommit;
|
||||||
|
|
||||||
NewCommitArgs new_commit_args = new NewCommitArgs (commit.Author.Name, commit.Author.EmailAddress,
|
NewCommitArgs new_commit_args = new NewCommitArgs (commit.Author.Name, commit.Author.EmailAddress,
|
||||||
commit.Message, Name);
|
commit.Message, LocalPath);
|
||||||
|
|
||||||
if (NewCommit != null)
|
if (NewCommit != null)
|
||||||
NewCommit (this, new_commit_args);
|
NewCommit (this, new_commit_args);
|
||||||
|
|
|
@ -9,6 +9,7 @@ LINK = $(REF_SPARKLESHARE)
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
SparkleBubble.cs \
|
SparkleBubble.cs \
|
||||||
|
SparkleController.cs \
|
||||||
SparkleEntry.cs \
|
SparkleEntry.cs \
|
||||||
SparkleInfobar.cs \
|
SparkleInfobar.cs \
|
||||||
SparkleIntro.cs \
|
SparkleIntro.cs \
|
||||||
|
|
625
SparkleShare/SparkleController.cs
Normal file
625
SparkleShare/SparkleController.cs
Normal file
|
@ -0,0 +1,625 @@
|
||||||
|
// SparkleShare, an instant update workflow to Git.
|
||||||
|
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using Mono.Unix;
|
||||||
|
using Mono.Unix.Native;
|
||||||
|
using SparkleLib;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace SparkleShare {
|
||||||
|
|
||||||
|
public class SparkleController {
|
||||||
|
|
||||||
|
public List <SparkleRepo> Repositories;
|
||||||
|
public string FolderSize;
|
||||||
|
|
||||||
|
|
||||||
|
public event RepositoryListChangedEventHandler RepositoryListChanged;
|
||||||
|
public delegate void RepositoryListChangedEventHandler ();
|
||||||
|
|
||||||
|
public event FolderSizeChangedEventHandler FolderSizeChanged;
|
||||||
|
public delegate void FolderSizeChangedEventHandler (string folder_size);
|
||||||
|
|
||||||
|
public event OnIdleEventHandler OnIdle;
|
||||||
|
public delegate void OnIdleEventHandler ();
|
||||||
|
|
||||||
|
public event OnSyncingEventHandler OnSyncing;
|
||||||
|
public delegate void OnSyncingEventHandler ();
|
||||||
|
|
||||||
|
public event OnErrorEventHandler OnError;
|
||||||
|
public delegate void OnErrorEventHandler ();
|
||||||
|
|
||||||
|
public event OnFirstRunEventHandler OnFirstRun;
|
||||||
|
public delegate void OnFirstRunEventHandler ();
|
||||||
|
|
||||||
|
public event OnInvitationEventHandler OnInvitation;
|
||||||
|
public delegate void OnInvitationEventHandler (string invitation_file_path);
|
||||||
|
|
||||||
|
public event ConflictNotificationRaisedEventHandler ConflictNotificationRaised;
|
||||||
|
public delegate void ConflictNotificationRaisedEventHandler ();
|
||||||
|
|
||||||
|
public event NotificationRaisedEventHandler NotificationRaised;
|
||||||
|
public delegate void NotificationRaisedEventHandler (string author, string email, string message,
|
||||||
|
string repository_path);
|
||||||
|
|
||||||
|
|
||||||
|
public SparkleController ()
|
||||||
|
{
|
||||||
|
|
||||||
|
SetProcessName ("sparkleshare");
|
||||||
|
|
||||||
|
InstallLauncher ();
|
||||||
|
EnableSystemAutostart ();
|
||||||
|
|
||||||
|
// Create the SparkleShare folder and add it to the bookmarks
|
||||||
|
if (CreateSparkleShareFolder ())
|
||||||
|
AddToBookmarks ();
|
||||||
|
|
||||||
|
FolderSize = GetFolderSize ();
|
||||||
|
|
||||||
|
// Watch the SparkleShare folder
|
||||||
|
FileSystemWatcher watcher = new FileSystemWatcher (SparklePaths.SparklePath) {
|
||||||
|
IncludeSubdirectories = false,
|
||||||
|
EnableRaisingEvents = true,
|
||||||
|
Filter = "*"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove the repository when a delete event occurs
|
||||||
|
watcher.Deleted += delegate (object o, FileSystemEventArgs args) {
|
||||||
|
|
||||||
|
RemoveRepository (args.FullPath);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the repository when a create event occurs
|
||||||
|
watcher.Created += delegate (object o, FileSystemEventArgs args) {
|
||||||
|
|
||||||
|
// Handle invitations when the user saves an
|
||||||
|
// invitation into the SparkleShare folder
|
||||||
|
if (args.Name.EndsWith (".invitation")) {
|
||||||
|
|
||||||
|
if (OnInvitation != null)
|
||||||
|
OnInvitation (args.FullPath);
|
||||||
|
|
||||||
|
} else if (Directory.Exists (Path.Combine (args.FullPath, ".git"))) {
|
||||||
|
|
||||||
|
AddRepository (args.FullPath);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CreateConfigurationFolders ();
|
||||||
|
|
||||||
|
string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config");
|
||||||
|
|
||||||
|
// Show the introduction screen if SparkleShare isn't configured
|
||||||
|
if (!File.Exists (global_config_file_path)) {
|
||||||
|
|
||||||
|
if (OnFirstRun != null)
|
||||||
|
OnFirstRun ();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
SparkleShare.UserName = SparkleShare.GetUserName ();
|
||||||
|
SparkleShare.UserEmail = SparkleShare.GetUserEmail ();
|
||||||
|
|
||||||
|
SparkleShare.AddKey ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread thread = new Thread (
|
||||||
|
new ThreadStart (PopulateRepositories)
|
||||||
|
);
|
||||||
|
|
||||||
|
thread.Start ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Creates a folder in the user's home folder to store configuration
|
||||||
|
private void CreateConfigurationFolders ()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!Directory.Exists (SparklePaths.SparkleTmpPath))
|
||||||
|
Directory.CreateDirectory (SparklePaths.SparkleTmpPath);
|
||||||
|
|
||||||
|
string config_path = SparklePaths.SparkleConfigPath;
|
||||||
|
string local_icon_path = SparklePaths.SparkleLocalIconPath;
|
||||||
|
|
||||||
|
if (!Directory.Exists (config_path)) {
|
||||||
|
|
||||||
|
// Create a folder to store settings
|
||||||
|
Directory.CreateDirectory (config_path);
|
||||||
|
SparkleHelpers.DebugInfo ("Config", "Created '" + config_path + "'");
|
||||||
|
|
||||||
|
// Create a folder to store the avatars
|
||||||
|
Directory.CreateDirectory (local_icon_path);
|
||||||
|
SparkleHelpers.DebugInfo ("Config", "Created '" + local_icon_path + "'");
|
||||||
|
|
||||||
|
string notify_setting_file = SparkleHelpers.CombineMore (config_path, "sparkleshare.notify");
|
||||||
|
|
||||||
|
// Enable notifications by default
|
||||||
|
if (!File.Exists (notify_setting_file))
|
||||||
|
File.Create (notify_setting_file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Creates a .desktop entry in autostart folder to
|
||||||
|
// start SparkleShare automatically at login
|
||||||
|
private void EnableSystemAutostart ()
|
||||||
|
{
|
||||||
|
|
||||||
|
string autostart_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".config", "autostart");
|
||||||
|
string desktopfile_path = SparkleHelpers.CombineMore (autostart_path, "sparkleshare.desktop");
|
||||||
|
|
||||||
|
if (!File.Exists (desktopfile_path)) {
|
||||||
|
|
||||||
|
if (!Directory.Exists (autostart_path))
|
||||||
|
Directory.CreateDirectory (autostart_path);
|
||||||
|
|
||||||
|
TextWriter writer = new StreamWriter (desktopfile_path);
|
||||||
|
writer.WriteLine ("[Desktop Entry]\n" +
|
||||||
|
"Type=Application\n" +
|
||||||
|
"Name=SparkleShare\n" +
|
||||||
|
"Exec=sparkleshare start\n" +
|
||||||
|
"Icon=folder-sparkleshare\n" +
|
||||||
|
"Terminal=false\n" +
|
||||||
|
"X-GNOME-Autostart-enabled=true\n" +
|
||||||
|
"Categories=Network");
|
||||||
|
writer.Close ();
|
||||||
|
|
||||||
|
// Give the launcher the right permissions so it can be launched by the user
|
||||||
|
Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU);
|
||||||
|
|
||||||
|
SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Installs a launcher so the user can launch SparkleShare
|
||||||
|
// from the Internet category if needed
|
||||||
|
private void InstallLauncher ()
|
||||||
|
{
|
||||||
|
|
||||||
|
string apps_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".local", "share", "applications");
|
||||||
|
string desktopfile_path = SparkleHelpers.CombineMore (apps_path, "sparkleshare.desktop");
|
||||||
|
|
||||||
|
if (!File.Exists (desktopfile_path)) {
|
||||||
|
|
||||||
|
if (!Directory.Exists (apps_path))
|
||||||
|
|
||||||
|
Directory.CreateDirectory (apps_path);
|
||||||
|
|
||||||
|
TextWriter writer = new StreamWriter (desktopfile_path);
|
||||||
|
writer.WriteLine ("[Desktop Entry]\n" +
|
||||||
|
"Type=Application\n" +
|
||||||
|
"Name=SparkleShare\n" +
|
||||||
|
"Comment=Share documents\n" +
|
||||||
|
"Exec=sparkleshare start\n" +
|
||||||
|
"Icon=folder-sparkleshare\n" +
|
||||||
|
"Terminal=false\n" +
|
||||||
|
"Categories=Network;");
|
||||||
|
writer.Close ();
|
||||||
|
|
||||||
|
// Give the launcher the right permissions so it can be launched by the user
|
||||||
|
Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU);
|
||||||
|
|
||||||
|
SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Adds the SparkleShare folder to the user's
|
||||||
|
// list of bookmarked places
|
||||||
|
private void AddToBookmarks ()
|
||||||
|
{
|
||||||
|
|
||||||
|
string bookmarks_file_path = Path.Combine (SparklePaths.HomePath, ".gtk-bookmarks");
|
||||||
|
string sparkleshare_bookmark = "file://" + SparklePaths.SparklePath + " SparkleShare";
|
||||||
|
|
||||||
|
if (File.Exists (bookmarks_file_path)) {
|
||||||
|
|
||||||
|
StreamReader reader = new StreamReader (bookmarks_file_path);
|
||||||
|
string bookmarks = reader.ReadToEnd ();
|
||||||
|
reader.Close ();
|
||||||
|
|
||||||
|
if (!bookmarks.Contains (sparkleshare_bookmark)) {
|
||||||
|
|
||||||
|
TextWriter writer = File.AppendText (bookmarks_file_path);
|
||||||
|
writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare");
|
||||||
|
writer.Close ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
StreamWriter writer = new StreamWriter (bookmarks_file_path);
|
||||||
|
writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare");
|
||||||
|
writer.Close ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Creates the SparkleShare folder in the user's home folder
|
||||||
|
private bool CreateSparkleShareFolder ()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!Directory.Exists (SparklePaths.SparklePath)) {
|
||||||
|
|
||||||
|
Directory.CreateDirectory (SparklePaths.SparklePath);
|
||||||
|
SparkleHelpers.DebugInfo ("Config", "Created '" + SparklePaths.SparklePath + "'");
|
||||||
|
|
||||||
|
string icon_file_path = SparkleHelpers.CombineMore (Defines.PREFIX, "share", "icons", "hicolor",
|
||||||
|
"48x48", "apps", "folder-sparkleshare.png");
|
||||||
|
|
||||||
|
string gvfs_command_path = SparkleHelpers.CombineMore (Path.VolumeSeparatorChar.ToString (),
|
||||||
|
"usr", "bin", "gvfs-set-attribute");
|
||||||
|
|
||||||
|
// Add a special icon to the SparkleShare folder
|
||||||
|
if (File.Exists (gvfs_command_path)) {
|
||||||
|
|
||||||
|
Process process = new Process ();
|
||||||
|
|
||||||
|
process.StartInfo.RedirectStandardOutput = true;
|
||||||
|
process.StartInfo.UseShellExecute = false;
|
||||||
|
|
||||||
|
process.StartInfo.FileName = "gvfs-set-attribute";
|
||||||
|
process.StartInfo.Arguments = SparklePaths.SparklePath + " metadata::custom-icon " +
|
||||||
|
"file://" + icon_file_path;
|
||||||
|
process.Start ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fires events for the current syncing state
|
||||||
|
private void UpdateState ()
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (SparkleRepo repo in Repositories) {
|
||||||
|
|
||||||
|
if (repo.IsSyncing || repo.IsBuffering) {
|
||||||
|
|
||||||
|
if (OnSyncing != null)
|
||||||
|
OnSyncing ();
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if (repo.HasUnsyncedChanges) {
|
||||||
|
|
||||||
|
if (OnError != null)
|
||||||
|
OnError ();
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (OnIdle != null)
|
||||||
|
OnIdle ();
|
||||||
|
|
||||||
|
|
||||||
|
FolderSize = GetFolderSize ();
|
||||||
|
|
||||||
|
if (FolderSizeChanged != null)
|
||||||
|
FolderSizeChanged (FolderSize);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Adds a repository to the list of repositories
|
||||||
|
private void AddRepository (string folder_path)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Check if the folder is a Git repository
|
||||||
|
if (!Directory.Exists (SparkleHelpers.CombineMore (folder_path, ".git")))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SparkleRepo repo = new SparkleRepo (folder_path);
|
||||||
|
|
||||||
|
repo.NewCommit += delegate (object o, NewCommitArgs args) {
|
||||||
|
if (NotificationsEnabled && NotificationRaised != null)
|
||||||
|
NotificationRaised (args.Author, args.Email, args.Message, args.RepositoryPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.FetchingStarted += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.FetchingFinished += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.FetchingFailed += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.ChangesDetected += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.PushingStarted += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.PushingFinished += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.CommitEndedUpEmpty += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.PushingFailed += delegate {
|
||||||
|
UpdateState ();
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.ConflictDetected += delegate {
|
||||||
|
if (ConflictNotificationRaised != null)
|
||||||
|
ConflictNotificationRaised ();
|
||||||
|
};
|
||||||
|
|
||||||
|
Repositories.Add (repo);
|
||||||
|
|
||||||
|
|
||||||
|
if (RepositoryListChanged != null)
|
||||||
|
RepositoryListChanged ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Removes a repository from the list of repositories and
|
||||||
|
// updates the statusicon menu
|
||||||
|
private void RemoveRepository (string folder_path)
|
||||||
|
{
|
||||||
|
|
||||||
|
string repo_name = Path.GetFileName (folder_path);
|
||||||
|
|
||||||
|
for (int i = 0; i < Repositories.Count; i++) {
|
||||||
|
|
||||||
|
SparkleRepo repo = Repositories [i];
|
||||||
|
|
||||||
|
if (repo.Name.Equals (repo_name)) {
|
||||||
|
|
||||||
|
Repositories.Remove (repo);
|
||||||
|
repo.Dispose ();
|
||||||
|
repo = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (RepositoryListChanged != null)
|
||||||
|
RepositoryListChanged ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Updates the list of repositories with all the
|
||||||
|
// folders in the SparkleShare folder
|
||||||
|
private void PopulateRepositories ()
|
||||||
|
{
|
||||||
|
|
||||||
|
Repositories = new List <SparkleRepo> ();
|
||||||
|
|
||||||
|
foreach (string folder_path in Directory.GetDirectories (SparklePaths.SparklePath))
|
||||||
|
AddRepository (folder_path);
|
||||||
|
|
||||||
|
if (RepositoryListChanged != null)
|
||||||
|
RepositoryListChanged ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool NotificationsEnabled {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
string notify_setting_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath,
|
||||||
|
"sparkleshare.notify");
|
||||||
|
|
||||||
|
return File.Exists (notify_setting_file_path);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void ToggleNotifications () {
|
||||||
|
|
||||||
|
string notify_setting_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath,
|
||||||
|
"sparkleshare.notify");
|
||||||
|
|
||||||
|
if (File.Exists (notify_setting_file_path))
|
||||||
|
File.Delete (notify_setting_file_path);
|
||||||
|
else
|
||||||
|
File.Create (notify_setting_file_path);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GetFolderSize ()
|
||||||
|
{
|
||||||
|
|
||||||
|
double folder_size = CalculateFolderSize (new DirectoryInfo (SparklePaths.SparklePath));
|
||||||
|
return FormatFolderSize (folder_size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Recursively gets a folder's size in bytes
|
||||||
|
private double CalculateFolderSize (DirectoryInfo parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!Directory.Exists (parent.ToString ()))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
double size = 0;
|
||||||
|
|
||||||
|
// Ignore the temporary 'rebase-apply' and '.tmp' directories. This prevents potential
|
||||||
|
// crashes when files are being queried whilst the files have already been deleted.
|
||||||
|
if (parent.Name.Equals ("rebase-apply") ||
|
||||||
|
parent.Name.Equals (".tmp"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
foreach (FileInfo file in parent.GetFiles()) {
|
||||||
|
|
||||||
|
if (!file.Exists)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size += file.Length;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (DirectoryInfo directory in parent.GetDirectories())
|
||||||
|
size += CalculateFolderSize (directory);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Format a file size nicely with small caps.
|
||||||
|
// Example: 1048576 becomes "1 ᴍʙ"
|
||||||
|
private string FormatFolderSize (double byte_count)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (byte_count >= 1099511627776)
|
||||||
|
|
||||||
|
return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 1));
|
||||||
|
|
||||||
|
else if (byte_count >= 1073741824)
|
||||||
|
|
||||||
|
return String.Format ("{0:##.##} ɢʙ", Math.Round (byte_count / 1073741824, 1));
|
||||||
|
|
||||||
|
else if (byte_count >= 1048576)
|
||||||
|
|
||||||
|
return String.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 1));
|
||||||
|
|
||||||
|
else if (byte_count >= 1024)
|
||||||
|
|
||||||
|
return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1));
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
return byte_count.ToString () + " bytes";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void OpenSparkleShareFolder ()
|
||||||
|
{
|
||||||
|
|
||||||
|
Process process = new Process ();
|
||||||
|
process.StartInfo.Arguments = SparklePaths.SparklePath;
|
||||||
|
|
||||||
|
string open_command_path = SparkleHelpers.CombineMore (Path.VolumeSeparatorChar.ToString (),
|
||||||
|
"usr", "bin");
|
||||||
|
|
||||||
|
if (File.Exists (Path.Combine (open_command_path, "xdg-open"))) {
|
||||||
|
|
||||||
|
process.StartInfo.FileName = "xdg-open";
|
||||||
|
|
||||||
|
} else if (File.Exists (Path.Combine (open_command_path, "gnome-open"))) {
|
||||||
|
|
||||||
|
process.StartInfo.FileName = "gnome-open";
|
||||||
|
|
||||||
|
} else if (File.Exists (Path.Combine (open_command_path, "open"))) {
|
||||||
|
|
||||||
|
process.StartInfo.FileName = "open";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
process.Start ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets the unix process name to 'sparkleshare' instead of 'mono'
|
||||||
|
private void SetProcessName (string name)
|
||||||
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (prctl (15, Encoding.ASCII.GetBytes (name + "\0"), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0) {
|
||||||
|
|
||||||
|
throw new ApplicationException ("Error setting process name: " +
|
||||||
|
Mono.Unix.Native.Stdlib.GetLastError ());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (EntryPointNotFoundException) {
|
||||||
|
|
||||||
|
Console.WriteLine ("SetProcessName: Entry point not found");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Strange magic needed by SetProcessName
|
||||||
|
[DllImport ("libc")]
|
||||||
|
private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
|
||||||
|
|
||||||
|
// Quits the program
|
||||||
|
public void Quit ()
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (SparkleRepo repo in Repositories)
|
||||||
|
repo.Dispose ();
|
||||||
|
|
||||||
|
// Remove the process ID file
|
||||||
|
File.Delete (SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, "sparkleshare.pid"));
|
||||||
|
|
||||||
|
Environment.Exit (0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -270,7 +270,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
FolderEntry.Changed += CheckServerForm;
|
FolderEntry.Changed += CheckServerForm;
|
||||||
|
|
||||||
Label folder_label = new Label ("<b>" + _("Folder Name:") + "</b>") {
|
Label folder_label = new Label ("<b>" + _("Remote Folder Name:") + "</b>") {
|
||||||
UseMarkup = true,
|
UseMarkup = true,
|
||||||
Xalign = 1
|
Xalign = 1
|
||||||
};
|
};
|
||||||
|
@ -577,7 +577,7 @@ namespace SparkleShare {
|
||||||
if (SparkleUI.StatusIcon == null)
|
if (SparkleUI.StatusIcon == null)
|
||||||
SparkleUI.StatusIcon = new SparkleStatusIcon ();
|
SparkleUI.StatusIcon = new SparkleStatusIcon ();
|
||||||
else
|
else
|
||||||
SparkleUI.StatusIcon.CreateMenu ();
|
SparkleUI.StatusIcon.UpdateMenu ();
|
||||||
|
|
||||||
Destroy ();
|
Destroy ();
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ namespace SparkleShare {
|
||||||
open_folder_button.Clicked += delegate (object o, EventArgs args) {
|
open_folder_button.Clicked += delegate (object o, EventArgs args) {
|
||||||
|
|
||||||
Process process = new Process ();
|
Process process = new Process ();
|
||||||
process.StartInfo.FileName = "xdg-open";
|
process.StartInfo.FileName = Defines.OPEN_COMMAND;
|
||||||
process.StartInfo.Arguments = LocalPath.Replace (" ", "\\ "); // Escape space-characters
|
process.StartInfo.Arguments = LocalPath.Replace (" ", "\\ "); // Escape space-characters
|
||||||
process.Start ();
|
process.Start ();
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ namespace SparkleShare {
|
||||||
public void Close ()
|
public void Close ()
|
||||||
{
|
{
|
||||||
|
|
||||||
foreach (SparkleRepo repo in SparkleUI.Repositories) {
|
foreach (SparkleRepo repo in SparkleShare.Controller.Repositories) {
|
||||||
|
|
||||||
if (repo.LocalPath.Equals (LocalPath)) {
|
if (repo.LocalPath.Equals (LocalPath)) {
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
List <SparkleCommit> commits = new List <SparkleCommit> ();
|
List <SparkleCommit> commits = new List <SparkleCommit> ();
|
||||||
|
|
||||||
foreach (SparkleRepo repo in SparkleUI.Repositories) {
|
foreach (SparkleRepo repo in SparkleShare.Controller.Repositories) {
|
||||||
|
|
||||||
// Get commits from the repository
|
// Get commits from the repository
|
||||||
if (repo.LocalPath.Equals (LocalPath)) {
|
if (repo.LocalPath.Equals (LocalPath)) {
|
||||||
|
@ -239,7 +239,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
VBox layout_vertical = new VBox (false, 0);
|
VBox layout_vertical = new VBox (false, 0);
|
||||||
|
|
||||||
if (SparkleUI.Repositories.Find (
|
if (SparkleShare.Controller.Repositories.Find (
|
||||||
delegate (SparkleRepo r)
|
delegate (SparkleRepo r)
|
||||||
{ return r.LocalPath.Equals (LocalPath) && r.HasUnsyncedChanges; }
|
{ return r.LocalPath.Equals (LocalPath) && r.HasUnsyncedChanges; }
|
||||||
) != null) {
|
) != null) {
|
||||||
|
@ -253,7 +253,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (SparkleUI.Repositories.Find (
|
if (SparkleShare.Controller.Repositories.Find (
|
||||||
delegate (SparkleRepo r)
|
delegate (SparkleRepo r)
|
||||||
{ return r.LocalPath.Equals (LocalPath) && r.HasUnsyncedChanges; }
|
{ return r.LocalPath.Equals (LocalPath) && r.HasUnsyncedChanges; }
|
||||||
) != null) {
|
) != null) {
|
||||||
|
|
|
@ -28,7 +28,8 @@ namespace SparkleShare {
|
||||||
// This is SparkleShare!
|
// This is SparkleShare!
|
||||||
public class SparkleShare {
|
public class SparkleShare {
|
||||||
|
|
||||||
public static SparkleUI SparkleUI;
|
public static SparkleController Controller;
|
||||||
|
public static SparkleUI UI;
|
||||||
public static string UserName;
|
public static string UserName;
|
||||||
public static string UserEmail;
|
public static string UserEmail;
|
||||||
|
|
||||||
|
@ -46,23 +47,6 @@ namespace SparkleShare {
|
||||||
// Use translations
|
// Use translations
|
||||||
Catalog.Init (Defines.GETTEXT_PACKAGE, Defines.LOCALE_DIR);
|
Catalog.Init (Defines.GETTEXT_PACKAGE, Defines.LOCALE_DIR);
|
||||||
|
|
||||||
// Check whether git is installed
|
|
||||||
Process process = new Process ();
|
|
||||||
process.StartInfo.FileName = "git";
|
|
||||||
process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
process.StartInfo.UseShellExecute = false;
|
|
||||||
process.Start ();
|
|
||||||
|
|
||||||
if (process.StandardOutput.ReadToEnd ().IndexOf ("version") == -1) {
|
|
||||||
|
|
||||||
Console.WriteLine (_("Git wasn't found."));
|
|
||||||
Console.WriteLine (_("You can get Git from http://git-scm.com/."));
|
|
||||||
|
|
||||||
Environment.Exit (0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UnixUserInfo user_info = new UnixUserInfo (UnixEnvironment.UserName);
|
UnixUserInfo user_info = new UnixUserInfo (UnixEnvironment.UserName);
|
||||||
|
|
||||||
// Don't allow running as root
|
// Don't allow running as root
|
||||||
|
@ -76,13 +60,13 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HideUI = false;
|
bool hide_ui = false;
|
||||||
bool ShowHelp = false;
|
bool show_help = false;
|
||||||
|
|
||||||
var p = new OptionSet () {
|
var p = new OptionSet () {
|
||||||
{ "d|disable-gui", _("Don't show the notification icon"), v => HideUI = v != null },
|
{ "d|disable-gui", _("Don't show the notification icon"), v => hide_ui = v != null },
|
||||||
{ "v|version", _("Show this help text"), v => { PrintVersion (); } },
|
{ "v|version", _("Show this help text"), v => { PrintVersion (); } },
|
||||||
{ "h|help", _("Print version information"), v => ShowHelp = v != null }
|
{ "h|help", _("Print version information"), v => show_help = v != null }
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -97,17 +81,19 @@ namespace SparkleShare {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShowHelp)
|
if (show_help)
|
||||||
DisplayHelp (p);
|
ShowHelp (p);
|
||||||
|
|
||||||
SparkleUI = new SparkleUI (HideUI);
|
|
||||||
SparkleUI.Run ();
|
|
||||||
|
|
||||||
|
Controller = new SparkleController ();
|
||||||
|
if (!hide_ui){
|
||||||
|
UI = new SparkleUI ();
|
||||||
|
UI.Run ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Prints the help output
|
// Prints the help output
|
||||||
public static void DisplayHelp (OptionSet option_set)
|
public static void ShowHelp (OptionSet option_set)
|
||||||
{
|
{
|
||||||
|
|
||||||
Console.WriteLine (" ");
|
Console.WriteLine (" ");
|
||||||
|
|
|
@ -27,22 +27,17 @@ namespace SparkleShare {
|
||||||
|
|
||||||
// The statusicon that stays in the
|
// The statusicon that stays in the
|
||||||
// user's notification area
|
// user's notification area
|
||||||
public class SparkleStatusIcon : StatusIcon
|
public class SparkleStatusIcon : StatusIcon {
|
||||||
{
|
|
||||||
|
|
||||||
private Menu Menu;
|
|
||||||
private MenuItem StatusMenuItem;
|
|
||||||
private string StateText;
|
|
||||||
|
|
||||||
private Timer Animation;
|
private Timer Animation;
|
||||||
private Gdk.Pixbuf [] AnimationFrames;
|
private Gdk.Pixbuf [] AnimationFrames;
|
||||||
private int FrameNumber;
|
private int FrameNumber;
|
||||||
|
private string StateText;
|
||||||
private double FolderSize;
|
private Menu Menu;
|
||||||
|
|
||||||
|
|
||||||
// Short alias for the translations
|
// Short alias for the translations
|
||||||
public static string _ (string s) {
|
public static string _ (string s)
|
||||||
|
{
|
||||||
return Catalog.GetString (s);
|
return Catalog.GetString (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,27 +45,50 @@ namespace SparkleShare {
|
||||||
public SparkleStatusIcon () : base ()
|
public SparkleStatusIcon () : base ()
|
||||||
{
|
{
|
||||||
|
|
||||||
SparkleUI.OpenLogs = new List <SparkleLog> ();
|
|
||||||
|
|
||||||
FolderSize = GetFolderSize (new DirectoryInfo (SparklePaths.SparklePath));
|
|
||||||
|
|
||||||
FrameNumber = 0;
|
FrameNumber = 0;
|
||||||
AnimationFrames = CreateAnimationFrames ();
|
AnimationFrames = CreateAnimationFrames ();
|
||||||
Animation = CreateAnimation ();
|
Animation = CreateAnimation ();
|
||||||
|
|
||||||
StateText = "";
|
Activate += ShowMenu; // Primary mouse button click
|
||||||
StatusMenuItem = new MenuItem ();
|
PopupMenu += ShowMenu; // Secondary mouse button click
|
||||||
|
|
||||||
CreateMenu ();
|
SetNormalState ();
|
||||||
|
UpdateMenu ();
|
||||||
|
|
||||||
// Primary mouse button click
|
|
||||||
Activate += ShowMenu;
|
|
||||||
|
|
||||||
// Secondary mouse button click
|
SparkleShare.Controller.FolderSizeChanged += delegate {
|
||||||
PopupMenu += ShowMenu;
|
Application.Invoke (delegate {
|
||||||
|
UpdateMenu ();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
SparkleShare.Controller.RepositoryListChanged += delegate {
|
||||||
|
Application.Invoke (delegate {
|
||||||
|
SetNormalState ();
|
||||||
|
UpdateMenu ();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
SetIdleState ();
|
SparkleShare.Controller.OnIdle += delegate {
|
||||||
ShowState ();
|
Application.Invoke (delegate {
|
||||||
|
SetNormalState ();
|
||||||
|
UpdateMenu ();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
SparkleShare.Controller.OnSyncing += delegate {
|
||||||
|
Application.Invoke (delegate {
|
||||||
|
SetAnimationState ();
|
||||||
|
UpdateMenu ();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
SparkleShare.Controller.OnError += delegate {
|
||||||
|
Application.Invoke (delegate {
|
||||||
|
SetNormalState (true);
|
||||||
|
UpdateMenu ();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +109,7 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creates the Animation that handles the syncing animation.
|
// Creates the Animation that handles the syncing animation
|
||||||
private Timer CreateAnimation ()
|
private Timer CreateAnimation ()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -107,9 +125,7 @@ namespace SparkleShare {
|
||||||
FrameNumber = 0;
|
FrameNumber = 0;
|
||||||
|
|
||||||
Application.Invoke (delegate {
|
Application.Invoke (delegate {
|
||||||
|
Pixbuf = AnimationFrames [FrameNumber];
|
||||||
SetPixbuf (AnimationFrames [FrameNumber]);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -119,148 +135,36 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// A method reference that makes sure that
|
|
||||||
// opening the event log for each repository
|
|
||||||
// works correctly.
|
|
||||||
private EventHandler OpenLogDelegate (string path)
|
|
||||||
{
|
|
||||||
|
|
||||||
return delegate {
|
|
||||||
|
|
||||||
SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) { return l.LocalPath.Equals (path); });
|
|
||||||
|
|
||||||
// Check whether the log is already open,
|
|
||||||
// create a new one if that's not the case or
|
|
||||||
// present it to the user if it is
|
|
||||||
if (log == null) {
|
|
||||||
|
|
||||||
log = new SparkleLog (path);
|
|
||||||
|
|
||||||
log.Hidden += delegate {
|
|
||||||
|
|
||||||
SparkleUI.OpenLogs.Remove (log);
|
|
||||||
log.Destroy ();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
SparkleUI.OpenLogs.Add (log);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
log.ShowAll ();
|
|
||||||
log.Present ();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Recursively gets a folder's size in bytes
|
|
||||||
private double GetFolderSize (DirectoryInfo parent)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!Directory.Exists (parent.ToString ()))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
double size = 0;
|
|
||||||
|
|
||||||
// Ignore the temporary 'rebase-apply' and '.tmp' directories.
|
|
||||||
// This prevents potential crashes when files are being
|
|
||||||
// queried whilst the files have already been deleted.
|
|
||||||
if (parent.Name.Equals ("rebase-apply") ||
|
|
||||||
parent.Name.Equals (".tmp"))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
foreach (FileInfo file in parent.GetFiles()) {
|
|
||||||
|
|
||||||
if (!file.Exists)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
size += file.Length;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (DirectoryInfo directory in parent.GetDirectories())
|
|
||||||
size += GetFolderSize (directory);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void UpdateFolderSize ()
|
|
||||||
{
|
|
||||||
|
|
||||||
FolderSize = GetFolderSize (new DirectoryInfo (SparklePaths.SparklePath));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Format a file size nicely with small caps.
|
|
||||||
// Example: 1048576 becomes "1 ᴍʙ"
|
|
||||||
private string FormatFileSize (double byte_count)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (byte_count >= 1099511627776)
|
|
||||||
|
|
||||||
return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 1));
|
|
||||||
|
|
||||||
else if (byte_count >= 1073741824)
|
|
||||||
|
|
||||||
return String.Format ("{0:##.##} ɢʙ", Math.Round (byte_count / 1073741824, 1));
|
|
||||||
|
|
||||||
else if (byte_count >= 1048576)
|
|
||||||
|
|
||||||
return String.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 1));
|
|
||||||
|
|
||||||
else if (byte_count >= 1024)
|
|
||||||
|
|
||||||
return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1));
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
return byte_count.ToString () + " bytes";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creates the menu that is popped up when the
|
// Creates the menu that is popped up when the
|
||||||
// user clicks the statusicon
|
// user clicks the status icon
|
||||||
public void CreateMenu ()
|
public void UpdateMenu ()
|
||||||
{
|
{
|
||||||
|
|
||||||
Menu = new Menu ();
|
Menu = new Menu ();
|
||||||
|
|
||||||
// The menu item showing the status and size of the SparkleShare folder
|
// The menu item showing the status and size of the SparkleShare folder
|
||||||
StatusMenuItem = new MenuItem (StateText) {
|
MenuItem status_menu_item = new MenuItem (StateText) {
|
||||||
Sensitive = false
|
Sensitive = false
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (StatusMenuItem);
|
// A menu item that provides a link to the SparkleShare folder
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
Gtk.Action folder_action = new Gtk.Action ("", "SparkleShare") {
|
||||||
|
IconName = "folder-sparkleshare",
|
||||||
|
IsImportant = true
|
||||||
|
};
|
||||||
|
|
||||||
// A menu item that provides a link to the SparkleShare folder
|
folder_action.Activated += delegate {
|
||||||
Gtk.Action folder_action = new Gtk.Action ("", "SparkleShare") {
|
SparkleShare.Controller.OpenSparkleShareFolder ();
|
||||||
IconName = "folder-sparkleshare",
|
};
|
||||||
IsImportant = true
|
|
||||||
};
|
|
||||||
|
|
||||||
folder_action.Activated += delegate {
|
Menu.Add (status_menu_item);
|
||||||
|
Menu.Add (new SeparatorMenuItem ());
|
||||||
|
Menu.Add (folder_action.CreateMenuItem ());
|
||||||
|
|
||||||
Process process = new Process ();
|
if (SparkleShare.Controller.Repositories.Count > 0) {
|
||||||
process.StartInfo.FileName = "xdg-open";
|
|
||||||
process.StartInfo.Arguments = SparklePaths.SparklePath;
|
|
||||||
process.Start ();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Menu.Add (folder_action.CreateMenuItem ());
|
|
||||||
|
|
||||||
|
|
||||||
if (SparkleUI.Repositories.Count > 0) {
|
|
||||||
|
|
||||||
// Creates a menu item for each repository with a link to their logs
|
// Creates a menu item for each repository with a link to their logs
|
||||||
foreach (SparkleRepo repo in SparkleUI.Repositories) {
|
foreach (SparkleRepo repo in SparkleShare.Controller.Repositories) {
|
||||||
|
|
||||||
folder_action = new Gtk.Action ("", repo.Name) {
|
folder_action = new Gtk.Action ("", repo.Name) {
|
||||||
IconName = "folder",
|
IconName = "folder",
|
||||||
|
@ -270,7 +174,7 @@ namespace SparkleShare {
|
||||||
if (repo.HasUnsyncedChanges)
|
if (repo.HasUnsyncedChanges)
|
||||||
folder_action.IconName = "dialog-error";
|
folder_action.IconName = "dialog-error";
|
||||||
|
|
||||||
folder_action.Activated += OpenLogDelegate (repo.LocalPath);
|
folder_action.Activated += OpenEventLogDelegate (repo.LocalPath);
|
||||||
|
|
||||||
MenuItem menu_item = (MenuItem) folder_action.CreateMenuItem ();
|
MenuItem menu_item = (MenuItem) folder_action.CreateMenuItem ();
|
||||||
|
|
||||||
|
@ -292,160 +196,105 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opens the wizard to add a new remote folder
|
// Opens the wizard to add a new remote folder
|
||||||
MenuItem add_item = new MenuItem (_("Sync Remote Folder…"));
|
MenuItem sync_item = new MenuItem (_("Sync Remote Folder…"));
|
||||||
|
|
||||||
add_item.Activated += delegate {
|
sync_item.Activated += delegate {
|
||||||
|
Application.Invoke (delegate {
|
||||||
|
|
||||||
SparkleIntro intro = new SparkleIntro ();
|
SparkleIntro intro = new SparkleIntro ();
|
||||||
|
intro.ShowServerForm ();
|
||||||
|
|
||||||
// Only show the server form in the wizard
|
});
|
||||||
intro.ShowServerForm (true);
|
};
|
||||||
|
|
||||||
};
|
Menu.Add (sync_item);
|
||||||
|
Menu.Add (new SeparatorMenuItem ());
|
||||||
Menu.Add (add_item);
|
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
|
||||||
|
|
||||||
// A checkbutton to toggle whether or not to show notifications
|
// A checkbutton to toggle whether or not to show notifications
|
||||||
CheckMenuItem notify_item = new CheckMenuItem (_("Show Notifications"));
|
CheckMenuItem notify_item = new CheckMenuItem (_("Show Notifications"));
|
||||||
|
|
||||||
|
if (SparkleShare.Controller.NotificationsEnabled)
|
||||||
|
notify_item.Active = true;
|
||||||
|
|
||||||
// Whether notifications are shown depends existence of this file
|
notify_item.Toggled += delegate {
|
||||||
string notify_setting_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath,
|
SparkleShare.Controller.ToggleNotifications ();
|
||||||
"sparkleshare.notify");
|
};
|
||||||
|
|
||||||
if (File.Exists (notify_setting_file_path))
|
|
||||||
notify_item.Active = true;
|
|
||||||
|
|
||||||
notify_item.Toggled += delegate {
|
Menu.Add (notify_item);
|
||||||
|
Menu.Add (new SeparatorMenuItem ());
|
||||||
|
|
||||||
if (File.Exists (notify_setting_file_path))
|
// A menu item that takes the user to http://www.sparkleshare.org/
|
||||||
File.Delete (notify_setting_file_path);
|
|
||||||
else
|
|
||||||
File.Create (notify_setting_file_path);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Menu.Add (notify_item);
|
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
|
||||||
|
|
||||||
// A menu item that takes the use to sparkleshare.org
|
|
||||||
MenuItem about_item = new MenuItem (_("Visit Website"));
|
MenuItem about_item = new MenuItem (_("Visit Website"));
|
||||||
|
|
||||||
about_item.Activated += delegate {
|
about_item.Activated += delegate {
|
||||||
|
|
||||||
Process process = new Process ();
|
Process process = new Process ();
|
||||||
|
process.StartInfo.FileName = "xdg-open";
|
||||||
|
process.StartInfo.Arguments = "http://www.sparkleshare.org/";
|
||||||
|
process.Start ();
|
||||||
|
|
||||||
process.StartInfo.FileName = "xdg-open";
|
};
|
||||||
process.StartInfo.Arguments = "http://www.sparkleshare.org/";
|
|
||||||
|
|
||||||
process.Start ();
|
Menu.Add (about_item);
|
||||||
|
Menu.Add (new SeparatorMenuItem ());
|
||||||
|
|
||||||
};
|
// A menu item that quits the application
|
||||||
|
MenuItem quit_item = new MenuItem (_("Quit"));
|
||||||
|
|
||||||
Menu.Add (about_item);
|
quit_item.Activated += delegate {
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
SparkleShare.Controller.Quit ();
|
||||||
|
};
|
||||||
|
|
||||||
// A menu item that quits the application
|
Menu.Add (quit_item);
|
||||||
MenuItem quit_item = new MenuItem (_("Quit"));
|
|
||||||
quit_item.Activated += Quit;
|
|
||||||
|
|
||||||
Menu.Add (quit_item);
|
Menu.ShowAll ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A method reference that makes sure that opening the
|
||||||
|
// event log for each repository works correctly
|
||||||
|
private EventHandler OpenEventLogDelegate (string path)
|
||||||
|
{
|
||||||
|
|
||||||
|
return delegate {
|
||||||
|
|
||||||
|
SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) { return l.LocalPath.Equals (path); });
|
||||||
|
|
||||||
|
// Check whether the log is already open, create a new one if
|
||||||
|
//that's not the case or present it to the user if it is
|
||||||
|
if (log == null) {
|
||||||
|
|
||||||
|
log = new SparkleLog (path);
|
||||||
|
|
||||||
|
log.Hidden += delegate {
|
||||||
|
|
||||||
|
SparkleUI.OpenLogs.Remove (log);
|
||||||
|
log.Destroy ();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
SparkleUI.OpenLogs.Add (log);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
log.ShowAll ();
|
||||||
|
log.Present ();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Makes the menu visible
|
||||||
private void ShowMenu (object o, EventArgs args)
|
private void ShowMenu (object o, EventArgs args)
|
||||||
{
|
{
|
||||||
|
|
||||||
CreateMenu ();
|
|
||||||
Menu.ShowAll ();
|
|
||||||
Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
|
Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Shows the state and keeps the number of syncing repositories in mind
|
|
||||||
public void ShowState ()
|
|
||||||
{
|
|
||||||
|
|
||||||
UpdateFolderSize ();
|
|
||||||
|
|
||||||
foreach (SparkleRepo repo in SparkleUI.Repositories)
|
|
||||||
|
|
||||||
if (repo.IsSyncing || repo.IsBuffering) {
|
|
||||||
|
|
||||||
SetSyncingState ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
SetIdleState ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the new status text
|
|
||||||
(StatusMenuItem.Children [0] as Label).Text = StateText;
|
|
||||||
Menu.ShowAll ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Changes the state to idle for when there's no syncing going on
|
|
||||||
private void SetIdleState ()
|
|
||||||
{
|
|
||||||
|
|
||||||
Animation.Stop ();
|
|
||||||
|
|
||||||
int unsynced_repo_count = 0;
|
|
||||||
foreach (SparkleRepo repo in SparkleUI.Repositories) {
|
|
||||||
if (repo.HasUnsyncedChanges)
|
|
||||||
unsynced_repo_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unsynced_repo_count > 0) {
|
|
||||||
|
|
||||||
Application.Invoke (delegate { SetPixbuf (SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24)); });
|
|
||||||
|
|
||||||
if (unsynced_repo_count == 1)
|
|
||||||
StateText = _("One of your folders failed to sync");
|
|
||||||
else
|
|
||||||
StateText = _("Some folders failed to sync");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Application.Invoke (delegate { SetPixbuf (AnimationFrames [0]); });
|
|
||||||
|
|
||||||
if (SparkleUI.Repositories.Count > 0)
|
|
||||||
StateText = _("Up to date") + " (" + FormatFileSize (FolderSize) + ")";
|
|
||||||
else
|
|
||||||
StateText = _("Welcome to SparkleShare!");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Changes the status icon to the syncing animation
|
|
||||||
private void SetSyncingState ()
|
|
||||||
{
|
|
||||||
|
|
||||||
StateText = _("Syncing…");
|
|
||||||
|
|
||||||
if (!Animation.Enabled)
|
|
||||||
Animation.Start ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Updates the icon used for the statusicon
|
|
||||||
private void SetPixbuf (Gdk.Pixbuf pixbuf)
|
|
||||||
{
|
|
||||||
|
|
||||||
Pixbuf = pixbuf;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Makes sure the menu pops up in the right position
|
// Makes sure the menu pops up in the right position
|
||||||
private void SetPosition (Menu menu, out int x, out int y, out bool push_in)
|
private void SetPosition (Menu menu, out int x, out int y, out bool push_in)
|
||||||
{
|
{
|
||||||
|
@ -455,16 +304,53 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Quits the program
|
// The state when there's nothing going on
|
||||||
private void Quit (object o, EventArgs args)
|
private void SetNormalState ()
|
||||||
{
|
{
|
||||||
|
|
||||||
foreach (SparkleRepo repo in SparkleUI.Repositories)
|
SetNormalState (false);
|
||||||
repo.Dispose ();
|
|
||||||
|
|
||||||
// Remove the process id file
|
}
|
||||||
File.Delete (SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, "sparkleshare.pid"));
|
|
||||||
Application.Quit ();
|
|
||||||
|
// The state when there's nothing going on
|
||||||
|
private void SetNormalState (bool error)
|
||||||
|
{
|
||||||
|
|
||||||
|
Animation.Stop ();
|
||||||
|
|
||||||
|
if (SparkleShare.Controller.Repositories.Count == 0) {
|
||||||
|
|
||||||
|
StateText = _("No folders yet");
|
||||||
|
Pixbuf = AnimationFrames [0];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
|
||||||
|
StateText = _("Not everything is synced");
|
||||||
|
Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
StateText = _("Up to date") + " (" + SparkleShare.Controller.FolderSize + ")";
|
||||||
|
Pixbuf = AnimationFrames [0];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The state when animating
|
||||||
|
private void SetAnimationState ()
|
||||||
|
{
|
||||||
|
|
||||||
|
StateText = _("Syncing…");
|
||||||
|
|
||||||
|
if (!Animation.Enabled)
|
||||||
|
Animation.Start ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
using Gtk;
|
using Gtk;
|
||||||
using Mono.Unix;
|
using Mono.Unix;
|
||||||
using Mono.Unix.Native;
|
using Mono.Unix.Native;
|
||||||
using SparkleLib;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -30,10 +29,10 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public class SparkleUI {
|
public class SparkleUI {
|
||||||
|
|
||||||
public static List <SparkleRepo> Repositories;
|
|
||||||
public static SparkleStatusIcon StatusIcon;
|
public static SparkleStatusIcon StatusIcon;
|
||||||
public static List <SparkleLog> OpenLogs;
|
public static List <SparkleLog> OpenLogs;
|
||||||
|
|
||||||
|
|
||||||
// Short alias for the translations
|
// Short alias for the translations
|
||||||
public static string _(string s)
|
public static string _(string s)
|
||||||
{
|
{
|
||||||
|
@ -41,97 +40,71 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SparkleUI (bool HideUI)
|
public SparkleUI ()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Initialize the application
|
// Initialize the application
|
||||||
Gtk.Application.Init ();
|
Application.Init ();
|
||||||
|
|
||||||
// Set the process name to something differen than 'mono'
|
// Create the statusicon
|
||||||
SetProcessName ("sparkleshare");
|
StatusIcon = new SparkleStatusIcon ();
|
||||||
|
|
||||||
|
// Keep track of event logs are open
|
||||||
|
SparkleUI.OpenLogs = new List <SparkleLog> ();
|
||||||
|
|
||||||
// The list of repositories
|
SparkleShare.Controller.OnFirstRun += delegate {
|
||||||
Repositories = new List <SparkleRepo> ();
|
Application.Invoke (delegate {
|
||||||
|
|
||||||
InstallLauncher ();
|
|
||||||
EnableSystemAutostart ();
|
|
||||||
|
|
||||||
// Create the SparkleShare folder and add it to the bookmarks
|
|
||||||
if (CreateSparkleShareFolder ())
|
|
||||||
AddToBookmarks ();
|
|
||||||
|
|
||||||
|
|
||||||
// Watch the SparkleShare folder
|
|
||||||
FileSystemWatcher watcher = new FileSystemWatcher (SparklePaths.SparklePath) {
|
|
||||||
IncludeSubdirectories = false,
|
|
||||||
EnableRaisingEvents = true,
|
|
||||||
Filter = "*"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove the repository when a delete event occurs
|
|
||||||
watcher.Deleted += delegate (object o, FileSystemEventArgs args) {
|
|
||||||
|
|
||||||
RemoveRepository (args.FullPath);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add the repository when a create event occurs
|
|
||||||
watcher.Created += delegate (object o, FileSystemEventArgs args) {
|
|
||||||
|
|
||||||
// Handle invitations when the user saves an
|
|
||||||
// invitation into the SparkleShare folder
|
|
||||||
if (args.Name.EndsWith (".invitation")) {
|
|
||||||
|
|
||||||
Application.Invoke (delegate {
|
|
||||||
|
|
||||||
SparkleInvitation invitation = new SparkleInvitation (args.FullPath);
|
|
||||||
invitation.Present ();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if (Directory.Exists (args.FullPath)) {
|
|
||||||
|
|
||||||
AddRepository (args.FullPath);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
CreateConfigurationFolders ();
|
|
||||||
|
|
||||||
// Don't create the window and status icon when
|
|
||||||
// the --disable-gui command line argument was given
|
|
||||||
if (!HideUI) {
|
|
||||||
|
|
||||||
string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config");
|
|
||||||
|
|
||||||
// Show the introduction screen if SparkleShare isn't configured
|
|
||||||
if (!File.Exists (global_config_file_path)) {
|
|
||||||
|
|
||||||
SparkleIntro intro = new SparkleIntro ();
|
SparkleIntro intro = new SparkleIntro ();
|
||||||
intro.ShowAll ();
|
intro.ShowAll ();
|
||||||
|
|
||||||
} else {
|
});
|
||||||
|
};
|
||||||
|
|
||||||
SparkleShare.UserName = SparkleShare.GetUserName ();
|
SparkleShare.Controller.OnInvitation += delegate (string invitation_file_path) {
|
||||||
SparkleShare.UserEmail = SparkleShare.GetUserEmail ();
|
Application.Invoke (delegate {
|
||||||
|
|
||||||
SparkleShare.AddKey ();
|
SparkleInvitation invitation = new SparkleInvitation (invitation_file_path);
|
||||||
|
invitation.Present ();
|
||||||
|
|
||||||
}
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Create the statusicon
|
// Show a bubble when there are new changes
|
||||||
StatusIcon = new SparkleStatusIcon ();
|
SparkleShare.Controller.NotificationRaised += delegate (string author, string email, string message,
|
||||||
|
string repository_path) {
|
||||||
|
|
||||||
}
|
Application.Invoke (delegate {
|
||||||
|
|
||||||
|
SparkleBubble bubble = new SparkleBubble (author, message) {
|
||||||
|
Icon = SparkleUIHelpers.GetAvatar (email, 32)
|
||||||
|
};
|
||||||
|
|
||||||
Thread thread = new Thread (
|
bubble.AddAction ("", "Show Events", delegate {
|
||||||
new ThreadStart (PopulateRepositories)
|
|
||||||
);
|
SparkleLog log = new SparkleLog (repository_path);
|
||||||
|
log.ShowAll ();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
thread.Start ();
|
bubble.Show ();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show a bubble when there was a conflict
|
||||||
|
SparkleShare.Controller.ConflictNotificationRaised += delegate {
|
||||||
|
Application.Invoke (delegate {
|
||||||
|
|
||||||
|
string title = _("Ouch! Mid-air collision!");
|
||||||
|
string subtext = _("Don't worry, SparkleShare made a copy of each conflicting file.");
|
||||||
|
|
||||||
|
SparkleBubble bubble = new SparkleBubble(title, subtext);
|
||||||
|
bubble.Show ();
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,401 +113,10 @@ namespace SparkleShare {
|
||||||
public void Run ()
|
public void Run ()
|
||||||
{
|
{
|
||||||
|
|
||||||
Gtk.Application.Run ();
|
Application.Run ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creates a folder in the user's home folder to store configuration
|
|
||||||
private void CreateConfigurationFolders ()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!Directory.Exists (SparklePaths.SparkleTmpPath))
|
|
||||||
Directory.CreateDirectory (SparklePaths.SparkleTmpPath);
|
|
||||||
|
|
||||||
string config_path = SparklePaths.SparkleConfigPath;
|
|
||||||
string local_icon_path = SparklePaths.SparkleLocalIconPath;
|
|
||||||
|
|
||||||
if (!Directory.Exists (config_path)) {
|
|
||||||
|
|
||||||
// Create a folder to store settings
|
|
||||||
Directory.CreateDirectory (config_path);
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "Created '" + config_path + "'");
|
|
||||||
|
|
||||||
// Create a folder to store the avatars
|
|
||||||
Directory.CreateDirectory (local_icon_path);
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "Created '" + local_icon_path + "'");
|
|
||||||
|
|
||||||
string notify_setting_file = SparkleHelpers.CombineMore (config_path, "sparkleshare.notify");
|
|
||||||
|
|
||||||
// Enable notifications by default
|
|
||||||
if (!File.Exists (notify_setting_file))
|
|
||||||
File.Create (notify_setting_file);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creates a .desktop entry in autostart folder to
|
|
||||||
// start SparkleShare automatically at login
|
|
||||||
private void EnableSystemAutostart ()
|
|
||||||
{
|
|
||||||
|
|
||||||
string autostart_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".config", "autostart");
|
|
||||||
string desktopfile_path = SparkleHelpers.CombineMore (autostart_path, "sparkleshare.desktop");
|
|
||||||
|
|
||||||
if (!File.Exists (desktopfile_path)) {
|
|
||||||
|
|
||||||
if (!Directory.Exists (autostart_path))
|
|
||||||
Directory.CreateDirectory (autostart_path);
|
|
||||||
|
|
||||||
TextWriter writer = new StreamWriter (desktopfile_path);
|
|
||||||
writer.WriteLine ("[Desktop Entry]\n" +
|
|
||||||
"Type=Application\n" +
|
|
||||||
"Name=SparkleShare\n" +
|
|
||||||
"Exec=sparkleshare start\n" +
|
|
||||||
"Icon=folder-sparkleshare\n" +
|
|
||||||
"Terminal=false\n" +
|
|
||||||
"X-GNOME-Autostart-enabled=true\n" +
|
|
||||||
"Categories=Network");
|
|
||||||
writer.Close ();
|
|
||||||
|
|
||||||
// Give the launcher the right permissions so it can be launched by the user
|
|
||||||
Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU);
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Installs a launcher so the user can launch SparkleShare
|
|
||||||
// from the Internet category if needed
|
|
||||||
private void InstallLauncher ()
|
|
||||||
{
|
|
||||||
|
|
||||||
string apps_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".local", "share", "applications");
|
|
||||||
string desktopfile_path = SparkleHelpers.CombineMore (apps_path, "sparkleshare.desktop");
|
|
||||||
|
|
||||||
if (!File.Exists (desktopfile_path)) {
|
|
||||||
|
|
||||||
if (!Directory.Exists (apps_path))
|
|
||||||
|
|
||||||
Directory.CreateDirectory (apps_path);
|
|
||||||
|
|
||||||
TextWriter writer = new StreamWriter (desktopfile_path);
|
|
||||||
writer.WriteLine ("[Desktop Entry]\n" +
|
|
||||||
"Type=Application\n" +
|
|
||||||
"Name=SparkleShare\n" +
|
|
||||||
"Comment=Share documents\n" +
|
|
||||||
"Exec=sparkleshare start\n" +
|
|
||||||
"Icon=folder-sparkleshare\n" +
|
|
||||||
"Terminal=false\n" +
|
|
||||||
"Categories=Network;");
|
|
||||||
writer.Close ();
|
|
||||||
|
|
||||||
// Give the launcher the right permissions so it can be launched by the user
|
|
||||||
Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU);
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Adds the SparkleShare folder to the user's
|
|
||||||
// list of bookmarked places
|
|
||||||
private void AddToBookmarks ()
|
|
||||||
{
|
|
||||||
|
|
||||||
string bookmarks_file_path = Path.Combine (SparklePaths.HomePath, ".gtk-bookmarks");
|
|
||||||
string sparkleshare_bookmark = "file://" + SparklePaths.SparklePath + " SparkleShare";
|
|
||||||
|
|
||||||
if (File.Exists (bookmarks_file_path)) {
|
|
||||||
|
|
||||||
StreamReader reader = new StreamReader (bookmarks_file_path);
|
|
||||||
string bookmarks = reader.ReadToEnd ();
|
|
||||||
reader.Close ();
|
|
||||||
|
|
||||||
if (!bookmarks.Contains (sparkleshare_bookmark)) {
|
|
||||||
|
|
||||||
TextWriter writer = File.AppendText (bookmarks_file_path);
|
|
||||||
writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare");
|
|
||||||
writer.Close ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
StreamWriter writer = new StreamWriter (bookmarks_file_path);
|
|
||||||
writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare");
|
|
||||||
writer.Close ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creates the SparkleShare folder in the user's home folder
|
|
||||||
private bool CreateSparkleShareFolder ()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!Directory.Exists (SparklePaths.SparklePath)) {
|
|
||||||
|
|
||||||
Directory.CreateDirectory (SparklePaths.SparklePath);
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "Created '" + SparklePaths.SparklePath + "'");
|
|
||||||
|
|
||||||
string icon_file_path = SparkleHelpers.CombineMore (Defines.PREFIX, "share", "icons", "hicolor",
|
|
||||||
"48x48", "apps", "folder-sparkleshare.png");
|
|
||||||
|
|
||||||
string gvfs_command_path = SparkleHelpers.CombineMore (Path.VolumeSeparatorChar.ToString (),
|
|
||||||
"usr", "bin", "gvfs-set-attribute");
|
|
||||||
|
|
||||||
// Add a special icon to the SparkleShare folder
|
|
||||||
if (File.Exists (gvfs_command_path)) {
|
|
||||||
|
|
||||||
Process process = new Process ();
|
|
||||||
|
|
||||||
process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
process.StartInfo.UseShellExecute = false;
|
|
||||||
|
|
||||||
process.StartInfo.FileName = "gvfs-set-attribute";
|
|
||||||
process.StartInfo.Arguments = SparklePaths.SparklePath + " metadata::custom-icon " +
|
|
||||||
"file://" + icon_file_path;
|
|
||||||
process.Start ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Shows a notification bubble when someone
|
|
||||||
// made a change to the repository
|
|
||||||
private void ShowNewCommitBubble (string author, string email, string message, string repository_name) {
|
|
||||||
|
|
||||||
string notify_settings_file = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath,
|
|
||||||
"sparkleshare.notify");
|
|
||||||
|
|
||||||
if (File.Exists (notify_settings_file)) {
|
|
||||||
|
|
||||||
SparkleBubble bubble = new SparkleBubble (author, message) {
|
|
||||||
Icon = SparkleUIHelpers.GetAvatar (email, 32)
|
|
||||||
};
|
|
||||||
|
|
||||||
bubble.AddAction ("", "Show Events", delegate {
|
|
||||||
|
|
||||||
string path = SparkleHelpers.CombineMore (SparklePaths.SparklePath, repository_name);
|
|
||||||
|
|
||||||
SparkleLog log = new SparkleLog (path);
|
|
||||||
log.ShowAll ();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
bubble.Show ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Shows a notification bubble when there
|
|
||||||
// was a conflict
|
|
||||||
private void ShowConflictBubble (object o, EventArgs args)
|
|
||||||
{
|
|
||||||
|
|
||||||
string title = _("Ouch! Mid-air collision!");
|
|
||||||
string subtext = _("Don't worry, SparkleShare made a copy of each conflicting file.");
|
|
||||||
|
|
||||||
SparkleBubble bubble = new SparkleBubble(title, subtext);
|
|
||||||
bubble.Show ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Tells the statusicon to update its state
|
|
||||||
private void UpdateStatusIcon (object o, EventArgs args)
|
|
||||||
{
|
|
||||||
|
|
||||||
StatusIcon.ShowState ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Adds a repository to the list of repositories and
|
|
||||||
// updates the statusicon menu
|
|
||||||
private void AddRepository (string folder_path)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Check if the folder is a git repo
|
|
||||||
if (!Directory.Exists (SparkleHelpers.CombineMore (folder_path, ".git")))
|
|
||||||
return;
|
|
||||||
|
|
||||||
SparkleRepo repo = new SparkleRepo (folder_path);
|
|
||||||
|
|
||||||
repo.NewCommit += delegate (object o, NewCommitArgs args) {
|
|
||||||
Application.Invoke (delegate { ShowNewCommitBubble (args.Author, args.Email, args.Message,
|
|
||||||
args.RepositoryName); });
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.Commited += delegate (object o, SparkleEventArgs args) {
|
|
||||||
Application.Invoke (delegate { CheckForUnicorns (args.Message); });
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.FetchingStarted += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.FetchingFinished += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.FetchingFailed += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.ChangesDetected += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.PushingStarted += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.PushingFinished += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.CommitEndedUpEmpty += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.PushingFailed += delegate {
|
|
||||||
Application.Invoke (UpdateStatusIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
repo.ConflictDetected += delegate {
|
|
||||||
Application.Invoke (ShowConflictBubble);
|
|
||||||
};
|
|
||||||
|
|
||||||
Repositories.Add (repo);
|
|
||||||
|
|
||||||
if (StatusIcon != null) {
|
|
||||||
|
|
||||||
Application.Invoke (delegate {
|
|
||||||
StatusIcon.CreateMenu ();
|
|
||||||
StatusIcon.ShowState ();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Removes a repository from the list of repositories and
|
|
||||||
// updates the statusicon menu
|
|
||||||
private void RemoveRepository (string folder_path)
|
|
||||||
{
|
|
||||||
|
|
||||||
string repo_name = Path.GetFileName (folder_path);
|
|
||||||
|
|
||||||
for (int i = 0; i < Repositories.Count; i++) {
|
|
||||||
|
|
||||||
SparkleRepo repo = Repositories [i];
|
|
||||||
|
|
||||||
if (repo.Name.Equals (repo_name)) {
|
|
||||||
|
|
||||||
repo.Dispose ();
|
|
||||||
Repositories.Remove (repo);
|
|
||||||
repo = null;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StatusIcon != null) {
|
|
||||||
|
|
||||||
Application.Invoke (delegate {
|
|
||||||
StatusIcon.CreateMenu ();
|
|
||||||
StatusIcon.ShowState ();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Updates the list of repositories with all the
|
|
||||||
// folders in the SparkleShare folder
|
|
||||||
private void PopulateRepositories ()
|
|
||||||
{
|
|
||||||
|
|
||||||
Repositories = new List <SparkleRepo> ();
|
|
||||||
|
|
||||||
foreach (string folder_path in Directory.GetDirectories (SparklePaths.SparklePath))
|
|
||||||
AddRepository (folder_path);
|
|
||||||
|
|
||||||
if (StatusIcon != null)
|
|
||||||
Application.Invoke (delegate { StatusIcon.ShowState (); });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Warns the user implicitly that unicorns are actually lethal creatures
|
|
||||||
private static void CheckForUnicorns (string message) {
|
|
||||||
|
|
||||||
message = message.ToLower ();
|
|
||||||
|
|
||||||
if (message.Contains ("unicorn") && (message.Contains (".png") || message.Contains (".jpg"))) {
|
|
||||||
|
|
||||||
string title = _("Hold your ponies!");
|
|
||||||
string subtext = _("SparkleShare is known to be insanely fast with " +
|
|
||||||
"pictures of unicorns. Please make sure your internets " +
|
|
||||||
"are upgraded to the latest version to avoid any problems.");
|
|
||||||
|
|
||||||
SparkleBubble bubble = new SparkleBubble (title, subtext);
|
|
||||||
bubble.Show ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Sets the unix process name to 'sparkleshare' instead of 'mono'
|
|
||||||
private void SetProcessName (string name)
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (prctl (15, Encoding.ASCII.GetBytes (name + "\0"), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0) {
|
|
||||||
|
|
||||||
throw new ApplicationException ("Error setting process name: " +
|
|
||||||
Mono.Unix.Native.Stdlib.GetLastError ());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (EntryPointNotFoundException) {
|
|
||||||
|
|
||||||
Console.WriteLine ("SetProcessName: Entry point not found");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Strange magic needed by SetProcessName
|
|
||||||
[DllImport ("libc")]
|
|
||||||
private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue