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 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + Address + + Remote Path + + On my own server + Github Free public repositories with collaborator management Where is your project? domain name or IP address /path/to/project + ? + ? + + Add Cancel Gitorious Open source infrastructure for hosting open source projects Everything under my control + G + + + + + +