diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs
index a3c02a4c..8d7229f7 100755
--- a/SparkleLib/Git/SparkleRepoGit.cs
+++ b/SparkleLib/Git/SparkleRepoGit.cs
@@ -357,7 +357,7 @@ namespace SparkleLib {
// We need to specifically mention the file, so
// we can't reuse the Add () method
SparkleGit git_add = new SparkleGit (LocalPath,
- "add " + conflicting_path);
+ "add \"" + conflicting_path + "\"");
git_add.Start ();
git_add.WaitForExit ();
diff --git a/SparkleLib/SparkleConfig.cs b/SparkleLib/SparkleConfig.cs
index 7e5acec3..27dcf7fa 100755
--- a/SparkleLib/SparkleConfig.cs
+++ b/SparkleLib/SparkleConfig.cs
@@ -79,7 +79,7 @@ namespace SparkleLib {
if (file.Length == 0) {
File.Delete (FullPath);
- CreateInitialConfig ();
+ CreateInitialConfig ();
} else {
throw new XmlException (FullPath + " does not contain a valid config XML structure.");
diff --git a/SparkleShare/Makefile.am b/SparkleShare/Makefile.am
index 802cbdbd..122a90ac 100755
--- a/SparkleShare/Makefile.am
+++ b/SparkleShare/Makefile.am
@@ -23,6 +23,7 @@ SOURCES = \
SparkleEventLog.cs \
SparkleEventLogController.cs \
SparkleExtensions.cs \
+ SparklePlugin.cs \
SparkleSetup.cs \
SparkleSetupController.cs \
SparkleSetupWindow.cs \
diff --git a/SparkleShare/SparkleEntry.cs b/SparkleShare/SparkleEntry.cs
index 3d0f846c..304fe941 100755
--- a/SparkleShare/SparkleEntry.cs
+++ b/SparkleShare/SparkleEntry.cs
@@ -22,8 +22,9 @@ namespace SparkleShare {
public class SparkleEntry : Entry {
- public bool ExampleTextActive;
- private string pExampleText;
+
+ private string example_text;
+ private bool example_text_active;
public SparkleEntry ()
@@ -32,7 +33,7 @@ namespace SparkleShare {
FocusGrabbed += delegate { OnEntered (); };
ClipboardPasted += delegate { OnEntered (); };
-
+
FocusOutEvent += delegate {
if (Text.Equals ("") || Text == null)
ExampleTextActive = true;
@@ -47,33 +48,46 @@ namespace SparkleShare {
{
if (ExampleTextActive) {
ExampleTextActive = false;
- Text = "";
+ Text = "";
UseNormalTextColor ();
}
}
+ public bool ExampleTextActive {
+ get {
+ return this.example_text_active;
+ }
+
+ set {
+ this.example_text_active = value;
+
+ if (this.example_text_active)
+ UseSecondaryTextColor ();
+ else
+ UseNormalTextColor ();
+ }
+ }
+
+
public string ExampleText
{
get {
- return pExampleText;
+ return this.example_text;
}
set {
- pExampleText = value;
-
- if (ExampleTextActive) {
+ this.example_text = value;
+ if (this.example_text_active)
UseExampleText ();
-
- }
}
}
private void UseExampleText ()
{
- Text = pExampleText;
+ Text = this.example_text;
UseSecondaryTextColor ();
}
diff --git a/SparkleShare/SparklePlugin.cs b/SparkleShare/SparklePlugin.cs
new file mode 100644
index 00000000..e77fc15d
--- /dev/null
+++ b/SparkleShare/SparklePlugin.cs
@@ -0,0 +1,71 @@
+// SparkleShare, a collaboration and sharing tool.
+// 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 System;
+using System.IO;
+using System.Xml;
+
+namespace SparkleShare {
+
+ public class SparklePlugin {
+
+ public string Name;
+ public string Description;
+ public string ImagePath;
+ public string Backend;
+
+ public string Address;
+ public string AddressExample;
+ public string Path;
+ public string PathExample;
+
+
+ public SparklePlugin (string plugin_path)
+ {
+ string plugin_directory = System.IO.Path.GetDirectoryName (plugin_path);
+
+ XmlDocument xml = new XmlDocument ();
+ xml.Load (plugin_path);
+
+ XmlNode node;
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/info/name/text()");
+ if (node != null) { Name = node.Value; }
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/info/description/text()");
+ if (node != null) { Description = node.Value; }
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/info/icon/text()");
+ if (node != null) { ImagePath = System.IO.Path.Combine (plugin_directory, node.Value); }
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/info/backend/text()");
+ if (node != null) { Backend = node.Value; }
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/address/value/text()");
+ if (node != null) { Address = node.Value; }
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/address/example/text()");
+ if (node != null) { AddressExample = node.Value; }
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/path/value/text()");
+ if (node != null) { Path = node.Value; }
+
+ node = xml.SelectSingleNode ("/sparkleshare/plugin/path/example/text()");
+ if (node != null) { PathExample = node.Value; }
+ }
+ }
+}
diff --git a/SparkleShare/SparkleSetup.cs b/SparkleShare/SparkleSetup.cs
index 2ea766ad..c5628395 100755
--- a/SparkleShare/SparkleSetup.cs
+++ b/SparkleShare/SparkleSetup.cs
@@ -53,6 +53,15 @@ namespace SparkleShare {
}
+ private void RenderServiceColumn (TreeViewColumn column, CellRenderer cell,
+ TreeModel model, TreeIter iter)
+ {
+ (cell as Gtk.CellRendererText).Markup = (string) model.GetValue (iter, 1);
+ // TODO: When the row is highlighted, the description text should be
+ // colored with a mix of the selected text color + the selected row color
+ }
+
+
public SparkleSetup () : base ()
{
SecondaryTextColor = SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive));
@@ -118,133 +127,184 @@ namespace SparkleShare {
case PageType.Add: {
- Header = _("Where is your project?");
+ Header = _("Where's your project hosted?");
- Table = new Table (6, 2, false) {
- RowSpacing = 0
+ VBox layout_vertical = new VBox (false, 12);
+ HBox layout_fields = new HBox (true, 12);
+ VBox layout_address = new VBox (true, 0);
+ VBox layout_path = new VBox (true, 0);
+
+ ListStore store = new ListStore (typeof (Gdk.Pixbuf),
+ typeof (string), typeof (SparklePlugin));
+
+ TreeView tree = new TreeView (store) { HeadersVisible = false };
+
+ // Icon column
+ tree.AppendColumn ("Icon", new Gtk.CellRendererPixbuf (), "pixbuf", 0);
+ tree.Columns [0].Cells [0].Xpad = 6;
+
+ // Service column
+ TreeViewColumn service_column = new TreeViewColumn () { Title = "Service" };
+ CellRendererText service_cell = new CellRendererText () { Ypad = 4 };
+ service_column.PackStart (service_cell, true);
+ service_column.SetCellDataFunc (service_cell, new TreeCellDataFunc (RenderServiceColumn));
+
+ store.AppendValues (new Gdk.Pixbuf ("/usr/share/icons/gnome/24x24/places/network-server.png"),
+ "On my own server\n" +
+ "Everything under my control",
+ null);
+
+ foreach (SparklePlugin plugin in Controller.Plugins) {
+ store.AppendValues (
+ new Gdk.Pixbuf (plugin.ImagePath),
+ "" + plugin.Name + "\n" +
+ "" + plugin.Description + "",
+ plugin);
+ }
+
+ tree.AppendColumn (service_column);
+
+ // Select "On my own server" by default
+ TreeSelection default_selection = tree.Selection;
+ TreePath default_path = new TreePath ("0");
+ default_selection.SelectPath (default_path);
+
+ tree.Model.Foreach (new TreeModelForeachFunc (delegate (TreeModel model,
+ TreePath path, TreeIter iter) {
+
+ string address;
+
+ try {
+ address = (model.GetValue (iter, 2) as SparklePlugin).Address;
+ } catch (NullReferenceException) {
+ address = "";
+ }
+
+ if (!string.IsNullOrEmpty (address) &&
+ address.Equals (Controller.PreviousServer)) {
+
+ tree.SetCursor (path, service_column, false);
+ // TODO: Scroll to the selection
+
+ return true;
+ } else {
+ return false;
+ }
+ }));
+
+ // Update the address field text when the selection changes
+ tree.CursorChanged += delegate(object sender, EventArgs e) {
+ TreeIter iter;
+ TreeModel model;
+
+ TreeSelection selection = (sender as TreeView).Selection;
+ selection.GetSelected (out model, out iter);
+
+ SparklePlugin plugin = (SparklePlugin) model.GetValue (iter, 2);
+
+ ServerEntry.Sensitive = true;
+ FolderEntry.Sensitive = true;
+
+ if (plugin != null) {
+ if (plugin.Path != null) {
+ FolderEntry.Text = plugin.Path;
+ FolderEntry.Sensitive = false;
+ FolderEntry.ExampleTextActive = false;
+
+ } else if (plugin.PathExample != null) {
+ FolderEntry.Text = "";
+ FolderEntry.ExampleText = plugin.PathExample;
+ FolderEntry.ExampleTextActive = true;
+ }
+
+ if (plugin.Address != null) {
+ ServerEntry.Text = plugin.Address;
+ ServerEntry.Sensitive = false;
+ ServerEntry.ExampleTextActive = false;
+
+ } else if (plugin.AddressExample != null) {
+ ServerEntry.Text = "";
+ ServerEntry.ExampleText = plugin.AddressExample;
+ ServerEntry.ExampleTextActive = true;
+ }
+
+ } else {
+ ServerEntry.Text = "";
+ ServerEntry.ExampleTextActive = true;
+ ServerEntry.ExampleText = _("domain name or IP address");
+ FolderEntry.Text = "";
+ FolderEntry.ExampleTextActive = true;
+ FolderEntry.ExampleText = _("/path/to/project");
+ }
+
+ // TODO: Scroll along with the selection
};
- HBox layout_server = new HBox (true, 0);
+ ScrolledWindow scrolled_window = new ScrolledWindow ();
+ scrolled_window.AddWithViewport (tree);
- // Own server radiobutton
- RadioButton radio_button = new RadioButton ("" + _("On my own server:") + "");
- (radio_button.Child as Label).UseMarkup = true;
-
- radio_button.Toggled += delegate {
- if (radio_button.Active) {
- FolderEntry.ExampleText = _("Folder");
- ServerEntry.Sensitive = true;
- CheckAddPage ();
- } else {
- ServerEntry.Sensitive = false;
- CheckAddPage ();
- }
-
- ShowAll ();
- };
-
- // Own server entry
- ServerEntry = new SparkleEntry () { };
- ServerEntry.Completion = new EntryCompletion();
-
- ListStore server_store = new ListStore (typeof (string));
+ ServerEntry = new SparkleEntry ();
+ ServerEntry.Completion = new EntryCompletion();
+ ListStore server_store = new ListStore (typeof (string));
foreach (string host in Program.Controller.PreviousHosts)
server_store.AppendValues (host);
- ServerEntry.Completion.Model = server_store;
+ ServerEntry.Completion.Model = server_store;
ServerEntry.Completion.TextColumn = 0;
if (!string.IsNullOrEmpty (Controller.PreviousServer)) {
- ServerEntry.Text = Controller.PreviousServer;
+ ServerEntry.Text = Controller.PreviousServer;
ServerEntry.ExampleTextActive = false;
+
} else {
- ServerEntry.ExampleText = _("address-to-server.com");
+ ServerEntry.ExampleText = _("domain name or IP address");
}
ServerEntry.Changed += delegate {
CheckAddPage ();
};
- layout_server.Add (radio_button);
- layout_server.Add (ServerEntry);
+ layout_address.PackStart (new Label () {
+ Markup = "" + _("Address") + "",
+ Xalign = 0
+ }, true, true, 0);
- Table.Attach (layout_server, 0, 2, 1, 2);
+ layout_address.PackStart (ServerEntry, true, true, 0);
- // Github radiobutton
- string github_text = "" + "Github" + "";
+ FolderEntry = new SparkleEntry ();
+ FolderEntry.ExampleText = _("/path/to/project");
+ FolderEntry.Completion = new EntryCompletion();
- RadioButton radio_button_github = new RadioButton (radio_button, github_text);
- (radio_button_github.Child as Label).UseMarkup = true;
- (radio_button_github.Child as Label).Wrap = true;
+ if (!string.IsNullOrEmpty (Controller.PreviousFolder)) {
+ FolderEntry.Text = Controller.PreviousFolder;
+ FolderEntry.ExampleTextActive = false;
+ }
- radio_button_github.Toggled += delegate {
- if (radio_button_github.Active)
- FolderEntry.ExampleText = _("Username/Folder");
- };
+ ListStore folder_store = new ListStore (typeof (string));
+ //foreach (string host in Program.Controller.FolderPaths)
+ // folder_store.AppendValues (host);
- // Gitorious radiobutton
- string gitorious_text = "" + _("Gitorious") + "";
+ FolderEntry.Completion.Model = folder_store;
+ FolderEntry.Completion.TextColumn = 0;
- RadioButton radio_button_gitorious = new RadioButton (radio_button, gitorious_text);
- (radio_button_gitorious.Child as Label).UseMarkup = true;
- (radio_button_gitorious.Child as Label).Wrap = true;
+ FolderEntry.Changed += delegate {
+ CheckAddPage ();
+ };
- radio_button_gitorious.Toggled += delegate {
- if (radio_button_gitorious.Active)
- FolderEntry.ExampleText = _("Project/Folder");
- };
+ layout_path.PackStart (new Label () { Markup = "" + _("Remote Path") + "", Xalign = 0 },
+ true, true, 0);
+ layout_path.PackStart (FolderEntry, true, true, 0);
+ layout_fields.PackStart (layout_address);
+ layout_fields.PackStart (layout_path);
- // GNOME radiobutton
- string gnome_text = "" + _("The GNOME Project") + "";
+ layout_vertical.PackStart (new Label (""), false, false, 0);
+ layout_vertical.PackStart (scrolled_window, true, true, 0);
+ layout_vertical.PackStart (layout_fields, false, false, 0);
- RadioButton radio_button_gnome = new RadioButton (radio_button, gnome_text);
- (radio_button_gnome.Child as Label).UseMarkup = true;
- (radio_button_gnome.Child as Label).Wrap = true;
-
- radio_button_gnome.Toggled += delegate {
- if (radio_button_gnome.Active)
- FolderEntry.ExampleText = _("Project");
- };
-
- Table.Attach (radio_button_github, 0, 2, 2, 3);
- Table.Attach (radio_button_gitorious, 0, 2, 3, 4);
- Table.Attach (radio_button_gnome, 0, 2, 4, 5);
-
- // Folder label and entry
- HBox layout_folder = new HBox (true, 0);
-
- Label folder_label = new Label (_("Folder Name:")) {
- UseMarkup = true,
- Xalign = 1
- };
-
- FolderEntry = new SparkleEntry ();
- FolderEntry.ExampleText = _("Folder");
- FolderEntry.Completion = new EntryCompletion();
-
- ListStore folder_store = new ListStore (typeof (string));
-
- //foreach (string host in Program.Controller.FolderPaths)
- // folder_store.AppendValues (host);
-
- FolderEntry.Completion.Model = folder_store;
- FolderEntry.Completion.TextColumn = 0;
-
- FolderEntry.Changed += delegate {
- CheckAddPage ();
- };
-
- layout_folder.PackStart (folder_label, true, true, 12);
- layout_folder.PackStart (FolderEntry, true, true, 0);
-
- Table.Attach (layout_folder, 0, 2, 5, 6);
-
- VBox box = new VBox (false, 0);
- box.PackStart (Table, false, false, 0);
- Add (box);
+ Add (layout_vertical);
// Cancel button
Button cancel_button = new Button (_("Cancel"));
@@ -253,7 +313,6 @@ namespace SparkleShare {
Close ();
};
-
// Sync button
SyncButton = new Button (_("Add"));
@@ -261,15 +320,6 @@ namespace SparkleShare {
string server = ServerEntry.Text;
string folder_name = FolderEntry.Text;
- if (radio_button_gitorious.Active)
- server = "gitorious.org";
-
- if (radio_button_github.Active)
- server = "github.com";
-
- if (radio_button_gnome.Active)
- server = "gnome.org";
-
Controller.AddPageCompleted (server, folder_name);
};
diff --git a/SparkleShare/SparkleSetupController.cs b/SparkleShare/SparkleSetupController.cs
index af0b141f..c2f7ff1f 100755
--- a/SparkleShare/SparkleSetupController.cs
+++ b/SparkleShare/SparkleSetupController.cs
@@ -16,8 +16,11 @@
using System;
+using System.Collections.Generic;
using System.IO;
+using SparkleLib;
+
namespace SparkleShare {
public enum PageType {
@@ -38,6 +41,8 @@ namespace SparkleShare {
public event UpdateProgressBarEventHandler UpdateProgressBarEvent;
public delegate void UpdateProgressBarEventHandler (double percentage);
+ public readonly List Plugins = new List ();
+
public int TutorialPageNumber {
get {
@@ -101,6 +106,24 @@ namespace SparkleShare {
public SparkleSetupController ()
{
+ string local_plugins_path = SparkleHelpers.CombineMore (
+ Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
+ "sparkleshare", "plugins");
+
+ string plugins_path = SparkleHelpers.CombineMore (
+ Defines.DATAROOTDIR, "sparkleshare", "plugins");
+
+ try {
+ foreach (string xml_file_path in Directory.GetFiles (local_plugins_path, "*.xml"))
+ Plugins.Add (new SparklePlugin (xml_file_path));
+
+ foreach (string xml_file_path in Directory.GetFiles (plugins_path, "*.xml"))
+ Plugins.Add (new SparklePlugin (xml_file_path));
+
+ } catch (DirectoryNotFoundException e) {
+ Console.WriteLine ("Could not find any plugins: " + e.Message);
+ }
+
ChangePageEvent += delegate (PageType page) {
this.previous_page = page;
};
diff --git a/SparkleShare/SparkleSetupWindow.cs b/SparkleShare/SparkleSetupWindow.cs
index 15ec845f..3ef464c8 100755
--- a/SparkleShare/SparkleSetupWindow.cs
+++ b/SparkleShare/SparkleSetupWindow.cs
@@ -24,7 +24,6 @@ using System.Timers;
using Gtk;
using Mono.Unix;
-using SparkleLib;
namespace SparkleShare {
diff --git a/SparkleShare/SparkleShare.csproj b/SparkleShare/SparkleShare.csproj
index 199f702d..74a4e64c 100755
--- a/SparkleShare/SparkleShare.csproj
+++ b/SparkleShare/SparkleShare.csproj
@@ -73,5 +73,6 @@
+
diff --git a/data/plugins/Makefile.am b/data/plugins/Makefile.am
new file mode 100644
index 00000000..646cf71b
--- /dev/null
+++ b/data/plugins/Makefile.am
@@ -0,0 +1,14 @@
+dist_plugins_DATA = \
+ github.xml \
+ github.png \
+ gitorious.xml \
+ gitorious.png \
+ bitbucket.xml \
+ bitbucket.png \
+ gnome.xml \
+ gnome.png
+
+pluginsdir = $(pkgdatadir)/plugins/
+
+MAINTAINERCLEANFILES = \
+ Makefile.in
diff --git a/data/plugins/bitbucket.png b/data/plugins/bitbucket.png
new file mode 100644
index 00000000..223d3fa1
Binary files /dev/null and b/data/plugins/bitbucket.png differ
diff --git a/data/plugins/bitbucket.xml b/data/plugins/bitbucket.xml
new file mode 100644
index 00000000..c343abd6
--- /dev/null
+++ b/data/plugins/bitbucket.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Bitbucket
+ Free code hosting for Mercurial
+ bitbucket.png
+ Mercurial
+
+
+ ssh://hg@bitbucket.org/
+
+
+
+
+ /username/project
+
+
+
+
diff --git a/data/plugins/github.png b/data/plugins/github.png
new file mode 100644
index 00000000..ca5dda80
Binary files /dev/null and b/data/plugins/github.png differ
diff --git a/data/plugins/github.xml b/data/plugins/github.xml
new file mode 100644
index 00000000..83d371b4
--- /dev/null
+++ b/data/plugins/github.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Github
+ Free public Git repositories with collaborator management
+ github.png
+ Git
+
+
+ ssh://git@github.com/
+
+
+
+
+ /username/project
+
+
+
+
diff --git a/data/plugins/gitorious.png b/data/plugins/gitorious.png
new file mode 100644
index 00000000..0a9ddb58
Binary files /dev/null and b/data/plugins/gitorious.png differ
diff --git a/data/plugins/gitorious.xml b/data/plugins/gitorious.xml
new file mode 100644
index 00000000..2abc3ae8
--- /dev/null
+++ b/data/plugins/gitorious.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Gitorious
+ Open source infrastructure for hosting open source projects
+ gitorious.png
+ Git
+
+
+ ssh://git@gitorious.org/
+
+
+
+
+ /project/repository
+
+
+
+
diff --git a/data/plugins/gnome.png b/data/plugins/gnome.png
new file mode 100644
index 00000000..d596c2bf
Binary files /dev/null and b/data/plugins/gnome.png differ
diff --git a/data/plugins/gnome.xml b/data/plugins/gnome.xml
new file mode 100644
index 00000000..716cbd10
--- /dev/null
+++ b/data/plugins/gnome.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ The GNOME Project
+ A free and easy interface for your computer
+ gnome.png
+ Git
+
+
+ ssh://git@gnome.org/
+
+
+
+
+ /project
+
+
+
+
diff --git a/data/src/add-project-dialog.svg b/data/src/add-project-dialog.svg
new file mode 100644
index 00000000..25c7ac79
--- /dev/null
+++ b/data/src/add-project-dialog.svg
@@ -0,0 +1,374 @@
+
+
+
+