From c6174704923b28c858cd31d7dbf9071a3f1b14d4 Mon Sep 17 00:00:00 2001 From: Andrew Shadura Date: Tue, 19 Jan 2016 09:06:32 +0100 Subject: Import sparkleshare_1.5.0.orig.tar.xz [dgit import orig sparkleshare_1.5.0.orig.tar.xz] --- .gitignore | 48 + Makefile.am | 23 + News.txt | 405 ++ README.md | 34 + SparkleLib/Defines.cs | 31 + SparkleLib/Defines.cs.in | 31 + SparkleLib/Git/Makefile.am | 22 + SparkleLib/Git/SparkleFetcherGit.cs | 450 ++ SparkleLib/Git/SparkleGit.cs | 166 + SparkleLib/Git/SparkleLib.Git.csproj | 59 + SparkleLib/Git/SparkleRepoGit.cs | 1225 ++++ SparkleLib/Makefile.am | 32 + SparkleLib/SparkleBackend.cs | 60 + SparkleLib/SparkleConfig.cs | 364 ++ SparkleLib/SparkleExtensions.cs | 146 + SparkleLib/SparkleFetcherBase.cs | 272 + SparkleLib/SparkleFetcherSSH.cs | 173 + SparkleLib/SparkleLib.csproj | 51 + SparkleLib/SparkleLib.sln | 20 + SparkleLib/SparkleListenerBase.cs | 216 + SparkleLib/SparkleListenerFactory.cs | 66 + SparkleLib/SparkleListenerTcp.cs | 259 + SparkleLib/SparkleLogger.cs | 106 + SparkleLib/SparkleRepoBase.cs | 632 +++ SparkleLib/SparkleUser.cs | 42 + SparkleLib/SparkleWatcher.cs | 63 + SparkleLib/SparkleWrappers.cs | 109 + SparkleShare/Common/HTML/Makefile.am | 10 + SparkleShare/Common/HTML/day-entry.html | 4 + SparkleShare/Common/HTML/event-entry.html | 13 + SparkleShare/Common/HTML/event-log.html | 224 + SparkleShare/Common/HTML/jquery.js | 18 + .../add-to-sparkleshare-button.png | Bin 0 -> 4339 bytes .../Common/HTML/protocol-handler-test/invite.xml | 9 + .../protocol-handler-test.htm | 38 + SparkleShare/Common/Makefile.am | 3 + SparkleShare/Common/Pixmaps/Makefile.am | 12 + .../Common/Pixmaps/Sources/about-dialog.svg | 3494 ++++++++++++ SparkleShare/Common/Pixmaps/Sources/actions.svg | 220 + SparkleShare/Common/Pixmaps/Sources/app-icons.svg | 2009 +++++++ SparkleShare/Common/Pixmaps/Sources/bitbucket.svg | 48 + .../Pixmaps/Sources/folder-icons-mac-yosemite.svg | 1500 +++++ .../Common/Pixmaps/Sources/folder-icons-mac.svg | 144 + .../Pixmaps/Sources/folder-icons-windows.svg | 1160 ++++ SparkleShare/Common/Pixmaps/Sources/github.svg | 82 + SparkleShare/Common/Pixmaps/Sources/gitorious.svg | 63 + .../Common/Pixmaps/Sources/side-splash.svg | 3752 +++++++++++++ SparkleShare/Common/Pixmaps/Sources/ssnet.svg | 105 + .../Common/Pixmaps/Sources/status-icons.svg | 3057 ++++++++++ .../Common/Pixmaps/Sources/tutorial-slides.svg | 5904 ++++++++++++++++++++ .../Common/Pixmaps/Sources/user-icon-default.svg | 35 + SparkleShare/Common/Pixmaps/about.png | Bin 0 -> 66572 bytes SparkleShare/Common/Pixmaps/about@2x.png | Bin 0 -> 197165 bytes SparkleShare/Common/Pixmaps/side-splash.png | Bin 0 -> 64937 bytes SparkleShare/Common/Pixmaps/side-splash@2x.png | Bin 0 -> 189579 bytes SparkleShare/Common/Pixmaps/text-balloon.png | Bin 0 -> 1118 bytes SparkleShare/Common/Pixmaps/text-balloon@2x.png | Bin 0 -> 2632 bytes SparkleShare/Common/Pixmaps/tutorial-slide-1.png | Bin 0 -> 27962 bytes .../Common/Pixmaps/tutorial-slide-1@2x.png | Bin 0 -> 71140 bytes SparkleShare/Common/Pixmaps/tutorial-slide-2.png | Bin 0 -> 23261 bytes .../Common/Pixmaps/tutorial-slide-2@2x.png | Bin 0 -> 63666 bytes SparkleShare/Common/Pixmaps/user-icon-default.png | Bin 0 -> 558 bytes SparkleShare/Common/Plugins/Makefile.am | 18 + SparkleShare/Common/Plugins/bitbucket.png | Bin 0 -> 1202 bytes SparkleShare/Common/Plugins/bitbucket.xml | 21 + SparkleShare/Common/Plugins/bitbucket@2x.png | Bin 0 -> 2599 bytes SparkleShare/Common/Plugins/github.png | Bin 0 -> 1578 bytes SparkleShare/Common/Plugins/github.xml | 20 + SparkleShare/Common/Plugins/github@2x.png | Bin 0 -> 3633 bytes SparkleShare/Common/Plugins/gitorious.png | Bin 0 -> 1238 bytes SparkleShare/Common/Plugins/gitorious.xml | 20 + SparkleShare/Common/Plugins/gitorious@2x.png | Bin 0 -> 2751 bytes SparkleShare/Common/Plugins/own-server.png | Bin 0 -> 1161 bytes SparkleShare/Common/Plugins/own-server.xml | 19 + SparkleShare/Common/Plugins/own-server@2x.png | Bin 0 -> 2409 bytes SparkleShare/Common/Plugins/parse_plugins.xsl | 33 + SparkleShare/Common/Plugins/planio.png | Bin 0 -> 3232 bytes SparkleShare/Common/Plugins/planio.xml | 21 + SparkleShare/Common/Plugins/planio@2x.png | Bin 0 -> 4609 bytes SparkleShare/Common/Plugins/ssnet.png | Bin 0 -> 1438 bytes SparkleShare/Common/Plugins/ssnet.xml | 19 + SparkleShare/Common/Plugins/ssnet@2x.png | Bin 0 -> 3701 bytes SparkleShare/Common/Translations/LINGUAS | 29 + SparkleShare/Common/Translations/Makefile.in.in | 222 + SparkleShare/Common/Translations/POTFILES.in | 24 + SparkleShare/Common/Translations/POTFILES.skip | 3 + SparkleShare/Common/Translations/README.transifex | 11 + SparkleShare/Common/Translations/ar.po | 414 ++ SparkleShare/Common/Translations/bg.po | 411 ++ SparkleShare/Common/Translations/ca.po | 413 ++ SparkleShare/Common/Translations/cs_CZ.po | 413 ++ SparkleShare/Common/Translations/da.po | 408 ++ SparkleShare/Common/Translations/de.po | 436 ++ SparkleShare/Common/Translations/el.po | 389 ++ SparkleShare/Common/Translations/eo.po | 407 ++ SparkleShare/Common/Translations/es.po | 394 ++ SparkleShare/Common/Translations/fi.po | 410 ++ SparkleShare/Common/Translations/fr.po | 421 ++ SparkleShare/Common/Translations/he.po | 407 ++ SparkleShare/Common/Translations/hu.po | 409 ++ SparkleShare/Common/Translations/it.po | 391 ++ SparkleShare/Common/Translations/ja.po | 407 ++ SparkleShare/Common/Translations/nl.po | 427 ++ SparkleShare/Common/Translations/nn_NO.po | 408 ++ SparkleShare/Common/Translations/no_NO.po | 418 ++ SparkleShare/Common/Translations/pl.po | 430 ++ SparkleShare/Common/Translations/pt_BR.po | 393 ++ SparkleShare/Common/Translations/ru.po | 425 ++ SparkleShare/Common/Translations/sk.po | 407 ++ SparkleShare/Common/Translations/sl.po | 411 ++ SparkleShare/Common/Translations/sort-potfiles | 6 + SparkleShare/Common/Translations/sr_RS.po | 379 ++ SparkleShare/Common/Translations/stamp-it | 0 SparkleShare/Common/Translations/sv.po | 424 ++ SparkleShare/Common/Translations/te.po | 405 ++ SparkleShare/Common/Translations/uk.po | 409 ++ SparkleShare/Common/Translations/zh_CN.po | 378 ++ SparkleShare/Common/Translations/zh_TW.po | 404 ++ SparkleShare/Linux/Makefile.am | 47 + SparkleShare/Linux/Pixmaps/Makefile.am | 9 + SparkleShare/Linux/Pixmaps/icons/Makefile.am | 48 + .../Linux/Pixmaps/icons/document-added-12.png | Bin 0 -> 193 bytes .../Linux/Pixmaps/icons/document-deleted-12.png | Bin 0 -> 117 bytes .../Linux/Pixmaps/icons/document-edited-12.png | Bin 0 -> 428 bytes .../Linux/Pixmaps/icons/document-moved-12.png | Bin 0 -> 445 bytes SparkleShare/Linux/Pixmaps/icons/gnome/Makefile.am | 20 + .../Pixmaps/icons/gnome/sparkleshare-symbolic.svg | 17 + SparkleShare/Linux/Pixmaps/icons/list-point-16.png | Bin 0 -> 575 bytes .../Linux/Pixmaps/icons/process-syncing-24.png | Bin 0 -> 831 bytes .../Linux/Pixmaps/icons/process-syncing-48.png | Bin 0 -> 1679 bytes .../Pixmaps/icons/process-syncing-down-24.png | Bin 0 -> 768 bytes .../Pixmaps/icons/process-syncing-down-48.png | Bin 0 -> 1620 bytes .../Pixmaps/icons/process-syncing-error-24.png | Bin 0 -> 1017 bytes .../Pixmaps/icons/process-syncing-error-48.png | Bin 0 -> 2699 bytes .../Linux/Pixmaps/icons/process-syncing-up-24.png | Bin 0 -> 768 bytes .../Linux/Pixmaps/icons/process-syncing-up-48.png | Bin 0 -> 1588 bytes .../Linux/Pixmaps/icons/process-working-22.png | Bin 0 -> 4104 bytes .../Linux/Pixmaps/icons/sparkleshare-16.png | Bin 0 -> 689 bytes .../Linux/Pixmaps/icons/sparkleshare-22.png | Bin 0 -> 926 bytes .../Linux/Pixmaps/icons/sparkleshare-24.png | Bin 0 -> 1196 bytes .../Linux/Pixmaps/icons/sparkleshare-256.png | Bin 0 -> 47701 bytes .../Linux/Pixmaps/icons/sparkleshare-32.png | Bin 0 -> 1270 bytes .../Linux/Pixmaps/icons/sparkleshare-48.png | Bin 0 -> 2182 bytes .../Pixmaps/icons/ubuntu-mono-dark/Makefile.am | 25 + .../icons/ubuntu-mono-dark/process-syncing-24.png | Bin 0 -> 268 bytes .../ubuntu-mono-dark/process-syncing-down-24.png | Bin 0 -> 271 bytes .../ubuntu-mono-dark/process-syncing-error-24.png | Bin 0 -> 266 bytes .../ubuntu-mono-dark/process-syncing-idle-24.png | Bin 0 -> 361 bytes .../ubuntu-mono-dark/process-syncing-up-24.png | Bin 0 -> 271 bytes .../Pixmaps/icons/ubuntu-mono-light/Makefile.am | 25 + .../icons/ubuntu-mono-light/process-syncing-24.png | Bin 0 -> 252 bytes .../ubuntu-mono-light/process-syncing-down-24.png | Bin 0 -> 258 bytes .../ubuntu-mono-light/process-syncing-error-24.png | Bin 0 -> 250 bytes .../ubuntu-mono-light/process-syncing-idle-24.png | Bin 0 -> 337 bytes .../ubuntu-mono-light/process-syncing-up-24.png | Bin 0 -> 259 bytes SparkleShare/Linux/Pixmaps/tutorial-slide-3.png | Bin 0 -> 36876 bytes SparkleShare/Linux/README.md | 93 + SparkleShare/Linux/SparkleAbout.cs | 182 + SparkleShare/Linux/SparkleBubbles.cs | 65 + SparkleShare/Linux/SparkleController.cs | 205 + SparkleShare/Linux/SparkleEventLog.cs | 289 + SparkleShare/Linux/SparkleNote.cs | 141 + SparkleShare/Linux/SparkleSetup.cs | 734 +++ SparkleShare/Linux/SparkleSetupWindow.cs | 155 + SparkleShare/Linux/SparkleStatusIcon.cs | 297 + SparkleShare/Linux/SparkleUI.cs | 99 + SparkleShare/Linux/SparkleUIHelpers.cs | 93 + .../Linux/sparkleshare-invite-opener.desktop | 7 + SparkleShare/Linux/sparkleshare.appdata.xml | 26 + SparkleShare/Linux/sparkleshare.desktop | 9 + SparkleShare/Linux/sparkleshare.in | 29 + SparkleShare/Mac/AppDelegate.cs | 31 + SparkleShare/Mac/Info.plist | 26 + SparkleShare/Mac/MainMenu.xib | 2195 ++++++++ SparkleShare/Mac/MainMenu.xib.designer.cs | 18 + SparkleShare/Mac/README.md | 57 + .../Mac/Resources/process-syncing-down.png | Bin 0 -> 270 bytes .../Mac/Resources/process-syncing-down@2x.png | Bin 0 -> 396 bytes .../Mac/Resources/process-syncing-error.png | Bin 0 -> 267 bytes .../Mac/Resources/process-syncing-error@2x.png | Bin 0 -> 388 bytes .../Mac/Resources/process-syncing-idle.png | Bin 0 -> 271 bytes .../Mac/Resources/process-syncing-idle@2x.png | Bin 0 -> 726 bytes SparkleShare/Mac/Resources/process-syncing-up.png | Bin 0 -> 273 bytes .../Mac/Resources/process-syncing-up@2x.png | Bin 0 -> 415 bytes SparkleShare/Mac/Resources/process-syncing.png | Bin 0 -> 271 bytes SparkleShare/Mac/Resources/process-syncing@2x.png | Bin 0 -> 329 bytes SparkleShare/Mac/Resources/sparkleshare-app.icns | Bin 0 -> 143098 bytes .../Resources/sparkleshare-folder-yosemite.icns | Bin 0 -> 58104 bytes .../Mac/Resources/sparkleshare-folder.icns | Bin 0 -> 100868 bytes SparkleShare/Mac/Resources/tutorial-slide-3.png | Bin 0 -> 91923 bytes SparkleShare/Mac/Resources/tutorial-slide-3@2x.png | Bin 0 -> 259208 bytes SparkleShare/Mac/SparkleAbout.cs | 219 + SparkleShare/Mac/SparkleBubbles.cs | 54 + SparkleShare/Mac/SparkleController.cs | 241 + SparkleShare/Mac/SparkleEventLog.cs | 419 ++ SparkleShare/Mac/SparkleMacWatcher.cs | 196 + SparkleShare/Mac/SparkleNote.cs | 233 + SparkleShare/Mac/SparkleSetup.cs | 878 +++ SparkleShare/Mac/SparkleSetupWindow.cs | 156 + SparkleShare/Mac/SparkleShare.csproj | 296 + SparkleShare/Mac/SparkleShare.sln | 56 + .../Contents/Info.plist | 57 + .../Contents/MacOS/applet | Bin 0 -> 34480 bytes .../SparkleShareInviteOpener.app/Contents/PkgInfo | 1 + .../Contents/Resources/Scripts/main.scpt | Bin 0 -> 3688 bytes .../Contents/Resources/applet.icns | Bin 0 -> 40291 bytes .../Contents/Resources/applet.rsrc | Bin 0 -> 362 bytes .../Contents/Resources/description.rtfd/TXT.rtf | 4 + SparkleShare/Mac/SparkleStatusIcon.cs | 288 + SparkleShare/Mac/SparkleUI.cs | 97 + SparkleShare/Mac/checkGit.sh | 37 + SparkleShare/Mac/config | 30 + SparkleShare/Mac/git.version | 1 + SparkleShare/Mac/packReleaseDist.sh | 24 + SparkleShare/Mac/postBuild.sh | 15 + SparkleShare/Makefile.am | 2 + SparkleShare/Program.cs | 96 + SparkleShare/SparkleAboutController.cs | 78 + SparkleShare/SparkleAvatars.cs | 131 + SparkleShare/SparkleBubblesController.cs | 59 + SparkleShare/SparkleControllerBase.cs | 796 +++ SparkleShare/SparkleEventLogController.cs | 643 +++ SparkleShare/SparkleExtensions.cs | 35 + SparkleShare/SparkleInvite.cs | 120 + SparkleShare/SparkleKeys.cs | 105 + SparkleShare/SparkleNoteController.cs | 67 + SparkleShare/SparklePlugin.cs | 123 + SparkleShare/SparkleSetupController.cs | 594 ++ SparkleShare/SparkleStatusIconController.cs | 408 ++ SparkleShare/Windows/LICENSE.rtf | 115 + SparkleShare/Windows/Pixmaps/folder.png | Bin 0 -> 639 bytes .../Windows/Pixmaps/process-syncing-down.png | Bin 0 -> 352 bytes .../Windows/Pixmaps/process-syncing-error.png | Bin 0 -> 300 bytes .../Windows/Pixmaps/process-syncing-idle.png | Bin 0 -> 433 bytes .../Windows/Pixmaps/process-syncing-up.png | Bin 0 -> 357 bytes SparkleShare/Windows/Pixmaps/process-syncing.png | Bin 0 -> 288 bytes SparkleShare/Windows/Pixmaps/sparkleshare-app.ico | Bin 0 -> 68092 bytes .../Windows/Pixmaps/sparkleshare-folder.ico | Bin 0 -> 38403 bytes .../Windows/Pixmaps/sparkleshare-folder.png | Bin 0 -> 633 bytes SparkleShare/Windows/Pixmaps/tutorial-slide-3.png | Bin 0 -> 24292 bytes SparkleShare/Windows/README.md | 43 + SparkleShare/Windows/Settings.StyleCop | 379 ++ SparkleShare/Windows/SparkleAbout.cs | 186 + SparkleShare/Windows/SparkleBubbles.cs | 37 + SparkleShare/Windows/SparkleController.cs | 270 + SparkleShare/Windows/SparkleEventLog.cs | 372 ++ SparkleShare/Windows/SparkleEventLogWindow.xaml | 38 + SparkleShare/Windows/SparkleEventLogWindow.xaml.cs | 262 + .../Windows/SparkleLib/Git/SparkleLib.Git.csproj | 71 + SparkleShare/Windows/SparkleLib/SparkleLib.csproj | 97 + SparkleShare/Windows/SparkleNote.xaml | 37 + SparkleShare/Windows/SparkleNote.xaml.cs | 123 + SparkleShare/Windows/SparkleNotifyIcon.cs | 188 + SparkleShare/Windows/SparkleSetup.cs | 985 ++++ SparkleShare/Windows/SparkleSetupWindow.cs | 193 + SparkleShare/Windows/SparkleShare.csproj | 294 + SparkleShare/Windows/SparkleShare.sln | 49 + SparkleShare/Windows/SparkleShare.sln.DotSettings | 18 + SparkleShare/Windows/SparkleShare.vssettings | 97 + SparkleShare/Windows/SparkleShare.wxs | 82 + .../Properties/AssemblyInfo.cs | 36 + .../SparkleShareInviteOpener/Settings.StyleCop | 1 + .../SparkleShareInviteOpener.csproj | 50 + .../Windows/SparkleShareInviteOpener/app.config | 3 + .../sparkleshare-invite-opener.cs | 69 + SparkleShare/Windows/SparkleShortcut.cs | 196 + SparkleShare/Windows/SparkleSpinner.cs | 91 + SparkleShare/Windows/SparkleStatusIcon.cs | 339 ++ SparkleShare/Windows/SparkleUI.cs | 73 + SparkleShare/Windows/SparkleUIHelpers.cs | 79 + SparkleShare/Windows/build.cmd | 28 + autogen.sh | 85 + build/Makefile.am | 6 + build/build.environment.mk | 31 + build/build.mk | 3 + build/build.rules.mk | 78 + build/bump-version.sh | 16 + build/icon-theme-installer | 187 + build/m4/Makefile.am | 7 + build/m4/shamrock/expansions.m4 | 50 + build/m4/shamrock/gnome-doc.m4 | 23 + build/m4/shamrock/i18n.m4 | 10 + build/m4/shamrock/mono.m4 | 68 + build/m4/shamrock/monodoc.m4 | 25 + build/m4/shamrock/nunit.m4 | 29 + build/m4/shamrock/programs.m4 | 15 + build/m4/shamrock/util.m4 | 11 + build/m4/shave/shave-libtool.in | 109 + build/m4/shave/shave.in | 109 + build/m4/shave/shave.m4 | 102 + build/m4/sparkleshare/gtk-sharp.m4 | 14 + configure.ac | 136 + legal/Authors.txt | 47 + legal/License_for_SparkleLib.txt | 166 + legal/License_for_SparkleShare.txt | 621 ++ legal/Trademark.txt | 41 + 296 files changed, 57714 insertions(+) create mode 100644 .gitignore create mode 100755 Makefile.am create mode 100755 News.txt create mode 100644 README.md create mode 100644 SparkleLib/Defines.cs create mode 100755 SparkleLib/Defines.cs.in create mode 100755 SparkleLib/Git/Makefile.am create mode 100755 SparkleLib/Git/SparkleFetcherGit.cs create mode 100644 SparkleLib/Git/SparkleGit.cs create mode 100644 SparkleLib/Git/SparkleLib.Git.csproj create mode 100644 SparkleLib/Git/SparkleRepoGit.cs create mode 100755 SparkleLib/Makefile.am create mode 100755 SparkleLib/SparkleBackend.cs create mode 100755 SparkleLib/SparkleConfig.cs create mode 100755 SparkleLib/SparkleExtensions.cs create mode 100755 SparkleLib/SparkleFetcherBase.cs create mode 100644 SparkleLib/SparkleFetcherSSH.cs create mode 100644 SparkleLib/SparkleLib.csproj create mode 100755 SparkleLib/SparkleLib.sln create mode 100755 SparkleLib/SparkleListenerBase.cs create mode 100644 SparkleLib/SparkleListenerFactory.cs create mode 100755 SparkleLib/SparkleListenerTcp.cs create mode 100755 SparkleLib/SparkleLogger.cs create mode 100755 SparkleLib/SparkleRepoBase.cs create mode 100644 SparkleLib/SparkleUser.cs create mode 100755 SparkleLib/SparkleWatcher.cs create mode 100644 SparkleLib/SparkleWrappers.cs create mode 100755 SparkleShare/Common/HTML/Makefile.am create mode 100755 SparkleShare/Common/HTML/day-entry.html create mode 100755 SparkleShare/Common/HTML/event-entry.html create mode 100755 SparkleShare/Common/HTML/event-log.html create mode 100755 SparkleShare/Common/HTML/jquery.js create mode 100644 SparkleShare/Common/HTML/protocol-handler-test/add-to-sparkleshare-button.png create mode 100644 SparkleShare/Common/HTML/protocol-handler-test/invite.xml create mode 100644 SparkleShare/Common/HTML/protocol-handler-test/protocol-handler-test.htm create mode 100644 SparkleShare/Common/Makefile.am create mode 100644 SparkleShare/Common/Pixmaps/Makefile.am create mode 100644 SparkleShare/Common/Pixmaps/Sources/about-dialog.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/actions.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/app-icons.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/bitbucket.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/folder-icons-mac-yosemite.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/folder-icons-mac.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/folder-icons-windows.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/github.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/gitorious.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/side-splash.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/ssnet.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/status-icons.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/tutorial-slides.svg create mode 100644 SparkleShare/Common/Pixmaps/Sources/user-icon-default.svg create mode 100755 SparkleShare/Common/Pixmaps/about.png create mode 100644 SparkleShare/Common/Pixmaps/about@2x.png create mode 100755 SparkleShare/Common/Pixmaps/side-splash.png create mode 100644 SparkleShare/Common/Pixmaps/side-splash@2x.png create mode 100644 SparkleShare/Common/Pixmaps/text-balloon.png create mode 100644 SparkleShare/Common/Pixmaps/text-balloon@2x.png create mode 100644 SparkleShare/Common/Pixmaps/tutorial-slide-1.png create mode 100644 SparkleShare/Common/Pixmaps/tutorial-slide-1@2x.png create mode 100644 SparkleShare/Common/Pixmaps/tutorial-slide-2.png create mode 100644 SparkleShare/Common/Pixmaps/tutorial-slide-2@2x.png create mode 100644 SparkleShare/Common/Pixmaps/user-icon-default.png create mode 100644 SparkleShare/Common/Plugins/Makefile.am create mode 100644 SparkleShare/Common/Plugins/bitbucket.png create mode 100644 SparkleShare/Common/Plugins/bitbucket.xml create mode 100644 SparkleShare/Common/Plugins/bitbucket@2x.png create mode 100644 SparkleShare/Common/Plugins/github.png create mode 100644 SparkleShare/Common/Plugins/github.xml create mode 100644 SparkleShare/Common/Plugins/github@2x.png create mode 100644 SparkleShare/Common/Plugins/gitorious.png create mode 100644 SparkleShare/Common/Plugins/gitorious.xml create mode 100644 SparkleShare/Common/Plugins/gitorious@2x.png create mode 100644 SparkleShare/Common/Plugins/own-server.png create mode 100644 SparkleShare/Common/Plugins/own-server.xml create mode 100644 SparkleShare/Common/Plugins/own-server@2x.png create mode 100644 SparkleShare/Common/Plugins/parse_plugins.xsl create mode 100644 SparkleShare/Common/Plugins/planio.png create mode 100644 SparkleShare/Common/Plugins/planio.xml create mode 100644 SparkleShare/Common/Plugins/planio@2x.png create mode 100644 SparkleShare/Common/Plugins/ssnet.png create mode 100644 SparkleShare/Common/Plugins/ssnet.xml create mode 100644 SparkleShare/Common/Plugins/ssnet@2x.png create mode 100755 SparkleShare/Common/Translations/LINGUAS create mode 100644 SparkleShare/Common/Translations/Makefile.in.in create mode 100755 SparkleShare/Common/Translations/POTFILES.in create mode 100755 SparkleShare/Common/Translations/POTFILES.skip create mode 100755 SparkleShare/Common/Translations/README.transifex create mode 100755 SparkleShare/Common/Translations/ar.po create mode 100755 SparkleShare/Common/Translations/bg.po create mode 100755 SparkleShare/Common/Translations/ca.po create mode 100755 SparkleShare/Common/Translations/cs_CZ.po create mode 100755 SparkleShare/Common/Translations/da.po create mode 100755 SparkleShare/Common/Translations/de.po create mode 100755 SparkleShare/Common/Translations/el.po create mode 100755 SparkleShare/Common/Translations/eo.po create mode 100755 SparkleShare/Common/Translations/es.po create mode 100755 SparkleShare/Common/Translations/fi.po create mode 100755 SparkleShare/Common/Translations/fr.po create mode 100755 SparkleShare/Common/Translations/he.po create mode 100755 SparkleShare/Common/Translations/hu.po create mode 100755 SparkleShare/Common/Translations/it.po create mode 100755 SparkleShare/Common/Translations/ja.po create mode 100755 SparkleShare/Common/Translations/nl.po create mode 100755 SparkleShare/Common/Translations/nn_NO.po create mode 100755 SparkleShare/Common/Translations/no_NO.po create mode 100755 SparkleShare/Common/Translations/pl.po create mode 100755 SparkleShare/Common/Translations/pt_BR.po create mode 100755 SparkleShare/Common/Translations/ru.po create mode 100644 SparkleShare/Common/Translations/sk.po create mode 100644 SparkleShare/Common/Translations/sl.po create mode 100755 SparkleShare/Common/Translations/sort-potfiles create mode 100755 SparkleShare/Common/Translations/sr_RS.po create mode 100644 SparkleShare/Common/Translations/stamp-it create mode 100755 SparkleShare/Common/Translations/sv.po create mode 100755 SparkleShare/Common/Translations/te.po create mode 100755 SparkleShare/Common/Translations/uk.po create mode 100755 SparkleShare/Common/Translations/zh_CN.po create mode 100755 SparkleShare/Common/Translations/zh_TW.po create mode 100644 SparkleShare/Linux/Makefile.am create mode 100755 SparkleShare/Linux/Pixmaps/Makefile.am create mode 100755 SparkleShare/Linux/Pixmaps/icons/Makefile.am create mode 100755 SparkleShare/Linux/Pixmaps/icons/document-added-12.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/document-deleted-12.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/document-edited-12.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/document-moved-12.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/gnome/Makefile.am create mode 100644 SparkleShare/Linux/Pixmaps/icons/gnome/sparkleshare-symbolic.svg create mode 100755 SparkleShare/Linux/Pixmaps/icons/list-point-16.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-syncing-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-syncing-48.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-syncing-down-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-syncing-down-48.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/process-syncing-error-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-syncing-error-48.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-syncing-up-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-syncing-up-48.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/process-working-22.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/sparkleshare-16.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/sparkleshare-22.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/sparkleshare-24.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/sparkleshare-256.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/sparkleshare-32.png create mode 100755 SparkleShare/Linux/Pixmaps/icons/sparkleshare-48.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/Makefile.am create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-down-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-error-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-idle-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-up-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/Makefile.am create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-down-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-error-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-idle-24.png create mode 100644 SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-up-24.png create mode 100755 SparkleShare/Linux/Pixmaps/tutorial-slide-3.png create mode 100644 SparkleShare/Linux/README.md create mode 100755 SparkleShare/Linux/SparkleAbout.cs create mode 100755 SparkleShare/Linux/SparkleBubbles.cs create mode 100755 SparkleShare/Linux/SparkleController.cs create mode 100755 SparkleShare/Linux/SparkleEventLog.cs create mode 100755 SparkleShare/Linux/SparkleNote.cs create mode 100755 SparkleShare/Linux/SparkleSetup.cs create mode 100755 SparkleShare/Linux/SparkleSetupWindow.cs create mode 100644 SparkleShare/Linux/SparkleStatusIcon.cs create mode 100644 SparkleShare/Linux/SparkleUI.cs create mode 100755 SparkleShare/Linux/SparkleUIHelpers.cs create mode 100644 SparkleShare/Linux/sparkleshare-invite-opener.desktop create mode 100644 SparkleShare/Linux/sparkleshare.appdata.xml create mode 100755 SparkleShare/Linux/sparkleshare.desktop create mode 100755 SparkleShare/Linux/sparkleshare.in create mode 100755 SparkleShare/Mac/AppDelegate.cs create mode 100755 SparkleShare/Mac/Info.plist create mode 100755 SparkleShare/Mac/MainMenu.xib create mode 100755 SparkleShare/Mac/MainMenu.xib.designer.cs create mode 100644 SparkleShare/Mac/README.md create mode 100644 SparkleShare/Mac/Resources/process-syncing-down.png create mode 100644 SparkleShare/Mac/Resources/process-syncing-down@2x.png create mode 100755 SparkleShare/Mac/Resources/process-syncing-error.png create mode 100644 SparkleShare/Mac/Resources/process-syncing-error@2x.png create mode 100755 SparkleShare/Mac/Resources/process-syncing-idle.png create mode 100644 SparkleShare/Mac/Resources/process-syncing-idle@2x.png create mode 100644 SparkleShare/Mac/Resources/process-syncing-up.png create mode 100644 SparkleShare/Mac/Resources/process-syncing-up@2x.png create mode 100644 SparkleShare/Mac/Resources/process-syncing.png create mode 100644 SparkleShare/Mac/Resources/process-syncing@2x.png create mode 100755 SparkleShare/Mac/Resources/sparkleshare-app.icns create mode 100644 SparkleShare/Mac/Resources/sparkleshare-folder-yosemite.icns create mode 100755 SparkleShare/Mac/Resources/sparkleshare-folder.icns create mode 100644 SparkleShare/Mac/Resources/tutorial-slide-3.png create mode 100644 SparkleShare/Mac/Resources/tutorial-slide-3@2x.png create mode 100755 SparkleShare/Mac/SparkleAbout.cs create mode 100755 SparkleShare/Mac/SparkleBubbles.cs create mode 100755 SparkleShare/Mac/SparkleController.cs create mode 100755 SparkleShare/Mac/SparkleEventLog.cs create mode 100755 SparkleShare/Mac/SparkleMacWatcher.cs create mode 100755 SparkleShare/Mac/SparkleNote.cs create mode 100755 SparkleShare/Mac/SparkleSetup.cs create mode 100755 SparkleShare/Mac/SparkleSetupWindow.cs create mode 100644 SparkleShare/Mac/SparkleShare.csproj create mode 100644 SparkleShare/Mac/SparkleShare.sln create mode 100644 SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Info.plist create mode 100755 SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/MacOS/applet create mode 100644 SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/PkgInfo create mode 100644 SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/Scripts/main.scpt create mode 100644 SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.icns create mode 100644 SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.rsrc create mode 100644 SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/description.rtfd/TXT.rtf create mode 100755 SparkleShare/Mac/SparkleStatusIcon.cs create mode 100755 SparkleShare/Mac/SparkleUI.cs create mode 100755 SparkleShare/Mac/checkGit.sh create mode 100644 SparkleShare/Mac/config create mode 100644 SparkleShare/Mac/git.version create mode 100755 SparkleShare/Mac/packReleaseDist.sh create mode 100755 SparkleShare/Mac/postBuild.sh create mode 100755 SparkleShare/Makefile.am create mode 100644 SparkleShare/Program.cs create mode 100755 SparkleShare/SparkleAboutController.cs create mode 100644 SparkleShare/SparkleAvatars.cs create mode 100755 SparkleShare/SparkleBubblesController.cs create mode 100644 SparkleShare/SparkleControllerBase.cs create mode 100755 SparkleShare/SparkleEventLogController.cs create mode 100644 SparkleShare/SparkleExtensions.cs create mode 100644 SparkleShare/SparkleInvite.cs create mode 100644 SparkleShare/SparkleKeys.cs create mode 100755 SparkleShare/SparkleNoteController.cs create mode 100644 SparkleShare/SparklePlugin.cs create mode 100755 SparkleShare/SparkleSetupController.cs create mode 100755 SparkleShare/SparkleStatusIconController.cs create mode 100644 SparkleShare/Windows/LICENSE.rtf create mode 100644 SparkleShare/Windows/Pixmaps/folder.png create mode 100644 SparkleShare/Windows/Pixmaps/process-syncing-down.png create mode 100644 SparkleShare/Windows/Pixmaps/process-syncing-error.png create mode 100644 SparkleShare/Windows/Pixmaps/process-syncing-idle.png create mode 100644 SparkleShare/Windows/Pixmaps/process-syncing-up.png create mode 100644 SparkleShare/Windows/Pixmaps/process-syncing.png create mode 100644 SparkleShare/Windows/Pixmaps/sparkleshare-app.ico create mode 100644 SparkleShare/Windows/Pixmaps/sparkleshare-folder.ico create mode 100644 SparkleShare/Windows/Pixmaps/sparkleshare-folder.png create mode 100644 SparkleShare/Windows/Pixmaps/tutorial-slide-3.png create mode 100644 SparkleShare/Windows/README.md create mode 100644 SparkleShare/Windows/Settings.StyleCop create mode 100644 SparkleShare/Windows/SparkleAbout.cs create mode 100644 SparkleShare/Windows/SparkleBubbles.cs create mode 100644 SparkleShare/Windows/SparkleController.cs create mode 100644 SparkleShare/Windows/SparkleEventLog.cs create mode 100644 SparkleShare/Windows/SparkleEventLogWindow.xaml create mode 100644 SparkleShare/Windows/SparkleEventLogWindow.xaml.cs create mode 100644 SparkleShare/Windows/SparkleLib/Git/SparkleLib.Git.csproj create mode 100644 SparkleShare/Windows/SparkleLib/SparkleLib.csproj create mode 100644 SparkleShare/Windows/SparkleNote.xaml create mode 100644 SparkleShare/Windows/SparkleNote.xaml.cs create mode 100644 SparkleShare/Windows/SparkleNotifyIcon.cs create mode 100644 SparkleShare/Windows/SparkleSetup.cs create mode 100644 SparkleShare/Windows/SparkleSetupWindow.cs create mode 100644 SparkleShare/Windows/SparkleShare.csproj create mode 100644 SparkleShare/Windows/SparkleShare.sln create mode 100644 SparkleShare/Windows/SparkleShare.sln.DotSettings create mode 100644 SparkleShare/Windows/SparkleShare.vssettings create mode 100644 SparkleShare/Windows/SparkleShare.wxs create mode 100644 SparkleShare/Windows/SparkleShareInviteOpener/Properties/AssemblyInfo.cs create mode 100644 SparkleShare/Windows/SparkleShareInviteOpener/Settings.StyleCop create mode 100644 SparkleShare/Windows/SparkleShareInviteOpener/SparkleShareInviteOpener.csproj create mode 100644 SparkleShare/Windows/SparkleShareInviteOpener/app.config create mode 100644 SparkleShare/Windows/SparkleShareInviteOpener/sparkleshare-invite-opener.cs create mode 100644 SparkleShare/Windows/SparkleShortcut.cs create mode 100644 SparkleShare/Windows/SparkleSpinner.cs create mode 100644 SparkleShare/Windows/SparkleStatusIcon.cs create mode 100644 SparkleShare/Windows/SparkleUI.cs create mode 100644 SparkleShare/Windows/SparkleUIHelpers.cs create mode 100644 SparkleShare/Windows/build.cmd create mode 100755 autogen.sh create mode 100755 build/Makefile.am create mode 100755 build/build.environment.mk create mode 100755 build/build.mk create mode 100755 build/build.rules.mk create mode 100755 build/bump-version.sh create mode 100755 build/icon-theme-installer create mode 100755 build/m4/Makefile.am create mode 100755 build/m4/shamrock/expansions.m4 create mode 100755 build/m4/shamrock/gnome-doc.m4 create mode 100755 build/m4/shamrock/i18n.m4 create mode 100755 build/m4/shamrock/mono.m4 create mode 100755 build/m4/shamrock/monodoc.m4 create mode 100755 build/m4/shamrock/nunit.m4 create mode 100755 build/m4/shamrock/programs.m4 create mode 100755 build/m4/shamrock/util.m4 create mode 100755 build/m4/shave/shave-libtool.in create mode 100755 build/m4/shave/shave.in create mode 100755 build/m4/shave/shave.m4 create mode 100755 build/m4/sparkleshare/gtk-sharp.m4 create mode 100755 configure.ac create mode 100755 legal/Authors.txt create mode 100644 legal/License_for_SparkleLib.txt create mode 100755 legal/License_for_SparkleShare.txt create mode 100644 legal/Trademark.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70faa4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +*~ +*.swp +*.swo +.DS_Store +*.exe +*.exe.mdb +*.userprefs +*.pidb +*.gmo +*.bak +*.suo +*.sln.cache +*.user +*.resources +Makefile.in +Makefile +intltool-* +configure +config.guess +config.h +config.h.in +config.log +config.status +config.sub +aclocal.m4 +autom4te.cache/ +bin/ +obj/ +install-sh +libtool +ltmain.sh +missing +build/m4/shave/shave +build/m4/*.m4 +build/m4/shave/shave-libtool +SparkleLib/Defines.cs +SparkleShare/Linux/sparkleshare +SparkleShare/Mac/git* +gnome-doc-utils.make +/sparkleshare-* +desktop.ini +_ReSharper.* +*.msi +*.wixobj +*.wixpdb +*.wxs +*.dotCover + diff --git a/Makefile.am b/Makefile.am new file mode 100755 index 0000000..47f3b20 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,23 @@ +basedirs = build SparkleLib SparkleLib/Git + +SUBDIRS = $(basedirs) $(GUISUBDIRS) +DIST_SUBDIRS = $(basedirs) SparkleShare + +EXTRA_DIST = \ + News.txt \ + README.md \ + legal/License_for_SparkleShare.txt \ + legal/License_for_SparkleLib.txt \ + legal/Trademark.txt \ + legal/Authors.txt \ + SparkleShare/Linux/README.md \ + SparkleShare/Linux/sparkleshare.appdata.xml + +DISTCLEANFILES = \ + intltool-extract \ + intltool-merge \ + intltool-update \ + gnome-doc-utils.make + +clean-local: + rm -rf $(top_builddir)/bin diff --git a/News.txt b/News.txt new file mode 100755 index 0000000..3203bc5 --- /dev/null +++ b/News.txt @@ -0,0 +1,405 @@ +1.5.0 for Linux, Mac and Windows (Tue Dec 22, 2015): + + Hylke: + - Mac UI updates to integrate well with Yosemite + - Per folder sync status in icon menu + - Add ability to pause sync and add a commit message on resume + - Remove dock icon on Mac and force windows on top + - Update certificate for Gravatar + - Resizable "Recent Changes" window on Windows + - Several stability fixes + - Improvements to filesystem watcher and exclude list + - Use more secure 4096 bit SSH keys + - Use hashed and salted password to encrypt files + - Fix change attribution in Recent Changes window on merges + - Fix disabled Continue button when entering encryption password + + +1.4.0 for Linux, Mac and Windows (Sun Apr 20, 2014): + + Hylke: + - Check user's local bin folders for git binary + - Show a notification after trying to start the app multiple times + - Set default focus on password fields when setting up encryption + - Show disclosure triangly on Recent Changes window timestamps + - Fix some conflict resolution issues by merging instead of rebasing on the remote + - Fix crash when copying to clipboard on Windows + - Sync more quickly after the system wakes up from sleep + - Fix conflict resolution when renaming folders + + +1.3.0 for Linux (Sat Oct 26 2013): + + Hylke: + This release focuses mainly on the move to GTK+3 and GNOME 3 integration. + If you're running SparkleShare on GNOME you're in for a treat. Special thanks + go to Bertrand Lorentz, Mirco Bauer and Stephan Sundermann for help with + the bindings, build system adjustments, and other things: + + - Port interface from GTK+2 to GTK+3, replace widget implementations with new APIs + - Use GTK+3 compatible bindings for libnotify, webkitgtk, and appindicator + - Many style usability and behaviour fixes in the setup dialog + - Fix annoying flicker when changing projects on the Recent Changes window + - Improved window scalability of the Recent Changes window and about dialog + - Remove menu item that toggles notifications (this can now be done in + GNOME's system menu) + - Refocus on existing SparkleShare instance when starting multiple times + - Include an appdata XML file for the GNOME Software application + - Show correct icon and application name on GNOME 3 and Ubuntu + + Cross-platform changes: + - Relicense SparkleLib, SparkleShare's common library, to GNU LGPLv3+ + - Set default focus on widgets for different forms in setup dialog + + +1.2.0 for Linux, Mac and Windows (Sun 6 Oct 2013): + + Hylke: + - Fixes to the invite feature, now works when SparkleShare isn't + running yet (by Jo Shields) + - Don't crash, but complain when FIPS is enabled on Windows + - Fix some interface logic in Add dialog + - Fix some inaccurate sync state messages in the status icon + - Fix conflict when running when TortoiseGit is installed + - Fix blank Add dialog on OS X Snow Leopard + - Fix crash when user cancels initial project download + - Fix Continue button not enabling when entering encryption password + - Fix Planio plugin name showing up as Gitorious on Linux + - Show download speed on initial project add + + +1.1.0 for Linux, Mac and Windows (Sun 26 May 2013): + + Hylke: + - Fixed retina Mac support by Aaron Bockover + - Don't sync files with names that are problematic on Windows + - Show Client ID (link code) in the status icon menu + - Don't show notifications for changes that you made yourself + - Use large message tray icon on GNOME 3 + - Added a plugin for plan.io + - Work with host keys other than just RSA + - "%20" and "_" in project names become spaces in folder names + - Stricter permissions on the SparkleShare folder on Unix systems + - Open folders in the event log by clicking project names + - Allow spaces in passwords + - Change invite scheme to sparkleshare://addProject/$URL + - Many other bug fixes and tweaks + + +1.0.0 for Linux, Mac and Windows (Sun Dec 9 2012): + + Hylke: + - Rebrand 0.9.10 with some minor changes to 1.0.0 + + +0.9.10 for Linux, Mac and Windows (Fri Dec 7 2012): + + Hylke: + - Fix folders not opening from statusicon menu on Windows + - Fix freeze on Mac when retrying a failed add a project attempt + - Fix a freeze on Mac when updating the status icon when the menu is open + + +0.9.9 for Linux, Mac and Windows (Mon Dec 3 2012): + + Hylke: + - Add high resolution images for retina displays on macs + - Put uncommonly used menu items in a submenu in the statusicon + - Fix an issue connecting to encrypted projects + - New tutorial slides + - Detect more types of sync errors + - Various small fixes and cleanups + + +0.9.8 for Linux, Mac and Windows (Sun Nov 18 2012): + + Hylke: + - Show both the cumulative upload and download speeds when multiple + projects are syncing at the same time + - Defer receiving changes when affected files are locked and show + a warning in the statusicon (mostly affects Windows) + - Fix an issue where changing the case of a file name that will be + synced to Windows or Mac would result in a no longer syncable project + - Add a "Try Again" action underneath every error reported in the + statusicon to force a retry + - Always sync to the default git branch even when it's not named + "master" (e.g. "gh-pages") + - Fix unicode characters displaying weirdly in the event log + + +0.9.7 for Linux, Mac and Windows (Sat Nov 10 2012): + + Hylke: + - Remove Growl and use native OS X notifications + - Treat underscores in project names as spaces for the folder names + - Allow periods "." in project names + - Depend on git >= 1.7.12 + - Fix Mac unicode compatibility (could cause duplicate files or folders + between different platforms) + + +0.9.6 for Linux, Mac and Windows (Sat Oct 27 2012): + + Hylke: + - Show link code and Copy button on last tutorial page + - Fix crash when the SparkleShare folder is on an unmounted drive + - Fix crash of the event log on Windows + - Keep Continue button in the same place on each tutorial page + - Remove dock icon badging on Mac now that Mountain Lion has + a notification queue + + +0.9.5 for Linux, Mac and Windows (Sun Oct 21 2012): + + Hylke: + - Fix "Show all" link not working in event log + - Fix wrong version number in the Windows about dialog + - Fix some problems with encrypted projects + - Fix .sparkleshare file not always being hidden on Windows + - Fix "Open files" button when an encrypted project has been added + - Fix a crash of the event log on Windows + + +0.9.4 for Linux, Mac and Windows (Fri Oct 19 2012): + + Hylke: + - Remove Nautilus extension + - Restore previous revisions of files from the event log + - Fix Mac file system watcher not always triggering + - Add symbolic icon for GNOME 3 (by Lapo) + - New Bitbucket and default user icon + - For encrypted projects, use a different salt for each project + + +0.9.3 for Linux, Mac and Windows (Mon Oct 1 2012): + + Hylke: + - Fix endless loop when adding empty folders + - Fix freeze when adding lots of files + - Fix using hosts with a non-standard SSH port + - Fix receiving of notification service message after the first one + - New non-animating status icons + - More descriptive error reporting in the status icon + - Add link to debug log in the about dialog + - Use port 443 on the notification service to work better in + restricted networks + + +0.9.2 for Linux, Mac and Windows (Wed Aug 29 2012): + + Hylke: + - This release fixes a crash that can happen after adding a new + project as well ssh-agent sometimes not starting on Windows + + +0.9.1 for Linux, Mac and Windows (Mon Aug 27 2012): + + Hylke: + - Use HTTPS to fetch gravatars + - Website links in the about dialog + - Scalable custom folder icon in Nautilus 3.x + - Default host user is now "storage" instead of "git" + - Create crash reports in ~/SparkleShare when things go wrong + - New Windows folder icons + - Project folders can now be renamed in the file manager + - Resizable event log on Mac + - Fix some bugs in conflict resolution mechanism + + +0.9.0 for Linux, Mac and Windows (Wed Jun 27 2012): + + Hylke: + - Experimental client side encryption using OpenSSL's AES + - Allow setting custom paths in config.xml + - Ship host keys of default plugins and verify on project add + - Don't touch the user's ~/.ssh/config to configure SSH + - Make fetching remote project's history optional + - Cached logs for faster event log loading/switching + - Sort event log file entries by time + - Change default notification service to use port 80 + - Show backend error message(s) when on failed project add + - Update Growl framework to version 1.3.1: A separate Growl + is no longer needed and ready for Mountain Lion's notifications + - Monochrome appindicator icons on Ubuntu + + Travis: + - Rewrote the notification service, now more robust and reliable + + +0.8.4 for Linux, Mac and Windows (Sun Mar 18 2012): + + Hylke: + - Show initial sync progress in taskbar item on Windows 7 + - Fix "Add" item being disabled on first run + - Fix some crashes in notfication mechanism + - Use ~/SparkleShare instead of ~/My Documents/SparkleShare on Windows + - Add option to add SparkleShare to startup items on Windows + - Add SparkleShare to Explorer sidebar + - Report whether we're sending or receiving (or both) in the status icon + - Fix some cases where SparkleShare would incorrectly say "not synced" + - Some UI changes on Windows to comply with the Windows HIG + + +0.8.3 for Linux, Mac and Windows (Sun Mar 11 2012): + + Hylke: + - Windows version implemented with WPF + - Invites feature: link to a host with one click + - Implement sparklshare:// protocol handlers for invites + - "Add SparkleShare to login items" checkbox on the last tutorial page + - Text entries aren't being reset when selecting plugins in the setup dialog + - A variety of new default avatars (GNOME style) + - More useful hints below the entries in the setup dialog + - Breadcrumbs for paths in the event log: directories can be clicked + - Allow backends to be in separate binaries (by Shish) + - If the dock icon is visible and has a count badge, open event log on click + - Add previously successfully used hosts as plugins + + +0.8.2 for Linux and Mac (Sat Feb 11 2012): + + Hylke: + - Use the more reliable and less resource intensive FSEvents on Mac. + - Improvements to the reconnect mechanism of the notification system + + +0.8.1 for Linux and Mac (Sun Jan 29 2012): + + Hylke: + - Disable the Quit menu item when a sync is going on + - Show remote url when hovering project names in the log + - Fix the event log on Linux + - Allow server ports to be specified once again + - Open Folder button after setup now takes you to SparkleShare/subfolder + - Close event log on Cmd+W on Mac + + +0.8.0 for Linux and Mac (Sun Jan 22 2012): + + Hylke: + - Show syncing progress in the status icon + - Hide dock icon on Mac until you open a window + - Update dates in the event log after midnight + - Don't let git compress already compressed files (.jpg .ogg .zip, etc.) + - Limit git's memory usage + - Ignore history of any added git/hg/bzr repositories, just add the files + - Spin status icon on syncing changes made before startup + + +0.6.0 for Linux and Mac (Sun Dec 25 2011): + + Hylke: + - Several fixes for annoying bugs and crashes + - Fix freeze on quit on Mac + - Show project and history size in the event log + + +0.4.2 for Linux and Mac (Fri Dec 2 2011): + Hylke: + - Fix crash trying to add a project + + +0.4.1 for Linux and Mac (Tue Nov 29 2011): + Hylke: Just some small tweaks and fixes: + + - Bundle git with the Mac application + - Warn about potential global gitignore files + - Remove SmartIrc4Net + - Build system fixes + - Code cleanups + + +0.4.0 for Linux and Mac (Sun Nov 12 2011): + Hylke: It has been a while since the last release. Since so many + things changed, and it being (softly) incompatible with 0.2, I decided + to call it 0.4. Here are the most important improvements: + + - Support OS X Lion + - Revamped "Add Hosted Project..." dialog + - First run tutorial + - Clicking notifications opens the event log + - Support for organisation/host plugins + - Adding empty folders now works + - More useful error reporting + - Progress bar on the initial sync, and a button to cancel + - Replace IRC by a custom protocol as the default notification system + - Many many fixes for crashes and bugs + + Travis: + - Nautilus 3.x plugin + - Bugfixes + + +0.2.5 for Linux and Mac (Mon Jul 25 2011): + + Hylke: Reimplement notes to be less buggy and backend independent. Polish + about dialog and event log html. Fix a bug where large collections of files + weren't being synced when adding them at the same time. The event log now + collapses huge change sets and squashes events together by day when they + are on the same day and in the same folder. Add a controller per UI component + to make the Windows verion easier to implement. + + +0.2.4 for Linux and Mac (Wed Jun 29, 2011): + + Hylke: Fix crash when setting up with an empty Git repository. + + +0.2.3 for Linux and Mac (Tue Jun 28, 2011): + + Hylke: Add the ability to add notes in the event logs. Fix some quirks + in the webkit view on Linux. Redid gravatar fetching parts to be more + efficient. Remove headless feature. Fix some small bugs and crashes. + SparkleShare will now also try to use your existing SSH keypair. Required + Git version is now 1.7.1 or later. + + +0.2.2 for Linux and Mac (Tue Jun 14, 2011): + + Hylke: Fix crash on first run when ~/.ssh doesn't exist. Sync algorithm + tweaks. New global event log. Ubuntu integration with libappindicator. Poll + sometimes even when using the notification service. + + +0.2.1 for Linux and Mac (Wed Jun 8, 2011): + + Hylke: Fix bug where host names with a "-" in them weren't accepted. Fix + crash that happens when the user doesn't have their "Real Name" set in the + OS and a race condition connecting to the announcements server. + + +0.2 for Linux and Mac (Mon Jun 6, 2011): + + Hylke: Removed the dependancy on GitSharp. File rename detection support + in the event logs. Fixed all crashes reported in RC1 and improved sync + algorithm. Redid collision detection and conflict resolving (use a copy + of each version). Improved about dialogs with version checking. Pluggable + backend (experimental Mercurial support). Added support for Growl to show + notifications on Mac. + + +0.2-rc1 for Linux and Mac (Sun Mar 20, 2011): + + Hylke: A lot of fixes and optimisations across the backend. Less memory + usage, less crashes. Instant notifications of new changes instead of polling. + Refreshed event log HTML theme. Keeping logs in memory for faster reopening and + loads more goodness. + + +0.2-beta2 for Mac (Sat Feb 12, 2011): + + Hylke: Mac version! Massive restructure of the code to an MVC-like model + to make building different front-ends easier. Ported the event logs to + Webkit, so users can style it to their liking. It also reduces the amount + of UI-porting that needs to be done between toolkits. + + +0.2-beta1 (Sun Sep 5, 2010): + + Hylke: Aside from the usual bug fixes and behind the scenes work I mainly + added features that increase productivity in the event logs. Not only does + it look a lot prettier, each entry in an event log now has a clickable link + for easy access to files. It refreshes automatically on new events as well. + The Nautilus plugin now has the "Copy Web Link" context menu item, which + makes sharing links a whole lot easier. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..f029e78 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# SparkleShare + +SparkleShare is an Open Source collaboration and sharing tool that is designed to keep things simple and to stay out of your way. It's available for Linux distributions, Mac, and Windows. + +![Banner](https://raw.githubusercontent.com/hbons/SparkleShare/master/SparkleShare/Common/Pixmaps/tutorial-slide-2%402x.png) + + +## How does it work? + +SparkleShare creates a special folder on your computer. You can add remotely hosted folders (or "projects") to this folder. These projects will be automatically kept in sync with both the host and all of your peers when someone adds, removes or edits a file. + + +## Setting up a host + +SparkleShare uses the version control system [Git](https://git-scm.com/) under the hood, so setting up a host yourself is relatively easy. Using your own host gives you more privacy and control, as well as lots of cheap storage space and higher transfer speeds. We've made a simple [script](https://github.com/hbons/Dazzle) that does the hard work for you. If you need to manage a lot of projects and/or users it may be worth setting up a [GitLab](https://www.gitlabhq.com) instance. + + +## Free and Open Source +`SparkleShare` is Free and Open Source software and licensed under the [GNU General Public License version 3 or later](legal/License_for_SparkleShare.txt). You are welcome to change and redistribute it under certain conditions. Its library `SparkleLib` is licensed under the [GNU Lesser General Public License version 3 or later](legal/License_for_SparkleLib.txt). + + +## Compiling from source + +Here are instructions to build SparkleShare on [Linux distributions](SparkleShare/Linux/README.md), [Mac](SparkleShare/Mac/README.md), and [Windows](SparkleShare/Windows/README.md). Make sure to have the `git` package installed when you're building on Linux. + + +## Useful links +[Website](http://www.sparkleshare.org/), [Twitter](https://www.twitter.com/SparkleShare), [Wiki](https://www.github.com/hbons/SparkleShare/wiki), and [Source Code](https://www.github.com/hbons/SparkleShare). Join the chat: #sparkleshare on irc.gnome.org. + + +## Finally + +Have fun, make awesome. :) + diff --git a/SparkleLib/Defines.cs b/SparkleLib/Defines.cs new file mode 100644 index 0000000..cd81609 --- /dev/null +++ b/SparkleLib/Defines.cs @@ -0,0 +1,31 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Reflection; + +[assembly:AssemblyTitle ("SparkleLib")] +[assembly:AssemblyVersion ("1.5.0")] +[assembly:AssemblyCopyright ("Copyright (c) 2010 Hylke Bons and others")] +[assembly:AssemblyTrademark ("SparkleShare is a trademark of SparkleShare Ltd.")] + +namespace SparkleLib { + + public class Defines { + public const string INSTALL_DIR = "/usr/share/sparkleshare"; + } +} diff --git a/SparkleLib/Defines.cs.in b/SparkleLib/Defines.cs.in new file mode 100755 index 0000000..2b0c836 --- /dev/null +++ b/SparkleLib/Defines.cs.in @@ -0,0 +1,31 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Reflection; + +[assembly:AssemblyTitle ("SparkleLib")] +[assembly:AssemblyVersion ("@VERSION@")] +[assembly:AssemblyCopyright ("Copyright (c) 2010 Hylke Bons and others")] +[assembly:AssemblyTrademark ("SparkleShare is a trademark of SparkleShare Ltd.")] + +namespace SparkleLib { + + public class Defines { + public const string INSTALL_DIR = "@expanded_datadir@/sparkleshare"; + } +} diff --git a/SparkleLib/Git/Makefile.am b/SparkleLib/Git/Makefile.am new file mode 100755 index 0000000..5d51640 --- /dev/null +++ b/SparkleLib/Git/Makefile.am @@ -0,0 +1,22 @@ +ASSEMBLY = SparkleLib.Git +TARGET = library + +LINK = -r:$(DIR_BIN)/SparkleLib.dll + +SOURCES = \ + SparkleGit.cs \ + SparkleFetcherGit.cs \ + SparkleRepoGit.cs + + +install-data-hook: + for ASM in $(EXTRA_BUNDLE); do \ + $(INSTALL) -m 0755 $$ASM $(DESTDIR)$(moduledir); \ + done; + +uninstall-hook: + for ASM in $(EXTRA_BUNDLE); do \ + rm -f $(DESTDIR)$(moduledir)/`basename $$ASM`; \ + done; + +include $(top_srcdir)/build/build.mk diff --git a/SparkleLib/Git/SparkleFetcherGit.cs b/SparkleLib/Git/SparkleFetcherGit.cs new file mode 100755 index 0000000..0b6ff9b --- /dev/null +++ b/SparkleLib/Git/SparkleFetcherGit.cs @@ -0,0 +1,450 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text.RegularExpressions; +using System.Threading; +using SparkleLib; + +namespace SparkleLib.Git { + + public class SparkleFetcher : SparkleFetcherSSH { + + private SparkleGit git; + private bool use_git_bin; + private string cached_salt; + + private Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled); + private Regex speed_regex = new Regex (@"([0-9\.]+) ([KM])iB/s", RegexOptions.Compiled); + + private bool crypto_password_is_hashed = true; + + private string crypto_salt { + get { + if (!string.IsNullOrEmpty (this.cached_salt)) + return this.cached_salt; + + // Check if the repo's salt is stored in a branch... + SparkleGit git = new SparkleGit (TargetFolder, "ls-remote --heads"); + string branches = git.StartAndReadStandardOutput (); + Regex salt_regex = new Regex ("refs/heads/salt-([0-9a-f]+)"); + Match salt_match = salt_regex.Match (branches); + + if (salt_match.Success) + this.cached_salt = salt_match.Groups [1].Value; + + // ...if not, create a new salt for the repo + if (string.IsNullOrEmpty (this.cached_salt)) { + this.cached_salt = GenerateCryptoSalt (); + string salt_file_path = new string [] { TargetFolder, ".git", "salt" }.Combine (); + + // Temporarily store the salt in a file, so the Repo object can + // push it to a branch on the host later + File.WriteAllText (salt_file_path, this.cached_salt); + } + + return this.cached_salt; + } + } + + + public SparkleFetcher (SparkleFetcherInfo info) : base (info) + { + if (RemoteUrl.ToString ().StartsWith ("ssh+")) + RemoteUrl = new Uri ("ssh" + RemoteUrl.ToString ().Substring (RemoteUrl.ToString ().IndexOf ("://"))); + + Uri uri = RemoteUrl; + + if (!uri.Scheme.Equals ("ssh") && !uri.Scheme.Equals ("https") && + !uri.Scheme.Equals ("http") && !uri.Scheme.Equals ("git")) { + + uri = new Uri ("ssh://" + uri); + } + + if (uri.Host.Equals ("gitorious.org") && !uri.Scheme.StartsWith ("http")) { + if (!uri.AbsolutePath.Equals ("/") && + !uri.AbsolutePath.EndsWith (".git")) { + + uri = new Uri ("ssh://git@gitorious.org" + uri.AbsolutePath + ".git"); + + } else { + uri = new Uri ("ssh://git@gitorious.org" + uri.AbsolutePath); + } + + } else if (uri.Host.Equals ("github.com") && !uri.Scheme.StartsWith ("http")) { + uri = new Uri ("ssh://git@github.com" + uri.AbsolutePath); + + } else if (uri.Host.Equals ("bitbucket.org") && !uri.Scheme.StartsWith ("http")) { + // Nothing really + + } else { + if (string.IsNullOrEmpty (uri.UserInfo) && !uri.Scheme.StartsWith ("http")) { + if (uri.Port == -1) + uri = new Uri (uri.Scheme + "://storage@" + uri.Host + uri.AbsolutePath); + else + uri = new Uri (uri.Scheme + "://storage@" + uri.Host + ":" + uri.Port + uri.AbsolutePath); + } + + this.use_git_bin = false; // TODO + } + + RemoteUrl = uri; + } + + + public override bool Fetch () + { + if (!base.Fetch ()) + return false; + + if (FetchPriorHistory) { + this.git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath, + "clone --progress --no-checkout \"" + RemoteUrl + "\" \"" + TargetFolder + "\""); + + } else { + this.git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath, + "clone --progress --no-checkout --depth=1 \"" + RemoteUrl + "\" \"" + TargetFolder + "\""); + } + + this.git.StartInfo.RedirectStandardError = true; + this.git.Start (); + + double percentage = 1.0; + + DateTime last_change = DateTime.Now; + TimeSpan change_interval = new TimeSpan (0, 0, 0, 1); + + try { + while (!this.git.StandardError.EndOfStream) { + string line = this.git.StandardError.ReadLine (); + Match match = this.progress_regex.Match (line); + + double number = 0.0; + double speed = 0.0; + if (match.Success) { + try { + number = double.Parse (match.Groups [1].Value, new CultureInfo ("en-US")); + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing progress: \"" + match.Groups [1] + "\""); + } + + // The pushing progress consists of two stages: the "Compressing + // objects" stage which we count as 20% of the total progress, and + // the "Writing objects" stage which we count as the last 80% + if (line.Contains ("Compressing")) { + // "Compressing objects" stage + number = (number / 100 * 20); + + } else { + // "Writing objects" stage + number = (number / 100 * 80 + 20); + Match speed_match = this.speed_regex.Match (line); + + if (speed_match.Success) { + try { + speed = double.Parse (speed_match.Groups [1].Value, new CultureInfo ("en-US")) * 1024; + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing speed: \"" + speed_match.Groups [1] + "\""); + } + + if (speed_match.Groups [2].Value.Equals ("M")) + speed = speed * 1024; + } + } + + } else { + SparkleLogger.LogInfo ("Fetcher", line); + line = line.Trim (new char [] {' ', '@'}); + + if (line.StartsWith ("fatal:", StringComparison.InvariantCultureIgnoreCase) || + line.StartsWith ("error:", StringComparison.InvariantCultureIgnoreCase)) { + + base.errors.Add (line); + + } else if (line.StartsWith ("WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!")) { + base.errors.Add ("warning: Remote host identification has changed!"); + + } else if (line.StartsWith ("WARNING: POSSIBLE DNS SPOOFING DETECTED!")) { + base.errors.Add ("warning: Possible DNS spoofing detected!"); + } + } + + if (number >= percentage) { + percentage = number; + + if (DateTime.Compare (last_change, DateTime.Now.Subtract (change_interval)) < 0) { + base.OnProgressChanged (percentage, speed); + last_change = DateTime.Now; + } + } + } + + } catch (Exception) { + IsActive = false; + return false; + } + + this.git.WaitForExit (); + + if (this.git.ExitCode == 0) { + while (percentage < 100) { + percentage += 25; + + if (percentage >= 100) + break; + + Thread.Sleep (500); + base.OnProgressChanged (percentage, 0); + } + + base.OnProgressChanged (100, 0); + + InstallConfiguration (); + InstallExcludeRules (); + InstallAttributeRules (); + + return true; + + } else { + return false; + } + } + + + public override bool IsFetchedRepoEmpty { + get { + SparkleGit git = new SparkleGit (TargetFolder, "rev-parse HEAD"); + git.StartAndWaitForExit (); + + return (git.ExitCode != 0); + } + } + + + public override void EnableFetchedRepoCrypto (string password) + { + // Set up the encryption filter + SparkleGit git_config_smudge = new SparkleGit (TargetFolder, + "config filter.encryption.smudge \"openssl enc -d -aes-256-cbc -base64 -S " + this.crypto_salt + + " -pass file:.git/info/encryption_password\""); + + SparkleGit git_config_clean = new SparkleGit (TargetFolder, + "config filter.encryption.clean \"openssl enc -e -aes-256-cbc -base64 -S " + this.crypto_salt + + " -pass file:.git/info/encryption_password\""); + + git_config_smudge.StartAndWaitForExit (); + git_config_clean.StartAndWaitForExit (); + + // Pass all files through the encryption filter + string git_attributes_file_path = new string [] { TargetFolder, ".git", "info", "attributes" }.Combine (); + File.WriteAllText (git_attributes_file_path, "\n* filter=encryption"); + + // Store the password + string password_file_path = new string [] { TargetFolder, ".git", "info", "encryption_password" }.Combine (); + + if (this.crypto_password_is_hashed) + File.WriteAllText (password_file_path, password.SHA256 (this.crypto_salt)); + else + File.WriteAllText (password_file_path, password); + } + + + public override bool IsFetchedRepoPasswordCorrect (string password) + { + string password_check_file_path = Path.Combine (TargetFolder, ".sparkleshare"); + + if (!File.Exists (password_check_file_path)) { + SparkleGit git = new SparkleGit (TargetFolder, "show HEAD:.sparkleshare"); + string output = git.StartAndReadStandardOutput (); + + if (git.ExitCode == 0) + File.WriteAllText (password_check_file_path, output); + else + return false; + } + + Process process = new Process (); + process.EnableRaisingEvents = true; + process.StartInfo.FileName = "openssl"; + process.StartInfo.WorkingDirectory = TargetFolder; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.CreateNoWindow = true; + + string [] possible_passwords = new string [] { + password.SHA256 (this.crypto_salt), + password + }; + + int i = 0; + foreach (string possible_password in possible_passwords) { + process.StartInfo.Arguments = "enc -d -aes-256-cbc -base64 -pass pass:\"" + possible_password + "\"" + + " -in \"" + password_check_file_path + "\""; + + SparkleLogger.LogInfo ("Cmd | " + System.IO.Path.GetFileName (process.StartInfo.WorkingDirectory), + System.IO.Path.GetFileName (process.StartInfo.FileName) + " " + process.StartInfo.Arguments); + + process.Start (); + process.WaitForExit (); + + if (process.ExitCode == 0) { + if (i > 0) + this.crypto_password_is_hashed = false; + + File.Delete (password_check_file_path); + return true; + } + + i++; + } + + return false; + } + + + public override void Stop () + { + try { + if (this.git != null && !this.git.HasExited) { + this.git.Kill (); + this.git.Dispose (); + } + + } catch (Exception e) { + SparkleLogger.LogInfo ("Fetcher", "Failed to dispose properly", e); + } + + if (Directory.Exists (TargetFolder)) { + try { + Directory.Delete (TargetFolder, true /* Recursive */ ); + SparkleLogger.LogInfo ("Fetcher", "Deleted '" + TargetFolder + "'"); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Fetcher", "Failed to delete '" + TargetFolder + "'", e); + } + } + } + + + public override void Complete () + { + if (!IsFetchedRepoEmpty) { + SparkleGit git = new SparkleGit (TargetFolder, "checkout --quiet HEAD"); + git.StartAndWaitForExit (); + } + + base.Complete (); + } + + + private void InstallConfiguration () + { + string [] settings = new string [] { + "core.autocrlf input", + "core.quotepath false", // Don't quote "unusual" characters in path names + "core.ignorecase false", // Be case sensitive explicitly to work on Mac + "core.filemode false", // Ignore permission changes + "core.precomposeunicode true", // Use the same Unicode form on all filesystems + "core.safecrlf false", + "core.excludesfile \"\"", + "core.packedGitLimit 128m", // Some memory limiting options + "core.packedGitWindowSize 128m", + "pack.deltaCacheSize 128m", + "pack.packSizeLimit 128m", + "pack.windowMemory 128m", + "push.default matching" + }; + + if (SparkleBackend.Platform == PlatformID.Win32NT) + settings [0] = "core.autocrlf true"; + + foreach (string setting in settings) { + SparkleGit git_config = new SparkleGit (TargetFolder, "config " + setting); + git_config.StartAndWaitForExit (); + } + + if (this.use_git_bin) + InstallGitBinConfiguration (); + } + + + public void InstallGitBinConfiguration () + { + string [] settings = new string [] { + "core.bigFileThreshold 1024g", + "filter.bin.clean \"git bin clean %f\"", + "filter.bin.smudge \"git bin smudge\"" + }; + + foreach (string setting in settings) { + SparkleGit git_config = new SparkleGit (TargetFolder, "config " + setting); + git_config.StartAndWaitForExit (); + } + } + + + // Add a .gitignore file to the repo + private void InstallExcludeRules () + { + string git_info_path = new string [] { TargetFolder, ".git", "info" }.Combine (); + + if (!Directory.Exists (git_info_path)) + Directory.CreateDirectory (git_info_path); + + string exclude_rules = string.Join (Environment.NewLine, ExcludeRules); + string exclude_rules_file_path = new string [] { git_info_path, "exclude" }.Combine (); + + File.WriteAllText (exclude_rules_file_path, exclude_rules); + } + + + private void InstallAttributeRules () + { + string attribute_rules_file_path = new string [] { TargetFolder, ".git", "info", "attributes" }.Combine (); + TextWriter writer = new StreamWriter (attribute_rules_file_path); + + if (this.use_git_bin) { + writer.WriteLine ("* filter=bin binary"); + + } else { + // Compile a list of files we don't want Git to compress. + // Not compressing already compressed files decreases memory usage and increases speed + string [] extensions = new string [] { + "jpg", "jpeg", "png", "tiff", "gif", // Images + "flac", "mp3", "ogg", "oga", // Audio + "avi", "mov", "mpg", "mpeg", "mkv", "ogv", "ogx", "webm", // Video + "zip", "gz", "bz", "bz2", "rpm", "deb", "tgz", "rar", "ace", "7z", "pak", "tc", "iso", ".dmg" // Archives + }; + + foreach (string extension in extensions) { + writer.WriteLine ("*." + extension + " -delta"); + writer.WriteLine ("*." + extension.ToUpper () + " -delta"); + } + + writer.WriteLine ("*.txt text"); + writer.WriteLine ("*.TXT text"); + } + + writer.Close (); + } + } +} diff --git a/SparkleLib/Git/SparkleGit.cs b/SparkleLib/Git/SparkleGit.cs new file mode 100644 index 0000000..b54f045 --- /dev/null +++ b/SparkleLib/Git/SparkleGit.cs @@ -0,0 +1,166 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.IO; +using System.Diagnostics; +using SparkleLib; + +namespace SparkleLib.Git { + + public abstract class SparkleProcess : Process { + + public SparkleProcess (string path, string args) : base () + { + StartInfo.FileName = path; + StartInfo.Arguments = args; + } + + + new public void Start () + { + SparkleLogger.LogInfo ("Cmd | " + System.IO.Path.GetFileName (StartInfo.WorkingDirectory), + System.IO.Path.GetFileName (StartInfo.FileName) + " " + StartInfo.Arguments); + + try { + base.Start (); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Cmd", "Couldn't execute command: " + e.Message); + Environment.Exit (-1); + } + } + + + public void StartAndWaitForExit () + { + Start (); + WaitForExit (); + } + + + public string StartAndReadStandardOutput () + { + Start (); + + // Reading the standard output HAS to go before + // WaitForExit, or it will hang forever on output > 4096 bytes + string output = StandardOutput.ReadToEnd (); + WaitForExit (); + + return output.TrimEnd (); + } + + + public string StartAndReadStandardError () + { + StartInfo.RedirectStandardError = true; + Start (); + + // Reading the standard output HAS to go before + // WaitForExit, or it will hang forever on output > 4096 bytes + string output = StandardError.ReadToEnd (); + WaitForExit (); + + return output.TrimEnd (); + } + + + protected string LocateCommand (string name) + { + string [] possible_command_paths = new string [] { + Environment.GetFolderPath (Environment.SpecialFolder.Personal) + "/bin/" + name, + Defines.INSTALL_DIR + "/bin/" + name, + "/usr/local/bin/" + name, + "/usr/bin/" + name, + "/opt/local/bin/" + name + }; + + foreach (string path in possible_command_paths) { + if (File.Exists (path)) + return path; + } + + return name; + } + } + + + public class SparkleGit : SparkleProcess { + + public static string ExecPath; + public static string GitPath; + public static string SSHPath; + + + public SparkleGit (string path, string args) : base (path, args) + { + if (string.IsNullOrEmpty (GitPath)) + GitPath = LocateCommand ("git"); + + EnableRaisingEvents = true; + StartInfo.FileName = GitPath; + StartInfo.RedirectStandardOutput = true; + StartInfo.UseShellExecute = false; + StartInfo.WorkingDirectory = path; + StartInfo.CreateNoWindow = true; + + if (StartInfo.EnvironmentVariables.ContainsKey ("LANG")) + StartInfo.EnvironmentVariables ["LANG"] = "en_US"; + else + StartInfo.EnvironmentVariables.Add ("LANG", "en_US"); + + if (StartInfo.EnvironmentVariables.ContainsKey ("GIT_TERMINAL_PROMPT")) + StartInfo.EnvironmentVariables ["GIT_TERMINAL_PROMPT"] = "0"; + else + StartInfo.EnvironmentVariables.Add ("GIT_TERMINAL_PROMPT", "0"); + + if (!string.IsNullOrEmpty (SSHPath)) { + if (StartInfo.EnvironmentVariables.ContainsKey ("GIT_SSH")) + StartInfo.EnvironmentVariables ["GIT_SSH"] = SSHPath; + else + StartInfo.EnvironmentVariables.Add ("GIT_SSH", SSHPath); + } + + if (string.IsNullOrEmpty (ExecPath)) + StartInfo.Arguments = args; + else + StartInfo.Arguments = "--exec-path=\"" + ExecPath + "\" " + args; + } + } + + + public class SparkleGitBin : SparkleProcess { + + public static string GitBinPath; + + + public SparkleGitBin (string path, string args) : base (path, args) + { + if (string.IsNullOrEmpty (GitBinPath)) + GitBinPath = LocateCommand ("git-bin"); + + EnableRaisingEvents = true; + StartInfo.FileName = GitBinPath; + StartInfo.RedirectStandardOutput = true; + StartInfo.UseShellExecute = false; + StartInfo.WorkingDirectory = path; + StartInfo.CreateNoWindow = true; + StartInfo.Arguments = args; + } + } +} diff --git a/SparkleLib/Git/SparkleLib.Git.csproj b/SparkleLib/Git/SparkleLib.Git.csproj new file mode 100644 index 0000000..ddfed9d --- /dev/null +++ b/SparkleLib/Git/SparkleLib.Git.csproj @@ -0,0 +1,59 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE} + Library + Properties + SparkleLib.Git + SparkleLib.Git + 512 + + + + + True + ..\..\bin\ + prompt + 4 + + + False + bin\Debug + 4 + TRACE DEBUG + true + + + + + + + + + + + + + + + + {2C914413-B31C-4362-93C7-1AE34F09112A} + SparkleLib + + + + + + + + diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs new file mode 100644 index 0000000..26eeee9 --- /dev/null +++ b/SparkleLib/Git/SparkleRepoGit.cs @@ -0,0 +1,1225 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using SparkleLib; + +namespace SparkleLib.Git { + + public class SparkleRepo : SparkleRepoBase { + + private bool user_is_set; + private bool use_git_bin; + private bool is_encrypted; + + private string cached_branch; + + private Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled); + private Regex speed_regex = new Regex (@"([0-9\.]+) ([KM])iB/s", RegexOptions.Compiled); + + private Regex log_regex = new Regex (@"commit ([a-f0-9]{40})*\n" + + "Author: (.+) <(.+)>\n" + + "Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " + + "([0-9]{2}):([0-9]{2}):([0-9]{2}) (.[0-9]{4})\n" + + "*", RegexOptions.Compiled); + + private Regex merge_regex = new Regex (@"commit ([a-f0-9]{40})\n" + + "Merge: [a-f0-9]{7} [a-f0-9]{7}\n" + + "Author: (.+) <(.+)>\n" + + "Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " + + "([0-9]{2}):([0-9]{2}):([0-9]{2}) (.[0-9]{4})\n" + + "*", RegexOptions.Compiled); + + private string branch { + get { + if (!string.IsNullOrEmpty (this.cached_branch)) + return this.cached_branch; + + SparkleGit git = new SparkleGit (LocalPath, "config core.ignorecase true"); + git.StartAndWaitForExit (); + + while (this.in_merge && HasLocalChanges) { + try { + ResolveConflict (); + + } catch (IOException e) { + SparkleLogger.LogInfo ("Git", Name + " | Failed to resolve conflict, trying again...", e); + } + } + + git = new SparkleGit (LocalPath, "config core.ignorecase false"); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "rev-parse --abbrev-ref HEAD"); + this.cached_branch = git.StartAndReadStandardOutput (); + + return this.cached_branch; + } + } + + + private bool in_merge { + get { + string merge_file_path = new string [] { LocalPath, ".git", "MERGE_HEAD" }.Combine (); + return File.Exists (merge_file_path); + } + } + + + public SparkleRepo (string path, SparkleConfig config) : base (path, config) + { + SparkleGit git = new SparkleGit (LocalPath, "config core.ignorecase false"); + git.StartAndWaitForExit (); + + // Check if we should use git-bin + git = new SparkleGit (LocalPath, "config --get filter.bin.clean"); + git.StartAndWaitForExit (); + + this.use_git_bin = (git.ExitCode == 0); + + if (this.use_git_bin) + ConfigureGitBin (); + + git = new SparkleGit (LocalPath, "config remote.origin.url \"" + RemoteUrl + "\""); + git.StartAndWaitForExit (); + + string password_file_path = Path.Combine (LocalPath, ".git", "password"); + + if (File.Exists (password_file_path)) + this.is_encrypted = true; + } + + + private void ConfigureGitBin () + { + SparkleGit git = new SparkleGit (LocalPath, "config filter.bin.clean \"git bin clean %f\""); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config filter.bin.smudge \"git bin smudge\""); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config git-bin.sftpUrl \"" + RemoteUrl + "\""); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config git-bin.sftpPrivateKeyFile \"" + base.local_config.User.PrivateKeyFilePath + "\""); + git.StartAndWaitForExit (); + } + + + public override List ExcludePaths { + get { + List rules = new List (); + rules.Add (".git"); + + return rules; + } + } + + + public override double Size { + get { + string file_path = new string [] { LocalPath, ".git", "info", "size" }.Combine (); + + try { + string size = File.ReadAllText (file_path); + return double.Parse (size); + + } catch { + return 0; + } + } + } + + + public override double HistorySize { + get { + string file_path = new string [] { LocalPath, ".git", "info", "history_size" }.Combine (); + + try { + string size = File.ReadAllText (file_path); + return double.Parse (size); + + } catch { + return 0; + } + } + } + + + private void UpdateSizes () + { + double size = CalculateSizes (new DirectoryInfo (LocalPath)); + double history_size = CalculateSizes (new DirectoryInfo (Path.Combine (LocalPath, ".git"))); + + string size_file_path = new string [] { LocalPath, ".git", "info", "size" }.Combine (); + string history_size_file_path = new string [] { LocalPath, ".git", "info", "history_size" }.Combine (); + + File.WriteAllText (size_file_path, size.ToString ()); + File.WriteAllText (history_size_file_path, history_size.ToString ()); + } + + + public override string CurrentRevision { + get { + SparkleGit git = new SparkleGit (LocalPath, "rev-parse HEAD"); + string output = git.StartAndReadStandardOutput (); + + if (git.ExitCode == 0) + return output; + else + return null; + } + } + + + public override bool HasRemoteChanges { + get { + SparkleLogger.LogInfo ("Git", Name + " | Checking for remote changes..."); + string current_revision = CurrentRevision; + + SparkleGit git = new SparkleGit (LocalPath, "ls-remote --heads --exit-code \"" + RemoteUrl + "\" " + this.branch); + string output = git.StartAndReadStandardOutput (); + + if (git.ExitCode != 0) + return false; + + string remote_revision = "" + output.Substring (0, 40); + + if (!remote_revision.Equals (current_revision)) { + git = new SparkleGit (LocalPath, "merge-base " + remote_revision + " master"); + git.StartAndWaitForExit (); + + if (git.ExitCode != 0) { + SparkleLogger.LogInfo ("Git", Name + " | Remote changes found, local: " + + current_revision + ", remote: " + remote_revision); + + Error = ErrorStatus.None; + return true; + + } else { + SparkleLogger.LogInfo ("Git", Name + " | Remote " + remote_revision + " is already in our history"); + return false; + } + } + + SparkleLogger.LogInfo ("Git", Name + " | No remote changes, local+remote: " + current_revision); + return false; + } + } + + + public override bool SyncUp () + { + if (!Add ()) { + Error = ErrorStatus.UnreadableFiles; + return false; + } + + string message = base.status_message.Replace ("\"", "\\\""); + + if (string.IsNullOrEmpty (message)) + message = FormatCommitMessage (); + + if (message != null) + Commit (message); + + if (this.use_git_bin) { + SparkleGitBin git_bin = new SparkleGitBin (LocalPath, "push"); + git_bin.StartAndWaitForExit (); + + // TODO: Progress + } + + SparkleGit git = new SparkleGit (LocalPath, "push --progress \"" + RemoteUrl + "\" " + this.branch); + git.StartInfo.RedirectStandardError = true; + git.Start (); + + double percentage = 1.0; + + while (!git.StandardError.EndOfStream) { + string line = git.StandardError.ReadLine (); + Match match = this.progress_regex.Match (line); + double speed = 0.0; + double number = 0.0; + + if (match.Success) { + try { + number = double.Parse (match.Groups [1].Value, new CultureInfo ("en-US")); + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing progress: \"" + match.Groups [1] + "\""); + } + + // The pushing progress consists of two stages: the "Compressing + // objects" stage which we count as 20% of the total progress, and + // the "Writing objects" stage which we count as the last 80% + if (line.StartsWith ("Compressing")) { + // "Compressing objects" stage + number = (number / 100 * 20); + + } else { + // "Writing objects" stage + number = (number / 100 * 80 + 20); + Match speed_match = this.speed_regex.Match (line); + + if (speed_match.Success) { + try { + speed = double.Parse (speed_match.Groups [1].Value, new CultureInfo ("en-US")) * 1024; + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing speed: \"" + speed_match.Groups [1] + "\""); + } + + if (speed_match.Groups [2].Value.Equals ("M")) + speed = speed * 1024; + } + } + + } else { + SparkleLogger.LogInfo ("Git", Name + " | " + line); + + if (FindError (line)) + return false; + } + + if (number >= percentage) { + percentage = number; + base.OnProgressChanged (percentage, speed); + } + } + + git.WaitForExit (); + UpdateSizes (); + + if (git.ExitCode == 0) { + ClearCache (); + + string salt_file_path = new string [] { LocalPath, ".git", "salt" }.Combine (); + + // If the repo is encrypted, create a branch to + // store the salt in and push it to the host + if (File.Exists (salt_file_path)) { + string salt = File.ReadAllText (salt_file_path).Trim (); + + SparkleGit git_salt = new SparkleGit (LocalPath, "branch salt-" + salt); + git_salt.StartAndWaitForExit (); + + git_salt = new SparkleGit (LocalPath, "push origin salt-" + salt); + git_salt.StartAndWaitForExit (); + + File.Delete (salt_file_path); + } + + return true; + + } else { + Error = ErrorStatus.HostUnreachable; + return false; + } + } + + + public override bool SyncDown () + { + SparkleGit git = new SparkleGit (LocalPath, "fetch --progress \"" + RemoteUrl + "\" " + this.branch); + + git.StartInfo.RedirectStandardError = true; + git.Start (); + + double percentage = 1.0; + + while (!git.StandardError.EndOfStream) { + string line = git.StandardError.ReadLine (); + Match match = this.progress_regex.Match (line); + double speed = 0.0; + double number = 0.0; + + if (match.Success) { + try { + number = double.Parse (match.Groups [1].Value, new CultureInfo ("en-US")); + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing progress: \"" + match.Groups [1] + "\""); + } + + // The fetching progress consists of two stages: the "Compressing + // objects" stage which we count as 20% of the total progress, and + // the "Receiving objects" stage which we count as the last 80% + if (line.StartsWith ("Compressing")) { + // "Compressing objects" stage + number = (number / 100 * 20); + + } else { + // "Writing objects" stage + number = (number / 100 * 80 + 20); + Match speed_match = this.speed_regex.Match (line); + + if (speed_match.Success) { + try { + speed = double.Parse (speed_match.Groups [1].Value, new CultureInfo ("en-US")) * 1024; + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing speed: \"" + speed_match.Groups [1] + "\""); + } + + if (speed_match.Groups [2].Value.Equals ("M")) + speed = speed * 1024; + } + } + + } else { + SparkleLogger.LogInfo ("Git", Name + " | " + line); + + if (FindError (line)) + return false; + } + + + if (number >= percentage) { + percentage = number; + base.OnProgressChanged (percentage, speed); + } + } + + git.WaitForExit (); + UpdateSizes (); + + if (git.ExitCode == 0) { + if (Merge ()) { + ClearCache (); + return true; + + } else { + return false; + } + + } else { + Error = ErrorStatus.HostUnreachable; + return false; + } + } + + + public override bool HasLocalChanges { + get { + PrepareDirectories (LocalPath); + + SparkleGit git = new SparkleGit (LocalPath, "status --porcelain"); + string output = git.StartAndReadStandardOutput (); + + return !string.IsNullOrEmpty (output); + } + } + + + public override bool HasUnsyncedChanges { + get { + string unsynced_file_path = new string [] { LocalPath, ".git", "has_unsynced_changes" }.Combine (); + return File.Exists (unsynced_file_path); + } + + set { + string unsynced_file_path = new string [] { LocalPath, ".git", "has_unsynced_changes" }.Combine (); + + if (value) + File.WriteAllText (unsynced_file_path, ""); + else + File.Delete (unsynced_file_path); + } + } + + + // Stages the made changes + private bool Add () + { + SparkleGit git = new SparkleGit (LocalPath, "add --all"); + git.StartAndWaitForExit (); + + return (git.ExitCode == 0); + } + + + // Commits the made changes + private void Commit (string message) + { + SparkleGit git; + + if (!this.user_is_set) { + git = new SparkleGit (LocalPath, "config user.name \"" + base.local_config.User.Name + "\""); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config user.email \"" + base.local_config.User.Email + "\""); + git.StartAndWaitForExit (); + + this.user_is_set = true; + } + + git = new SparkleGit (LocalPath, "commit --all --message=\"" + message + "\" " + + "--author=\"" + base.local_config.User.Name + " <" + base.local_config.User.Email + ">\""); + + git.StartAndReadStandardOutput (); + } + + + // Merges the fetched changes + private bool Merge () + { + string message = FormatCommitMessage (); + + if (message != null) { + Add (); + Commit (message); + } + + SparkleGit git; + + // Stop if we're already in a merge because something went wrong + if (this.in_merge) { + git = new SparkleGit (LocalPath, "merge --abort"); + git.StartAndWaitForExit (); + + return false; + } + + // Temporarily change the ignorecase setting to true to avoid + // conflicts in file names due to letter case changes + git = new SparkleGit (LocalPath, "config core.ignorecase true"); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "merge FETCH_HEAD"); + git.StartInfo.RedirectStandardOutput = false; + + string error_output = git.StartAndReadStandardError (); + + if (git.ExitCode != 0) { + // Stop when we can't merge due to locked local files + // error: cannot stat 'filename': Permission denied + if (error_output.Contains ("error: cannot stat")) { + Error = ErrorStatus.UnreadableFiles; + SparkleLogger.LogInfo ("Git", Name + " | Error status changed to " + Error); + + git = new SparkleGit (LocalPath, "merge --abort"); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config core.ignorecase false"); + git.StartAndWaitForExit (); + + return false; + + } else { + SparkleLogger.LogInfo ("Git", error_output); + SparkleLogger.LogInfo ("Git", Name + " | Conflict detected, trying to get out..."); + + while (this.in_merge && HasLocalChanges) { + try { + ResolveConflict (); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Git", Name + " | Failed to resolve conflict, trying again...", e); + } + } + + SparkleLogger.LogInfo ("Git", Name + " | Conflict resolved"); + } + } + + git = new SparkleGit (LocalPath, "config core.ignorecase false"); + git.StartAndWaitForExit (); + + return true; + } + + + private void ResolveConflict () + { + // This is a list of conflict status codes that Git uses, their + // meaning, and how SparkleShare should handle them. + // + // DD unmerged, both deleted -> Do nothing + // AU unmerged, added by us -> Use server's, save ours as a timestamped copy + // UD unmerged, deleted by them -> Use ours + // UA unmerged, added by them -> Use server's, save ours as a timestamped copy + // DU unmerged, deleted by us -> Use server's + // AA unmerged, both added -> Use server's, save ours as a timestamped copy + // UU unmerged, both modified -> Use server's, save ours as a timestamped copy + // ?? unmerged, new files -> Stage the new files + + SparkleGit git_status = new SparkleGit (LocalPath, "status --porcelain"); + string output = git_status.StartAndReadStandardOutput (); + + string [] lines = output.Split ("\n".ToCharArray ()); + bool trigger_conflict_event = false; + + foreach (string line in lines) { + string conflicting_path = line.Substring (3); + conflicting_path = EnsureSpecialCharacters (conflicting_path); + conflicting_path = conflicting_path.Trim ("\"".ToCharArray ()); + + // Remove possible rename indicators + string [] separators = {" -> \"", " -> "}; + foreach (string separator in separators) { + if (conflicting_path.Contains (separator)) { + conflicting_path = conflicting_path.Substring ( + conflicting_path.IndexOf (separator) + separator.Length); + } + } + + SparkleLogger.LogInfo ("Git", Name + " | Conflict type: " + line); + + // Ignore conflicts in hidden files and use the local versions + if (conflicting_path.EndsWith (".sparkleshare") || conflicting_path.EndsWith (".empty")) { + SparkleLogger.LogInfo ("Git", Name + " | Ignoring conflict in special file: " + conflicting_path); + + // Recover local version + SparkleGit git_ours = new SparkleGit (LocalPath, "checkout --ours \"" + conflicting_path + "\""); + git_ours.StartAndWaitForExit (); + + string abs_conflicting_path = Path.Combine (LocalPath, conflicting_path); + + if (File.Exists (abs_conflicting_path)) + File.SetAttributes (abs_conflicting_path, FileAttributes.Hidden); + + continue; + } + + SparkleLogger.LogInfo ("Git", Name + " | Resolving: " + conflicting_path); + + // Both the local and server version have been modified + if (line.StartsWith ("UU") || line.StartsWith ("AA") || + line.StartsWith ("AU") || line.StartsWith ("UA")) { + + // Recover local version + SparkleGit git_ours = new SparkleGit (LocalPath, "checkout --ours \"" + conflicting_path + "\""); + git_ours.StartAndWaitForExit (); + + // Append a timestamp to local version. + // Windows doesn't allow colons in the file name, so + // we use "h" between the hours and minutes instead. + string timestamp = DateTime.Now.ToString ("MMM d H\\hmm"); + string our_path = Path.GetFileNameWithoutExtension (conflicting_path) + + " (" + base.local_config.User.Name + ", " + timestamp + ")" + Path.GetExtension (conflicting_path); + + string abs_conflicting_path = Path.Combine (LocalPath, conflicting_path); + string abs_our_path = Path.Combine (LocalPath, our_path); + + if (File.Exists (abs_conflicting_path) && !File.Exists (abs_our_path)) + File.Move (abs_conflicting_path, abs_our_path); + + // Recover server version + SparkleGit git_theirs = new SparkleGit (LocalPath, "checkout --theirs \"" + conflicting_path + "\""); + git_theirs.StartAndWaitForExit (); + + trigger_conflict_event = true; + + + // The server version has been modified, but the local version was removed + } else if (line.StartsWith ("DU")) { + + // The modified local version is already in the checkout, so it just needs to be added. + // We need to specifically mention the file, so we can't reuse the Add () method + SparkleGit git_add = new SparkleGit (LocalPath, "add \"" + conflicting_path + "\""); + git_add.StartAndWaitForExit (); + + + // The local version has been modified, but the server version was removed + } else if (line.StartsWith ("UD")) { + + // Recover server version + SparkleGit git_theirs = new SparkleGit (LocalPath, "checkout --theirs \"" + conflicting_path + "\""); + git_theirs.StartAndWaitForExit (); + + + // Server and local versions were removed + } else if (line.StartsWith ("DD")) { + SparkleLogger.LogInfo ("Git", Name + " | No need to resolve: " + line); + + // New local files + } else if (line.StartsWith ("??")) { + SparkleLogger.LogInfo ("Git", Name + " | Found new file, no need to resolve: " + line); + + } else { + SparkleLogger.LogInfo ("Git", Name + " | Don't know what to do with: " + line); + } + } + + Add (); + + SparkleGit git = new SparkleGit (LocalPath, "commit --message \"Conflict resolution by SparkleShare\""); + git.StartInfo.RedirectStandardOutput = false; + git.StartAndWaitForExit (); + + if (trigger_conflict_event) + OnConflictResolved (); + } + + + public override void RestoreFile (string path, string revision, string target_file_path) + { + if (path == null) + throw new ArgumentNullException ("path"); + + if (revision == null) + throw new ArgumentNullException ("revision"); + + SparkleLogger.LogInfo ("Git", Name + " | Restoring \"" + path + "\" (revision " + revision + ")"); + + // git-show doesn't decrypt objects, so we can't use it to retrieve + // files from the index. This is a suboptimal workaround but it does the job + if (this.is_encrypted) { + // Restore the older file... + SparkleGit git = new SparkleGit (LocalPath, "checkout " + revision + " \"" + path + "\""); + git.StartAndWaitForExit (); + + string local_file_path = Path.Combine (LocalPath, path); + + // ...move it... + try { + File.Move (local_file_path, target_file_path); + + } catch { + SparkleLogger.LogInfo ("Git", + Name + " | Could not move \"" + local_file_path + "\" to \"" + target_file_path + "\""); + } + + // ...and restore the most recent revision + git = new SparkleGit (LocalPath, "checkout " + CurrentRevision + " \"" + path + "\""); + git.StartAndWaitForExit (); + + // The correct way + } else { + path = path.Replace ("\"", "\\\""); + + SparkleGit git = new SparkleGit (LocalPath, "show " + revision + ":\"" + path + "\""); + git.Start (); + + FileStream stream = File.OpenWrite (target_file_path); + git.StandardOutput.BaseStream.CopyTo (stream); + stream.Close (); + + git.WaitForExit (); + } + + if (target_file_path.StartsWith (LocalPath)) + new Thread (() => OnFileActivity (null)).Start (); + } + + + private bool FindError (string line) + { + Error = ErrorStatus.None; + + if (line.Contains ("WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!") || + line.Contains ("WARNING: POSSIBLE DNS SPOOFING DETECTED!")) { + + Error = ErrorStatus.HostIdentityChanged; + + } else if (line.StartsWith ("Permission denied") || + line.StartsWith ("ssh_exchange_identification: Connection closed by remote host") || + line.StartsWith ("The authenticity of host")) { + + Error = ErrorStatus.AuthenticationFailed; + + } else if (line.EndsWith ("does not appear to be a git repository")) { + Error = ErrorStatus.NotFound; + + } else if (line.EndsWith ("expected old/new/ref, got 'shallow")) { + Error = ErrorStatus.IncompatibleClientServer; + + } else if (line.StartsWith ("error: Disk space exceeded") || + line.EndsWith ("No space left on device") || + line.EndsWith ("file write error (Disk quota exceeded)")) { + + Error = ErrorStatus.DiskSpaceExceeded; + } + + if (Error != ErrorStatus.None) { + SparkleLogger.LogInfo ("Git", Name + " | Error status changed to " + Error); + return true; + + } else { + return false; + } + } + + + public override List UnsyncedChanges { + get { + return ParseStatus (); + } + } + + + public override List GetChangeSets () + { + return GetChangeSetsInternal (null); + } + + public override List GetChangeSets (string path) + { + return GetChangeSetsInternal (path); + } + + private List GetChangeSetsInternal (string path) + { + List change_sets = new List (); + SparkleGit git; + + if (path == null) { + git = new SparkleGit (LocalPath, "log --since=1.month --raw --find-renames --date=iso " + + "--format=medium --no-color --no-merges"); + + } else { + path = path.Replace ("\\", "/"); + + git = new SparkleGit (LocalPath, "log --raw --find-renames --date=iso " + + "--format=medium --no-color --no-merges -- \"" + path + "\""); + } + + string output = git.StartAndReadStandardOutput (); + + if (path == null && string.IsNullOrWhiteSpace (output)) { + git = new SparkleGit (LocalPath, "log -n 75 --raw --find-renames --date=iso " + + "--format=medium --no-color --no-merges"); + + output = git.StartAndReadStandardOutput (); + } + + string [] lines = output.Split ("\n".ToCharArray ()); + List entries = new List (); + + // Split up commit entries + int line_number = 0; + bool first_pass = true; + string entry = "", last_entry = ""; + foreach (string line in lines) { + if (line.StartsWith ("commit") && !first_pass) { + entries.Add (entry); + entry = ""; + line_number = 0; + + } else { + first_pass = false; + } + + // Only parse first 250 files to prevent memory issues + if (line_number < 250) { + entry += line + "\n"; + line_number++; + } + + last_entry = entry; + } + + entries.Add (last_entry); + + // Parse commit entries + foreach (string log_entry in entries) { + Match match = this.log_regex.Match (log_entry); + + if (!match.Success) { + match = this.merge_regex.Match (log_entry); + + if (!match.Success) + continue; + } + + SparkleChangeSet change_set = new SparkleChangeSet (); + + change_set.Folder = new SparkleFolder (Name); + change_set.Revision = match.Groups [1].Value; + change_set.User = new SparkleUser (match.Groups [2].Value, match.Groups [3].Value); + change_set.RemoteUrl = RemoteUrl; + + change_set.Timestamp = new DateTime (int.Parse (match.Groups [4].Value), + int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value), + int.Parse (match.Groups [7].Value), int.Parse (match.Groups [8].Value), + int.Parse (match.Groups [9].Value)); + + string time_zone = match.Groups [10].Value; + int our_offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Hours; + int their_offset = int.Parse (time_zone.Substring (0, 3)); + change_set.Timestamp = change_set.Timestamp.AddHours (their_offset * -1); + change_set.Timestamp = change_set.Timestamp.AddHours (our_offset); + + string [] entry_lines = log_entry.Split ("\n".ToCharArray ()); + + // Parse file list. Lines containing file changes start with ":" + foreach (string entry_line in entry_lines) { + // Skip lines containing backspace characters + if (!entry_line.StartsWith (":") || entry_line.Contains ("\\177")) + continue; + + string file_path = entry_line.Substring (39); + + if (file_path.Equals (".sparkleshare")) + continue; + + string type_letter = entry_line [37].ToString (); + bool change_is_folder = false; + + if (file_path.EndsWith (".empty")) { + file_path = file_path.Substring (0, file_path.Length - ".empty".Length); + change_is_folder = true; + } + + try { + file_path = EnsureSpecialCharacters (file_path); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Local", "Error parsing file name '" + file_path + "'", e); + continue; + } + + file_path = file_path.Replace ("\\\"", "\""); + + SparkleChange change = new SparkleChange () { + Path = file_path, + IsFolder = change_is_folder, + Timestamp = change_set.Timestamp, + Type = SparkleChangeType.Added + }; + + if (type_letter.Equals ("R")) { + int tab_pos = entry_line.LastIndexOf ("\t"); + file_path = entry_line.Substring (42, tab_pos - 42); + string to_file_path = entry_line.Substring (tab_pos + 1); + + try { + file_path = EnsureSpecialCharacters (file_path); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Local", "Error parsing file name '" + file_path + "'", e); + continue; + } + + try { + to_file_path = EnsureSpecialCharacters (to_file_path); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Local", "Error parsing file name '" + to_file_path + "'", e); + continue; + } + + file_path = file_path.Replace ("\\\"", "\""); + to_file_path = to_file_path.Replace ("\\\"", "\""); + + if (file_path.EndsWith (".empty")) { + file_path = file_path.Substring (0, file_path.Length - 6); + change_is_folder = true; + } + + if (to_file_path.EndsWith (".empty")) { + to_file_path = to_file_path.Substring (0, to_file_path.Length - 6); + change_is_folder = true; + } + + change.Path = file_path; + change.MovedToPath = to_file_path; + change.Type = SparkleChangeType.Moved; + + } else if (type_letter.Equals ("M")) { + change.Type = SparkleChangeType.Edited; + + } else if (type_letter.Equals ("D")) { + change.Type = SparkleChangeType.Deleted; + } + + change_set.Changes.Add (change); + } + + // Group commits per user, per day + if (change_sets.Count > 0 && path == null) { + SparkleChangeSet last_change_set = change_sets [change_sets.Count - 1]; + + if (change_set.Timestamp.Year == last_change_set.Timestamp.Year && + change_set.Timestamp.Month == last_change_set.Timestamp.Month && + change_set.Timestamp.Day == last_change_set.Timestamp.Day && + change_set.User.Name.Equals (last_change_set.User.Name)) { + + last_change_set.Changes.AddRange (change_set.Changes); + + if (DateTime.Compare (last_change_set.Timestamp, change_set.Timestamp) < 1) { + last_change_set.FirstTimestamp = last_change_set.Timestamp; + last_change_set.Timestamp = change_set.Timestamp; + last_change_set.Revision = change_set.Revision; + + } else { + last_change_set.FirstTimestamp = change_set.Timestamp; + } + + } else { + change_sets.Add (change_set); + } + + } else { + // Don't show removals or moves in the revision list of a file + if (path != null) { + List changes_to_skip = new List (); + + foreach (SparkleChange change in change_set.Changes) { + if ((change.Type == SparkleChangeType.Deleted || change.Type == SparkleChangeType.Moved) + && change.Path.Equals (path)) { + + changes_to_skip.Add (change); + } + } + + foreach (SparkleChange change_to_skip in changes_to_skip) + change_set.Changes.Remove (change_to_skip); + } + + change_sets.Add (change_set); + } + } + + return change_sets; + } + + + private string EnsureSpecialCharacters (string path) + { + // The path is quoted if it contains special characters + if (path.StartsWith ("\"")) + path = ResolveSpecialChars (path.Substring (1, path.Length - 2)); + + return path; + } + + + private string ResolveSpecialChars (string s) + { + StringBuilder builder = new StringBuilder (s.Length); + List codes = new List (); + + for (int i = 0; i < s.Length; i++) { + while (s [i] == '\\' && + s.Length - i > 3 && + char.IsNumber (s [i + 1]) && + char.IsNumber (s [i + 2]) && + char.IsNumber (s [i + 3])) { + + codes.Add (Convert.ToByte (s.Substring (i + 1, 3), 8)); + i += 4; + } + + if (codes.Count > 0) { + builder.Append (Encoding.UTF8.GetString (codes.ToArray ())); + codes.Clear (); + } + + builder.Append (s [i]); + } + + return builder.ToString (); + } + + + private void ClearCache () + { + if (!this.use_git_bin) + return; + + SparkleGitBin git_bin = new SparkleGitBin (LocalPath, "clear -f"); + git_bin.StartAndWaitForExit (); + } + + + // Git doesn't track empty directories, so this method + // fills them all with a hidden empty file. + // + // It also prevents git repositories from becoming + // git submodules by renaming the .git/HEAD file + private void PrepareDirectories (string path) + { + try { + foreach (string child_path in Directory.GetDirectories (path)) { + if (IsSymlink (child_path)) + continue; + + if (child_path.EndsWith (".git")) { + if (child_path.Equals (Path.Combine (LocalPath, ".git"))) + continue; + + string HEAD_file_path = Path.Combine (child_path, "HEAD"); + + if (File.Exists (HEAD_file_path)) { + File.Move (HEAD_file_path, HEAD_file_path + ".backup"); + SparkleLogger.LogInfo ("Git", Name + " | Renamed " + HEAD_file_path); + } + + continue; + } + + PrepareDirectories (child_path); + } + + if (Directory.GetFiles (path).Length == 0 && + Directory.GetDirectories (path).Length == 0 && + !path.Equals (LocalPath)) { + + if (!File.Exists (Path.Combine (path, ".empty"))) { + try { + File.WriteAllText (Path.Combine (path, ".empty"), "I'm a folder!"); + File.SetAttributes (Path.Combine (path, ".empty"), FileAttributes.Hidden); + + } catch { + SparkleLogger.LogInfo ("Git", Name + " | Failed adding empty folder " + path); + } + } + } + + } catch (IOException e) { + SparkleLogger.LogInfo ("Git", "Failed preparing directory", e); + } + } + + + + private List ParseStatus () + { + List changes = new List (); + + SparkleGit git_status = new SparkleGit (LocalPath, "status --porcelain"); + git_status.Start (); + + while (!git_status.StandardOutput.EndOfStream) { + string line = git_status.StandardOutput.ReadLine (); + line = line.Trim (); + + if (line.EndsWith (".empty") || line.EndsWith (".empty\"")) + line = line.Replace (".empty", ""); + + SparkleChange change; + + if (line.StartsWith ("R")) { + string path = line.Substring (3, line.IndexOf (" -> ") - 3).Trim ("\" ".ToCharArray ()); + string moved_to_path = line.Substring (line.IndexOf (" -> ") + 4).Trim ("\" ".ToCharArray ()); + + change = new SparkleChange () { + Type = SparkleChangeType.Moved, + Path = EnsureSpecialCharacters (path), + MovedToPath = EnsureSpecialCharacters (moved_to_path) + }; + + } else { + string path = line.Substring (2).Trim ("\" ".ToCharArray ()); + change = new SparkleChange () { Path = EnsureSpecialCharacters (path) }; + change.Type = SparkleChangeType.Added; + + if (line.StartsWith ("M")) { + change.Type = SparkleChangeType.Edited; + + } else if (line.StartsWith ("D")) { + change.Type = SparkleChangeType.Deleted; + } + } + + changes.Add (change); + } + + git_status.StandardOutput.ReadToEnd (); + git_status.WaitForExit (); + + return changes; + } + + + // Creates a pretty commit message based on what has changed + private string FormatCommitMessage () + { + string message = ""; + + foreach (SparkleChange change in ParseStatus ()) { + if (change.Type == SparkleChangeType.Moved) { + message += "< ‘" + EnsureSpecialCharacters (change.Path) + "’\n"; + message += "> ‘" + EnsureSpecialCharacters (change.MovedToPath) + "’\n"; + + } else { + if (change.Type == SparkleChangeType.Edited) { + message += "/"; + + } else if (change.Type == SparkleChangeType.Deleted) { + message += "-"; + + } else if (change.Type == SparkleChangeType.Added) { + message += "+"; + } + + message += " ‘" + change.Path + "’\n"; + } + } + + if (string.IsNullOrWhiteSpace (message)) + return null; + else + return message; + } + + + // Recursively gets a folder's size in bytes + private long CalculateSizes (DirectoryInfo parent) + { + long size = 0; + + try { + foreach (DirectoryInfo directory in parent.GetDirectories ()) { + if (directory.IsSymlink () || + directory.Name.Equals (".git") || + directory.Name.Equals ("rebase-apply")) { + + continue; + } + + size += CalculateSizes (directory); + } + + } catch (Exception e) { + SparkleLogger.LogInfo ("Local", "Error calculating directory size", e); + } + + try { + foreach (FileInfo file in parent.GetFiles ()) { + if (file.IsSymlink ()) + continue; + + if (file.Name.Equals (".empty")) + File.SetAttributes (file.FullName, FileAttributes.Hidden); + else + size += file.Length; + } + + } catch (Exception e) { + SparkleLogger.LogInfo ("Local", "Error calculating file size", e); + } + + return size; + } + + + private bool IsSymlink (string file) + { + FileAttributes attributes = File.GetAttributes (file); + return ((attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint); + } + } +} diff --git a/SparkleLib/Makefile.am b/SparkleLib/Makefile.am new file mode 100755 index 0000000..47da468 --- /dev/null +++ b/SparkleLib/Makefile.am @@ -0,0 +1,32 @@ +ASSEMBLY = SparkleLib +TARGET = library + +ASSEMBLY_INFO_SOURCE = Defines.cs + +SOURCES = \ + SparkleBackend.cs \ + SparkleConfig.cs \ + SparkleExtensions.cs \ + SparkleFetcherBase.cs \ + SparkleFetcherSSH.cs \ + SparkleListenerBase.cs \ + SparkleListenerFactory.cs \ + SparkleListenerTcp.cs \ + SparkleLogger.cs \ + SparkleRepoBase.cs \ + SparkleUser.cs \ + SparkleWatcher.cs \ + SparkleWrappers.cs + + +install-data-hook: + for ASM in $(EXTRA_BUNDLE); do \ + $(INSTALL) -m 0755 $$ASM $(DESTDIR)$(moduledir); \ + done; + +uninstall-hook: + for ASM in $(EXTRA_BUNDLE); do \ + rm -f $(DESTDIR)$(moduledir)/`basename $$ASM`; \ + done; + +include $(top_srcdir)/build/build.mk diff --git a/SparkleLib/SparkleBackend.cs b/SparkleLib/SparkleBackend.cs new file mode 100755 index 0000000..2c22122 --- /dev/null +++ b/SparkleLib/SparkleBackend.cs @@ -0,0 +1,60 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace SparkleLib { + + public static class SparkleBackend { + + public static string Version { + get { + string version = "" + Assembly.GetExecutingAssembly ().GetName ().Version; + return version.Substring (0, version.Length - 2); + } + } + + + // This fixes the PlatformID enumeration for MacOSX in Environment.OSVersion.Platform, + // which is intentionally broken in Mono for historical reasons + public static PlatformID Platform { + get { + IntPtr buf = IntPtr.Zero; + + try { + buf = Marshal.AllocHGlobal (8192); + + if (uname (buf) == 0 && Marshal.PtrToStringAnsi (buf) == "Darwin") + return PlatformID.MacOSX; + + } catch { + } finally { + if (buf != IntPtr.Zero) + Marshal.FreeHGlobal (buf); + } + + return Environment.OSVersion.Platform; + } + } + + + [DllImport ("libc")] + private static extern int uname (IntPtr buf); + } +} diff --git a/SparkleLib/SparkleConfig.cs b/SparkleLib/SparkleConfig.cs new file mode 100755 index 0000000..ad75c7c --- /dev/null +++ b/SparkleLib/SparkleConfig.cs @@ -0,0 +1,364 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.IO; +using System.Collections.Generic; +using System.Xml; + +namespace SparkleLib { + + public class SparkleConfig : XmlDocument { + + public static SparkleConfig DefaultConfig; + public static bool DebugMode = true; + + public string FullPath; + public string TmpPath; + public string LogFilePath; + + + public string HomePath { + get { + if (SparkleBackend.Platform == PlatformID.Win32NT) + return Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); + else + return Environment.GetFolderPath (Environment.SpecialFolder.Personal); + } + } + + + public string FoldersPath { + get { + if (GetConfigOption ("folders_path") != null) + return GetConfigOption ("folders_path"); + else + return Path.Combine (HomePath, "SparkleShare"); + } + } + + + public SparkleConfig (string config_path, string config_file_name) + { + FullPath = Path.Combine (config_path, config_file_name); + string logs_path = Path.Combine (config_path, "logs"); + + int i = 1; + do { + LogFilePath = Path.Combine ( + logs_path, "debug_log_" + DateTime.Now.ToString ("yyyy-MM-dd") + "." + i + ".txt"); + + i++; + + } while (File.Exists (LogFilePath)); + + if (!Directory.Exists (logs_path)) + Directory.CreateDirectory (logs_path); + + // Delete logs older than a week + foreach (FileInfo file in new DirectoryInfo (logs_path).GetFiles ("debug_log*.txt")) { + if (file.LastWriteTime < DateTime.Now.AddDays (-7)) + file.Delete (); + } + + if (!Directory.Exists (config_path)) + Directory.CreateDirectory (config_path); + + try { + Load (FullPath); + + } catch (TypeInitializationException) { + CreateInitialConfig (); + + } catch (FileNotFoundException) { + CreateInitialConfig (); + + } catch (XmlException) { + FileInfo file = new FileInfo (FullPath); + + if (file.Length == 0) { + File.Delete (FullPath); + CreateInitialConfig (); + + } else { + throw new XmlException (FullPath + " does not contain a valid config XML structure."); + } + + } finally { + Load (FullPath); + TmpPath = Path.Combine (FoldersPath, ".tmp"); + Directory.CreateDirectory (TmpPath); + } + } + + + private void CreateInitialConfig () + { + string user_name = "Unknown"; + + if (SparkleBackend.Platform == PlatformID.Unix || + SparkleBackend.Platform == PlatformID.MacOSX) { + + user_name = Environment.UserName; + if (string.IsNullOrEmpty (user_name)) + user_name = "Unknown"; + else + user_name = user_name.TrimEnd (",".ToCharArray ()); + + } else { + user_name = Environment.UserName; + } + + + string n = Environment.NewLine; + File.WriteAllText (FullPath, + "" + n + + "" + n + + " " + n + + " " + user_name + "" + n + + " Unknown" + n + + " " + n + + ""); + } + + + public SparkleUser User { + get { + XmlNode name_node = SelectSingleNode ("/sparkleshare/user/name/text()"); + XmlNode email_node = SelectSingleNode ("/sparkleshare/user/email/text()"); + string user_name = name_node.Value; + string user_email = email_node.Value; + + SparkleUser user = new SparkleUser (user_name, user_email); + + string [] private_key_file_paths = Directory.GetFiles (Path.GetDirectoryName (FullPath), "*.key"); + + if (private_key_file_paths.Length > 0) { + user.PrivateKey = File.ReadAllText (private_key_file_paths [0]); + user.PrivateKeyFilePath = private_key_file_paths [0]; + + user.PublicKey = File.ReadAllText (private_key_file_paths [0] + ".pub"); + user.PublicKeyFilePath = private_key_file_paths [0] + ".pub"; + } + + return user; + } + + set { + SparkleUser user = (SparkleUser) value; + + XmlNode name_node = SelectSingleNode ("/sparkleshare/user/name/text()"); + XmlNode email_node = SelectSingleNode ("/sparkleshare/user/email/text()"); + name_node.InnerText = user.Name; + email_node.InnerText = user.Email; + + Save (); + } + } + + + public List Folders { + get { + List folders = new List (); + + foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) + folders.Add (node_folder ["name"].InnerText); + + folders.Sort (); + + return folders; + } + } + + + public void AddFolder (string name, string identifier, string url, string backend) + { + XmlNode node_name = CreateElement ("name"); + XmlNode node_identifier = CreateElement ("identifier"); + XmlNode node_url = CreateElement ("url"); + XmlNode node_backend = CreateElement ("backend"); + + node_name.InnerText = name; + node_identifier.InnerText = identifier; + node_url.InnerText = url; + node_backend.InnerText = backend; + + XmlNode node_folder = CreateNode (XmlNodeType.Element, "folder", null); + + node_folder.AppendChild (node_name); + node_folder.AppendChild (node_identifier); + node_folder.AppendChild (node_url); + node_folder.AppendChild (node_backend); + + XmlNode node_root = SelectSingleNode ("/sparkleshare"); + node_root.AppendChild (node_folder); + + Save (); + } + + + public void RemoveFolder (string name) + { + foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) { + if (node_folder ["name"].InnerText.Equals (name)) + SelectSingleNode ("/sparkleshare").RemoveChild (node_folder); + } + + Save (); + } + + + public void RenameFolder (string identifier, string name) + { + XmlNode node_folder = SelectSingleNode ( + string.Format ("/sparkleshare/folder[identifier=\"{0}\"]", identifier)); + + node_folder ["name"].InnerText = name; + Save (); + } + + + public string GetBackendForFolder (string name) + { + return GetFolderValue (name, "backend"); + } + + + public string GetIdentifierForFolder (string name) + { + return GetFolderValue (name, "identifier"); + } + + + public string GetUrlForFolder (string name) + { + return GetFolderValue (name, "url"); + } + + + public bool IdentifierExists (string identifier) + { + if (identifier == null) + throw new ArgumentNullException (); + + foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) { + XmlElement folder_id = node_folder ["identifier"]; + + if (folder_id != null && identifier.Equals (folder_id.InnerText)) + return true; + } + + return false; + } + + + public bool SetFolderOptionalAttribute (string folder_name, string key, string value) + { + XmlNode folder = GetFolder (folder_name); + + if (folder == null) + return false; + + if (folder [key] != null) { + folder [key].InnerText = value; + + } else { + XmlNode new_node = CreateElement (key); + new_node.InnerText = value; + folder.AppendChild (new_node); + } + + Save (); + + return true; + } + + + public string GetFolderOptionalAttribute (string folder_name, string key) + { + XmlNode folder = GetFolder (folder_name); + + if (folder != null) { + if (folder [key] != null) + return folder [key].InnerText; + else + return null; + + } else { + return null; + } + } + + + public string GetConfigOption (string name) + { + XmlNode node = SelectSingleNode ("/sparkleshare/" + name); + + if (node != null) + return node.InnerText; + else + return null; + } + + + public void SetConfigOption (string name, string content) + { + XmlNode node = SelectSingleNode ("/sparkleshare/" + name); + + if (node != null) { + node.InnerText = content; + + } else { + node = CreateElement (name); + node.InnerText = content; + + XmlNode node_root = SelectSingleNode ("/sparkleshare"); + node_root.AppendChild (node); + } + + Save (); + SparkleLogger.LogInfo ("Config", "Updated option " + name + ":" + content); + } + + + private XmlNode GetFolder (string name) + { + return SelectSingleNode (string.Format ("/sparkleshare/folder[name=\"{0}\"]", name)); + } + + + private string GetFolderValue (string name, string key) + { + XmlNode folder = GetFolder(name); + + if ((folder != null) && (folder [key] != null)) + return folder [key].InnerText; + else + return null; + } + + + private void Save () + { + if (!File.Exists (FullPath)) + throw new FileNotFoundException (FullPath + " does not exist"); + + Save (FullPath); + SparkleLogger.LogInfo ("Config", "Wrote to '" + FullPath + "'"); + } + } +} diff --git a/SparkleLib/SparkleExtensions.cs b/SparkleLib/SparkleExtensions.cs new file mode 100755 index 0000000..0b28480 --- /dev/null +++ b/SparkleLib/SparkleExtensions.cs @@ -0,0 +1,146 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace SparkleLib { + + public static class Extensions { + + public static string Combine (this string [] parts) + { + string new_path = ""; + + foreach (string part in parts) + new_path = Path.Combine (new_path, part); + + return new_path; + } + + + public static string SHA1 (this string s) + { + SHA1 sha1 = new SHA1CryptoServiceProvider (); + byte [] bytes = ASCIIEncoding.Default.GetBytes (s); + byte [] sha1_bytes = sha1.ComputeHash (bytes); + + return BitConverter.ToString (sha1_bytes).ToLower ().Replace ("-", ""); + } + + + public static string SHA256 (this string s) + { + SHA256 sha256 = new SHA256CryptoServiceProvider (); + byte [] bytes = ASCIIEncoding.Default.GetBytes (s); + byte [] sha256_bytes = sha256.ComputeHash (bytes); + + return BitConverter.ToString (sha256_bytes).ToLower ().Replace ("-", ""); + } + + + public static string SHA256 (this string s, string salt) + { + SHA256 sha256 = new SHA256CryptoServiceProvider (); + byte [] bytes = ASCIIEncoding.Default.GetBytes (s + salt); + byte [] sha256_bytes = sha256.ComputeHash (bytes); + + return BitConverter.ToString (sha256_bytes).ToLower ().Replace ("-", ""); + } + + + public static string MD5 (this string s) + { + MD5 md5 = new MD5CryptoServiceProvider (); + byte [] bytes = ASCIIEncoding.Default.GetBytes (s); + byte [] md5_bytes = md5.ComputeHash (bytes); + + return BitConverter.ToString (md5_bytes).ToLower ().Replace ("-", ""); + } + + + // Format a file size nicely with small caps. + // Example: 1048576 becomes "1 ᴍʙ" + public static string ToSize (this double byte_count) + { + if (byte_count >= 1099511627776) + return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 2)); + 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, 0)); + else + return byte_count.ToString () + " ʙ"; + } + + + public static bool IsSymlink (this FileSystemInfo file) + { + return ((file.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint); + } + + + public static string ToPrettyDate (this DateTime timestamp) + { + TimeSpan time_diff = DateTime.Now.Subtract (timestamp); + int day_diff = (int) time_diff.TotalDays; + DateTime yesterday = DateTime.Today.AddDays (-1); + + if (timestamp >= yesterday && timestamp < DateTime.Today) { + return "yesterday at " + timestamp.ToString ("HH:mm"); + + } else if (day_diff == 0) { + return "today at " + timestamp.ToString ("HH:mm"); + + } else if (day_diff < 7) { + return timestamp.ToString ("dddd"); + + } else if (day_diff < 31) { + if (day_diff < 14) + return "last week"; + else + return string.Format ("{0} weeks ago", Math.Ceiling ((double) day_diff / 7)); + + } else if (day_diff < 62) { + return "last month"; + + } else { + return string.Format ("{0} months ago", Math.Ceiling ((double) day_diff / 31)); + } + } + + + public static string ReplaceUnderscoreWithSpace (this string s) + { + int len = s.Length, lead = 0, trail = 0; + for (int i = 0; i < len && s[i] == '_'; i++, lead++) + ; // nop + for (int i = len - 1; i >= lead && s[i] == '_'; i--, trail++) + ; // nop + if (lead == 0 && trail == 0) + return s.Replace("_", " "); // fast code path + else + return s.Substring (0, lead) + + s.Substring (lead, len - lead - trail).Replace ("_", " ") + + s.Substring (len - trail, trail); + } + } +} diff --git a/SparkleLib/SparkleFetcherBase.cs b/SparkleLib/SparkleFetcherBase.cs new file mode 100755 index 0000000..4e91f4d --- /dev/null +++ b/SparkleLib/SparkleFetcherBase.cs @@ -0,0 +1,272 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Security.Cryptography; +using System.Threading; + +namespace SparkleLib { + + public class SparkleFetcherInfo { + public string Address; + public string RemotePath; + public string Backend; + public string Fingerprint; + public string TargetDirectory; + public string AnnouncementsUrl; + public bool FetchPriorHistory; + } + + + public abstract class SparkleFetcherBase { + + public event Action Started = delegate { }; + public event Action Failed = delegate { }; + + public event FinishedEventHandler Finished = delegate { }; + public delegate void FinishedEventHandler (bool repo_is_encrypted, bool repo_is_empty, string [] warnings); + + public event ProgressChangedEventHandler ProgressChanged = delegate { }; + public delegate void ProgressChangedEventHandler (double percentage, double speed); + + + public abstract bool Fetch (); + public abstract void Stop (); + public abstract bool IsFetchedRepoEmpty { get; } + public abstract bool IsFetchedRepoPasswordCorrect (string password); + public abstract void EnableFetchedRepoCrypto (string password); + + public double ProgressPercentage { get; private set; } + public double ProgressSpeed { get; private set; } + + public Uri RemoteUrl { get; protected set; } + public string RequiredFingerprint { get; protected set; } + public readonly bool FetchPriorHistory = false; + public string TargetFolder { get; protected set; } + public bool IsActive { get; protected set; } + public string Identifier; + public SparkleFetcherInfo OriginalFetcherInfo; + + public string [] Warnings { + get { + return this.warnings.ToArray (); + } + } + + public string [] Errors { + get { + return this.errors.ToArray (); + } + } + + + protected List warnings = new List (); + protected List errors = new List (); + + protected string [] ExcludeRules = new string [] { + "*.autosave", // Various autosaving apps + "*~", // gedit and emacs + ".~lock.*", // LibreOffice + "*.part", "*.crdownload", // Firefox and Chromium temporary download files + ".*.sw[a-z]", "*.un~", "*.swp", "*.swo", // vi(m) + ".directory", // KDE + "*.kate-swp", // Kate + ".DS_Store", "Icon\r", "._*", ".Spotlight-V100", ".Trashes", // Mac OS X + "*(Autosaved).graffle", // Omnigraffle + "Thumbs.db", "Desktop.ini", // Windows + "~*.tmp", "~*.TMP", "*~*.tmp", "*~*.TMP", // MS Office + "~*.ppt", "~*.PPT", "~*.pptx", "~*.PPTX", + "~*.xls", "~*.XLS", "~*.xlsx", "~*.XLSX", + "~*.doc", "~*.DOC", "~*.docx", "~*.DOCX", + "~$*", + "*.a$v", // QuarkXPress + "*/CVS/*", ".cvsignore", "*/.cvsignore", // CVS + "/.svn/*", "*/.svn/*", // Subversion + "/.hg/*", "*/.hg/*", "*/.hgignore", // Mercurial + "/.bzr/*", "*/.bzr/*", "*/.bzrignore", // Bazaar + "*<*", "*>*", "*:*", "*\"*", "*|*", "*\\?*", "*\\**", "*\\\\*" // Not allowed on Windows systems, + // see (http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx) + }; + + + private Thread thread; + + + public SparkleFetcherBase (SparkleFetcherInfo info) + { + OriginalFetcherInfo = info; + RequiredFingerprint = info.Fingerprint; + FetchPriorHistory = info.FetchPriorHistory; + string remote_path = info.RemotePath.Trim ("/".ToCharArray ()); + string address = info.Address; + + if (address.EndsWith ("/")) + address = address.Substring (0, address.Length - 1); + + if (!remote_path.StartsWith ("/")) + remote_path = "/" + remote_path; + + if (!address.Contains ("://")) + address = "ssh://" + address; + + TargetFolder = info.TargetDirectory; + + RemoteUrl = new Uri (address + remote_path); + IsActive = false; + } + + + public void Start () + { + IsActive = true; + Started (); + + SparkleLogger.LogInfo ("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl); + + try { + if (Directory.Exists (TargetFolder)) + Directory.Delete (TargetFolder, true); + + } catch (IOException) { + this.errors.Add ("\"" + TargetFolder + "\" is read-only."); + Failed (); + return; + } + + this.thread = new Thread (() => { + if (Fetch ()) { + Thread.Sleep (500); + SparkleLogger.LogInfo ("Fetcher", "Finished"); + + IsActive = false; + + bool repo_is_encrypted = (RemoteUrl.AbsolutePath.Contains ("-crypto") || + RemoteUrl.Host.Equals ("sparkleshare.net")); + + Finished (repo_is_encrypted, IsFetchedRepoEmpty, Warnings); + + } else { + Thread.Sleep (500); + + if (IsActive) { + SparkleLogger.LogInfo ("Fetcher", "Failed"); + Failed (); + + } else { + SparkleLogger.LogInfo ("Fetcher", "Failed: cancelled by user"); + } + + IsActive = false; + } + }); + + this.thread.Start (); + } + + + public virtual void Complete () + { + string identifier_path = Path.Combine (TargetFolder, ".sparkleshare"); + + if (File.Exists (identifier_path)) { + Identifier = File.ReadAllText (identifier_path).Trim (); + + } else { + Identifier = CreateIdentifier (); + File.WriteAllText (identifier_path, Identifier); + + if (IsFetchedRepoEmpty) + CreateInitialChangeSet (); + } + + File.SetAttributes (identifier_path, FileAttributes.Hidden); + } + + + // Create an initial change set when the + // user has fetched an empty remote folder + private void CreateInitialChangeSet () + { + string file_path = Path.Combine (TargetFolder, "SparkleShare.txt"); + string n = Environment.NewLine; + + UriBuilder uri_builder = new UriBuilder (RemoteUrl); + + if (RemoteUrl.Scheme.Contains ("http")) { + uri_builder.UserName = ""; + uri_builder.Password = ""; + } + + string text = "Congratulations, you've successfully created a SparkleShare repository!" + n + + n + + "Any files you add or change in this folder will be automatically synced to " + n + + uri_builder.ToString () + " and everyone connected to it." + n + + n + + "SparkleShare is an Open Source software program that helps people collaborate and " + n + + "share files. If you like what we do, consider buying us a beer: http://www.sparkleshare.org/" + n + + n + + "Have fun! :)" + n; + + if (RemoteUrl.AbsolutePath.Contains ("-crypto") || RemoteUrl.Host.Equals ("sparkleshare.net")) + text = text.Replace ("a SparkleShare repository", "an encrypted SparkleShare repository"); + + File.WriteAllText (file_path, text); + } + + + public static string CreateIdentifier () + { + return Path.GetRandomFileName ().SHA1 (); + } + + + public void Dispose () + { + if (this.thread != null) + this.thread.Abort (); + } + + + protected void OnProgressChanged (double percentage, double speed) { + ProgressChanged (percentage, speed); + } + + + protected string GenerateCryptoSalt () + { + string salt = Path.GetRandomFileName ().SHA1 (); + return salt.Substring (0, 16); + } + + + public static string GetBackend (string address) + { + if (address.StartsWith ("ssh+")) { + string backend = address.Substring (0, address.IndexOf ("://")); + backend = backend.Substring (4); + + return char.ToUpper (backend [0]) + backend.Substring (1); + + } else { + return "Git"; + } + } + } +} diff --git a/SparkleLib/SparkleFetcherSSH.cs b/SparkleLib/SparkleFetcherSSH.cs new file mode 100644 index 0000000..d6b7bb9 --- /dev/null +++ b/SparkleLib/SparkleFetcherSSH.cs @@ -0,0 +1,173 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Security.Cryptography; +using System.Threading; + +namespace SparkleLib { + + public abstract class SparkleFetcherSSH : SparkleFetcherBase { + + public SparkleFetcherSSH (SparkleFetcherInfo info) : base (info) + { + } + + + public override bool Fetch () + { + if (RemoteUrl.Host.EndsWith (".onion")) { + // Tor has special domain names called ".onion addresses". They can only be + // resolved by using a proxy via tor. While the rest of the openssh suite + // fully supports proxying, ssh-keyscan does not, so we can't use it for .onion + SparkleLogger.LogInfo ("Auth", "using tor .onion address skipping ssh-keyscan"); + + } else if (!RemoteUrl.Scheme.StartsWith ("http")) { + string host_key = FetchHostKey (); + + if (string.IsNullOrEmpty (RemoteUrl.Host) || host_key == null) { + SparkleLogger.LogInfo ("Auth", "Could not fetch host key"); + this.errors.Add ("error: Could not fetch host key"); + + return false; + } + + bool warn = true; + if (RequiredFingerprint != null) { + string host_fingerprint; + + try { + host_fingerprint = DeriveFingerprint (host_key); + + } catch (InvalidOperationException e) { + // "Unapproved cryptographic algorithms" won't work when FIPS is enabled on Windows. + // Software like Cisco AnyConnect can demand this feature is on, so we show an error + SparkleLogger.LogInfo ("Auth", "Unable to derive fingerprint: ", e); + this.errors.Add ("error: Can't check fingerprint due to FIPS being enabled"); + + return false; + } + + if (host_fingerprint == null || !RequiredFingerprint.Equals (host_fingerprint)) { + SparkleLogger.LogInfo ("Auth", "Fingerprint doesn't match"); + this.errors.Add ("error: Host fingerprint doesn't match"); + + return false; + } + + warn = false; + SparkleLogger.LogInfo ("Auth", "Fingerprint matches"); + + } else { + SparkleLogger.LogInfo ("Auth", "Skipping fingerprint check"); + } + + AcceptHostKey (host_key, warn); + } + + return true; + } + + + private string FetchHostKey () + { + SparkleLogger.LogInfo ("Auth", "Fetching host key for " + RemoteUrl.Host); + + Process process = new Process (); + process.StartInfo.FileName = "ssh-keyscan"; + process.StartInfo.WorkingDirectory = SparkleConfig.DefaultConfig.TmpPath; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.CreateNoWindow = true; + process.EnableRaisingEvents = true; + + string [] key_types = {"rsa", "dsa", "ecdsa"}; + + foreach (string key_type in key_types) { + if (RemoteUrl.Port < 1) + process.StartInfo.Arguments = "-t " + key_type + " -p 22 " + RemoteUrl.Host; + else + process.StartInfo.Arguments = "-t " + key_type + " -p " + RemoteUrl.Port + " " + RemoteUrl.Host; + + SparkleLogger.LogInfo ("Cmd", process.StartInfo.FileName + " " + process.StartInfo.Arguments); + + process.Start (); + string host_key = process.StandardOutput.ReadToEnd ().Trim (); + process.WaitForExit (); + + if (process.ExitCode == 0 && !string.IsNullOrWhiteSpace (host_key)) + return host_key; + } + + return null; + } + + + private string DeriveFingerprint (string public_key) + { + try { + MD5 md5 = new MD5CryptoServiceProvider (); + string key = public_key.Split (" ".ToCharArray ()) [2]; + byte [] b64_bytes = Convert.FromBase64String (key); + byte [] md5_bytes = md5.ComputeHash (b64_bytes); + string fingerprint = BitConverter.ToString (md5_bytes); + + return fingerprint.ToLower ().Replace ("-", ":"); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Fetcher", "Failed creating fingerprint: " + e.Message + " " + e.StackTrace); + return null; + } + } + + + private void AcceptHostKey (string host_key, bool warn) + { + string ssh_config_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".ssh"); + string known_hosts_file_path = Path.Combine (ssh_config_path, "known_hosts"); + + if (!File.Exists (known_hosts_file_path)) { + if (!Directory.Exists (ssh_config_path)) + Directory.CreateDirectory (ssh_config_path); + + File.Create (known_hosts_file_path).Close (); + } + + string host = RemoteUrl.Host; + string known_hosts = File.ReadAllText (known_hosts_file_path); + string [] known_hosts_lines = File.ReadAllLines (known_hosts_file_path); + + foreach (string line in known_hosts_lines) { + if (line.StartsWith (host + " ")) + return; + } + + if (known_hosts.EndsWith ("\n")) + File.AppendAllText (known_hosts_file_path, host_key + "\n"); + else + File.AppendAllText (known_hosts_file_path, "\n" + host_key + "\n"); + + SparkleLogger.LogInfo ("Auth", "Accepted host key for " + host); + + if (warn) + this.warnings.Add ("The following host key has been accepted:\n" + DeriveFingerprint (host_key)); + } + } +} diff --git a/SparkleLib/SparkleLib.csproj b/SparkleLib/SparkleLib.csproj new file mode 100644 index 0000000..d90138a --- /dev/null +++ b/SparkleLib/SparkleLib.csproj @@ -0,0 +1,51 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {2C914413-B31C-4362-93C7-1AE34F09112A} + Library + SparkleLib + SparkleLib + + + + + none + true + ..\bin + prompt + 4 + False + + + False + ..\bin + 4 + true + DEBUG + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleLib/SparkleLib.sln b/SparkleLib/SparkleLib.sln new file mode 100755 index 0000000..bd1d858 --- /dev/null +++ b/SparkleLib/SparkleLib.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleLib", "SparkleLib.csproj", "{2C914413-B31C-4362-93C7-1AE34F09112A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = SparkleLib.csproj + EndGlobalSection +EndGlobal diff --git a/SparkleLib/SparkleListenerBase.cs b/SparkleLib/SparkleListenerBase.cs new file mode 100755 index 0000000..152b625 --- /dev/null +++ b/SparkleLib/SparkleListenerBase.cs @@ -0,0 +1,216 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Collections.Generic; +using System.Timers; + +namespace SparkleLib { + + public enum DisconnectReason { + None, + TimeOut, + SystemSleep + } + + + // A persistent connection to the server that + // listens for change notifications + public abstract class SparkleListenerBase { + + public event Action Connected = delegate { }; + + public event DisconnectedEventHandler Disconnected = delegate { }; + public delegate void DisconnectedEventHandler (DisconnectReason reason); + + public event AnnouncementReceivedEventHandler AnnouncementReceived = delegate { }; + public delegate void AnnouncementReceivedEventHandler (SparkleAnnouncement announcement); + + public readonly Uri Server; + + public abstract void Connect (); + public abstract bool IsConnected { get; } + public abstract bool IsConnecting { get; } + + + protected abstract void AnnounceInternal (SparkleAnnouncement announcent); + protected abstract void AlsoListenToInternal (string folder_identifier); + + protected List channels = new List (); + + + private int max_recent_announcements = 10; + + private Dictionary> recent_announcements = + new Dictionary> (); + + private Dictionary queue_up = new Dictionary (); + + private Timer reconnect_timer = new Timer { + Interval = 60 * 1000, + Enabled = true + }; + + + public SparkleListenerBase (Uri server, string folder_identifier) + { + Server = server; + this.channels.Add (folder_identifier); + + this.reconnect_timer.Elapsed += OnTimerElapsed; + this.reconnect_timer.Start (); + } + + private void OnTimerElapsed(object sender, EventArgs args) + { + if (!IsConnected && !IsConnecting) + Reconnect (); + } + + public void Announce (SparkleAnnouncement announcement) + { + if (!IsRecentAnnouncement (announcement)) { + if (IsConnected) { + SparkleLogger.LogInfo ("Listener", "Announcing message " + announcement.Message + + " to " + announcement.FolderIdentifier + " on " + Server); + + AnnounceInternal (announcement); + AddRecentAnnouncement (announcement); + + } else { + SparkleLogger.LogInfo ("Listener", "Can't send message to " + Server + ". Queuing message"); + this.queue_up [announcement.FolderIdentifier] = announcement; + } + + } else { + SparkleLogger.LogInfo ("Listener", "Already processed message " + announcement.Message + + " to " + announcement.FolderIdentifier + " from " + Server); + } + } + + + public void AlsoListenTo (string channel) + { + if (!this.channels.Contains (channel)) + this.channels.Add (channel); + + if (IsConnected) { + SparkleLogger.LogInfo ("Listener", "Subscribing to channel " + channel + " on " + Server); + AlsoListenToInternal (channel); + } + } + + + public void Reconnect () + { + SparkleLogger.LogInfo ("Listener", "Trying to reconnect to " + Server); + Connect (); + } + + + public void OnConnected () + { + foreach (string channel in this.channels.GetRange (0, this.channels.Count)) { + SparkleLogger.LogInfo ("Listener", "Subscribing to channel " + channel + " on " + Server); + AlsoListenToInternal (channel); + } + + SparkleLogger.LogInfo ("Listener", "Listening for announcements on " + Server); + Connected (); + + if (this.queue_up.Count > 0) { + SparkleLogger.LogInfo ("Listener", "Delivering " + this.queue_up.Count + " queued messages..."); + + foreach (KeyValuePair item in this.queue_up) { + SparkleAnnouncement announcement = item.Value; + Announce (announcement); + } + } + } + + + public void OnDisconnected (DisconnectReason reason, string message) + { + SparkleLogger.LogInfo ("Listener", "Disconnected from " + Server + ": " + message); + Disconnected (reason); + } + + + public void OnAnnouncement (SparkleAnnouncement announcement) + { + SparkleLogger.LogInfo ("Listener", "Got message " + announcement.Message + " from " + + announcement.FolderIdentifier + " on " + Server); + + if (IsRecentAnnouncement (announcement)) + return; + + AddRecentAnnouncement (announcement); + AnnouncementReceived (announcement); + } + + + public virtual void Dispose () + { + if (this.reconnect_timer != null) { + this.reconnect_timer.Stop (); + + this.reconnect_timer.Elapsed -= OnTimerElapsed; + this.reconnect_timer.Dispose (); + + this.reconnect_timer = null; + } + } + + + private bool IsRecentAnnouncement (SparkleAnnouncement announcement) + { + if (!this.recent_announcements.ContainsKey (announcement.FolderIdentifier)) { + return false; + + } else { + foreach (SparkleAnnouncement recent_announcement in GetRecentAnnouncements (announcement.FolderIdentifier)) { + if (recent_announcement.Message.Equals (announcement.Message)) + return true; + } + + return false; + } + } + + + private List GetRecentAnnouncements (string folder_identifier) + { + if (!this.recent_announcements.ContainsKey (folder_identifier)) + this.recent_announcements [folder_identifier] = new List (); + + return this.recent_announcements [folder_identifier]; + } + + + private void AddRecentAnnouncement (SparkleAnnouncement announcement) + { + List recent_announcements = + GetRecentAnnouncements (announcement.FolderIdentifier); + + if (!IsRecentAnnouncement (announcement)) + recent_announcements.Add (announcement); + + if (recent_announcements.Count > this.max_recent_announcements) + recent_announcements.RemoveRange (0, recent_announcements.Count - this.max_recent_announcements); + } + } +} diff --git a/SparkleLib/SparkleListenerFactory.cs b/SparkleLib/SparkleListenerFactory.cs new file mode 100644 index 0000000..a42f480 --- /dev/null +++ b/SparkleLib/SparkleListenerFactory.cs @@ -0,0 +1,66 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Collections.Generic; + +namespace SparkleLib { + + public static class SparkleListenerFactory { + + private static List listeners = new List (); + + + public static SparkleListenerBase CreateListener (string folder_name, string folder_identifier) + { + // Check if the user wants to use a global custom notification service + string uri = SparkleConfig.DefaultConfig.GetConfigOption ("announcements_url"); + + // Check if the user wants a use a custom notification service for this folder + if (string.IsNullOrEmpty (uri)) + uri = SparkleConfig.DefaultConfig.GetFolderOptionalAttribute (folder_name, "announcements_url"); + + // This is SparkleShare's centralized notification service. + // It communicates "It's time to sync!" signals between clients. + // + // Please see the SparkleShare wiki if you wish to run + // your own service instead + if (string.IsNullOrEmpty (uri)) + uri = "tcp://notifications.sparkleshare.org:443"; + + Uri announce_uri = new Uri (uri); + + // Use only one listener per notification service to keep + // the number of connections as low as possible + foreach (SparkleListenerBase listener in listeners) { + if (listener.Server.Equals (announce_uri)) { + SparkleLogger.LogInfo ("ListenerFactory", "Refered to existing listener for " + announce_uri); + + // We already seem to have a listener for this server, + // refer to the existing one instead + listener.AlsoListenTo (folder_identifier); + return (SparkleListenerBase) listener; + } + } + + listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier)); + SparkleLogger.LogInfo ("ListenerFactory", "Issued new listener for " + announce_uri); + + return (SparkleListenerBase) listeners [listeners.Count - 1]; + } + } +} diff --git a/SparkleLib/SparkleListenerTcp.cs b/SparkleLib/SparkleListenerTcp.cs new file mode 100755 index 0000000..f022cbb --- /dev/null +++ b/SparkleLib/SparkleListenerTcp.cs @@ -0,0 +1,259 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace SparkleLib { + + public class SparkleListenerTcp : SparkleListenerBase { + + private Socket socket; + private Thread thread; + private bool is_connected = false; + private bool is_connecting = false; + private DateTime last_ping = DateTime.Now; + + + public SparkleListenerTcp (Uri server, string folder_identifier) : base (server, folder_identifier) + { + } + + + public override bool IsConnected { + get { + return this.is_connected; + } + } + + + public override bool IsConnecting { + get { + return this.is_connecting; + } + } + + + // Starts a new thread and listens to the channel + public override void Connect () + { + this.is_connecting = true; + + this.thread = new Thread (() => { + int port = Server.Port; + + if (port < 0) + port = 443; + + try { + this.socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { + ReceiveTimeout = 5 * 1000, + SendTimeout = 5 * 1000 + }; + + // Try to connect to the server + this.socket.Connect (Server.Host, port); + + this.is_connecting = false; + this.is_connected = true; + + OnConnected (); + + } catch (Exception e) { + this.is_connected = false; + this.is_connecting = false; + + if (this.socket != null) + this.socket.Close (); + + OnDisconnected (SparkleLib.DisconnectReason.TimeOut, e.Message); + return; + } + + + byte [] bytes = new byte [4096]; + int bytes_read = 0; + this.last_ping = DateTime.Now; + + // Wait for messages + while (this.is_connected) { + try { + int i = 0; + int timeout = 300; + DisconnectReason reason = DisconnectReason.TimeOut; + + // This blocks the thread + while (this.socket.Available < 1) { + try { + // We've timed out, let's ping the server to + // see if the connection is still up + if (i == timeout) { + SparkleLogger.LogInfo ("ListenerTcp", "Pinging " + Server); + + byte [] ping_bytes = Encoding.UTF8.GetBytes ("ping\n"); + byte [] pong_bytes = new byte [4096]; + + this.socket.Send (ping_bytes); + + if (this.socket.Receive (pong_bytes) < 1) + // 10057 means "Socket is not connected" + throw new SocketException (10057); + + SparkleLogger.LogInfo ("ListenerTcp", "Received pong from " + Server); + + i = 0; + this.last_ping = DateTime.Now; + + } else { + + // Check when the last ping occured. If it's + // significantly longer than our regular interval the + // system likely woke up from sleep and we want to + // simulate a disconnect + int sleepiness = DateTime.Compare ( + this.last_ping.AddMilliseconds (timeout * 1000 * 1.2), + DateTime.Now + ); + + if (sleepiness <= 0) { + SparkleLogger.LogInfo ("ListenerTcp", "System woke up from sleep"); + reason = DisconnectReason.SystemSleep; + + // 10057 means "Socket is not connected" + throw new SocketException (10057); + } + } + + // The ping failed: disconnect completely + } catch (SocketException e) { + Disconnect(reason, "Ping timeout: " + e.Message); + return; + } + + Thread.Sleep (1000); + i++; + } + + } catch (Exception) { + return; + } + + try { + if (this.socket.Available > 0) + bytes_read = this.socket.Receive (bytes); + + // Parse the received message + if (bytes_read > 0) { + string received = Encoding.UTF8.GetString (bytes); + string line = received.Substring (0, received.IndexOf ("\n")); + + if (!line.Contains ("!")) + continue; + + string folder_identifier = line.Substring (0, line.IndexOf ("!")); + string message = CleanMessage (line.Substring (line.IndexOf ("!") + 1)); + + // We have a message! + if (!folder_identifier.Equals ("debug") && !string.IsNullOrEmpty (message)) + OnAnnouncement (new SparkleAnnouncement (folder_identifier, message)); + } + + } catch (SocketException e) { + Disconnect (DisconnectReason.TimeOut, "Timeout during receiving: " + e.Message); + return; + } + } + }); + + this.thread.Start (); + } + + + private void Disconnect (DisconnectReason reason, string message) + { + this.is_connected = false; + this.is_connecting = false; + + if (this.socket != null) { + this.socket.Close (); + this.socket = null; + } + + OnDisconnected (reason, message); + } + + + protected override void AlsoListenToInternal (string folder_identifier) + { + string to_send = "subscribe " + folder_identifier + "\n"; + + try { + this.socket.Send (Encoding.UTF8.GetBytes (to_send)); + this.last_ping = DateTime.Now; + + } catch (Exception e) { + this.is_connected = false; + this.is_connecting = false; + + OnDisconnected (DisconnectReason.TimeOut, e.Message); + } + } + + + protected override void AnnounceInternal (SparkleAnnouncement announcement) + { + string to_send = "announce " + announcement.FolderIdentifier + " " + announcement.Message + "\n"; + + try { + if (this.socket != null) + this.socket.Send (Encoding.UTF8.GetBytes (to_send)); + + this.last_ping = DateTime.Now; + + } catch (Exception e) { + this.is_connected = false; + this.is_connecting = false; + + OnDisconnected (DisconnectReason.TimeOut, e.Message); + } + } + + + public override void Dispose () + { + if (this.socket != null) { + this.socket.Close (); + this.socket = null; + } + + this.thread.Abort (); + this.thread.Join (); + + base.Dispose (); + } + + + private string CleanMessage (string message) + { + message = message.Replace ("\n", ""); + message = message.Replace ("\0", ""); + return message.Trim (); + } + } +} diff --git a/SparkleLib/SparkleLogger.cs b/SparkleLib/SparkleLogger.cs new file mode 100755 index 0000000..8913671 --- /dev/null +++ b/SparkleLib/SparkleLogger.cs @@ -0,0 +1,106 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.IO; + +namespace SparkleLib { + + public static class SparkleLogger { + + private static Object debug_lock = new Object (); + private static int log_size = 0; + + public static void LogInfo (string type, string message) + { + LogInfo (type, message, null); + } + + + public static void LogInfo (string type, string message, Exception exception) + { + string timestamp = DateTime.Now.ToString ("HH:mm:ss"); + string line; + + if (string.IsNullOrEmpty (type)) + line = timestamp + " | " + message; + else + line = timestamp + " | " + type + " | " + message; + + if (exception != null) + line += ": " + exception.Message + " " + exception.StackTrace; + + if (SparkleConfig.DebugMode) + Console.WriteLine (line); + + lock (debug_lock) { + // Don't let the log get bigger than 1000 lines + if (log_size >= 1000) { + File.WriteAllText (SparkleConfig.DefaultConfig.LogFilePath, line + Environment.NewLine); + log_size = 0; + + } else { + File.AppendAllText (SparkleConfig.DefaultConfig.LogFilePath, line + Environment.NewLine); + log_size++; + } + } + } + + + public static void WriteCrashReport (Exception e) + { + string home_path = Environment.GetFolderPath (Environment.SpecialFolder.Personal); + + if (SparkleBackend.Platform == PlatformID.Win32NT) + home_path = Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); + + string crash_report_file_path = new string [] { home_path, "SparkleShare", "crash_report.txt" }.Combine (); + + string n = Environment.NewLine; + string crash_report = "Oops! SparkleShare has crashed... :(" + n + n + + "If you want to help fix this crash, please report it at " + n + + "https://github.com/hbons/SparkleShare/issues and include the lines below." + n + n + + "Remove any sensitive information like file names, IP addresses, domain names, etc. if needed." + n + n + + "------" + n + n + + "SparkleShare version: " + SparkleLib.SparkleBackend.Version + n + + "Operating system: " + SparkleLib.SparkleBackend.Platform + " (" + Environment.OSVersion + ")" + n; + + crash_report += e.GetType () + ": " + e.Message + n + e.StackTrace + n; + + if (e.InnerException != null) + crash_report += n + e.InnerException.Message + n + e.InnerException.StackTrace + n; + + if (SparkleConfig.DefaultConfig != null && File.Exists (SparkleConfig.DefaultConfig.LogFilePath)) { + string debug_log = File.ReadAllText (SparkleConfig.DefaultConfig.LogFilePath); + string [] debug_lines = debug_log.Split (Environment.NewLine.ToCharArray ()); + int line_count = 50; + + if (debug_lines.Length > line_count) { + crash_report += string.Join (Environment.NewLine, debug_lines, + (debug_lines.Length - line_count), line_count) + n; + + } else { + crash_report += debug_log + n; + } + } + + File.WriteAllText (crash_report_file_path, crash_report); + Console.WriteLine (DateTime.Now.ToString ("HH:mm:ss") + " | Wrote crash report to " + crash_report_file_path); + } + } +} + diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs new file mode 100755 index 0000000..33f90dd --- /dev/null +++ b/SparkleLib/SparkleRepoBase.cs @@ -0,0 +1,632 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +using Timers = System.Timers; + +namespace SparkleLib { + + public enum SyncStatus { + Idle, + Paused, + SyncUp, + SyncDown, + Error + } + + + public enum ErrorStatus { + None, + HostUnreachable, + HostIdentityChanged, + AuthenticationFailed, + DiskSpaceExceeded, + UnreadableFiles, + NotFound, + IncompatibleClientServer + } + + + public abstract class SparkleRepoBase { + + public abstract bool SyncUp (); + public abstract bool SyncDown (); + public abstract void RestoreFile (string path, string revision, string target_file_path); + public abstract bool HasUnsyncedChanges { get; set; } + public abstract bool HasLocalChanges { get; } + public abstract bool HasRemoteChanges { get; } + + public abstract string CurrentRevision { get; } + public abstract double Size { get; } + public abstract double HistorySize { get; } + + public abstract List ExcludePaths { get; } + public abstract List UnsyncedChanges { get; } + public abstract List GetChangeSets (); + public abstract List GetChangeSets (string path); + + public static bool UseCustomWatcher = false; + + + public event SyncStatusChangedEventHandler SyncStatusChanged = delegate { }; + public delegate void SyncStatusChangedEventHandler (SyncStatus new_status); + + public event ProgressChangedEventHandler ProgressChanged = delegate { }; + public delegate void ProgressChangedEventHandler (); + + public event NewChangeSetEventHandler NewChangeSet = delegate { }; + public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set); + + public event Action ConflictResolved = delegate { }; + public event Action ChangesDetected = delegate { }; + + + public readonly string LocalPath; + public readonly string Name; + public readonly Uri RemoteUrl; + public List ChangeSets { get; private set; } + public SyncStatus Status { get; private set; } + public ErrorStatus Error { get; protected set; } + public bool IsBuffering { get; private set; } + public double ProgressPercentage { get; private set; } + public double ProgressSpeed { get; private set; } + + public DateTime LastSync { + get { + if (ChangeSets != null && ChangeSets.Count > 0) + return ChangeSets [0].Timestamp; + else + return DateTime.MinValue; + } + } + + public virtual string Identifier { + get { + if (this.identifier != null) + return this.identifier; + + string id_path = Path.Combine (LocalPath, ".sparkleshare"); + + if (File.Exists (id_path)) + this.identifier = File.ReadAllText (id_path).Trim (); + + if (!string.IsNullOrEmpty (this.identifier)) { + return this.identifier; + + } else { + string config_identifier = this.local_config.GetIdentifierForFolder (Name); + + if (!string.IsNullOrEmpty (config_identifier)) + this.identifier = config_identifier; + else + this.identifier = SparkleFetcherBase.CreateIdentifier (); + + File.WriteAllText (id_path, this.identifier); + File.SetAttributes (id_path, FileAttributes.Hidden); + + SparkleLogger.LogInfo ("Local", Name + " | Assigned identifier: " + this.identifier); + + return this.identifier; + } + } + } + + + protected SparkleConfig local_config; + + + private string identifier; + private SparkleListenerBase listener; + private SparkleWatcher watcher; + private TimeSpan poll_interval = PollInterval.Short; + private DateTime last_poll = DateTime.Now; + private DateTime progress_last_change = DateTime.Now; + private Timers.Timer remote_timer = new Timers.Timer () { Interval = 5000 }; + private DisconnectReason last_disconnect_reason = DisconnectReason.None; + + private bool is_syncing { + get { return (Status == SyncStatus.SyncUp || Status == SyncStatus.SyncDown || IsBuffering); } + } + + private static class PollInterval { + public static readonly TimeSpan Short = new TimeSpan (0, 0, 5, 0); + public static readonly TimeSpan Long = new TimeSpan (0, 0, 15, 0); + } + + + public SparkleRepoBase (string path, SparkleConfig config) + { + SparkleLogger.LogInfo (path, "Initializing..."); + + Status = SyncStatus.Idle; + Error = ErrorStatus.None; + this.local_config = config; + LocalPath = path; + Name = Path.GetFileName (LocalPath); + RemoteUrl = new Uri (this.local_config.GetUrlForFolder (Name)); + IsBuffering = false; + this.identifier = Identifier; + ChangeSets = GetChangeSets (); + + string is_paused = this.local_config.GetFolderOptionalAttribute (Name, "paused"); + if (is_paused != null && is_paused.Equals (bool.TrueString)) + Status = SyncStatus.Paused; + + string identifier_file_path = Path.Combine (LocalPath, ".sparkleshare"); + File.SetAttributes (identifier_file_path, FileAttributes.Hidden); + + if (!UseCustomWatcher) + this.watcher = new SparkleWatcher (LocalPath); + + new Thread (() => CreateListener ()).Start (); + + this.remote_timer.Elapsed += RemoteTimerElapsedDelegate; + } + + + private void RemoteTimerElapsedDelegate (object sender, EventArgs args) + { + if (this.is_syncing || IsBuffering || Status == SyncStatus.Paused) + return; + + int time_comparison = DateTime.Compare (this.last_poll, DateTime.Now.Subtract (this.poll_interval)); + + if (time_comparison < 0) { + if (HasUnsyncedChanges && !this.is_syncing) + SyncUpBase (); + + this.last_poll = DateTime.Now; + + if (HasRemoteChanges && !this.is_syncing) + SyncDownBase (); + + if (this.listener.IsConnected) + this.poll_interval = PollInterval.Long; + } + + // In the unlikely case that we haven't synced up our + // changes or the server was down, sync up again + if (HasUnsyncedChanges && !this.is_syncing && Error == ErrorStatus.None) + SyncUpBase (); + + if (Status != SyncStatus.Idle && Status != SyncStatus.Error) { + Status = SyncStatus.Idle; + SyncStatusChanged (Status); + } + } + + + public void Initialize () + { + // Sync up everything that changed since we've been offline + new Thread (() => { + if (Status != SyncStatus.Paused) { + if (HasRemoteChanges) + SyncDownBase (); + + if (HasUnsyncedChanges || HasLocalChanges) { + do { + SyncUpBase (); + + } while (HasLocalChanges); + } + } + + if (!UseCustomWatcher) + this.watcher.ChangeEvent += OnFileActivity; + + this.remote_timer.Start (); + + }).Start (); + } + + + private Object buffer_lock = new Object (); + + public void OnFileActivity (FileSystemEventArgs args) + { + if (IsBuffering || this.is_syncing) + return; + + if (args != null) { + foreach (string exclude_path in ExcludePaths) { + if (args.FullPath.Contains (Path.DirectorySeparatorChar + exclude_path)) + return; + } + } + + if (Status == SyncStatus.Paused) { + ChangesDetected (); + return; + } + + lock (this.buffer_lock) { + if (IsBuffering || this.is_syncing || !HasLocalChanges) + return; + + IsBuffering = true; + } + + ChangesDetected (); + + if (!UseCustomWatcher) + this.watcher.Disable (); + + SparkleLogger.LogInfo ("Local", Name + " | Activity detected, waiting for it to settle..."); + + List size_buffer = new List (); + DirectoryInfo info = new DirectoryInfo (LocalPath); + + do { + if (size_buffer.Count >= 4) + size_buffer.RemoveAt (0); + + size_buffer.Add (CalculateSize (info)); + + if (size_buffer.Count >= 4 && + size_buffer [0].Equals (size_buffer [1]) && + size_buffer [1].Equals (size_buffer [2]) && + size_buffer [2].Equals (size_buffer [3])) { + + SparkleLogger.LogInfo ("Local", Name + " | Activity has settled"); + IsBuffering = false; + + bool first_sync = true; + + if (HasLocalChanges && Status == SyncStatus.Idle) { + do { + if (!first_sync) + SparkleLogger.LogInfo ("Local", Name + " | More changes found"); + + SyncUpBase (); + + if (Error == ErrorStatus.UnreadableFiles) + return; + + first_sync = false; + + } while (HasLocalChanges); + } + + if (Status != SyncStatus.Idle && Status != SyncStatus.Error) { + Status = SyncStatus.Idle; + SyncStatusChanged (Status); + } + + } else { + Thread.Sleep (500); + } + + } while (IsBuffering); + + if (!UseCustomWatcher) + this.watcher.Enable (); + } + + + public void ForceRetry () + { + if (Error != ErrorStatus.None && !this.is_syncing) + SyncUpBase (); + } + + + protected void OnConflictResolved () + { + ConflictResolved (); + } + + + protected void OnProgressChanged (double progress_percentage, double progress_speed) + { + if (progress_percentage < 1) + return; + + // Only trigger the ProgressChanged event once per second + if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (new TimeSpan (0, 0, 0, 1))) >= 0) + return; + + if (progress_percentage == 100.0) + progress_percentage = 99.0; + + ProgressPercentage = progress_percentage; + ProgressSpeed = progress_speed; + this.progress_last_change = DateTime.Now; + + ProgressChanged (); + } + + + private void SyncUpBase () + { + if (!UseCustomWatcher) + this.watcher.Disable (); + + SparkleLogger.LogInfo ("SyncUp", Name + " | Initiated"); + HasUnsyncedChanges = true; + + Status = SyncStatus.SyncUp; + SyncStatusChanged (Status); + + if (SyncUp ()) { + SparkleLogger.LogInfo ("SyncUp", Name + " | Done"); + ChangeSets = GetChangeSets (); + + HasUnsyncedChanges = false; + this.poll_interval = PollInterval.Long; + + this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision)); + + Status = SyncStatus.Idle; + SyncStatusChanged (Status); + + } else { + SparkleLogger.LogInfo ("SyncUp", Name + " | Error"); + SyncDownBase (); + + if (!UseCustomWatcher) + this.watcher.Disable (); + + if (Error == ErrorStatus.None && SyncUp ()) { + HasUnsyncedChanges = false; + + this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision)); + + Status = SyncStatus.Idle; + SyncStatusChanged (Status); + + } else { + this.poll_interval = PollInterval.Short; + + Status = SyncStatus.Error; + SyncStatusChanged (Status); + } + } + + ProgressPercentage = 0.0; + ProgressSpeed = 0.0; + + if (!UseCustomWatcher) + this.watcher.Enable (); + + this.status_message = ""; + } + + + private void SyncDownBase () + { + if (!UseCustomWatcher) + this.watcher.Disable (); + + SparkleLogger.LogInfo ("SyncDown", Name + " | Initiated"); + + Status = SyncStatus.SyncDown; + SyncStatusChanged (Status); + + string pre_sync_revision = CurrentRevision; + + if (SyncDown ()) { + Error = ErrorStatus.None; + + string identifier_file_path = Path.Combine (LocalPath, ".sparkleshare"); + File.SetAttributes (identifier_file_path, FileAttributes.Hidden); + + ChangeSets = GetChangeSets (); + + if (!pre_sync_revision.Equals (CurrentRevision) && + ChangeSets != null && ChangeSets.Count > 0 && + !ChangeSets [0].User.Name.Equals (this.local_config.User.Name)) { + + bool emit_change_event = true; + + foreach (SparkleChange change in ChangeSets [0].Changes) { + if (change.Path.EndsWith (".sparkleshare")) { + emit_change_event = false; + break; + } + } + + if (emit_change_event) + NewChangeSet (ChangeSets [0]); + } + + SparkleLogger.LogInfo ("SyncDown", Name + " | Done"); + + // There could be changes from a resolved + // conflict. Tries only once, then lets + // the timer try again periodically + if (HasUnsyncedChanges) { + Status = SyncStatus.SyncUp; + SyncStatusChanged (Status); + + if (SyncUp ()) + HasUnsyncedChanges = false; + } + + Status = SyncStatus.Idle; + SyncStatusChanged (Status); + + } else { + SparkleLogger.LogInfo ("SyncDown", Name + " | Error"); + + ChangeSets = GetChangeSets (); + + Status = SyncStatus.Error; + SyncStatusChanged (Status); + } + + ProgressPercentage = 0.0; + ProgressSpeed = 0.0; + + Status = SyncStatus.Idle; + SyncStatusChanged (Status); + + if (!UseCustomWatcher) + this.watcher.Enable (); + } + + + private void CreateListener () + { + this.listener = SparkleListenerFactory.CreateListener (Name, Identifier); + + if (this.listener.IsConnected) + this.poll_interval = PollInterval.Long; + + this.listener.Connected += ListenerConnectedDelegate; + this.listener.Disconnected += ListenerDisconnectedDelegate; + this.listener.AnnouncementReceived += ListenerAnnouncementReceivedDelegate; + + if (!this.listener.IsConnected && !this.listener.IsConnecting) + this.listener.Connect (); + } + + + private void ListenerConnectedDelegate () + { + if (this.last_disconnect_reason == DisconnectReason.SystemSleep) { + this.last_disconnect_reason = DisconnectReason.None; + + if (HasRemoteChanges && !this.is_syncing) + SyncDownBase (); + } + + this.poll_interval = PollInterval.Long; + } + + + private void ListenerDisconnectedDelegate (DisconnectReason reason) + { + SparkleLogger.LogInfo (Name, "Falling back to regular polling"); + this.poll_interval = PollInterval.Short; + + this.last_disconnect_reason = reason; + + if (reason == DisconnectReason.SystemSleep) { + this.remote_timer.Stop (); + + int backoff_time = 2; + + do { + SparkleLogger.LogInfo (Name, "Next reconnect attempt in " + backoff_time + " seconds"); + Thread.Sleep (backoff_time * 1000); + this.listener.Connect (); + backoff_time *= 2; + + } while (backoff_time < 64 && !this.listener.IsConnected); + + this.remote_timer.Start (); + } + } + + + private void ListenerAnnouncementReceivedDelegate (SparkleAnnouncement announcement) + { + string identifier = Identifier; + + if (!announcement.FolderIdentifier.Equals (identifier)) + return; + + if (!announcement.Message.Equals (CurrentRevision)) { + while (this.is_syncing) + Thread.Sleep (100); + + SparkleLogger.LogInfo (Name, "Syncing due to announcement"); + + if (Status == SyncStatus.Paused) + SparkleLogger.LogInfo (Name, "We're paused, skipping sync"); + else + SyncDownBase (); + } + } + + + // Recursively gets a folder's size in bytes + private long CalculateSize (DirectoryInfo parent) + { + if (ExcludePaths.Contains (parent.Name)) + return 0; + + long size = 0; + + try { + foreach (DirectoryInfo directory in parent.GetDirectories ()) + size += CalculateSize (directory); + + foreach (FileInfo file in parent.GetFiles ()) + size += file.Length; + + } catch (Exception e) { + SparkleLogger.LogInfo ("Local", "Error calculating directory size", e); + } + + return size; + } + + + public void Pause () + { + if (Status == SyncStatus.Idle) { + this.local_config.SetFolderOptionalAttribute (Name, "paused", bool.TrueString); + Status = SyncStatus.Paused; + } + } + + + protected string status_message = ""; + + public void Resume (string message) + { + this.status_message = message; + + if (Status == SyncStatus.Paused) { + this.local_config.SetFolderOptionalAttribute (Name, "paused", bool.FalseString); + Status = SyncStatus.Idle; + + if (HasUnsyncedChanges || HasLocalChanges) { + do { + SyncUpBase (); + + } while (HasLocalChanges); + } + } + } + + + public void Dispose () + { + if (remote_timer != null) { + this.remote_timer.Elapsed -= RemoteTimerElapsedDelegate; + this.remote_timer.Stop (); + this.remote_timer.Dispose (); + this.remote_timer = null; + } + + this.listener.Disconnected -= ListenerDisconnectedDelegate; + this.listener.AnnouncementReceived -= ListenerAnnouncementReceivedDelegate; + + this.listener.Dispose (); + + if (!UseCustomWatcher) + this.watcher.Dispose (); + } + } +} diff --git a/SparkleLib/SparkleUser.cs b/SparkleLib/SparkleUser.cs new file mode 100644 index 0000000..75d4383 --- /dev/null +++ b/SparkleLib/SparkleUser.cs @@ -0,0 +1,42 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; + +namespace SparkleLib { + + public class SparkleUser { + + public readonly string Name; + public readonly string Email; + + public string AvatarFilePath; + + public string PrivateKey; + public string PrivateKeyFilePath; + + public string PublicKey; + public string PublicKeyFilePath; + + + public SparkleUser (string name, string email) + { + Name = name; + Email = email; + } + } +} diff --git a/SparkleLib/SparkleWatcher.cs b/SparkleLib/SparkleWatcher.cs new file mode 100755 index 0000000..463fba7 --- /dev/null +++ b/SparkleLib/SparkleWatcher.cs @@ -0,0 +1,63 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.IO; + +namespace SparkleLib { + + public class SparkleWatcher : FileSystemWatcher { + + public event ChangeEventEventHandler ChangeEvent = delegate { }; + public delegate void ChangeEventEventHandler (FileSystemEventArgs args); + + private Object thread_lock = new Object (); + + + public SparkleWatcher (string path) : base (path) + { + IncludeSubdirectories = true; + EnableRaisingEvents = true; + Filter = "*"; + + Changed += OnChanged; + Created += OnChanged; + Deleted += OnChanged; + Renamed += OnChanged; + } + + + private void OnChanged (object sender, FileSystemEventArgs args) + { + ChangeEvent (args); + } + + + public void Enable () + { + lock (this.thread_lock) + EnableRaisingEvents = true; + } + + + public void Disable () + { + lock (this.thread_lock) + EnableRaisingEvents = false; + } + } +} diff --git a/SparkleLib/SparkleWrappers.cs b/SparkleLib/SparkleWrappers.cs new file mode 100644 index 0000000..9af9df2 --- /dev/null +++ b/SparkleLib/SparkleWrappers.cs @@ -0,0 +1,109 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 . + + +using System; +using System.IO; +using System.Collections.Generic; + +namespace SparkleLib { + + public enum SparkleChangeType { + Added, + Edited, + Deleted, + Moved + } + + + public class SparkleChangeSet { + + public SparkleUser User = new SparkleUser ("Unknown", "Unknown"); + + public SparkleFolder Folder; + public string Revision; + public DateTime Timestamp; + public DateTime FirstTimestamp; + public Uri RemoteUrl; + + public List Changes = new List (); + + public string ToMessage () + { + string message = "added: {0}"; + + switch (Changes [0].Type) { + case SparkleChangeType.Edited: message = "edited: {0}"; break; + case SparkleChangeType.Deleted: message = "deleted: {0}"; break; + case SparkleChangeType.Moved: message = "moved: {0}"; break; + } + + if (Changes.Count > 0) + return string.Format (message, Changes [0].Path); + else + return "did something magical"; + } + } + + + public class SparkleChange { + + public SparkleChangeType Type; + public DateTime Timestamp; + public bool IsFolder = false; + + public string Path; + public string MovedToPath; + } + + + public class SparkleFolder { + + public string Name; + public Uri RemoteAddress; + + public string FullPath { + get { + string custom_path = SparkleConfig.DefaultConfig.GetFolderOptionalAttribute (Name, "path"); + + if (custom_path != null) + return Path.Combine (custom_path, Name); + else + return Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, Name); + } + } + + + public SparkleFolder (string name) + { + Name = name; + } + } + + + public class SparkleAnnouncement { + + public readonly string FolderIdentifier; + public readonly string Message; + + + public SparkleAnnouncement (string folder_identifier, string message) + { + FolderIdentifier = folder_identifier; + Message = message; + } + } +} diff --git a/SparkleShare/Common/HTML/Makefile.am b/SparkleShare/Common/HTML/Makefile.am new file mode 100755 index 0000000..dffbf0a --- /dev/null +++ b/SparkleShare/Common/HTML/Makefile.am @@ -0,0 +1,10 @@ +dist_html_DATA = \ + day-entry.html \ + event-entry.html \ + event-log.html \ + jquery.js + +htmldir = $(pkgdatadir)/html/ + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/SparkleShare/Common/HTML/day-entry.html b/SparkleShare/Common/HTML/day-entry.html new file mode 100755 index 0000000..43b2d52 --- /dev/null +++ b/SparkleShare/Common/HTML/day-entry.html @@ -0,0 +1,4 @@ +
+
+
+
diff --git a/SparkleShare/Common/HTML/event-entry.html b/SparkleShare/Common/HTML/event-entry.html new file mode 100755 index 0000000..c0fa976 --- /dev/null +++ b/SparkleShare/Common/HTML/event-entry.html @@ -0,0 +1,13 @@ +
+ +
+
+
+ + + + +
+ + Show all +
diff --git a/SparkleShare/Common/HTML/event-log.html b/SparkleShare/Common/HTML/event-log.html new file mode 100755 index 0000000..cbc5b3a --- /dev/null +++ b/SparkleShare/Common/HTML/event-log.html @@ -0,0 +1,224 @@ + + + + + SparkleShare Event Log + + + + + + + + + + diff --git a/SparkleShare/Common/HTML/jquery.js b/SparkleShare/Common/HTML/jquery.js new file mode 100755 index 0000000..3a8cd46 --- /dev/null +++ b/SparkleShare/Common/HTML/jquery.js @@ -0,0 +1,18 @@ +/*! + * jQuery JavaScript Library v1.6.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu May 12 15:04:36 2011 -0400 + */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!cj[a]){var b=f("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),c.body.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write("");b=cl.createElement(a),cl.body.appendChild(b),d=f.css(b,"display"),c.body.removeChild(ck)}cj[a]=d}return cj[a]}function cu(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function ct(){cq=b}function cs(){setTimeout(ct,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g=0===c})}function W(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function O(a,b){return(a&&a!=="*"?a+".":"")+b.replace(A,"`").replace(B,"&")}function N(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function L(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function F(){return!0}function E(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function H(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(H,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=d.userAgent,x,y,z,A=Object.prototype.toString,B=Object.prototype.hasOwnProperty,C=Array.prototype.push,D=Array.prototype.slice,E=String.prototype.trim,F=Array.prototype.indexOf,G={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.1",length:0,size:function(){return this.length},toArray:function(){return D.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?C.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(D.apply(this,arguments),"slice",D.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:C,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!y){y=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",z,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",z),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&H()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):G[A.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!B.call(a,"constructor")&&!B.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||B.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};f=c.createElement("select"),g=f.appendChild(c.createElement("option")),h=a.getElementsByTagName("input")[0],j={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},h.checked=!0,j.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,j.optDisabled=!g.disabled;try{delete a.test}catch(s){j.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function b(){j.noCloneEvent=!1,a.detachEvent("onclick",b)}),a.cloneNode(!0).fireEvent("onclick")),h=c.createElement("input"),h.value="t",h.setAttribute("type","radio"),j.radioValue=h.value==="t",h.setAttribute("checked","checked"),a.appendChild(h),k=c.createDocumentFragment(),k.appendChild(a.firstChild),j.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",l=c.createElement("body"),m={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};for(q in m)l.style[q]=m[q];l.appendChild(a),b.insertBefore(l,b.firstChild),j.appendChecked=h.checked,j.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,j.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",j.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",n=a.getElementsByTagName("td"),r=n[0].offsetHeight===0,n[0].style.display="",n[1].style.display="none",j.reliableHiddenOffsets=r&&n[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(i=c.createElement("div"),i.style.width="0",i.style.marginRight="0",a.appendChild(i),j.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(i,null)||{marginRight:0}).marginRight,10)||0)===0),l.innerHTML="",b.removeChild(l);if(a.attachEvent)for(q in{submit:1,change:1,focusin:1})p="on"+q,r=p in a,r||(a.setAttribute(p,"return;"),r=typeof a[p]=="function"),j[q+"Bubbles"]=r;return j}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;return(e.value||"").replace(p,"")}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);c=j&&f.attrFix[c]||c,i=f.attrHooks[c],i||(!t.test(c)||typeof d!="boolean"&&d!==b&&d.toLowerCase()!==c.toLowerCase()?v&&(f.nodeName(a,"form")||u.test(c))&&(i=v):i=w);if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j)return i.get(a,c);h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);c=i&&f.propFix[c]||c,h=f.propHooks[c];return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return a[f.propFix[c]||c]?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=b),a.setAttribute(c,c.toLowerCase()));return c}},f.attrHooks.value={get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return a.value},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=Object.prototype.hasOwnProperty,y=/\.(.*)$/,z=/^(?:textarea|input|select)$/i,A=/\./g,B=/ /g,C=/[^\w\s.|`]/g,D=function(a){return a.replace(C,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=E;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=E);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),D).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem +)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},K=function(c){var d=c.target,e,g;if(!!z.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=J(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:K,beforedeactivate:K,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&K.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&K.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",J(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in I)f.event.add(this,c+".specialChange",I[c]);return z.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return z.test(this.nodeName)}},I=f.event.special.change.filters,I.focus=I.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=U.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(W(c[0])||W(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=T.call(arguments);P.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!V[a]?f.unique(e):e,(this.length>1||R.test(d))&&Q.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y=/ jQuery\d+="(?:\d+|null)"/g,Z=/^\s+/,$=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,_=/<([\w:]+)/,ba=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument|| +b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/)<[^<]*)*<\/script>/gi,bP=/^(?:select|textarea)/i,bQ=/\s+/,bR=/([?&])_=[^&]*/,bS=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bT=f.fn.load,bU={},bV={},bW,bX;try{bW=e.href}catch(bY){bW=c.createElement("a"),bW.href="",bW=bW.href}bX=bS.exec(bW.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bT)return bT.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bO,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bP.test(this.nodeName)||bJ.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bG,"\r\n")}}):{name:b.name,value:c.replace(bG,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bW,isLocal:bK.test(bX[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bZ(bU),ajaxTransport:bZ(bV),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?ca(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=cb(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bI.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bH,"").replace(bM,bX[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bQ),d.crossDomain==null&&(r=bS.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bX[1]&&r[2]==bX[2]&&(r[3]||(r[1]==="http:"?80:443))==(bX[3]||(bX[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bU,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bL.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bN.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bR,"$1_="+x);d.url=y+(y===d.url?(bN.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bV,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bE,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq,cr=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){return this[0]?parseFloat(f.css(this[0],d,"padding")):null},f.fn["outer"+c]=function(a){return this[0]?parseFloat(f.css(this[0],d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); diff --git a/SparkleShare/Common/HTML/protocol-handler-test/add-to-sparkleshare-button.png b/SparkleShare/Common/HTML/protocol-handler-test/add-to-sparkleshare-button.png new file mode 100644 index 0000000..be46a09 Binary files /dev/null and b/SparkleShare/Common/HTML/protocol-handler-test/add-to-sparkleshare-button.png differ diff --git a/SparkleShare/Common/HTML/protocol-handler-test/invite.xml b/SparkleShare/Common/HTML/protocol-handler-test/invite.xml new file mode 100644 index 0000000..5c4f9d1 --- /dev/null +++ b/SparkleShare/Common/HTML/protocol-handler-test/invite.xml @@ -0,0 +1,9 @@ + + + +
ssh://git@github.com/
+ /hbons/Stuff + http://www.sparkleshare.org/test.php +
+
+ diff --git a/SparkleShare/Common/HTML/protocol-handler-test/protocol-handler-test.htm b/SparkleShare/Common/HTML/protocol-handler-test/protocol-handler-test.htm new file mode 100644 index 0000000..da10310 --- /dev/null +++ b/SparkleShare/Common/HTML/protocol-handler-test/protocol-handler-test.htm @@ -0,0 +1,38 @@ + + + SparkleShare Protocol Handler Test + + + +
+ hbons's stuff on Github + + Add to SparkleShare + +
+ + + diff --git a/SparkleShare/Common/Makefile.am b/SparkleShare/Common/Makefile.am new file mode 100644 index 0000000..2f972e5 --- /dev/null +++ b/SparkleShare/Common/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = HTML \ + Plugins \ + Pixmaps diff --git a/SparkleShare/Common/Pixmaps/Makefile.am b/SparkleShare/Common/Pixmaps/Makefile.am new file mode 100644 index 0000000..825b196 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Makefile.am @@ -0,0 +1,12 @@ +dist_pixmaps_DATA = \ + side-splash.png \ + user-icon-default.png \ + text-balloon.png \ + tutorial-slide-1.png\ + tutorial-slide-2.png \ + about.png + +pixmapsdir = $(pkgdatadir)/pixmaps/ + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/SparkleShare/Common/Pixmaps/Sources/about-dialog.svg b/SparkleShare/Common/Pixmaps/Sources/about-dialog.svg new file mode 100644 index 0000000..c07d454 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/about-dialog.svg @@ -0,0 +1,3494 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/actions.svg b/SparkleShare/Common/Pixmaps/Sources/actions.svg new file mode 100644 index 0000000..c3d028d --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/actions.svg @@ -0,0 +1,220 @@ + + + + Text Editor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Text Editor + + + text + editor + gedit + + + + + + + + + + + + + + + + + + + + + Lapo Calamandrei + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + actions + list-remove + + + + + + + apps + accessories-text-editor + + + + + + + + + + + + + + + + + actions + list-add + + + + + actions + edit-redo + + + + + + + + + + + + + + + + + + + + actions + list-remove + + + + + + + + + + actions + list-add + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/app-icons.svg b/SparkleShare/Common/Pixmaps/Sources/app-icons.svg new file mode 100644 index 0000000..275580d --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/app-icons.svg @@ -0,0 +1,2009 @@ + + + + + + + + + + + image/svg+xml + + + + Hylke Bons, Lapo Calamandrei + + + sparkleshare + + + folder + directory + share + dir + + + Derived from Jakub Steiner's design + + + + Hylke Bons, Lapo Calamandrei + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + places + sparkleshare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/bitbucket.svg b/SparkleShare/Common/Pixmaps/Sources/bitbucket.svg new file mode 100644 index 0000000..5f3a754 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/bitbucket.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/folder-icons-mac-yosemite.svg b/SparkleShare/Common/Pixmaps/Sources/folder-icons-mac-yosemite.svg new file mode 100644 index 0000000..5b5bfb6 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/folder-icons-mac-yosemite.svg @@ -0,0 +1,1500 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/folder-icons-mac.svg b/SparkleShare/Common/Pixmaps/Sources/folder-icons-mac.svg new file mode 100644 index 0000000..5ae65da --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/folder-icons-mac.svg @@ -0,0 +1,144 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + places + sparkleshare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/folder-icons-windows.svg b/SparkleShare/Common/Pixmaps/Sources/folder-icons-windows.svg new file mode 100644 index 0000000..14e3173 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/folder-icons-windows.svg @@ -0,0 +1,1160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/github.svg b/SparkleShare/Common/Pixmaps/Sources/github.svg new file mode 100644 index 0000000..ccc55a4 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/github.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/gitorious.svg b/SparkleShare/Common/Pixmaps/Sources/gitorious.svg new file mode 100644 index 0000000..e1c011d --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/gitorious.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/side-splash.svg b/SparkleShare/Common/Pixmaps/Sources/side-splash.svg new file mode 100644 index 0000000..2602f5b --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/side-splash.svg @@ -0,0 +1,3752 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/ssnet.svg b/SparkleShare/Common/Pixmaps/Sources/ssnet.svg new file mode 100644 index 0000000..6971d98 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/ssnet.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + places + sparkleshare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/status-icons.svg b/SparkleShare/Common/Pixmaps/Sources/status-icons.svg new file mode 100644 index 0000000..207cd11 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/status-icons.svg @@ -0,0 +1,3057 @@ + + + + + + + + + + + image/svg+xml + + + + Hylke Bons, Lapo Calamandrei + + + + + + folder + directory + share + dir + + + Derived from Jakub Steiner's design + + + + Hylke Bons, Lapo Calamandrei + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + places + sparkleshare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ubuntu Mac Windows + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Status icons GNOME and legacy panels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GNOME 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/tutorial-slides.svg b/SparkleShare/Common/Pixmaps/Sources/tutorial-slides.svg new file mode 100644 index 0000000..faec290 --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/tutorial-slides.svg @@ -0,0 +1,5904 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/Sources/user-icon-default.svg b/SparkleShare/Common/Pixmaps/Sources/user-icon-default.svg new file mode 100644 index 0000000..872a50e --- /dev/null +++ b/SparkleShare/Common/Pixmaps/Sources/user-icon-default.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Pixmaps/about.png b/SparkleShare/Common/Pixmaps/about.png new file mode 100755 index 0000000..c0d0c59 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/about.png differ diff --git a/SparkleShare/Common/Pixmaps/about@2x.png b/SparkleShare/Common/Pixmaps/about@2x.png new file mode 100644 index 0000000..fc92a09 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/about@2x.png differ diff --git a/SparkleShare/Common/Pixmaps/side-splash.png b/SparkleShare/Common/Pixmaps/side-splash.png new file mode 100755 index 0000000..ca7f68f Binary files /dev/null and b/SparkleShare/Common/Pixmaps/side-splash.png differ diff --git a/SparkleShare/Common/Pixmaps/side-splash@2x.png b/SparkleShare/Common/Pixmaps/side-splash@2x.png new file mode 100644 index 0000000..f5fa864 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/side-splash@2x.png differ diff --git a/SparkleShare/Common/Pixmaps/text-balloon.png b/SparkleShare/Common/Pixmaps/text-balloon.png new file mode 100644 index 0000000..b95e7e6 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/text-balloon.png differ diff --git a/SparkleShare/Common/Pixmaps/text-balloon@2x.png b/SparkleShare/Common/Pixmaps/text-balloon@2x.png new file mode 100644 index 0000000..6b86ad4 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/text-balloon@2x.png differ diff --git a/SparkleShare/Common/Pixmaps/tutorial-slide-1.png b/SparkleShare/Common/Pixmaps/tutorial-slide-1.png new file mode 100644 index 0000000..bb6268e Binary files /dev/null and b/SparkleShare/Common/Pixmaps/tutorial-slide-1.png differ diff --git a/SparkleShare/Common/Pixmaps/tutorial-slide-1@2x.png b/SparkleShare/Common/Pixmaps/tutorial-slide-1@2x.png new file mode 100644 index 0000000..fbf4ac3 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/tutorial-slide-1@2x.png differ diff --git a/SparkleShare/Common/Pixmaps/tutorial-slide-2.png b/SparkleShare/Common/Pixmaps/tutorial-slide-2.png new file mode 100644 index 0000000..15624a4 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/tutorial-slide-2.png differ diff --git a/SparkleShare/Common/Pixmaps/tutorial-slide-2@2x.png b/SparkleShare/Common/Pixmaps/tutorial-slide-2@2x.png new file mode 100644 index 0000000..2c99291 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/tutorial-slide-2@2x.png differ diff --git a/SparkleShare/Common/Pixmaps/user-icon-default.png b/SparkleShare/Common/Pixmaps/user-icon-default.png new file mode 100644 index 0000000..b962747 Binary files /dev/null and b/SparkleShare/Common/Pixmaps/user-icon-default.png differ diff --git a/SparkleShare/Common/Plugins/Makefile.am b/SparkleShare/Common/Plugins/Makefile.am new file mode 100644 index 0000000..dc0a049 --- /dev/null +++ b/SparkleShare/Common/Plugins/Makefile.am @@ -0,0 +1,18 @@ +dist_plugins_DATA = \ + bitbucket.xml \ + github.xml \ + gitorious.xml \ + ssnet.xml \ + own-server.xml \ + planio.xml \ + github.png \ + gitorious.png \ + bitbucket.png \ + ssnet.png \ + planio.png \ + own-server.png + +pluginsdir = $(pkgdatadir)/plugins/ + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/SparkleShare/Common/Plugins/bitbucket.png b/SparkleShare/Common/Plugins/bitbucket.png new file mode 100644 index 0000000..c2de052 Binary files /dev/null and b/SparkleShare/Common/Plugins/bitbucket.png differ diff --git a/SparkleShare/Common/Plugins/bitbucket.xml b/SparkleShare/Common/Plugins/bitbucket.xml new file mode 100644 index 0000000..1737448 --- /dev/null +++ b/SparkleShare/Common/Plugins/bitbucket.xml @@ -0,0 +1,21 @@ + + + + + Bitbucket + Free code hosting for Git and Mercurial + bitbucket.png + Git + 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40 + +
+ ssh://git@bitbucket.org/ + +
+ + + /username/project + True + +
+
diff --git a/SparkleShare/Common/Plugins/bitbucket@2x.png b/SparkleShare/Common/Plugins/bitbucket@2x.png new file mode 100644 index 0000000..01ecba8 Binary files /dev/null and b/SparkleShare/Common/Plugins/bitbucket@2x.png differ diff --git a/SparkleShare/Common/Plugins/github.png b/SparkleShare/Common/Plugins/github.png new file mode 100644 index 0000000..62bb35b Binary files /dev/null and b/SparkleShare/Common/Plugins/github.png differ diff --git a/SparkleShare/Common/Plugins/github.xml b/SparkleShare/Common/Plugins/github.xml new file mode 100644 index 0000000..bf24fd0 --- /dev/null +++ b/SparkleShare/Common/Plugins/github.xml @@ -0,0 +1,20 @@ + + + + + GitHub + Collaborate on projects hosted on GitHub + github.png + Git + 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48 + +
+ ssh://git@github.com/ + +
+ + + /username/project + +
+
diff --git a/SparkleShare/Common/Plugins/github@2x.png b/SparkleShare/Common/Plugins/github@2x.png new file mode 100644 index 0000000..fd32047 Binary files /dev/null and b/SparkleShare/Common/Plugins/github@2x.png differ diff --git a/SparkleShare/Common/Plugins/gitorious.png b/SparkleShare/Common/Plugins/gitorious.png new file mode 100644 index 0000000..731835b Binary files /dev/null and b/SparkleShare/Common/Plugins/gitorious.png differ diff --git a/SparkleShare/Common/Plugins/gitorious.xml b/SparkleShare/Common/Plugins/gitorious.xml new file mode 100644 index 0000000..d0cee9e --- /dev/null +++ b/SparkleShare/Common/Plugins/gitorious.xml @@ -0,0 +1,20 @@ + + + + + Gitorious + Open source infrastructure for hosting open source projects + gitorious.png + Git + 7e:af:8d:ec:f0:39:5e:ba:52:16:ce:19:fa:d4:b8:7d + +
+ ssh://git@gitorious.org/ + +
+ + + /project/repository + +
+
diff --git a/SparkleShare/Common/Plugins/gitorious@2x.png b/SparkleShare/Common/Plugins/gitorious@2x.png new file mode 100644 index 0000000..806f113 Binary files /dev/null and b/SparkleShare/Common/Plugins/gitorious@2x.png differ diff --git a/SparkleShare/Common/Plugins/own-server.png b/SparkleShare/Common/Plugins/own-server.png new file mode 100644 index 0000000..c5d0a08 Binary files /dev/null and b/SparkleShare/Common/Plugins/own-server.png differ diff --git a/SparkleShare/Common/Plugins/own-server.xml b/SparkleShare/Common/Plugins/own-server.xml new file mode 100644 index 0000000..eb9b401 --- /dev/null +++ b/SparkleShare/Common/Plugins/own-server.xml @@ -0,0 +1,19 @@ + + + + + On my own server + Everything under my control + own-server.png + Git + +
+ + ssh://[user@]hostname[:port] +
+ + + /path/to/project + +
+
diff --git a/SparkleShare/Common/Plugins/own-server@2x.png b/SparkleShare/Common/Plugins/own-server@2x.png new file mode 100644 index 0000000..4312338 Binary files /dev/null and b/SparkleShare/Common/Plugins/own-server@2x.png differ diff --git a/SparkleShare/Common/Plugins/parse_plugins.xsl b/SparkleShare/Common/Plugins/parse_plugins.xsl new file mode 100644 index 0000000..bded3cc --- /dev/null +++ b/SparkleShare/Common/Plugins/parse_plugins.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Common/Plugins/planio.png b/SparkleShare/Common/Plugins/planio.png new file mode 100644 index 0000000..d11e070 Binary files /dev/null and b/SparkleShare/Common/Plugins/planio.png differ diff --git a/SparkleShare/Common/Plugins/planio.xml b/SparkleShare/Common/Plugins/planio.xml new file mode 100644 index 0000000..1e91c90 --- /dev/null +++ b/SparkleShare/Common/Plugins/planio.xml @@ -0,0 +1,21 @@ + + + + + Planio + 500MB of unlimited free hosted Git repos and project management + planio.png + Git + 77:d1:54:d7:33:7e:38:43:40:70:ca:2d:3a:24:05:22 + tcp://sparkleshare-notifications.plan.io:443 + +
+ + ssh://git@[account].plan.io +
+ + + /[account]-[project].git + +
+
diff --git a/SparkleShare/Common/Plugins/planio@2x.png b/SparkleShare/Common/Plugins/planio@2x.png new file mode 100644 index 0000000..97ec2a3 Binary files /dev/null and b/SparkleShare/Common/Plugins/planio@2x.png differ diff --git a/SparkleShare/Common/Plugins/ssnet.png b/SparkleShare/Common/Plugins/ssnet.png new file mode 100644 index 0000000..8aac460 Binary files /dev/null and b/SparkleShare/Common/Plugins/ssnet.png differ diff --git a/SparkleShare/Common/Plugins/ssnet.xml b/SparkleShare/Common/Plugins/ssnet.xml new file mode 100644 index 0000000..718e6f3 --- /dev/null +++ b/SparkleShare/Common/Plugins/ssnet.xml @@ -0,0 +1,19 @@ + + + + + SparkleShare.Net + The easiest way to share projects with SparkleShare + ssnet.png + Git + +
+ ssh://storage@sparkleshare.net/ + +
+ + + /username/project + +
+
diff --git a/SparkleShare/Common/Plugins/ssnet@2x.png b/SparkleShare/Common/Plugins/ssnet@2x.png new file mode 100644 index 0000000..3449b9e Binary files /dev/null and b/SparkleShare/Common/Plugins/ssnet@2x.png differ diff --git a/SparkleShare/Common/Translations/LINGUAS b/SparkleShare/Common/Translations/LINGUAS new file mode 100755 index 0000000..008172a --- /dev/null +++ b/SparkleShare/Common/Translations/LINGUAS @@ -0,0 +1,29 @@ +ar +bg +ca +cs_CZ +da +de +el +eo +es +fi +fr +he +hu +it +ja +nl +no_NO +nn_NO +pl +pt_BR +ru +sk +sl +sr_RS +sv +te +uk +zh_CN +zh_TW diff --git a/SparkleShare/Common/Translations/Makefile.in.in b/SparkleShare/Common/Translations/Makefile.in.in new file mode 100644 index 0000000..06a8cfe --- /dev/null +++ b/SparkleShare/Common/Translations/Makefile.in.in @@ -0,0 +1,222 @@ +# Makefile for program source directory in GNU NLS utilities package. +# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper +# Copyright (C) 2004-2008 Rodney Dawes +# +# This file may be copied and used freely without restrictions. It may +# be used in projects which are not available under a GNU Public License, +# but which still want to provide support for the GNU gettext functionality. +# +# - Modified by Owen Taylor to use GETTEXT_PACKAGE +# instead of PACKAGE and to look for po2tbl in ./ not in intl/ +# +# - Modified by jacob berkman to install +# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize +# +# - Modified by Rodney Dawes for use with intltool +# +# We have the following line for use by intltoolize: +# INTLTOOL_MAKEFILE + +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = @datadir@ +datarootdir = @datarootdir@ +libdir = @libdir@ +DATADIRNAME = @DATADIRNAME@ +itlocaledir = $(prefix)/$(DATADIRNAME)/locale +subdir = po +install_sh = @install_sh@ +# Automake >= 1.8 provides @mkdir_p@. +# Until it can be supposed, use the safe fallback: +mkdir_p = $(install_sh) -d + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +GMSGFMT = @GMSGFMT@ +MSGFMT = @MSGFMT@ +XGETTEXT = @XGETTEXT@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist +GENPOT = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot + +ALL_LINGUAS = @ALL_LINGUAS@ + +PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) + +USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) + +USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) + +POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) + +DISTFILES = Makefile.in.in POTFILES.in $(POFILES) +EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS + +POTFILES = \ +# This comment gets stripped out + +CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) + +.SUFFIXES: +.SUFFIXES: .po .pox .gmo .mo .msg .cat + +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V)) +INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY)) +INTLTOOL__v_MSGFMT_0 = @echo " MSGFMT" $@; + +.po.pox: + $(MAKE) $(GETTEXT_PACKAGE).pot + $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox + +.po.mo: + $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< + +.po.gmo: + $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \ + && rm -f $$file && $(GMSGFMT) -o $$file $< + +.po.cat: + sed -f ../intl/po2msg.sed < $< > $*.msg \ + && rm -f $@ && gencat $@ $*.msg + + +all: all-@USE_NLS@ + +all-yes: $(CATALOGS) +all-no: + +$(GETTEXT_PACKAGE).pot: $(POTFILES) + $(GENPOT) + +install: install-data +install-data: install-data-@USE_NLS@ +install-data-no: all +install-data-yes: all + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $$dir; \ + if test -r $$lang.gmo; then \ + $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ + else \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $(srcdir)/$$lang.gmo as" \ + "$$dir/$(GETTEXT_PACKAGE).mo"; \ + fi; \ + if test -r $$lang.gmo.m; then \ + $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + if test -r $(srcdir)/$$lang.gmo.m ; then \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ + $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $(srcdir)/$$lang.gmo.m as" \ + "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + true; \ + fi; \ + fi; \ + done + +# Empty stubs to satisfy archaic automake needs +dvi info ctags tags CTAGS TAGS ID: + +# Define this as empty until I found a useful application. +install-exec installcheck: + +uninstall: + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ + rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ + done + +check: all $(GETTEXT_PACKAGE).pot + rm -f missing notexist + srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m + if [ -r missing -o -r notexist ]; then \ + exit 1; \ + fi + +mostlyclean: + rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp + rm -f .intltool-merge-cache + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES stamp-it + rm -f *.mo *.msg *.cat *.cat.m *.gmo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f Makefile.in.in + +distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: $(DISTFILES) + dists="$(DISTFILES)"; \ + extra_dists="$(EXTRA_DISTFILES)"; \ + for file in $$extra_dists; do \ + test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ + done; \ + for file in $$dists; do \ + test -f $$file || file="$(srcdir)/$$file"; \ + ln $$file $(distdir) 2> /dev/null \ + || cp -p $$file $(distdir); \ + done + +update-po: Makefile + $(MAKE) $(GETTEXT_PACKAGE).pot + tmpdir=`pwd`; \ + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + echo "$$lang:"; \ + result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ + if $$result; then \ + if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.gmo failed!"; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi; \ + done + +Makefile POTFILES: stamp-it + @if test ! -f $@; then \ + rm -f stamp-it; \ + $(MAKE) stamp-it; \ + fi + +stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ + $(SHELL) ./config.status + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/SparkleShare/Common/Translations/POTFILES.in b/SparkleShare/Common/Translations/POTFILES.in new file mode 100755 index 0000000..39e92b6 --- /dev/null +++ b/SparkleShare/Common/Translations/POTFILES.in @@ -0,0 +1,24 @@ +# List of source files containing translatable strings. +# Please keep this file in alphabetical order; run ./sort-potfiles +# after adding files here. +[encoding: UTF-8] +data/plugins/bitbucket.xml.in +data/plugins/github.xml.in +data/plugins/gitorious.xml.in +data/plugins/gnome.xml.in +data/plugins/own-server.xml.in +data/plugins/ssnet.xml.in +SparkleShare/Linux/Nautilus/sparkleshare-nautilus-extension.py.in +SparkleShare/Linux/Nautilus/sparkleshare-nautilus3-extension.py.in +SparkleShare/Linux/Nautilus/sparkleshare-nautilus-extension.py +SparkleShare/Linux/Nautilus/sparkleshare-nautilus3-extension.py +SparkleShare/Program.cs +SparkleShare/Linux/SparkleAbout.cs +SparkleShare/Linux/SparkleController.cs +SparkleShare/SparkleControllerBase.cs +SparkleShare/Linux/SparkleEventLog.cs +SparkleShare/Linux/SparkleSetup.cs +SparkleShare/Linux/SparkleSetupWindow.cs +SparkleShare/Linux/SparkleStatusIcon.cs +SparkleShare/Linux/SparkleUI.cs + diff --git a/SparkleShare/Common/Translations/POTFILES.skip b/SparkleShare/Common/Translations/POTFILES.skip new file mode 100755 index 0000000..0125bc0 --- /dev/null +++ b/SparkleShare/Common/Translations/POTFILES.skip @@ -0,0 +1,3 @@ +MacCore/src/Options.cs +SparkleShare/Linux/Nautilus/sparkleshare-nautilus-extension.py +SparkleShare/Linux/Nautilus/sparkleshare-nautilus3-extension.py diff --git a/SparkleShare/Common/Translations/README.transifex b/SparkleShare/Common/Translations/README.transifex new file mode 100755 index 0000000..3f38a1c --- /dev/null +++ b/SparkleShare/Common/Translations/README.transifex @@ -0,0 +1,11 @@ +Transifex.net Token Verification +================================= + +The list of tokens bellow guarantee the respective users to be able to enable +submission on components using the following repository url: + +git@gitorious.org:sparkleshare/sparkleshare.git + +Tokens: + +AkNvJ9GmsC73D3hUQGH3yYZsBNRaF5hj / hbons diff --git a/SparkleShare/Common/Translations/ar.po b/SparkleShare/Common/Translations/ar.po new file mode 100755 index 0000000..b4d3c9a --- /dev/null +++ b/SparkleShare/Common/Translations/ar.po @@ -0,0 +1,414 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Majid Al-Dharrab , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ar\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "مشروع جنوم." + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "مرحبًا بك في سباركل‌شير!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "محدَّث" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "يزامن..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "ليس كل شيء مزامَنًا" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "انسخ رابط الملف" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "انسخ عنوان الوِب الخاص بهذا الملف إلى الحافظة" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "احصل على إصدارة سابقة" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "اصنع نسخة من إصدارة سابقة من هذا المجلد" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "اختر لتحصل على نسخة من هذه الإصدارة" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "اطبع معلومات الإصدارة" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "أظهر نص المساعدة هذا" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "سباركل‌شير، أداة تعاون ومشاركة." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "لا يشمل هذا البرنامج أي ضمان" + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "هذا برنامج حر، ونحن نرحب بتوزيعه " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"ضمن شروط معينة. يرجى قراءة رخصة جنو العمومية - الإصدارة الثالثة للاطلاع على " +"التفاصيل." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "يزامن سباركل‌شير مستودعات جِت الموجودة في " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "مجلد ~/SparkleShare مع أصولها البعيدة آليًا." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "طريقة الاستخدام: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "زامن مجلد سباركل‌شير مع مستودعات بعيدة." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "المعطيات:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "سباركل‌شير " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "حوْل سباركل‌شير" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "أنت تستخدم الإصدارة الأحدث." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "يبحث عن تحديثات..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "الأحداث الأخيرة" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "كل المجلدات" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"نحتاج بعض المعلومات منك قبل أن نتمكن من إنشاء مجلد سباركل‌شير في هذا " +"الحاسوب." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "الاسم كاملًا:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "البريد الإلكتروني:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "التالي" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "ألغِ" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "أمتأكد أنه ليس وقت احتساء القهوة؟" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "أنهِ" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "نجحت إضافة ‘{0}’" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "افتح المجلد" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "إعداد سباركل‌شير" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "عطِّل التنبيهات" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "فعِّل التنبيهات" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "اخرج" + + diff --git a/SparkleShare/Common/Translations/bg.po b/SparkleShare/Common/Translations/bg.po new file mode 100755 index 0000000..0f46559 --- /dev/null +++ b/SparkleShare/Common/Translations/bg.po @@ -0,0 +1,411 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Łukasz Jernaś , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: bg\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Проектът GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Здравейте в SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Обновено" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Синхронизиране…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Синхронизирането не е приключило" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Копиране на адреса" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Копиране в буфера на адреса на връзката към този файл" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Предишна версия" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Копие в тази папка на по-ранна версия" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Изберете за копие на версията" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Извеждане на информация за версията" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Показване на този помощен текст" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Авторски права: © 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Тази програма идва БЕЗ НИКАКВИ ГАРАНЦИИ." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "" +"Това е свободен софтуер, можете да го разпространявате при определени " +"условия." + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "За повече информация вижте Общия публичен лиценз на GNU, версия 3." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare автоматично синхронизира хранилища на Git" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "в папката ~/SparkleShare с отдалечените им източници." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Употреба: sparkleshare [start|stop|restart] [ОПЦИЯ]…" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "" +"Синхронизиране на папката ви за SparkleShare с отдалечените източници." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Аргументи:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Относно SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Трябва да попълните някои данни за себе си, преди да се създаде папка на " +"компютъра, ползваща SparkleShare." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Лично име:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Е-поща:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Нататък" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Отказване" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Не е ли време за кафенце?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Завършване" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Отваряне на папката" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Изключване на уведомяванията" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Включване на уведомленията" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Спиране на програмата" + + diff --git a/SparkleShare/Common/Translations/ca.po b/SparkleShare/Common/Translations/ca.po new file mode 100755 index 0000000..92690c5 --- /dev/null +++ b/SparkleShare/Common/Translations/ca.po @@ -0,0 +1,413 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +# alexandresaiz , 2011. +# , 2011. +# Carles Mateu , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ca\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "El projecte GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Benvinguts a SparkleShare" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Al dia" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Sincronitzant ..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "No està tot sincronitzat" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Copiar adreça web" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Copia l'adreça web d'aquest fitxer al portapapers" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Obtenir versió anterior" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Fer una còpia d'una versió anterior d'aquesta carpeta" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Selecciona per obtenir una còpia d'aquesta versió" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Imprimir la informació de versió" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Mostra aquest text d'ajuda" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "una eina d'intercanvi i col·laboració" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Aquest programa ve sense, absolutament, cap garantia." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Aquest és programari lliure, i estas convidat a redistribuir-lo" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"sota certes condicions. Si us plau, llegeix la GNU GPLv3 per obtenir més " +"detalls." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare sincronitza automàticament repositoris Git a" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "carpeta ~ / SparkleShare amb els seus orígens remots." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Ús: sparkleshare [start|stop|restart] [OPCIÓ] ..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Sincronitza carpeta SparkleShare amb repositoris remots." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Arguments:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Sobre SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Hi ha una nova versió ({0}) disponible!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Estas utilitzant la darrera versió" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Comprovant actualitzacions..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Accions recents" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Totes les carpetes" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Abans de crear una carpeta de SparkleShare en aquest ordinador, necessitem " +"algunes informacions sobre tu" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Nom sencer:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Correu electrònic:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Següent" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Cancel·la" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Això pot trigar una estona." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Segur que no és l'hora del cafè?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Finalitzar" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Quelcom ha fallat." + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "‘{0}’ ha estat afegit satisfactoriament" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Obrir Carpeta" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Instal·lació SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Desactiva les Notificacions" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Activa les Notificacions" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Sortir" + + diff --git a/SparkleShare/Common/Translations/cs_CZ.po b/SparkleShare/Common/Translations/cs_CZ.po new file mode 100755 index 0000000..c4147df --- /dev/null +++ b/SparkleShare/Common/Translations/cs_CZ.po @@ -0,0 +1,413 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Jiri Slezka , 2011. +# , 2011. +# zzanzare , 2011. +# Martin Vancl , 2013. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs_CZ\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Projekt GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Vše pod vlastní kontrolou" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Vlastní server" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Vítejte ve SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Aktuální" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synchronizuji…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Něco není synchronizováno" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopírovat webový odkaz" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Zkopírovat webovou adresu tohoto souboru do schránky" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Získat dřívější verzi" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Vytvořit kopii dřívější verze souboru v tomto adresáři" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Vyberte pro získání kopie této verze" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Vypíše informace o verzi" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Zobrazit tuto nápovědu" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, nástroj pro sdílení a spolupráci." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Všechna práva vyhrazena (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Tento program je ABSOLUTNĚ BEZ ZÁRUKY." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Toto je svobodný software a můžete jej dále šířit." + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"za jistých podmínek. Prosím, přečtěte si GNU GPLv3 pro více informací." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare automaticky synchronizuje repozitáře Git v " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "složce ~/SparkleShare s jejich vzdálenými protistranami." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Použití: sparkleshare [start|stop|restart] [VOLBY]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Synchronizovat složku SparkleShare se vzdálenými repozitáři." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Argumenty:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "O SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Je dostupná nová verze ({0})!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Používáte aktuální verzi." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Kontroluji aktualizace..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Nedávné události" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Všechny složky" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Než vytvoříme SparkeShare složku v tomto počítači, potřebujeme od Vás pár " +"drobných informací." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Celé jméno:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Další" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Kde je projekt hostován?" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Adresa" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "Vzdálená cesta" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Zrušit" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Přidávám projekt ‘{0}’…" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Jste si jistí, že není čas na kafe?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Dokončit" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Něco je špatně" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Zkusit znovu…" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' byl úspěšně přidán" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Projekt byl úspěšne přidán!" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Zobrazit soubory ve SparkleShare složce." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Otevřít složku" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Přeskočit tutoriál" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Pokračovat" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Sdílet soubory s ostatními" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "Stavová ikona je tady, aby vám pomohla" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Přidávám projekt do SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "Přidat hostovaný projekt…" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Nastavení SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Nemáte žádné projekty" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "Otevřít nedávné události" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Vypnout upozornění" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Zapnout upozornění" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Ukončit" + + diff --git a/SparkleShare/Common/Translations/da.po b/SparkleShare/Common/Translations/da.po new file mode 100755 index 0000000..a85995e --- /dev/null +++ b/SparkleShare/Common/Translations/da.po @@ -0,0 +1,408 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Aputsiaq Janussen , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: da\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GNOME-projektet" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Velkommen til SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Opdateret" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synkroniseret" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Ikke alt er synkroniseret" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopiér web-henvisning" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopiér web-adressen for denne til fil udklipsholder" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Hent tidligere versioner" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Lav en kopi af en tidligere version i denne mappe" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Vælg for at hente en kopi af denne version" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Vis versioninformation" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Vis denne hjælpetekst" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright(C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Dette program modtages UDEN NOGEN GARANTIER OVERHOVEDET." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Dette er fri software, og du er velkommen til at distribuere den " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "under visse betingelser. Læs venligst GNU GPL v3 for detaljer." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synkroniserer automatisk Git-depoter i " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "mappen ~/SparkleShare med deres fjerne kilder." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Anvendelse: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Synkroniser SparkleShare-mappe med fjerndepot" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Argumenter:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Før vi kan oprette en SparkleShare-mappe på denne maskine, så har vi brug " +"for nogle få informationer fra dig." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Fuldt navn:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "E-post:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Næste" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Afbryd" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Afslut" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Åbn mappe" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Afslut" + + diff --git a/SparkleShare/Common/Translations/de.po b/SparkleShare/Common/Translations/de.po new file mode 100755 index 0000000..b60fdfd --- /dev/null +++ b/SparkleShare/Common/Translations/de.po @@ -0,0 +1,436 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +# , 2011. +# Heffer , 2011. +# Jan-Christoph Borchardt , 2011. +# kabum , 2011. +# , 2011. +# kxnop , 2011. +# Łukasz Jernaś , 2011. +# , 2011. +# Sascha , 2011. +# , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-11-12 18:42+0100\n" +"PO-Revision-Date: 2011-11-16 09:20+0000\n" +"Last-Translator: iwsnipy \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/username/project" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Freies Code-Hosting für Git und Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Freie öffentliche Git Repositories mit Mitarbeiterverwaltung" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/Projekt/Ablage" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "Quelloffene Infrastruktur zum hosten von quelloffenen Projekten" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/Projekt" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Eine freie und einfache Schnittstelle für deinen Computer" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Das GNOME Projekt" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/Pfad/zum/Projekt" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Alles unter meiner Kontrolle" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Auf meinem eigenen Server" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:84 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:102 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Willkommen bei SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:86 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:104 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Aktualisiert" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:113 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synchronisiere..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:123 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Es ist nicht alles synchronisiert" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:140 +msgid "Copy Web Link" +msgstr "Web Link kopieren" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:141 +msgid "Copy the web address of this file to the clipboard" +msgstr "Die Internetadresse dieser Datei in die Zwischenablage kopieren" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:173 +msgid "Get Earlier Version" +msgstr "Frühere Version abrufen" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:174 +msgid "Make a copy of an earlier version in this folder" +msgstr "Erstelle eine Kopie einer früheren Version in diesem Verzeichnis" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:187 +msgid "Select to get a copy of this version" +msgstr "Selektieren, um eine Kopie dieser Version abzurufen" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Versionsinformationen anzeigen" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Diesen Hilfetext anzeigen" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, ein Werkzeug für verteilte Zusammenarbeit." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Diese Anwendung kommt OHNE IRGENDEINE GARANTIE." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Dies ist freie Software, die Sie gerne weitergeben dürfen" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"unter bestimmten Bedingungen. Bitte lesen Sie die GNU GPLv3 für weitere " +"Details." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synchronisiert sich automatisch mit Git Repositories" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "den SparkleShare-Ordner mit den entfernten Quellen." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Verwendung: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "SparkleShare Ordner mit dem Remote-Repository synchronisieren." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Parameter:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Über SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Eine neuere Version ({0}) ist verfügbar!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Sie verwenden die aktuelle Version." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Suche Aktualisierungen..." + +#: ../SparkleShare/SparkleControllerBase.cs:494 +msgid "dddd, MMMM d, yyyy" +msgstr "dd mm, yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:500 +msgid "dddd, MMMM d" +msgstr "dd mm" + +#: ../SparkleShare/SparkleControllerBase.cs:708 +#, csharp-format +msgid "added ‘{0}’" +msgstr "Hinzugefügt '{0}'" + +#: ../SparkleShare/SparkleControllerBase.cs:713 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "'{0}' verschoben" + +#: ../SparkleShare/SparkleControllerBase.cs:718 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "Bearbeitet '{0}'" + +#: ../SparkleShare/SparkleControllerBase.cs:723 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "Gelöscht '{0}'" + +#: ../SparkleShare/SparkleControllerBase.cs:732 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "und {0} mehr" +msgstr[1] "und {0} mehr" + +#: ../SparkleShare/SparkleControllerBase.cs:736 +msgid "did something magical" +msgstr "hat etwas magisches" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Letzte Ereignisse" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Alle Ordner" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Bevor wir einen SparkleShare-Ordner auf diesem Computer einrichten können, " +"benötigen wir einige Informationen von Ihnen." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Vollständiger Name:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "E-Mail:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Weiter" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Wo ist dein Projekt gehostet?" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Adresse" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "Entfernter Pfad" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Abbrechen" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "Hinzufügen" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Füge Projekt '{0}' hinzu..." + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Das dauert vielleicht einen Moment." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Meinst Du nicht, dass es Kaffeezeit ist?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Fertigstellen" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Etwas ist schiefgelaufen" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Nochmal versuchen..." + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "»{0}« wurde erfolgreich hinzugefügt" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Projekt erfolgreich hinzugefügt!" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Zugriff auf die Dateien von Ihrem SparkleShare Ordner." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Ordner öffnen" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "Was passiert als nächstes?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"SparkleShare erzeugt einen eigenen Ordner in Ihrem persönlichen Ordner, der " +"den Überblick über Ihre Projekte behalten." + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Tutorial überspringen" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Weiter" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Dateien mit anderen teilen" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Alle zu Ihrem Projekt hinzugefügten Dateien sind automatisch mit dem Server " +"und Ihren Mitarbeitern synchronisiert." + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "Das Status Icon ist da um dir zu helfen" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Es zeigt den Synchronisierungsstatus und beinhaltet Links zu deinem Projekt " +"und deinen letzten Ereignissen." + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Füge Projekte zu SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Klicken den Button, wenn du ihn im Internet siehst, und das Projekt wird " +"automatisch hinzu gefügt:" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"... oder wähle 'Füge gehostetes Projekt hinzu...' im Statusmenü um " +"einen via Hand hinzu zu fügen." + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "Füge ein gehostetes Projekt hinzu..." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleShare Konfiguration" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Bislang keine Projekte " + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "Öffne letzte Ereignisse" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Benachrichtigungen deaktivieren" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Benachrichtigungen aktivieren" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Beenden" + + diff --git a/SparkleShare/Common/Translations/el.po b/SparkleShare/Common/Translations/el.po new file mode 100755 index 0000000..dde0ee2 --- /dev/null +++ b/SparkleShare/Common/Translations/el.po @@ -0,0 +1,389 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2012. +# , 2011. +# Nikos Roussos , 2012. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-01-17 19:31+0100\n" +"PO-Revision-Date: 2012-02-22 10:43+0000\n" +"Last-Translator: Nikos Roussos \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: el\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/username/project" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Δωρεάν φιλοξενία κώδικα για Git και Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Δωρεάν δημόσια Git αποθετήρια με διαχείριση συνεργατών" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/project/repository" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "Open source υποδομή για φιλοξενία open source projects" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/project" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Ένα ελεύθερο και απλό interface για τον υπολογιστή σου" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Το GNOME Project" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/path/to/project" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Όλα κάτω απ' τον δικό μου έλεγχο" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Στον δικό μου server" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:85 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:103 +#: ../SparkleShare/SparkleSetup.cs:66 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Καλώς ήλθατε στο SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:87 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:105 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Ενημερωμένα" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:114 +msgid "Syncing… " +msgstr "Συγχρονισμός... " + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:129 +#: ../SparkleShare/SparkleStatusIcon.cs:118 +msgid "Not everything is synced" +msgstr "Δεν είναι όλα συγχρονισμένα" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:141 +msgid "Copy Web Link" +msgstr "Αντιγραφή Συνδέσμου Ιστού" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:115 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:142 +msgid "Copy the web address of this file to the clipboard" +msgstr "Αντιγραφή της διεύθυνσης ιστού αυτού του αρχείου στο πρόχειρο" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:174 +msgid "Get Earlier Version" +msgstr "Λήψη Προηγούμενης Έκδοσης" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:149 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:175 +msgid "Make a copy of an earlier version in this folder" +msgstr "Δημιουργία αντιγράφου προηγούμενης έκδοσης αυτού του φακέλου" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:162 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:188 +msgid "Select to get a copy of this version" +msgstr "Επιλογή για την λήψη αντιγράφου αυτής της έκδοσης" + +#: ../SparkleShare/Program.cs:50 +msgid "Print version information" +msgstr "Εκτύπωση πληροφοριών έκδοσης" + +#: ../SparkleShare/Program.cs:51 +msgid "Show this help text" +msgstr "Εμφάνιση κειμένου βοήθειας" + +#: ../SparkleShare/Program.cs:83 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, ένα εργαλείο συνεργασίας και ανταλλαγής." + +#: ../SparkleShare/Program.cs:84 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:86 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Το πρόγραμμα αυτό δεν περιλαμβάνει ΑΠΟΛΥΤΩΣ ΚΑΜΙΑ ΕΓΓΥΗΣΗ" + +#: ../SparkleShare/Program.cs:88 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Αυτό είναι ένα δωρεάν πρόγραμμα, και είστε ευπρόσδεκτοι να το αναδιανείμετε " + +#: ../SparkleShare/Program.cs:89 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "υπό συγκεκριμένες προϋποθέσεις. Παρακαλώ διαβάστε το GNU GPLv3 για λεπτομέρειες." + +#: ../SparkleShare/Program.cs:91 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "Το SparkleShare συγχρονίζει αυτόματα αποθετήρια Git σε " + +#: ../SparkleShare/Program.cs:92 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "τον φάκελο ~/SparkleShare με τις απομακρυσμένες προελεύσεις τους." + +#: ../SparkleShare/Program.cs:94 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Χρήση: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:95 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Συγχρονισμός φακέλου SparkleShare με απομακρυσμένα αποθετήρια." + +#: ../SparkleShare/Program.cs:97 +msgid "Arguments:" +msgstr "Παράμετροι:" + +#: ../SparkleShare/Program.cs:107 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Σχετικά με το SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Είναι διαθέσιμη μια πιο πρόσφατη έκδοση ({0})!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Έχετε την τελευταία έκδοση." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:110 +msgid "Checking for updates..." +msgstr "Έλεγχος ενημερώσεων..." + +#: ../SparkleShare/SparkleControllerBase.cs:471 +#: ../SparkleShare/SparkleControllerBase.cs:479 +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d" +msgstr "dddd, MMMM d" + +#: ../SparkleShare/SparkleControllerBase.cs:472 +msgid "Today" +msgstr "Σήμερα" + +#: ../SparkleShare/SparkleControllerBase.cs:480 +msgid "Yesterday" +msgstr "Χτες" + +#: ../SparkleShare/SparkleControllerBase.cs:487 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd, MMMM d, yyyy" + +#: ../SparkleShare/SparkleEventLog.cs:57 +msgid "Recent Events" +msgstr "Πρόσφατα γεγονότα" + +#: ../SparkleShare/SparkleEventLog.cs:160 +msgid "All Projects" +msgstr "Όλα τα projects" + +#: ../SparkleShare/SparkleEventLog.cs:179 +msgid "All Folders" +msgstr "Όλοι οι Φάκελοι" + +#: ../SparkleShare/SparkleOptions.cs:486 +msgid "OptionName" +msgstr "OptionName" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "Full Name:" +msgstr "Πλήρες όνομα:" + +#: ../SparkleShare/SparkleSetup.cs:97 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:110 ../SparkleShare/SparkleSetup.cs:512 +#: ../SparkleShare/SparkleSetup.cs:532 ../SparkleShare/SparkleSetup.cs:550 +msgid "Continue" +msgstr "Συνέχεια" + +#: ../SparkleShare/SparkleSetup.cs:138 +msgid "Where's your project hosted?" +msgstr "Που φιλοξενείται το project σου;" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Διεύθυνση" + +#: ../SparkleShare/SparkleSetup.cs:296 +msgid "Remote Path" +msgstr "Απομακρυσμένο path" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:312 ../SparkleShare/SparkleSetup.cs:348 +msgid "Cancel" +msgstr "Ακύρωση" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:319 +msgid "Add" +msgstr "Προσθήκη" + +#: ../SparkleShare/SparkleSetup.cs:338 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Προσθήκη project ‘{0}’…" + +#: ../SparkleShare/SparkleSetup.cs:339 +msgid "This may take a while." +msgstr "Αυτό μπορεί να πάρει λίγο χρόνο." + +#: ../SparkleShare/SparkleSetup.cs:340 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Είστε σίγουροι ότι δεν είναι ώρα για καφέ;" + +#: ../SparkleShare/SparkleSetup.cs:344 ../SparkleShare/SparkleSetup.cs:460 +#: ../SparkleShare/SparkleSetup.cs:577 +msgid "Finish" +msgstr "Τέλος" + +#: ../SparkleShare/SparkleSetup.cs:377 +msgid "Something went wrong" +msgstr "Κάτι πήγε λάθος" + +#: ../SparkleShare/SparkleSetup.cs:425 +msgid "Try Again…" +msgstr "Προσπαθήστε ξανά..." + +#: ../SparkleShare/SparkleSetup.cs:444 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "‘{0}’ προστέθηκε με επιτυχία" + +#: ../SparkleShare/SparkleSetup.cs:450 +msgid "Project successfully added!" +msgstr "Το project προστέθηκε με επιτυχία!" + +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Access the files from your SparkleShare folder." +msgstr "Πρόσβαση στα αρχεία του SparkleShare φακέλου σας." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:454 +msgid "Open Folder" +msgstr "Άνοιγμα Φακέλου" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "What's happening next?" +msgstr "Τι γίνεται μετά;" + +#: ../SparkleShare/SparkleSetup.cs:504 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "Το SparkleShare δημιουργεί έναν ειδικό φάκελο στον προσωπικό σας φάκελο, στον οποίο παρακολουθεί τα project σας." + +#: ../SparkleShare/SparkleSetup.cs:507 +msgid "Skip Tutorial" +msgstr "Παράληψη Οδηγού" + +#: ../SparkleShare/SparkleSetup.cs:528 +msgid "Sharing files with others" +msgstr "Διαμοιρασμός αρχείων με άλλους" + +#: ../SparkleShare/SparkleSetup.cs:529 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "Όλα τα αρχεία που προστίθενται στους φακέλους των project σου συγχρονίζονται αυτόματα με τον host, όπως και με τους συνεργάτες σου." + +#: ../SparkleShare/SparkleSetup.cs:546 +msgid "The status icon is here to help" +msgstr "Το status icon είναι εδώ για να βοηθήσει" + +#: ../SparkleShare/SparkleSetup.cs:547 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "Απεικονίζει την κατάσταση συγχρονισμού, και περιέχει συνδέσμους για τα projects και το ημερολόγιο ενεργειών." + +#: ../SparkleShare/SparkleSetup.cs:564 +msgid "Adding projects to SparkleShare" +msgstr "Προσθήκη projects στο SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:565 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "Απλώς πάτα αυτό το κουμπί όταν το δεις στο web, και το project θα προστεθεί αυτόματα:" + +#: ../SparkleShare/SparkleSetup.cs:568 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "…ή επέλεξε ‘Προσθήκη Project…’ από το μενού του status icon για να προσθέσεις κάποιο χειροκίνητα." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Στήσιμο SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Συγχρονισμός..." + +#: ../SparkleShare/SparkleStatusIcon.cs:229 +msgid "No projects yet" +msgstr "Κανένα project ακόμα" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleStatusIcon.cs:239 +msgid "Add Hosted Project…" +msgstr "Προσθήκη Project..." + +#: ../SparkleShare/SparkleStatusIcon.cs:263 +msgid "Open Recent Events" +msgstr "Πρόσφατες ενέργειες" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Ενεργοποίηση ειδοποιήσεων" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Απενεργοποίηση ειδοποιήσεων" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Εγκατάλειψη" diff --git a/SparkleShare/Common/Translations/eo.po b/SparkleShare/Common/Translations/eo.po new file mode 100755 index 0000000..f0d5799 --- /dev/null +++ b/SparkleShare/Common/Translations/eo.po @@ -0,0 +1,407 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# eliovir , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: eo\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "La GNOME-projekto" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Bonvenon ĉe SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopii retejan ligilon" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopii la retejan adreson de tiu dosiero en la tondejon" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Akiri pli fruan version" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Elekti por akiri kopion de tiu versio" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Kopirajto (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "" + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "" + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Ĉiuj dosierujoj" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Nomo:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Retadreso:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Sekva" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Rezigni" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Malfermi dosierujon" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "" + + diff --git a/SparkleShare/Common/Translations/es.po b/SparkleShare/Common/Translations/es.po new file mode 100755 index 0000000..5640fdf --- /dev/null +++ b/SparkleShare/Common/Translations/es.po @@ -0,0 +1,394 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Claudio Rodrigo Pereyra Diaz , 2011. +# , 2011. +# jamelrom , 2011. +# , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-04 12:45+0100\n" +"PO-Revision-Date: 2011-12-09 14:13+0000\n" +"Last-Translator: miguxbe \n" +"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/sparkleshare/team/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/usuario/proyecto" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Alojamiento gratuito de código fuente para Git y Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Repositorios públicos y gratuitos de Git con gestión de colaboradores" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/proyecto/repositorio" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" +"Infraestructura de código libre para almacenar proyectos de código libre" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/proyecto" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Una interfaz libre y sencilla para tu ordenador" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "El Proyecto GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/ruta/al/proyecto" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Todo bajo mi control" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "En mi propio servidor" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:84 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:102 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "¡Bienvenido a SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:86 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:104 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Actualizado" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:113 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Sincronizando..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:125 +#: ../SparkleShare/SparkleStatusIcon.cs:118 +msgid "Not everything is synced" +msgstr "Pendiente de sincronizar" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:141 +msgid "Copy Web Link" +msgstr "Copiar Enlace" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:115 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:142 +msgid "Copy the web address of this file to the clipboard" +msgstr "Copiar la dirección web de este archivo al portapapeles" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:174 +msgid "Get Earlier Version" +msgstr "Obtener versión anterior" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:149 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:175 +msgid "Make a copy of an earlier version in this folder" +msgstr "Hacer una copia de una versión anterior en esta carpeta" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:162 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:188 +msgid "Select to get a copy of this version" +msgstr "Seleccionar para obtener una copia de esta versión" + +#: ../SparkleShare/Program.cs:50 +msgid "Print version information" +msgstr "Muestra la información de la versión" + +#: ../SparkleShare/Program.cs:51 +msgid "Show this help text" +msgstr "Mostrar este texto de ayuda" + +#: ../SparkleShare/Program.cs:83 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, una herramienta de compartición y colaboración" + +#: ../SparkleShare/Program.cs:84 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:86 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Este programa viene SIN NINGUNA GARANTÍA." + +#: ../SparkleShare/Program.cs:88 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Esto es software libre, y esta invitado a redistribuirlo" + +#: ../SparkleShare/Program.cs:89 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"bajo determinadas condiciones. Por favor lea la GNU GPLv3 para más detalles." + +#: ../SparkleShare/Program.cs:91 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare sincroniza automaticamente repositorios Git en " + +#: ../SparkleShare/Program.cs:92 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "La carpeta ~/SparkleShare con su origen remoto." + +#: ../SparkleShare/Program.cs:94 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Uso: sparkleshare [start|stop|restart] [OPCIÓN]..." + +#: ../SparkleShare/Program.cs:95 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Sincronizar carpeta SparkleShare con el repositorio remoto." + +#: ../SparkleShare/Program.cs:97 +msgid "Arguments:" +msgstr "Parámetros:" + +#: ../SparkleShare/Program.cs:107 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:297 +msgid "About SparkleShare" +msgstr "Acerca de SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Esta disponible una nueva versión ({0})" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Estas ejecutando la última versión" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:110 +msgid "Checking for updates..." +msgstr "Comprobando actualizaciones..." + +#: ../SparkleShare/SparkleControllerBase.cs:489 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd, MMMM d, yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:495 +msgid "dddd, MMMM d" +msgstr "dddd, MMMM d" + +#: ../SparkleShare/SparkleEventLog.cs:56 +msgid "Recent Events" +msgstr "Eventos recientes" + +#: ../SparkleShare/SparkleEventLog.cs:145 +#: ../SparkleShare/SparkleEventLog.cs:164 +msgid "All Folders" +msgstr "Todas las carpetas" + +#: ../SparkleShare/SparkleOptions.cs:486 +msgid "OptionName" +msgstr "OptionName" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Nombre completo:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Correo electrónico:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Siguiente" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "¿Dónde está almacenado su proyecto?" + +#: ../SparkleShare/SparkleSetup.cs:266 +msgid "Address" +msgstr "Dirección" + +#: ../SparkleShare/SparkleSetup.cs:286 +msgid "Remote Path" +msgstr "Ruta remota" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:300 ../SparkleShare/SparkleSetup.cs:336 +msgid "Cancel" +msgstr "Cancelar" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:307 +msgid "Add" +msgstr "Añadir" + +#: ../SparkleShare/SparkleSetup.cs:326 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Añadiendo proyecto '{0}'..." + +#: ../SparkleShare/SparkleSetup.cs:327 +msgid "This may take a while." +msgstr "Esto tardara un poco." + +#: ../SparkleShare/SparkleSetup.cs:328 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "¿Seguro que no es la hora del café?" + +#: ../SparkleShare/SparkleSetup.cs:332 ../SparkleShare/SparkleSetup.cs:448 +#: ../SparkleShare/SparkleSetup.cs:558 +msgid "Finish" +msgstr "Finalizar" + +#: ../SparkleShare/SparkleSetup.cs:365 +msgid "Something went wrong" +msgstr "Algo falló" + +#: ../SparkleShare/SparkleSetup.cs:413 +msgid "Try Again…" +msgstr "Intenta de nuevo..." + +#: ../SparkleShare/SparkleSetup.cs:432 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' Ha sido añadido correctamente" + +#: ../SparkleShare/SparkleSetup.cs:438 +msgid "Project successfully added!" +msgstr "Proyecto añadido con éxito!" + +#: ../SparkleShare/SparkleSetup.cs:439 +msgid "Access the files from your SparkleShare folder." +msgstr "Acceso a los archivos desde tu carpeta de SparkleShare." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:442 +msgid "Open Folder" +msgstr "Abrir carpeta" + +#: ../SparkleShare/SparkleSetup.cs:484 +msgid "What's happening next?" +msgstr "¿Qué está pasando ahora?" + +#: ../SparkleShare/SparkleSetup.cs:485 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"SparkleShare crea una carpeta especial en tu carpeta personal que mantendrá " +"un historial de tus proyectos." + +#: ../SparkleShare/SparkleSetup.cs:488 +msgid "Skip Tutorial" +msgstr "Saltar Tutorial" + +#: ../SparkleShare/SparkleSetup.cs:493 ../SparkleShare/SparkleSetup.cs:513 +#: ../SparkleShare/SparkleSetup.cs:531 +msgid "Continue" +msgstr "Continuar" + +#: ../SparkleShare/SparkleSetup.cs:509 +msgid "Sharing files with others" +msgstr "Compartiendo archivos con otros" + +#: ../SparkleShare/SparkleSetup.cs:510 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Todos los ficheros añadidos a tus carpetas de proyectos son sincronizadas " +"automáticamente con el equipo, asi como con tus colaboradores." + +#: ../SparkleShare/SparkleSetup.cs:527 +msgid "The status icon is here to help" +msgstr "El icono de estado esta aquí para ayudarte" + +#: ../SparkleShare/SparkleSetup.cs:528 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Muestra el proceso de sincronización, y contiene enlaces a tus proyectos y " +"al registro de eventos." + +#: ../SparkleShare/SparkleSetup.cs:545 +msgid "Adding projects to SparkleShare" +msgstr "Añadiendo proyectos a SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:546 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Basta con hacer clic en este botón cuando lo veas en la web, y el proyecto " +"se agregará automáticamente:" + +#: ../SparkleShare/SparkleSetup.cs:549 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"... o seleccione \"Agregar proyecto alojado ... \" en el menú del " +"icono de estado para agregar uno manualmente." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Configuración de SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:230 +msgid "No projects yet" +msgstr "No hay proyectos aún" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleStatusIcon.cs:240 +msgid "Add Hosted Project…" +msgstr "Añadir proyecto almacenado..." + +#: ../SparkleShare/SparkleStatusIcon.cs:264 +msgid "Open Recent Events" +msgstr "Abrir eventos recientes" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications Off" +msgstr "Desactivar las notificaciones" + +#: ../SparkleShare/SparkleStatusIcon.cs:286 +msgid "Turn Notifications On" +msgstr "Activar las notificaciones" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:313 +msgid "Quit" +msgstr "Salir" + + diff --git a/SparkleShare/Common/Translations/fi.po b/SparkleShare/Common/Translations/fi.po new file mode 100755 index 0000000..3fadc18 --- /dev/null +++ b/SparkleShare/Common/Translations/fi.po @@ -0,0 +1,410 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +# Łukasz Jernaś , 2011. +# Olli Jarva , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fi\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GNOME-projekti" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Tervetuloa SparkleShareen!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Ajantasalla" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synkronoidaan..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Kaikkea ei ole synkronoitu" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopioi web-linkki" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopioi tämän tiedoston osoite leikepöydälle" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Hae vanhempi versio" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Tee kopio tämän hakemiston aikaisemmasta versiosta" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Tee kopio tästä versiosta" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Tulosta versiotiedot" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Näytä tämä ohjeteksti" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, yhteistyö- ja jakotyökalu." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Tällä ohjelmalla EI OLE TAKUUTA." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Tämä on vapaa ohjelma, ja saat vapaasti levittää sitä" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "tietyin ehdoin. Saat lisätietoja GNU GPLv3:sta." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synkronoi automaattisesti Git-tietokannat" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "~/SparkleShare-kansiosta etäpalvelinten kanssa." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Käyttö: sparkleshare [start|stop|restart] [asetukset]" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Synkronoi SparkleShare-kansio etätietokantoihin." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Parametrit:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Tietoja SparkleSharesta" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Sinulla on uusin versio käytössäsi" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Tarkistetaan päivityksiä..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Ennen kuin voit luoda SparkleShare-kansio tälle tietokoneelle, tarvitsemme " +"joitain tietoja sinusta." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Koko nimi:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Sähköposti:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Seuraava" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Peruuta" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Oletko varma, että ei ole kahvitauon paikka?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Valmis" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' lisättiin onnistuneesti" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Avaa hakemisto" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleSharen asennus" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Poista ilmoitukset käytöstä" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Ota ilmoitukset käyttöön" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Lopeta" + + diff --git a/SparkleShare/Common/Translations/fr.po b/SparkleShare/Common/Translations/fr.po new file mode 100755 index 0000000..c4479fe --- /dev/null +++ b/SparkleShare/Common/Translations/fr.po @@ -0,0 +1,421 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# angelini paa , 2011. +# , 2011. +# Bruno ARLIGUY , 2011. +# Crash , 2011. +# Thomas Menga , 2011. +# Yann Yann , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-11-04 22:18+0000\n" +"Last-Translator: chezyann \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/nom-d-utilisateur/projet" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Hébergement gratuit de code pour Git et Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Dépôts Git gratuits avec gestion des collaborateurs" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/projet/depot" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "Infrastructure open source d'hébergement de projets open source" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/projet" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Une interface facile et gratuite pour votre ordinateur" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Le projet GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/chemin/du/projet" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Tout est sous mon contrôle" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Mon propre serveur" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Bienvenue sur SparkleShare !" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "À jour" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synchronisation en cours…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Tout n'est pas synchronisé" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Copier le lien web" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Copier l'adresse internet de ce fichier dans le presse‑papier" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Obtenir une version antérieure" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Créer une copie d'une version antérieure de ce dossier" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Sélectionner pour obtenir une copie de cette version" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Affiche les informations de la version" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Afficher ce texte d’aide" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, outils de collaboration et de partage" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Ce logiciel est diffusé sans AUCUNE GARANTIE." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Ce logiciel est libre et vous êtes invité à le re‑distribuer " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"sous certaines conditions. Merci de lire la licence GNU GPLv3 pour de plus " +"amples informations." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synchronise automatiquement les dépôts Git dans " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "le dossier ~/SparkleShare avec leurs racines distantes." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Utilisation : sparkleshare [start|stop|restart] [OPTION]…" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Synchroniser le dossier SparkleShare avec les dépôts distants." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Paramètres :" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "À propos de SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Une nouvelle version ({0}) est disponible!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Vous disposez de la dernière version." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Vérification des mises à jour…" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd d MMMM yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "dddd d MMMM" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "Ajouté: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "Déplacé: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "Modifié: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "Supprimé: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "Attendez un miracle" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Évènements récents" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Tous les dossiers" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Afin de pouvoir créer un dossier SparkleShare sur cet ordinateur, nous avons" +" besoin de quelques informations." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Nom et prénom :" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email :" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Suivant" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Où est hebergé votre projet ?" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Adresse" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "Chemin à distance" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Annuler" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "Ajouter" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Ajout du projet '{0}'" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Cela peut prendre un peu de temps." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Ne pensez-vous pas qu'il est temps de prendre un café ?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Terminer" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Il y a eu un problème" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Réessayez..." + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "« {0} » a été ajouté avec succès" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Projet ajouté !" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Accéder vos fichiers depuis le répertoire Sparkleshare" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Ouvrir le dossier" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "Et ensuite ?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "Sparkleshare crée un répertoire spécial pour vos projets" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Passer ce tutoriel" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Continuer" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Partager des fichers avec d'autres utilisateurs" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Tous les fichiers ajoutés à votre projet sont synchronisés automatiquement, " +"avec les vôtres ou ceux qui collaborent avec vous" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "L'îcone d'état est là pour vous aider" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Elle montre l'état du processus de synchronisation et contient les liens " +"vers vos projets, ainsi que l'historique des évènements " + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Ajout de projets dans SpakleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Cliquez sur ce bouton dans une page Web, et le projet sera automatiquement " +"ajouté" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "Ajouter un projet hébergé..." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Configuration de SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Pas de projets déclarés" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "Ouvrir les évènements récents" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Désactiver les notifications" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Activer les notifications" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Quitter" + + diff --git a/SparkleShare/Common/Translations/he.po b/SparkleShare/Common/Translations/he.po new file mode 100755 index 0000000..8752c0f --- /dev/null +++ b/SparkleShare/Common/Translations/he.po @@ -0,0 +1,407 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-11-01 20:06+0000\n" +"Last-Translator: ophir \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: he\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "גיטוריוס" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "פרוייקט גנום" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "הכל תחת שליטתי" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "שרת משלי" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "ברוכים הבאים לספארקלשר!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "מעודכן" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "מסנכרן..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "לא הכל מסונכרן" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "העתק לינק" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "העתק את כתובת האינטרנט של קובץ זה ללוח העריכה (clipboard)" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "קבל גרסה קודמת" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "צור העתק של גרסה קודמת בתקייה זו" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "בחר כדי לקבל העתק של גרסה זו" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "מידע גרסת ההדפסה" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "הראה את מלל העזרה" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "זכויות שמורות (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "תוכנה זו באה ללא כל אחריות." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "תוכנה זו הינה חופשית ואתם מוזמנים להפיצה" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "תחת תנאים מסויימים. אנא קראו את רשיון GNU GPLv3 לקבלת פרטים." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "" + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "שימוש: sparkleshare [start|stop|restart] [אפשרויות]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "סנכרן תקיית ספארקלשר עם מאגרים מרוחקים." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "ארגומנטים:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "ספארקלשר" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "אודות ספארקלשר" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "גירסה חדשה יותר ({0}) זמינה!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "אתה מריץ את הגרסה המעודכנת ביותר" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "בודק עדכונים..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "‘{0}’ הוסף" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "‘{0}’ הוזז" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "‘{0}’ שונה" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "‘{0}’ נמחק" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "אירועים אחרונים" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "כל התיקיות" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"לפני שנוכל ליצור תקיית ספארקלשר על מחשב זה, אנו צריכים כמה פיסות מידע ממך." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "שם מלא:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "דוא\"ל:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "הבא" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "בטל" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "הוסף" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "מוסיף פרויקט ‘{0}’…" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "זה עלול לקחת זמן מה" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "מה אתה אומר על קפה?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "סיים" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "משהו השתבש" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "נסה שוב..." + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "‘{0}’ הוסף בהצלחה" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "פרויקט הוסף בהצלחה!" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "גש לקבצים מתיקיית ספארקלשר" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "פתח תקייה" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "מה עכשיו?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "דלג על הדרכה" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "המשך" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "שיתוף קבצים עם אחרים" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "הוספת פרויקטים לספארקלשר" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "לחץ כאן כשאתה רואה אותו ברשת, והפרויקט יתווסף אוטומטית:" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "התקנת ספארקלשר" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "עדיין אין פרויקטים" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "פתח אירועים אחרונים" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "כבה הודעות" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "הפעל הודעות" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "צא" + + diff --git a/SparkleShare/Common/Translations/hu.po b/SparkleShare/Common/Translations/hu.po new file mode 100755 index 0000000..d73ac4c --- /dev/null +++ b/SparkleShare/Common/Translations/hu.po @@ -0,0 +1,409 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Zoltan Hoppár , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: hu\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "A GNOME Project" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Üdvözli a SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Naprakész" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Szinkronizálás..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Nincs minden szinkronizálva" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Weblink kimásolása" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kimásolja ennek a fájlnak webcímét a vágólapra" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Korábbi verzió beszerzése" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Korábbi verzió másolása ebbe a mappába" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Válasszon hogy egy korábbi változatot megkapjon" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Verzió információk nyomtatása" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Ezt a súgó segítséget jeleníti meg" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, az együttműködés és megosztás eszköze." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Erre a programra nincs SEMMIFÉLE GARANCIA." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Ez egy szabad szoftver, és mindig örülünk, ha terjesztik " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"bizonyos feltételek mellett. Kérjük, olvassa el a GNU GPLv3 a részletekért." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare automatikusan szinkronizálja Git adattárakat a" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "a ~/SparkleShare mappával a távoli eredetükkel." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Használat: sparkleshare [start | stop | újraindítás] [OPCIÓK] ..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "A SparkleShare mappa szinkronizálása a távoli tárolókkal." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Paraméterek:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "A SparkleShare-ről" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Az elérhető legújabb verziót használja." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Frissítések keresése..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Utóbbi események" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "MInden mappa" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Mielőtt még egy SparkleShare mappát készítenénk ezen a gépen, még néhány " +"apró információra lenne szükség." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Teljes név:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Következő" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Mégsem" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Biztos benne, hogy nincs kávészünet?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Befejezés" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' sikeresen hozzáadva" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Mappa megnyitása" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleShare beállítása" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Értesítések kikapcsolása" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Értesítések bekapcsolása" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Kilépés" + + diff --git a/SparkleShare/Common/Translations/it.po b/SparkleShare/Common/Translations/it.po new file mode 100755 index 0000000..63faad3 --- /dev/null +++ b/SparkleShare/Common/Translations/it.po @@ -0,0 +1,391 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Ilias Bartolini , 2011. +# , 2011. +# Luca Delucchi , 2011. +# Łukasz Jernaś , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-04 12:45+0100\n" +"PO-Revision-Date: 2011-12-19 14:27+0000\n" +"Last-Translator: yakky \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/nome-utente/progetto" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Hosting gratuito di codice per Git e Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Repository pubblici gratuiti con gestione dei collaboratori" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/progetto/repository" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorius" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "Infrastruttura Open sourc per lo hosting di progetti open source" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/progetto" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Un'interfaccia gratuita e facile per il tuo computer" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "The GNOME Project" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/percorso/per/progetto" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Tutto sotto il mio controllo" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Il mio server" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:84 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:102 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Benvenuto in SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:86 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:104 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Aggiornato" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:113 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Sincronizzazione in corso..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:125 +#: ../SparkleShare/SparkleStatusIcon.cs:118 +msgid "Not everything is synced" +msgstr "Non tutto è sincronizzato" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:141 +msgid "Copy Web Link" +msgstr "Copia link web" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:115 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:142 +msgid "Copy the web address of this file to the clipboard" +msgstr "Copia l'indirizzo web di questo file" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:174 +msgid "Get Earlier Version" +msgstr "Prendi versione precedente" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:149 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:175 +msgid "Make a copy of an earlier version in this folder" +msgstr "Esegui una copia di una precedente versione di questa cartella" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:162 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:188 +msgid "Select to get a copy of this version" +msgstr "Seleziona per ottenere una copia di questa versione" + +#: ../SparkleShare/Program.cs:50 +msgid "Print version information" +msgstr "Stampa informazioni sulla versione" + +#: ../SparkleShare/Program.cs:51 +msgid "Show this help text" +msgstr "Mostra questo messaggio di aiuto" + +#: ../SparkleShare/Program.cs:83 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, uno strumento collaborativo e di condivisione" + +#: ../SparkleShare/Program.cs:84 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:86 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Questo programma viene fornito ASSOLUTAMENTE SENZA NESSUNA GARANZIA." + +#: ../SparkleShare/Program.cs:88 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Questo è software libero e sei invitato a redistribuirlo" + +#: ../SparkleShare/Program.cs:89 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"rispettando alcune restrizioni. Leggi la licenza GNU GPLv3 per i dettagli" + +#: ../SparkleShare/Program.cs:91 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare sincronizza automaticamente i repository Git nella" + +#: ../SparkleShare/Program.cs:92 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "cartella ~/.SparkleShare con le loro origini." + +#: ../SparkleShare/Program.cs:94 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Utilizzo: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:95 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Sincronizza cartella SparkleShare con repository remoti." + +#: ../SparkleShare/Program.cs:97 +msgid "Arguments:" +msgstr "Argomenti" + +#: ../SparkleShare/Program.cs:107 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:297 +msgid "About SparkleShare" +msgstr "Informazioni su SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "È disponibile una nuova versione ({0})" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Stai eseguendo l'ultima versione" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:110 +msgid "Checking for updates..." +msgstr "Controllo aggiornamenti..." + +#: ../SparkleShare/SparkleControllerBase.cs:489 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd, MMMM d, yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:495 +msgid "dddd, MMMM d" +msgstr "dddd, MMMM d" + +#: ../SparkleShare/SparkleEventLog.cs:56 +msgid "Recent Events" +msgstr "Eventi recenti" + +#: ../SparkleShare/SparkleEventLog.cs:145 +#: ../SparkleShare/SparkleEventLog.cs:164 +msgid "All Folders" +msgstr "Tutte le cartelle" + +#: ../SparkleShare/SparkleOptions.cs:486 +msgid "OptionName" +msgstr "OptionName" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Nome e Cognome:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Successivo" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Dov'è ospitato il tuo progetto?" + +#: ../SparkleShare/SparkleSetup.cs:266 +msgid "Address" +msgstr "Indirizzo" + +#: ../SparkleShare/SparkleSetup.cs:286 +msgid "Remote Path" +msgstr "Percorso remoto" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:300 ../SparkleShare/SparkleSetup.cs:336 +msgid "Cancel" +msgstr "Cancella" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:307 +msgid "Add" +msgstr "Aggiungi" + +#: ../SparkleShare/SparkleSetup.cs:326 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Progetto '{0}' in aggiunta..." + +#: ../SparkleShare/SparkleSetup.cs:327 +msgid "This may take a while." +msgstr "Questa operazione potrebbe richiedere un po' di tempo." + +#: ../SparkleShare/SparkleSetup.cs:328 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Sei sicuro che non sia l'ora di un caffè?" + +#: ../SparkleShare/SparkleSetup.cs:332 ../SparkleShare/SparkleSetup.cs:448 +#: ../SparkleShare/SparkleSetup.cs:558 +msgid "Finish" +msgstr "Fine" + +#: ../SparkleShare/SparkleSetup.cs:365 +msgid "Something went wrong" +msgstr "Qualcosa è andato storto" + +#: ../SparkleShare/SparkleSetup.cs:413 +msgid "Try Again…" +msgstr "Prova ancora..." + +#: ../SparkleShare/SparkleSetup.cs:432 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "‘{0}’ è stato aggiunto con successo" + +#: ../SparkleShare/SparkleSetup.cs:438 +msgid "Project successfully added!" +msgstr "Progetto aggiunto con successo" + +#: ../SparkleShare/SparkleSetup.cs:439 +msgid "Access the files from your SparkleShare folder." +msgstr "Accedi i file dalla tua cartella SparkleShare." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:442 +msgid "Open Folder" +msgstr "Apri cartella" + +#: ../SparkleShare/SparkleSetup.cs:484 +msgid "What's happening next?" +msgstr "Cosa fare adesso?" + +#: ../SparkleShare/SparkleSetup.cs:485 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"SparkleShare crea una cartella speciale nella tua cartella personale per " +"tenere traccia dei tuoi progetti." + +#: ../SparkleShare/SparkleSetup.cs:488 +msgid "Skip Tutorial" +msgstr "Salta l'Introduzione" + +#: ../SparkleShare/SparkleSetup.cs:493 ../SparkleShare/SparkleSetup.cs:513 +#: ../SparkleShare/SparkleSetup.cs:531 +msgid "Continue" +msgstr "Continua" + +#: ../SparkleShare/SparkleSetup.cs:509 +msgid "Sharing files with others" +msgstr "Condividere i tuoi file con altri" + +#: ../SparkleShare/SparkleSetup.cs:510 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Tutti i file inseriti nelle cartelle dei tuoi progetti sono sincronizzati in" +" automatico con il server e con i tuoi collaboratori." + +#: ../SparkleShare/SparkleSetup.cs:527 +msgid "The status icon is here to help" +msgstr "L'icona di stato è qui per aiutare" + +#: ../SparkleShare/SparkleSetup.cs:528 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Mostra il progresso della sicronizzazione, e contiene collegamenti ai tuoi " +"progetti e al registro degli eventi." + +#: ../SparkleShare/SparkleSetup.cs:545 +msgid "Adding projects to SparkleShare" +msgstr "Aggiungere progetti a SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:546 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Fai click su questo bottone quando lo vedi sul web e il progetto sarà " +"automaticamente aggiunto:" + +#: ../SparkleShare/SparkleSetup.cs:549 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"...o seleziona 'Aggiungi progetto ospitato' dall'icona di stato per " +"aggiungerne uno a mano." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Impostazioni " + +#: ../SparkleShare/SparkleStatusIcon.cs:230 +msgid "No projects yet" +msgstr "Nessun progetto per il momento" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleStatusIcon.cs:240 +msgid "Add Hosted Project…" +msgstr "Aggiungi progetto ospitato..." + +#: ../SparkleShare/SparkleStatusIcon.cs:264 +msgid "Open Recent Events" +msgstr "Apri eventi recenti" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications Off" +msgstr "Spegni le notifiche" + +#: ../SparkleShare/SparkleStatusIcon.cs:286 +msgid "Turn Notifications On" +msgstr "Accendi le notifiche" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:313 +msgid "Quit" +msgstr "Esci" + + diff --git a/SparkleShare/Common/Translations/ja.po b/SparkleShare/Common/Translations/ja.po new file mode 100755 index 0000000..0971fd3 --- /dev/null +++ b/SparkleShare/Common/Translations/ja.po @@ -0,0 +1,407 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +# , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ja\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GNOMEプロジェクト" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "SparkleShareへようこそ!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "最新の状態です。" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "同期中..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "すべてが同期されていません" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "ウェブリンクのコピー" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "このファイルのウェブアドレスをクリップボードにコピー" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "新しいバージョンの取得" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "このフォルダに古いヴァージョンのコピーを作成" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "このヴァージョンを選択し、コピー" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "バージョン情報の表示" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "このヘルプテキストを表示" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare、コラボレーションと共有のためのツールです。" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C)2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "このプログラムは完全無保証です。" + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "これはフリーソフトウェアであり、再配布を歓迎します。" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "一定の条件の下で。詳細については、GNUのGPLv3をお読みください。" + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShareは自動的に..のGitリポジトリと同期します" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "リモートの元フォルダを含んだ~/SparkleShareフォルダ" + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "使用法: sparkleshare [start|stop|restart] [オプション]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "SparkleShareフォルダをリモートのリポジトリと同期。" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "引数:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "SparkleShareについて" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "新しいバージョン ({0}) が利用できます!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "最新のバージョンです。" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "更新の確認中..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "最近のイベント" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "全てのフォルダ" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "SparkleShareのフォルダをこのコンピュータ上に作成する前に、少しですがお知らせがあります。" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "氏名:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "電子メール:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "次" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "アドレス" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "リモートパス" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "キャンセル" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "コーヒー時ではありませんか?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "完了" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}'は正常に追加されました" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "フォルダを開く" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "チュートリアルをスキップする" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "続ける" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleShareセ​​ットアップ" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "最近のイベントを開く" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "通知をオフ" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "通知をオン" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "終了" + + diff --git a/SparkleShare/Common/Translations/nl.po b/SparkleShare/Common/Translations/nl.po new file mode 100755 index 0000000..6aa7dd2 --- /dev/null +++ b/SparkleShare/Common/Translations/nl.po @@ -0,0 +1,427 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +# , 2011. +# , 2011. +# Łukasz Jernaś , 2011. +# , 2011. +# , 2011. +# smeagiel , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-11-06 22:01+0000\n" +"Last-Translator: mmans \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: nl\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/gebruikersnaam/project" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Gratis hosting voor Git en Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Gratis publieke repositories met teambeheer." + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/project/repository" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "Opensource infrastructuur voor het hosten van opensource projecten." + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/project" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Een gratis en gemakkelijke interface voor uw computer" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Het GNOME Project" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/pad/naar/project" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Alles onder mijn controle" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Op mijn eigen server" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Welkom bij SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Up-to-date" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synchroniseren…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Niet alles is gesynchroniseerd" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopiëer weblink" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopiëer het web-adres van dit bestand naar het plakbord" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Verkrijg eerdere versie" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Maak een kopie van een oudere versie naar deze map" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Selecteer voor een kopie van deze versie" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Druk versie-informatie af" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Toon deze helptekst" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, een programma om samen te werken en te delen." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Er zit ABSOLUUT GEEN GARANTIE op dit programma." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "" +"Dit is vrije software en je bent van harte uitgenodigd om het te " +"herdistribueren " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr " onder bepaalde voorwaarden. Zie de GNU GPLv3 voor meer informatie." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synchroniseert automatisch Git repositories in " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "de ~/SparkleShare map met de externe bron." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Gebruik: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Synchroniseer de SparkleShare map met externe repositories" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Argumenten:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Over SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Een nieuwe versie ({0}) is beschikbaar!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "U werkt met de nieuwste versie." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Controleren op updates ..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd, MMMM d, yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "dddd, MMMM d" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "toegevoegd: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "verplaatst: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "bewerkt: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "verwijderd: ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "en nog {0}" +msgstr[1] "en nog {0}" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "deed iets magisch" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Recente gebeurtenissen" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Alle mappen" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Voordat we een SparkleShare map op deze computer kunnen aanmaken, hebben we " +"eerst wat informatie van je nodig." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Volledige naam:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "E-mailadres" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Volgende" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Waar word het project gehost?" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Adres" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "Extern pad" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Annuleren" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "Toevoegen" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Project '{0}' toevoegen..." + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Dit kan even duren." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Tijd voor een Cup-a-Soup?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Voltooien" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Er ging iets mis" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Opnieuw proberen..." + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' is met succes toegevoegd" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Project succesvol toegevoegd!" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Benader de gesynchroniseerde bestanden in je SparkleShare-map." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Map openen" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "What gebeurt er nu?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"SparkleShare maakt een speciale map in je persoonlijke map die je projecten " +"in de gaten houdt." + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Tutorial overslaan" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Doorgaan" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Bestanden delen met anderen" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Alle bestanden die je aan je projectmappen toevoegt worden automatisch " +"gesynchroniseerd met de host en je team." + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "Het statusicoon bied hulp" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Het toont de voortgang van het synchroniseerproces en bevat links naar je " +"projecten en het logboek." + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Projecten toevoegen aan SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Klik op deze knop wanneer je deze tegenkomt op het web, en het project wordt" +" automatisch toegevoegd." + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"…of selecteer ‘Gehost project toevoegen…’ in het menu van het " +"statusicoon om een project met de hand toe te voegen." + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "Gehost project toevoegen…" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleShare Setup" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Nog geen projecten" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "Logboek openen" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Zet mededelingen uit" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Zet mededelingen aan" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Afsluiten" + + diff --git a/SparkleShare/Common/Translations/nn_NO.po b/SparkleShare/Common/Translations/nn_NO.po new file mode 100755 index 0000000..5d37aec --- /dev/null +++ b/SparkleShare/Common/Translations/nn_NO.po @@ -0,0 +1,408 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: nn_NO\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GNOME-prosjektet" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Velkommen åt SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synkroniserer..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Ikkje alt er synkronisert" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopier web-lenke" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Skaff ein tidlegare versjon" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Lag ein kopi av ein tidlegare versjon i denne mappa" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Vel for å få ein kopi av tidlegare versjon" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Skriv ut versjonsinformasjon" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Vis denne hjølpsomme teksten" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Dette programmet kjem heilt uten garantiar." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Dette er fri programvare, og du står fritt til å spre det" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "under nokre få vilkår. Les GNU GPLv3 for fleire detaljar" + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synkroniserer automatisk Git-strukturar i" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "~/SparkleShare-mappa med fjernfilane" + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Om SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Du køyrer den nyaste versjonen." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Ser etter oppdateringar..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Siste hendingar" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Alle mapper" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Før me kan lage ei SparkleShare-mappe på denne datamaskina, må me ha litt " +"meir informasjon frå deg." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Fullt namn:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "E-post:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Neste" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Avbryt" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Dette kan ta ei tid" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Ta deg ei kaffitår" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Ferdig" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Noko gjekk gale" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Opne mappe" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Avslutt" + + diff --git a/SparkleShare/Common/Translations/no_NO.po b/SparkleShare/Common/Translations/no_NO.po new file mode 100755 index 0000000..9b825f2 --- /dev/null +++ b/SparkleShare/Common/Translations/no_NO.po @@ -0,0 +1,418 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +# habakke , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: no_NO\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GNOME Prosjektet" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Velkommen til SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Oppdatert" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synkroniserer..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Ikke alt er synkronisert" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopier web-link" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopier denne filens web-addresse til utklippstavlen" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Hent tidligere versjon" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Lag en kopi av en tidligere versjon i denne mappen" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Velg for å få en kopi av denne versjonen." + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Print versjons informasjon" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Vis denne hjelpeteksten" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, et samarbeids- og fildelingsverktøy" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Dette programmet kommer med ABSOLUTT INGEN GARANTI." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "" +"Dette er fri programvare, og du er velkommen til å videredistribuere det" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "under visse vilkår. Vennligst les GNU GPLv3 for detaljer." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synkroniserer automatisk Git repositories i" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "på ~ / SparkleShare mappe med deres eksterne opprinnelse." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Bruk: sparkleshare [start | stop | restart] [VALG] ..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Synkroniser SparkleShare mappe med eksterne repositories." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Argumenter:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Om SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "En nyere versjon ({0}) er tilgjengelig!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Du kjører siste versjon" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Ser etter oppdateringer..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Nylige hendelser" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Alle mapper" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Før vi kan lage en SparkleShare mappe på denne datamaskinen, trenger vi litt" +" informasjon fra deg." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Fullt navn:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "E-post:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Neste" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Avbryt" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Dette kan ta en stund." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "" +"Ta deg en kopp te:\n" +"Kok opp vann\n" +"Ha litt varmt vann i koppen\n" +"Tøm koppen, og ha i teposen\n" +"Tilsett varmt vann, ev. sukker og melk eller sitronsaft\n" +"Nyt teen\n" +"Kom tilbake, og nyt SparkleShare!" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Fullfør" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Noe gikk galt" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "‘{0}’ har blitt lagt til" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Åpne Mappe" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Sett opp SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Slå av varslinger" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Slå på varslinger" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Avslutt" + + diff --git a/SparkleShare/Common/Translations/pl.po b/SparkleShare/Common/Translations/pl.po new file mode 100755 index 0000000..1dcdd54 --- /dev/null +++ b/SparkleShare/Common/Translations/pl.po @@ -0,0 +1,430 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Łukasz Jernaś , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-11-12 13:18+0100\n" +"PO-Revision-Date: 2011-11-12 12:34+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pl\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/nazwa uzytkownika/projekt" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" +"Darmowe utrzymywanie kodu dla projektów zarządzanych przez git oraz " +"Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Darmowe publiczne repozytoria git z obsługą współpracowników" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/projekt/repozytorium" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" +"Infrastruktura o otwartym kodzie źródłowym dla projektów o otwartym kodzie " +"źródłowym" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/project" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Wolny i prosty interfejs dla komputerów" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Projekt GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/ścieżka/do/projektu" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Wszystko pod własną kontrolą" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Na własnym serwerze" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:84 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:102 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Witamy w programie SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:86 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:104 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Wszystko jest aktualne" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:113 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synchronizowanie…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:123 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Nie wszystko zostało zsynchronizowane" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Skopiuj odnośnik" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopiuje adres URL tego pliku do schowka" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Pobierz wcześniejszą wersję" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Tworzy kopię wcześniejszej wersji w tym katalogu" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Zaznacz, aby pobrać kopię tej wersji" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Wyświetla informacje o wersji" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Wyświetla opcje pomocy" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare ‒ narzędzie wspomagające współpracę." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Niniejszy program dostarczany jest BEZ JAKIEJKOLWIEK GWARANCJI." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "" +"Niniejszy program jest wolnym oprogramowaniem, można go rozprowadzać dalej " +"pod pewnymi warunkami." + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"Aby uzyskać więcej informacji, proszę zapoznać się z tekstem licencji GNU " +"GPLv3." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "" +"Program SparkleShare automatycznie synchronizuje repozytoria Git znajdujące " +"się" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "w katalogu ~/SparkleShare z ich zdalnymi gałęziami." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Użycie: sparkleshare [start|stop|restart] [OPCJA]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "" +"Synchronizuj zawartość katalogu SparkleShare ze zdalnymi repozytoriami." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Parametry:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Informacje o" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Dostępna jest nowa wersja: {0}" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Korzystasz z najnowszej wersji." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Wyszukiwanie aktualizacji" + +#: ../SparkleShare/SparkleControllerBase.cs:494 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd, d MMMM yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:500 +msgid "dddd, MMMM d" +msgstr "dddd, d MMMM" + +#: ../SparkleShare/SparkleControllerBase.cs:708 +#, csharp-format +msgid "added ‘{0}’" +msgstr "dodano \"{0}\"" + +#: ../SparkleShare/SparkleControllerBase.cs:713 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "przesunięto \"{0}\"" + +#: ../SparkleShare/SparkleControllerBase.cs:718 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "edytowano \"{0}\"" + +#: ../SparkleShare/SparkleControllerBase.cs:723 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "usunięto \"{0}\"" + +#: ../SparkleShare/SparkleControllerBase.cs:732 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "oraz {0} więcej" +msgstr[1] "oraz {0} więcej" +msgstr[2] "oraz {0} więcej" + +#: ../SparkleShare/SparkleControllerBase.cs:736 +msgid "did something magical" +msgstr "stało się coś magicznego" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Ostatnie zdarzenia" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Wszystkie katalogi" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Program SparkleShare wymaga podania kilku informacji, nim możliwe będzie " +"utworzenie katalogu na tym komputerze." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Imię i nazwisko:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Następny" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Gdzie jest utrzymywany projekt?" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Adres" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "Zdalna ścieżka" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Anuluj" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "Dodaj" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Dodawanie projektu \"{0}\"…" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Może to chwilę zająć." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Czy to nie jest czasem przerwa na kawę?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Zakończ" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Coś się nie udało" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Proszę spróbować ponownie" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "„{0}” został poprawnie dodany" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Projekt został dodany pomyślnie." + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Dostęp do plików możliwy jest z katalogu SparkleShare." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Otwórz katalog" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "Co wydarzy się za chwilę?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"Program SparkleShare utworzy specjalny katalog w katalogu domowym, który " +"będzie zajmował się projektami." + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Pomiń samouczek" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Dalej" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Współdzielenie plików z innymi" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Wszystkie pliki dodane do katalogów projektów są automatycznie " +"synchronizowane zarówno serwerem jak i ze współpracownikami." + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "Ikona powiadamiania jest po to, by pomagać" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Wyświetla stan synchronizacji, jak i zawiera odnośniki do projektów oraz " +"dziennika zdarzeń." + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Dodawanie projektu do programu SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Kliknięcie tego przycisku na stronie internetowej spowoduje automatyczne " +"dodanie projektu:" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"…lub można wybrać opcję \"Dodaj utrzymywany projekt…\" z menu " +"powiadamiania, aby dodać projekt ręcznie." + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "Dodaj utrzymywany projekt…" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Ustawienia programu SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Nie dodano projektów" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "Otwórz ostatnie zdarzenia" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Wyłącz powiadomienia" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Włącz powiadomienia" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Zakończ" + + diff --git a/SparkleShare/Common/Translations/pt_BR.po b/SparkleShare/Common/Translations/pt_BR.po new file mode 100755 index 0000000..031f0cf --- /dev/null +++ b/SparkleShare/Common/Translations/pt_BR.po @@ -0,0 +1,393 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# DigitalDead , 2011. +# , 2011. +# Nícolas Lazarte , 2011. +# Paulo Paulo , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-04 12:45+0100\n" +"PO-Revision-Date: 2011-12-04 11:46+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt_BR\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/usuário/projeto" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Hospedagem gratuita de código para Git e Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Repositórios públicos Git, gratuitos com gestão de colaboradores" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/projeto/repositório" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" +"Infra-estrutura de código aberto para hospedagem de projetos com código " +"aberto " + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/projeto" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Uma interface fácil e gratuita para o seu computador" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "O projeto GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/caminho/para/projeto" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Tudo sob meu controle" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Em meu próprio servidor" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:84 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:102 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Bem-vindo ao SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:86 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:104 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Atualizado" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:113 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Sincronizando…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:125 +#: ../SparkleShare/SparkleStatusIcon.cs:118 +msgid "Not everything is synced" +msgstr "Nem tudo foi sincronizado" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:141 +msgid "Copy Web Link" +msgstr "Copiar Endereço Web" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:115 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:142 +msgid "Copy the web address of this file to the clipboard" +msgstr "Copiar o endereço web deste arquivo" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:174 +msgid "Get Earlier Version" +msgstr "Obter Versão Anterior" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:149 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:175 +msgid "Make a copy of an earlier version in this folder" +msgstr "Fazer uma cópia de uma anterior nesta pasta" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:162 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:188 +msgid "Select to get a copy of this version" +msgstr "Selecione para obter uma cópia dessa versão" + +#: ../SparkleShare/Program.cs:50 +msgid "Print version information" +msgstr "Imprimir informações da versão" + +#: ../SparkleShare/Program.cs:51 +msgid "Show this help text" +msgstr "Exibir esse texto de ajuda" + +#: ../SparkleShare/Program.cs:83 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, uma ferramenta de colaboração e compartilhamento" + +#: ../SparkleShare/Program.cs:84 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons - Todos os direitos reservados" + +#: ../SparkleShare/Program.cs:86 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Este programa vem com ABSOLUTAMENTE NENHUMA GARANTIA." + +#: ../SparkleShare/Program.cs:88 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Este é um software livre, e você está convidado a distribuí-lo" + +#: ../SparkleShare/Program.cs:89 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"sob certas condições. Por favor leia a licença GNU GPLv3 para mais detalhes." + +#: ../SparkleShare/Program.cs:91 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "O SparkleShare sincroniza os repositórios do Git automaticamente" + +#: ../SparkleShare/Program.cs:92 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "a pasta ~/SparkleShare com suas origens remotas" + +#: ../SparkleShare/Program.cs:94 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Utilização: sparkleshare [start|stop|restart] [OPÇÕES]..." + +#: ../SparkleShare/Program.cs:95 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Sincroniza a pasta SparkleShare com repositórios remotos." + +#: ../SparkleShare/Program.cs:97 +msgid "Arguments:" +msgstr "Argumentos:" + +#: ../SparkleShare/Program.cs:107 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:297 +msgid "About SparkleShare" +msgstr "Sobre o SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Uma nova versão ({0}) está disponível!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Você está executando a última versão" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:110 +msgid "Checking for updates..." +msgstr "Verificando atualizações" + +#: ../SparkleShare/SparkleControllerBase.cs:489 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd, MMMM d, yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:495 +msgid "dddd, MMMM d" +msgstr "dddd, MMMM d" + +#: ../SparkleShare/SparkleEventLog.cs:56 +msgid "Recent Events" +msgstr "Eventos Recentes" + +#: ../SparkleShare/SparkleEventLog.cs:145 +#: ../SparkleShare/SparkleEventLog.cs:164 +msgid "All Folders" +msgstr "Todas as pastas" + +#: ../SparkleShare/SparkleOptions.cs:486 +msgid "OptionName" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Nome Completo:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Próximo" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Onde está o seu projeto está hospedado?" + +#: ../SparkleShare/SparkleSetup.cs:266 +msgid "Address" +msgstr "Endereço" + +#: ../SparkleShare/SparkleSetup.cs:286 +msgid "Remote Path" +msgstr "Caminho remoto" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:300 ../SparkleShare/SparkleSetup.cs:336 +msgid "Cancel" +msgstr "Cancelar" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:307 +msgid "Add" +msgstr "Adicionar" + +#: ../SparkleShare/SparkleSetup.cs:326 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Adicionando projeto '{0}' ..." + +#: ../SparkleShare/SparkleSetup.cs:327 +msgid "This may take a while." +msgstr "Isto pode demorar um pouco." + +#: ../SparkleShare/SparkleSetup.cs:328 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Você tem certeza de que não é hora do café?" + +#: ../SparkleShare/SparkleSetup.cs:332 ../SparkleShare/SparkleSetup.cs:448 +#: ../SparkleShare/SparkleSetup.cs:558 +msgid "Finish" +msgstr "Finalizar" + +#: ../SparkleShare/SparkleSetup.cs:365 +msgid "Something went wrong" +msgstr "Algum problema ocorreu" + +#: ../SparkleShare/SparkleSetup.cs:413 +msgid "Try Again…" +msgstr "Tente novamente..." + +#: ../SparkleShare/SparkleSetup.cs:432 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' foi incluída com sucesso" + +#: ../SparkleShare/SparkleSetup.cs:438 +msgid "Project successfully added!" +msgstr "Projeto adicionado com sucesso!" + +#: ../SparkleShare/SparkleSetup.cs:439 +msgid "Access the files from your SparkleShare folder." +msgstr "Acessar os arquivos da pasta SparkleShare." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:442 +msgid "Open Folder" +msgstr "Abrir Pasta" + +#: ../SparkleShare/SparkleSetup.cs:484 +msgid "What's happening next?" +msgstr "O que está acontecendo em seguida?" + +#: ../SparkleShare/SparkleSetup.cs:485 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"SparkleShare cria uma pasta especial em sua pasta pessoal que vai manter o " +"controle de seus projetos." + +#: ../SparkleShare/SparkleSetup.cs:488 +msgid "Skip Tutorial" +msgstr "Pular Tutorial" + +#: ../SparkleShare/SparkleSetup.cs:493 ../SparkleShare/SparkleSetup.cs:513 +#: ../SparkleShare/SparkleSetup.cs:531 +msgid "Continue" +msgstr "Continuar" + +#: ../SparkleShare/SparkleSetup.cs:509 +msgid "Sharing files with others" +msgstr "Compartilhar arquivos com outras pessoas" + +#: ../SparkleShare/SparkleSetup.cs:510 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Todos os arquivos adicionados a pasta do seu projeto são sincronizados " +"automaticamente com o servidor, bem como com seus colaboradores." + +#: ../SparkleShare/SparkleSetup.cs:527 +msgid "The status icon is here to help" +msgstr "O ícone de status está aqui para ajudar" + +#: ../SparkleShare/SparkleSetup.cs:528 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Mostra o status do processo de sincronização, e contém links para seus " +"projetos e log de eventos." + +#: ../SparkleShare/SparkleSetup.cs:545 +msgid "Adding projects to SparkleShare" +msgstr "Adicionando projetos ao SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:546 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Basta clicar neste botão quando você vê-la na web, e o projeto será " +"automaticamente adicionado automaticamente:" + +#: ../SparkleShare/SparkleSetup.cs:549 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"... Ou selecione 'Adicionar Projeto Hosted ...' no menu do ícone de " +"status para adicionar manualmente." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Configurações do SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:230 +msgid "No projects yet" +msgstr "Nenhum projeto ainda" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleStatusIcon.cs:240 +msgid "Add Hosted Project…" +msgstr "Adicionar Projeto Hospedado..." + +#: ../SparkleShare/SparkleStatusIcon.cs:264 +msgid "Open Recent Events" +msgstr "Abrir Eventos Recentes" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications Off" +msgstr "Desligar as notificações" + +#: ../SparkleShare/SparkleStatusIcon.cs:286 +msgid "Turn Notifications On" +msgstr "Ligar as notificações" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:313 +msgid "Quit" +msgstr "Sair" + + diff --git a/SparkleShare/Common/Translations/ru.po b/SparkleShare/Common/Translations/ru.po new file mode 100755 index 0000000..d4aeada --- /dev/null +++ b/SparkleShare/Common/Translations/ru.po @@ -0,0 +1,425 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Dmitry Golubkov , 2011. +# , 2011. +# Just a baka , 2011. +# Misha Shnurapet , 2011. +# Oleg Shmelyov , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-11-02 11:31+0000\n" +"Last-Translator: shnurapet \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/username/project" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" +"Бесплатный хостинг проектов и их совместной разработки, основанный на " +"системе контроля версий Mercurial и Git" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Бесплатные публичные Git репозитории с совместной разработкой" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/project/repository" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "Open source инфраструктура для размещения ваших open source проектов" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/project" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Бесплатный и простой интерфейс для вашего компьютера" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "The GNOME Project" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/path/to/project" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Всё под моим контролем" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "Мой личный сервер" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Добро пожаловать в SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Обновлено" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Синхронизация…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Синхронизация не завершена" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Копировать ссылку" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Копировать ссылку в буфер обмена" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Получить более раннюю версию" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Сделать копию более ранней версии в этой папке" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Выберите, чтобы скопировать эту версию" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Вывести информацию о версии программы." + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Показать это справочное сообщение" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, утилита совместной разработки и обмена." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Эта программа поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Эта программа является свободной, ее распространение разрешено " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "при соблюдении требований лицензии GNU GPLv3." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare автоматически синхронизирует Git-репозитории," + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "находящиеся в папке ~/SparkleShare, с их удалёнными ветвями." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Синтаксис: sparkleshare [start|stop|restart] [КЛЮЧ]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Синхронизировать папку SparkleShare с удаленными источниками." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Параметры:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "О программе" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Доступна более новая версия ({0})!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "У вас уже установлена самая последняя версия." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Проверка обновлений…" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "дддд, ММММ д, гггг" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "дддд, ММММ д" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "«{0}» добавлено" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "«{0}» перемещено" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "«{0}» изменено" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "«{0}» удалено" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "и ещё над {0}" +msgstr[1] "и ещё над {0}" +msgstr[2] "и ещё над {0}" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "совершено какое-то колдовство" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Недавние события" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Все папки" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Прежде чем мы сможем создать папку SparkleShare на этом компьютере, нам " +"нужно от вас немного информации." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Полное имя:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Эл. почта:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Следующий" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Где находится Ваш проект?" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Адрес" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "Удалённый путь" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Отменить" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "Добавить" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Добавить проект ‘{0}’…" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Это может занять некоторое время." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Не пора ли выпить кофе?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Завершить" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Что-то пошло не так" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Попробуйте снова..." + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "{0}’ был успешно добавлен" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Проект успешно добавлен!" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Получить доступ к файлам из своей папки SparkleShare." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Открыть папку" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "Что произойдёт дальше?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"SparkleShare создаёт специальную папку в вашей личной папке, которая будет " +"отслеживать ваши проекты." + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Пропустить обучение" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Продолжить" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Обмен файлами с другими" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Все файлы, добавленные в директорию Вашего проекта, автоматически " +"синхронизируются с сервером, также как и с Вашими коллегами по проекту." + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "Значок статуса здесь для помощи" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Он показывает статус процесса синхронизации и содержит ссылки на Ваши " +"проекты, а также лог событий." + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Добавление проектов в SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Просто нажмите эту кнопку, когда увидите её в сети, и проект будет добавлен " +"автоматически:" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"...или выберите «Добавить ведомый проект...» через меню в области " +"уведомлений, чтобы добавить проект вручную." + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "Добавить ведомый проект..." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Установка SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Ещё нет проектов" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "Открыть Недавние события" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Выключить уведомления" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Включить уведомления" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Выход" + + diff --git a/SparkleShare/Common/Translations/sk.po b/SparkleShare/Common/Translations/sk.po new file mode 100644 index 0000000..6913e9f --- /dev/null +++ b/SparkleShare/Common/Translations/sk.po @@ -0,0 +1,407 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Matej Moško , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sk\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Vitajte v Sparkleshare" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Aktualizované" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synchronizujem..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Nie všetko je synchronizované" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Skopíruj webový odkaz" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Skopíruj webový odkaz na tento súbor do schránky" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Vyber staršiu verziu" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Vytvor kópiu staršej verzie v tomto priečinku" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Vyber si verziu na skopírovanie" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Vytlačiť informácie o verzii" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Zobraziť tohto pomocníka" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, nástroj na spoluprácu a zdieľanie" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "" + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "" + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Prepínače:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "O SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Novšia verzia ({0}) je k dispozícii!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Používate najnovšiu verziu." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Kontrolujem aktualizácie" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Nedávne udalosti" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Všetky priečinky" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Celé meno:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Ďalej" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Zrušiť" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "Pridať" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Pridávam projekt '{0}' ..." + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Toto môže chvíľu trvať." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Ste si istý, že nie je čas na kávu?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Dokončiť" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Niečo sa nepodarilo" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Skúste znovu..." + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "\"{0}\" bol úspešne pridaný" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Projekt bol úspešne pridaný!" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Pristupovať k súborom zo SparkleShare priečinka." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Otvoriť priečinok" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "Čo sa deje ďalej?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Preskočiť výučbu" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Pokračovať" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Zdieľanie súborov s ostatnými" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "Ikona stavu je tu pre Vás" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Pridanie projektov do SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "Nastavenia SparkleShare" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Zatiaľ žiadne projekty" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Vypni upozornenia" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Zapni upozornenia" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Vypnúť" + + diff --git a/SparkleShare/Common/Translations/sl.po b/SparkleShare/Common/Translations/sl.po new file mode 100644 index 0000000..4c38401 --- /dev/null +++ b/SparkleShare/Common/Translations/sl.po @@ -0,0 +1,411 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sl\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Projekt GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Dobrodošli v SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Posodobljeno" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Sinhroniziram..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Sinhronizacija še ni dokončana" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopiraj spletno povezavo" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopiraj spletno povezavo do te datoteke v odložišče" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Pridobi starejšo različico" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Ustvari kopijo prejšnje različice v tej mapi" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Izberite za pridobitev kopije te različice" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Izpiši informacije o različici" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Prikaži to besedilo za pomoč" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, orodje za deljenje in sodelovanje." + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Ta programska oprema je na voljo BREZ GARANCIJE." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "To je prosta programska oprema in jo lahko redistribuirate " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" +"pod določenimi pogoji. Prosimo preberite licenco GNU GPLv3 za podrobnosti." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare avtomatsko sinhronizira Git repozitorije" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "~/SparkleShare mapi z njihovimi oddaljenimi izvori." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Uporaba: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Sinhroniziraj SparkleShare mapo z oddaljenimi repozitoriji." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Argumenti:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "O SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Novejša različica ({0}) je na voljo!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Uporabljate najnovejšo različico." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Preverjam za posodobitve..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Nedavni dogodki" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Vse mape" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Preden lahko ustvarimo SparkleShare mape na tem računalniku potrebujemo od " +"vas nekaj informacij." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Polno ime:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Email:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Naprej" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Prekliči" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "To lahko nekaj časa traja." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "A ste prepričani da ni čas za kavo?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Dokončaj" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Nekaj je šlo narobe" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' uspešno dodano" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Odpri mapo" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleShare Nastavitev" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Izključi obvestila" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Vključi obvestila" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Izhod" + + diff --git a/SparkleShare/Common/Translations/sort-potfiles b/SparkleShare/Common/Translations/sort-potfiles new file mode 100755 index 0000000..9f6f8a1 --- /dev/null +++ b/SparkleShare/Common/Translations/sort-potfiles @@ -0,0 +1,6 @@ +#!/bin/bash + +head -n 4 < POTFILES.in > POTFILES.in.tmp +grep -v "^[\\[#]" < POTFILES.in | sort >> POTFILES.in.tmp +mv POTFILES.in.tmp POTFILES.in + diff --git a/SparkleShare/Common/Translations/sr_RS.po b/SparkleShare/Common/Translations/sr_RS.po new file mode 100755 index 0000000..cc38f7f --- /dev/null +++ b/SparkleShare/Common/Translations/sr_RS.po @@ -0,0 +1,379 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Aleksandar Antoski , 2011. +# , 2011. +# Небојша Јаковљевић , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-04 12:45+0100\n" +"PO-Revision-Date: 2011-12-22 10:42+0000\n" +"Last-Translator: Aleksandar Antoski \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sr_RS\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Гиториус" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Пројекат ГНОМ" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:84 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:102 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Добродошли у СпарклШер!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:86 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:104 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Све је синхронизовано" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:113 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Синхронизација..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:125 +#: ../SparkleShare/SparkleStatusIcon.cs:118 +msgid "Not everything is synced" +msgstr "Није све синхронизовано" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:141 +msgid "Copy Web Link" +msgstr "Копирај веб линк" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:115 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:142 +msgid "Copy the web address of this file to the clipboard" +msgstr "Копирај веб адресу ове датотеке" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:174 +msgid "Get Earlier Version" +msgstr "Добави ранију верзију" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:149 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:175 +msgid "Make a copy of an earlier version in this folder" +msgstr "Направи копију раније верзије у овом директоријуму" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:162 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:188 +msgid "Select to get a copy of this version" +msgstr "Изабери да добавиш копију ове верзије" + +#: ../SparkleShare/Program.cs:50 +msgid "Print version information" +msgstr "Исписује информацију о верзији" + +#: ../SparkleShare/Program.cs:51 +msgid "Show this help text" +msgstr "Приказује овај текст помоћи" + +#: ../SparkleShare/Program.cs:83 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "СпарклШер, алатка за сарадњу и дељење." + +#: ../SparkleShare/Program.cs:84 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:86 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Овај програм долази БЕЗ ИКАКВЕ ГАРАНЦИЈЕ." + +#: ../SparkleShare/Program.cs:88 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Ово је слободан софтвер, и можете га редистрибуирати" + +#: ../SparkleShare/Program.cs:89 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "под одређеним условима. Молимо прочитајте ГНУ ОЈЛв3 за више детаља." + +#: ../SparkleShare/Program.cs:91 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "СпарклШер аутоматски синхронизује Гит ризнице у" + +#: ../SparkleShare/Program.cs:92 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "директоријуму ~/SparkleShare са њиховим удаљеним изворима." + +#: ../SparkleShare/Program.cs:94 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Употреба: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:95 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Синхронизуј СпарклШер директоријум са удаљеним ризницама." + +#: ../SparkleShare/Program.cs:97 +msgid "Arguments:" +msgstr "Аргументи:" + +#: ../SparkleShare/Program.cs:107 +msgid "SparkleShare " +msgstr "СпарклШер" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:297 +msgid "About SparkleShare" +msgstr "О СпарклШеру" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "Новија верзија ({0}) је доступна!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Кориситите последњу верзију." + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:110 +msgid "Checking for updates..." +msgstr "Проверавам освежења..." + +#: ../SparkleShare/SparkleControllerBase.cs:489 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:495 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:56 +msgid "Recent Events" +msgstr "Скорашњи догађаји" + +#: ../SparkleShare/SparkleEventLog.cs:145 +#: ../SparkleShare/SparkleEventLog.cs:164 +msgid "All Folders" +msgstr "Сви директоријуми" + +#: ../SparkleShare/SparkleOptions.cs:486 +msgid "OptionName" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Пуно име:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Е-пошта:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Даље" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:266 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:286 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:300 ../SparkleShare/SparkleSetup.cs:336 +msgid "Cancel" +msgstr "Одустани" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:307 +msgid "Add" +msgstr "Додајте" + +#: ../SparkleShare/SparkleSetup.cs:326 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Додавање пројекта ‘{0}’…" + +#: ../SparkleShare/SparkleSetup.cs:327 +msgid "This may take a while." +msgstr "Ово може да потраје." + +#: ../SparkleShare/SparkleSetup.cs:328 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Да ли сте сигурни да није време за кафу?" + +#: ../SparkleShare/SparkleSetup.cs:332 ../SparkleShare/SparkleSetup.cs:448 +#: ../SparkleShare/SparkleSetup.cs:558 +msgid "Finish" +msgstr "Заврши" + +#: ../SparkleShare/SparkleSetup.cs:365 +msgid "Something went wrong" +msgstr "Нешто је пошло наопако" + +#: ../SparkleShare/SparkleSetup.cs:413 +msgid "Try Again…" +msgstr "Покушајте поново..." + +#: ../SparkleShare/SparkleSetup.cs:432 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "‘{0}’ успешно додато" + +#: ../SparkleShare/SparkleSetup.cs:438 +msgid "Project successfully added!" +msgstr "Пројекат је успешно додат!" + +#: ../SparkleShare/SparkleSetup.cs:439 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:442 +msgid "Open Folder" +msgstr "Отвори директоријум" + +#: ../SparkleShare/SparkleSetup.cs:484 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:485 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:488 +msgid "Skip Tutorial" +msgstr "Прескочи туторијал" + +#: ../SparkleShare/SparkleSetup.cs:493 ../SparkleShare/SparkleSetup.cs:513 +#: ../SparkleShare/SparkleSetup.cs:531 +msgid "Continue" +msgstr "Настави" + +#: ../SparkleShare/SparkleSetup.cs:509 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:510 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:527 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:528 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:545 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:546 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:549 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "СпарклШер подешавања" + +#: ../SparkleShare/SparkleStatusIcon.cs:230 +msgid "No projects yet" +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleStatusIcon.cs:240 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:264 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications Off" +msgstr "Угаси обавештења" + +#: ../SparkleShare/SparkleStatusIcon.cs:286 +msgid "Turn Notifications On" +msgstr "Укључи обавештења" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:313 +msgid "Quit" +msgstr "Крај рада" + + diff --git a/SparkleShare/Common/Translations/stamp-it b/SparkleShare/Common/Translations/stamp-it new file mode 100644 index 0000000..e69de29 diff --git a/SparkleShare/Common/Translations/sv.po b/SparkleShare/Common/Translations/sv.po new file mode 100755 index 0000000..178d5c2 --- /dev/null +++ b/SparkleShare/Common/Translations/sv.po @@ -0,0 +1,424 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Håkan Sahlström , 2011. +# Jan Lindblom , 2011. +# , 2011. +# Robin Jakobsson , 2011. +# smygrokarn , 2011. +# , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-11-05 22:22+0000\n" +"Last-Translator: shlstrm \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sv\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/användare/projekt" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "Bitbucket" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "Gratis källkodslagring för Git och Mercurial" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "Gratis offentliga Git-arkiv med medarbetarehantering" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/projekt/arkiv" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "Infrastruktur för delning av öppen källkod-projekt" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/projekt" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "Ett gratis och enkelt gränssnitt för din dator" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GNOME-projektet" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/sökväg/till/projekt" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "Allting under min kontroll" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "På min egen server" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Välkommen till SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Aktuell" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Synkroniserar…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Allt har inte synkroniserats" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Kopiera webblänk" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Kopiera URL för denna fil till klippbordet" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Hämta tidigare version" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Gör en kopia av en tidigare version i denna katalog" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Välj för att få en kopia av den här versionen" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Skriv ut versionsinformation" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Visa denna hjälp-text" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare, ett verktyg för samarbete och delning" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Copyright (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Detta program kommer utan några som helst garantier." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Detta är fri programvara och du är välkommen att distribuera det " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "under vissa förhållanden. Vänligen läs GNU GPL v3 för detaljer." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare synkroniserar automatiskt Git-källor i " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "katalogen ~/SparkleShare med deras fjärrkällor." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Användning: sparkleshare [start|stop|restart] [VÄXEL]" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Synkronisera SparkleShare-mappen med fjärrkällor." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Argument:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Om SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "En nyare version ({0}) är tillgänglig!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "Du kör den senaste versionen" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "Söker efter uppdateringar..." + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "lade till ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "flyttade ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "ändrade ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "raderade ‘{0}’" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "och {0} till" +msgstr[1] "och {0} fler" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "gjorde någonting magiskt" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "Senaste händelser" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "Alla kataloger" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Innan vi kan skapa en SparkleShare-katalog på den här datorn så behöver vi " +"lite information från dig." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "För- och efternamn:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "E-postadress:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Nästa" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "Var är ditt projekt lagrat?" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "Adress" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "Fjärrsökväg" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Avbryt" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "Lägg till" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "Lägger till projektet ‘{0}’…" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "Det här kan ta en stund." + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "Är du säker på att det inte är fikadags?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Slutför" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "Något blev fel" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "Försök igen..." + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}' har lagts till korrekt" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "Projektet har lagts till!" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "Kom åt filer i din SparkleShare-mapp." + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Öppna katalog" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "Vad händer nu?" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" +"SparkleShare skapar en särskild katalog i din hemmapp som håller reda på " +"dina projekt." + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "Hoppa över handledning" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "Fortsätt" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "Delar filer med andra" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" +"Alla filer som läggs till i dina projektmappar synkas automatiskt med " +"servern och med dina medarbetare." + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "Statusikonen är här för att hjälpa till" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" +"Den visar status för synkronisering och länkar till dina projekt och " +"händelseloggen." + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "Lägga till projekt till SparkleShare" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" +"Klicka på den här knappen när du ser den på webben och projektet läggs till " +"automatiskt:" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" +"...eller välj ‘Lägg till Projekt…’ i statusmenyn för att lägga till " +"ett projekt manuellt." + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "Lägg till delat projekt..." + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleShare-inställningar" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "Inga projekt ännu" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "Öppna senaste händelser" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Stäng av notifieringar" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Sätt på notifieringar" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Avsluta" + + diff --git a/SparkleShare/Common/Translations/te.po b/SparkleShare/Common/Translations/te.po new file mode 100755 index 0000000..d3c04c8 --- /dev/null +++ b/SparkleShare/Common/Translations/te.po @@ -0,0 +1,405 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: te\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "స్పార్కిల్‌షేర్‌కి స్వాగతం!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "" + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "" + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "" + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "" + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "సంచయాన్ని తెరువు" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "చాలించు" + + diff --git a/SparkleShare/Common/Translations/uk.po b/SparkleShare/Common/Translations/uk.po new file mode 100755 index 0000000..93afa18 --- /dev/null +++ b/SparkleShare/Common/Translations/uk.po @@ -0,0 +1,409 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# Сергій Гаврилов , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: uk\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "Проект GNOME" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "Ласкаво просимо до SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "Оновлено" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "Синхронізація..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "Ще не все синхронізовано" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "Копіювати веб-посилання" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "Скопіювати веб-адресу цього файла до буферу" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "Отримати старішу версію" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "Створити копію старішої версії в цій теці" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "Вибрати та отримати копію цієї версії" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "Вивести дані про версію" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "Показати текст цієї довідки" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "Авторське право (C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "Ця програма розповсюджується БЕЗ ВСЯКОЇ ГАРАНТІЇ." + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "Це вільна програма і ви можете поширювати її " + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "за певних умов. Детальніше читайте ліцензію GNU GPLv3." + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare автоматично синхронізує сховища Git в " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "теці ~/SparkleShare з її віддаленими походженнями." + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "Використання: sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "Синхронізація теки SparkleShare з віддаленими сховищами." + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "Аргументи:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "Про SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "" +"Щоб створити теку SparkleShare на цьому комп'ютері, потрібна деяка " +"інформація про вас." + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "Повне ім'я:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "Ел. адреса:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "Далі" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "Скасувати" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "А чи не здається вам, що настав час для кави?" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "Завершити" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "‘{0}’ успішно додано" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "Відкрити теку" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "Вимкнути сповіщення" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "Увімкнути сповіщення" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "Вийти" + + diff --git a/SparkleShare/Common/Translations/zh_CN.po b/SparkleShare/Common/Translations/zh_CN.po new file mode 100755 index 0000000..acbdc6e --- /dev/null +++ b/SparkleShare/Common/Translations/zh_CN.po @@ -0,0 +1,378 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +# , 2011. +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-04 12:45+0100\n" +"PO-Revision-Date: 2011-12-08 07:18+0000\n" +"Last-Translator: focusheart \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "/username/project" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "小桶" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "免费的Git与Mercurial代码托管" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "具备协作管理的免费开放仓库" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "Github" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "/project/repository" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "托管开源项目的开源架构" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "/project" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "为你的计算机提供一个免费并且简单的接口" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GMOME项目" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "/path/to/project" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "一切尽在你的掌控" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "拥有你自己的服务器" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:84 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:102 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "欢迎使用 SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:86 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:104 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "保持最新" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:113 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "同步中..." + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:125 +#: ../SparkleShare/SparkleStatusIcon.cs:118 +msgid "Not everything is synced" +msgstr "尚有内容未同步" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:141 +msgid "Copy Web Link" +msgstr "复制Web链接" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:115 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:142 +msgid "Copy the web address of this file to the clipboard" +msgstr "复制该文件的Web地址到剪贴板" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:174 +msgid "Get Earlier Version" +msgstr "获取较早的版本" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:149 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:175 +msgid "Make a copy of an earlier version in this folder" +msgstr "在本目录中制作一个较早的版本" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:162 +#: ../SparkleShare/Nautilus/sparkleshare-nautilus3-extension.py.in:188 +msgid "Select to get a copy of this version" +msgstr "获取该版本的复制" + +#: ../SparkleShare/Program.cs:50 +msgid "Print version information" +msgstr "打印版本信息" + +#: ../SparkleShare/Program.cs:51 +msgid "Show this help text" +msgstr "显示当前帮助文字" + +#: ../SparkleShare/Program.cs:83 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "SparkleShare,协作与分享的工具" + +#: ../SparkleShare/Program.cs:84 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "版权(C) 2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:86 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "本程序不提供任何质量保证" + +#: ../SparkleShare/Program.cs:88 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "这是自由软件,欢迎您再次分发。" + +#: ../SparkleShare/Program.cs:89 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "在某种条件下。详情请参见 GNU GPLv3。" + +#: ../SparkleShare/Program.cs:91 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare 自动同步Git仓库" + +#: ../SparkleShare/Program.cs:92 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "~/SparkleShare 目录与远程所有" + +#: ../SparkleShare/Program.cs:94 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "用法:sparkleshare [start|stop|restart] [OPTION]..." + +#: ../SparkleShare/Program.cs:95 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "与远程仓库同步SparkleShare " + +#: ../SparkleShare/Program.cs:97 +msgid "Arguments:" +msgstr "参数:" + +#: ../SparkleShare/Program.cs:107 +msgid "SparkleShare " +msgstr "SparkleShare" + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:297 +msgid "About SparkleShare" +msgstr "关于 SparkleShare" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "有新版本({0})了!" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "你所使用的是最新版本" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:110 +msgid "Checking for updates..." +msgstr "正在检查更新..." + +#: ../SparkleShare/SparkleControllerBase.cs:489 +msgid "dddd, MMMM d, yyyy" +msgstr "dddd,MMMM d, yyyy" + +#: ../SparkleShare/SparkleControllerBase.cs:495 +msgid "dddd, MMMM d" +msgstr "ddd, MMMM d" + +#: ../SparkleShare/SparkleEventLog.cs:56 +msgid "Recent Events" +msgstr "最近事件" + +#: ../SparkleShare/SparkleEventLog.cs:145 +#: ../SparkleShare/SparkleEventLog.cs:164 +msgid "All Folders" +msgstr "所有目录" + +#: ../SparkleShare/SparkleOptions.cs:486 +msgid "OptionName" +msgstr "选项名称" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "全名:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "电子邮件" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "下一步" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "你的项目托管在哪里?" + +#: ../SparkleShare/SparkleSetup.cs:266 +msgid "Address" +msgstr "地址" + +#: ../SparkleShare/SparkleSetup.cs:286 +msgid "Remote Path" +msgstr "远程路径" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:300 ../SparkleShare/SparkleSetup.cs:336 +msgid "Cancel" +msgstr "取消" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:307 +msgid "Add" +msgstr "添加" + +#: ../SparkleShare/SparkleSetup.cs:326 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "添加项目'{0}'..." + +#: ../SparkleShare/SparkleSetup.cs:327 +msgid "This may take a while." +msgstr "这可能要花一点时间。" + +#: ../SparkleShare/SparkleSetup.cs:328 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "你不觉得现在是休息时间么?" + +#: ../SparkleShare/SparkleSetup.cs:332 ../SparkleShare/SparkleSetup.cs:448 +#: ../SparkleShare/SparkleSetup.cs:558 +msgid "Finish" +msgstr "完成" + +#: ../SparkleShare/SparkleSetup.cs:365 +msgid "Something went wrong" +msgstr "好像有什么问题" + +#: ../SparkleShare/SparkleSetup.cs:413 +msgid "Try Again…" +msgstr "再试试看..." + +#: ../SparkleShare/SparkleSetup.cs:432 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "'{0}'被成功添加" + +#: ../SparkleShare/SparkleSetup.cs:438 +msgid "Project successfully added!" +msgstr "项目成功添加!" + +#: ../SparkleShare/SparkleSetup.cs:439 +msgid "Access the files from your SparkleShare folder." +msgstr "从你的SparkleShare目录访问这些文件。" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:442 +msgid "Open Folder" +msgstr "打开文件夹" + +#: ../SparkleShare/SparkleSetup.cs:484 +msgid "What's happening next?" +msgstr "下来做什么?" + +#: ../SparkleShare/SparkleSetup.cs:485 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "SparkleShare在你的个人文件夹中创建了一个特别的文件夹用以保持跟踪你的项目。" + +#: ../SparkleShare/SparkleSetup.cs:488 +msgid "Skip Tutorial" +msgstr "跳过教程" + +#: ../SparkleShare/SparkleSetup.cs:493 ../SparkleShare/SparkleSetup.cs:513 +#: ../SparkleShare/SparkleSetup.cs:531 +msgid "Continue" +msgstr "继续" + +#: ../SparkleShare/SparkleSetup.cs:509 +msgid "Sharing files with others" +msgstr "与他人分享文件" + +#: ../SparkleShare/SparkleSetup.cs:510 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "所有添加到你的项目中的文件都将与服务器自动同步,你的所有协作伙伴们也是如此。" + +#: ../SparkleShare/SparkleSetup.cs:527 +msgid "The status icon is here to help" +msgstr "状态图标可以提供帮助" + +#: ../SparkleShare/SparkleSetup.cs:528 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "此处显示同步进度状态,并且包含了到你的项目和事件日志的链接。" + +#: ../SparkleShare/SparkleSetup.cs:545 +msgid "Adding projects to SparkleShare" +msgstr "向SparkleShare添加项目" + +#: ../SparkleShare/SparkleSetup.cs:546 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "在网页上看到这个按钮的时候即可点击,项目会被自动添加进去;" + +#: ../SparkleShare/SparkleSetup.cs:549 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "...或者从状态图标菜单中选择 '添加已托管的项目...'来手工添加。" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "SparkleShare " + +#: ../SparkleShare/SparkleStatusIcon.cs:230 +msgid "No projects yet" +msgstr "尚无项目" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleStatusIcon.cs:240 +msgid "Add Hosted Project…" +msgstr "添加已托管的项目" + +#: ../SparkleShare/SparkleStatusIcon.cs:264 +msgid "Open Recent Events" +msgstr "打开最近的活动" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications Off" +msgstr "关闭通知" + +#: ../SparkleShare/SparkleStatusIcon.cs:286 +msgid "Turn Notifications On" +msgstr "打开通知" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:313 +msgid "Quit" +msgstr "退出" + + diff --git a/SparkleShare/Common/Translations/zh_TW.po b/SparkleShare/Common/Translations/zh_TW.po new file mode 100755 index 0000000..87944c2 --- /dev/null +++ b/SparkleShare/Common/Translations/zh_TW.po @@ -0,0 +1,404 @@ +# This file is distributed under the same license as the SparkleShare package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: SparkleShare\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-30 15:50+0100\n" +"PO-Revision-Date: 2011-10-30 14:50+0000\n" +"Last-Translator: deejay1 \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_TW\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#: ../data/plugins/bitbucket.xml.in.h:1 ../data/plugins/github.xml.in.h:1 +msgid "/username/project" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:2 +msgid "Bitbucket" +msgstr "" + +#: ../data/plugins/bitbucket.xml.in.h:3 +msgid "Free code hosting for Git and Mercurial" +msgstr "" + +#: ../data/plugins/github.xml.in.h:2 +msgid "Free public Git repositories with collaborator management" +msgstr "" + +#: ../data/plugins/github.xml.in.h:3 +msgid "Github" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:1 +msgid "/project/repository" +msgstr "" + +#: ../data/plugins/gitorious.xml.in.h:2 +msgid "Gitorious" +msgstr "Gitorious" + +#: ../data/plugins/gitorious.xml.in.h:3 +msgid "Open source infrastructure for hosting open source projects" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:1 +msgid "/project" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:2 +msgid "A free and easy interface for your computer" +msgstr "" + +#: ../data/plugins/gnome.xml.in.h:3 +msgid "The GNOME Project" +msgstr "GNOME 專案" + +#: ../data/plugins/own-server.xml.in.h:1 +msgid "/path/to/project" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:2 +msgid "Everything under my control" +msgstr "" + +#: ../data/plugins/own-server.xml.in.h:3 +msgid "On my own server" +msgstr "" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:70 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:88 +#: ../SparkleShare/SparkleSetup.cs:75 ../SparkleShare/SparkleStatusIcon.cs:75 +#: ../SparkleShare/SparkleStatusIcon.cs:89 +msgid "Welcome to SparkleShare!" +msgstr "歡迎使用 SparkleShare!" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:72 +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:90 +#: ../SparkleShare/SparkleStatusIcon.cs:77 +#: ../SparkleShare/SparkleStatusIcon.cs:91 +msgid "Up to date" +msgstr "更新" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:99 +#: ../SparkleShare/SparkleStatusIcon.cs:106 +msgid "Syncing…" +msgstr "同步中…" + +#: ../SparkleShare/Mac/SparkleStatusIcon.cs:109 +#: ../SparkleShare/SparkleStatusIcon.cs:116 +msgid "Not everything is synced" +msgstr "" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:113 +msgid "Copy Web Link" +msgstr "複製網頁鏈結" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:114 +msgid "Copy the web address of this file to the clipboard" +msgstr "複製該檔案的網址到剪貼簿" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:147 +msgid "Get Earlier Version" +msgstr "取得較早的版本" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:148 +msgid "Make a copy of an earlier version in this folder" +msgstr "在本資料夾中製作一個較早的版本" + +#: ../SparkleShare/Nautilus/sparkleshare-nautilus-extension.py.in:161 +msgid "Select to get a copy of this version" +msgstr "選擇以取得該版本的複本" + +#: ../SparkleShare/Program.cs:51 +msgid "Print version information" +msgstr "列印版本資訊" + +#: ../SparkleShare/Program.cs:52 +msgid "Show this help text" +msgstr "顯示這份說明文字" + +#: ../SparkleShare/Program.cs:84 +msgid "SparkleShare, a collaboration and sharing tool." +msgstr "" + +#: ../SparkleShare/Program.cs:85 +msgid "Copyright (C) 2010 Hylke Bons" +msgstr "著作權©2010 Hylke Bons" + +#: ../SparkleShare/Program.cs:87 +msgid "This program comes with ABSOLUTELY NO WARRANTY." +msgstr "本程式不提供任何擔保" + +#: ../SparkleShare/Program.cs:89 +msgid "This is free software, and you are welcome to redistribute it " +msgstr "這是自由軟體,歡迎您在某些條件之下" + +#: ../SparkleShare/Program.cs:90 +msgid "under certain conditions. Please read the GNU GPLv3 for details." +msgstr "繼續散布它。詳情請參見 GNU GPLv3。" + +#: ../SparkleShare/Program.cs:92 +msgid "SparkleShare automatically syncs Git repositories in " +msgstr "SparkleShare 自動同步 Git 儲存庫於 " + +#: ../SparkleShare/Program.cs:93 +msgid "the ~/SparkleShare folder with their remote origins." +msgstr "~/SparkleShare 資料夾與它們的遠端來源。" + +#: ../SparkleShare/Program.cs:95 +msgid "Usage: sparkleshare [start|stop|restart] [OPTION]..." +msgstr "用法:sparkleshare [start|stop|restart] [選項]…" + +#: ../SparkleShare/Program.cs:96 +msgid "Sync SparkleShare folder with remote repositories." +msgstr "同步 SparkleShare 資料夾與遠端儲存庫。" + +#: ../SparkleShare/Program.cs:98 +msgid "Arguments:" +msgstr "引數:" + +#: ../SparkleShare/Program.cs:108 +msgid "SparkleShare " +msgstr "SparkleShare " + +#. A menu item that takes the user to http://www.sparkleshare.org/ +#: ../SparkleShare/SparkleAbout.cs:53 ../SparkleShare/SparkleStatusIcon.cs:295 +msgid "About SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:70 +#, csharp-format +msgid "A newer version ({0}) is available!" +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:79 +msgid "You are running the latest version." +msgstr "" + +#: ../SparkleShare/SparkleAbout.cs:88 ../SparkleShare/SparkleAbout.cs:113 +msgid "Checking for updates..." +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:493 +msgid "dddd, MMMM d, yyyy" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:499 +msgid "dddd, MMMM d" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:707 +#, csharp-format +msgid "added ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:712 +#, csharp-format +msgid "moved ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:717 +#, csharp-format +msgid "edited ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:722 +#, csharp-format +msgid "deleted ‘{0}’" +msgstr "" + +#: ../SparkleShare/SparkleControllerBase.cs:731 +#, csharp-format +msgid "and {0} more" +msgid_plural "and {0} more" +msgstr[0] "" + +#: ../SparkleShare/SparkleControllerBase.cs:735 +msgid "did something magical" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:58 +msgid "Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleEventLog.cs:169 +#: ../SparkleShare/SparkleEventLog.cs:188 +msgid "All Folders" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:76 +msgid "" +"Before we can create a SparkleShare folder on this computer, we need a few " +"bits of information from you." +msgstr "我們在這臺電腦中可以建立 SparkleShare 資料夾之前,我們需要您的幾點資訊。" + +#: ../SparkleShare/SparkleSetup.cs:83 +msgid "Full Name:" +msgstr "全名:" + +#: ../SparkleShare/SparkleSetup.cs:98 +msgid "Email:" +msgstr "電子郵件:" + +#: ../SparkleShare/SparkleSetup.cs:108 +msgid "Next" +msgstr "下一步" + +#: ../SparkleShare/SparkleSetup.cs:129 +msgid "Where's your project hosted?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:275 +msgid "Address" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:295 +msgid "Remote Path" +msgstr "" + +#. Cancel button +#: ../SparkleShare/SparkleSetup.cs:309 ../SparkleShare/SparkleSetup.cs:345 +msgid "Cancel" +msgstr "取消" + +#. Sync button +#: ../SparkleShare/SparkleSetup.cs:316 +msgid "Add" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:335 +#, csharp-format +msgid "Adding project ‘{0}’…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:336 +msgid "This may take a while." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:337 +msgid "Are you sure it’s not coffee o'clock?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:341 ../SparkleShare/SparkleSetup.cs:457 +#: ../SparkleShare/SparkleSetup.cs:556 +msgid "Finish" +msgstr "完成" + +#: ../SparkleShare/SparkleSetup.cs:374 +msgid "Something went wrong" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:422 +msgid "Try Again…" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:441 +#, csharp-format +msgid "‘{0}’ has been successfully added" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:447 +msgid "Project successfully added!" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:448 +msgid "Access the files from your SparkleShare folder." +msgstr "" + +#. A button that opens the synced folder +#: ../SparkleShare/SparkleSetup.cs:451 +msgid "Open Folder" +msgstr "開啟資料夾" + +#: ../SparkleShare/SparkleSetup.cs:477 +msgid "What's happening next?" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:478 +msgid "" +"SparkleShare creates a special folder in your personal folder that will keep" +" track of your projects." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:481 +msgid "Skip Tutorial" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:486 ../SparkleShare/SparkleSetup.cs:506 +#: ../SparkleShare/SparkleSetup.cs:524 +msgid "Continue" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:502 +msgid "Sharing files with others" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:503 +msgid "" +"All files added to your project folders are synced with the host " +"automatically, as well as with your collaborators." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:520 +msgid "The status icon is here to help" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:521 +msgid "" +"It shows the syncing process status, and contains links to your projects and" +" the event log." +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:538 +msgid "Adding projects to SparkleShare" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:539 +msgid "" +"Just click this button when you see it on the web, and the project will be " +"automatically added:" +msgstr "" + +#: ../SparkleShare/SparkleSetup.cs:542 +msgid "" +"…or select ‘Add Hosted Project…’ from the status icon menu to add one" +" by hand." +msgstr "" + +#. Opens the wizard to add a new remote folder +#: ../SparkleShare/SparkleSetup.cs:551 +#: ../SparkleShare/SparkleStatusIcon.cs:238 +msgid "Add Hosted Project…" +msgstr "" + +#: ../SparkleShare/SparkleSetupWindow.cs:44 +msgid "SparkleShare Setup" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:228 +msgid "No projects yet" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:262 +msgid "Open Recent Events" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:282 +msgid "Turn Notifications Off" +msgstr "" + +#: ../SparkleShare/SparkleStatusIcon.cs:284 +msgid "Turn Notifications On" +msgstr "" + +#. A menu item that quits the application +#: ../SparkleShare/SparkleStatusIcon.cs:311 +msgid "Quit" +msgstr "離開" + + diff --git a/SparkleShare/Linux/Makefile.am b/SparkleShare/Linux/Makefile.am new file mode 100644 index 0000000..b54a392 --- /dev/null +++ b/SparkleShare/Linux/Makefile.am @@ -0,0 +1,47 @@ +SUBDIRS = Pixmaps + +ASSEMBLY = SparkleShare +TARGET = exe + +LINK = $(REF_SPARKLESHARE) $(NOTIFY_SHARP_LIBS) $(WEBKITGTK_SHARP_LIBS) + +if HAVE_APP_INDICATOR +BUILD_DEFINES="-define:HAVE_APP_INDICATOR" +endif + +SOURCES = \ + ../Program.cs \ + ../SparkleAboutController.cs \ + ../SparkleAvatars.cs \ + ../SparkleBubblesController.cs \ + ../SparkleControllerBase.cs \ + ../SparkleEventLogController.cs \ + ../SparkleExtensions.cs \ + ../SparkleInvite.cs \ + ../SparkleKeys.cs \ + ../SparkleNoteController.cs \ + ../SparklePlugin.cs \ + ../SparkleSetupController.cs \ + ../SparkleStatusIconController.cs \ + SparkleAbout.cs \ + SparkleBubbles.cs \ + SparkleController.cs \ + SparkleEventLog.cs \ + SparkleNote.cs \ + SparkleSetup.cs \ + SparkleSetupWindow.cs \ + SparkleStatusIcon.cs \ + SparkleUI.cs \ + SparkleUIHelpers.cs + +include $(top_srcdir)/build/build.mk + +bin_SCRIPTS = sparkleshare + +Applicationsdir = $(datadir)/applications +dist_Applications_DATA = sparkleshare.desktop \ + sparkleshare-invite-opener.desktop + +install-data-hook: + test -f $(datadir)/applications/defaults.list && \ + test -z $(DESTDIR) && update-desktop-database $(datadir)/applications || : diff --git a/SparkleShare/Linux/Pixmaps/Makefile.am b/SparkleShare/Linux/Pixmaps/Makefile.am new file mode 100755 index 0000000..91e7038 --- /dev/null +++ b/SparkleShare/Linux/Pixmaps/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS = icons + +dist_pixmaps_DATA = \ + tutorial-slide-3.png + +pixmapsdir = $(pkgdatadir)/pixmaps/ + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/SparkleShare/Linux/Pixmaps/icons/Makefile.am b/SparkleShare/Linux/Pixmaps/icons/Makefile.am new file mode 100755 index 0000000..9d4fca7 --- /dev/null +++ b/SparkleShare/Linux/Pixmaps/icons/Makefile.am @@ -0,0 +1,48 @@ +SUBDIRS = ubuntu-mono-dark \ + ubuntu-mono-light\ + gnome + +theme = hicolor +system_themedir = $(datadir)/icons/$(theme) +app_themedir = $(pkgdatadir)/icons/$(theme) + +system_theme_icons = \ + apps,sparkleshare-16.png \ + apps,sparkleshare-22.png \ + apps,sparkleshare-24.png \ + apps,sparkleshare-256.png \ + apps,sparkleshare-32.png \ + apps,sparkleshare-48.png \ + status,process-syncing-up-24.png \ + status,process-syncing-down-24.png \ + status,process-syncing-24.png \ + status,process-syncing-error-24.png \ + status,process-syncing-up-48.png \ + status,process-syncing-down-48.png \ + status,process-syncing-48.png \ + status,process-syncing-error-48.png + +app_theme_icons = \ + status,document-added-12.png \ + status,document-edited-12.png \ + status,document-deleted-12.png \ + status,document-moved-12.png \ + status,list-point-16.png + +install_icon_exec = $(top_srcdir)/build/icon-theme-installer \ + -t "$(theme)" \ + -s "$(srcdir)" \ + -d "x$(DESTDIR)" \ + -m "$(mkinstalldirs)" \ + -x "$(INSTALL_DATA)" + +install-data-local: + @-$(install_icon_exec) -i -b "$(system_themedir)" $(system_theme_icons) + @-$(install_icon_exec) -i -b "$(app_themedir)" $(app_theme_icons) + +uninstall-hook: + @-$(install_icon_exec) -u -b "$(system_themedir)" $(system_theme_icons) + @-$(install_icon_exec) -u -b "$(app_themedir)" $(app_theme_icons) + +MAINTAINERCLEANFILES = Makefile.in +EXTRA_DIST = $(wildcard *.png *.svg) diff --git a/SparkleShare/Linux/Pixmaps/icons/document-added-12.png b/SparkleShare/Linux/Pixmaps/icons/document-added-12.png new file mode 100755 index 0000000..7c4c1bd Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/document-added-12.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/document-deleted-12.png b/SparkleShare/Linux/Pixmaps/icons/document-deleted-12.png new file mode 100755 index 0000000..06f4291 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/document-deleted-12.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/document-edited-12.png b/SparkleShare/Linux/Pixmaps/icons/document-edited-12.png new file mode 100755 index 0000000..c8b8f66 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/document-edited-12.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/document-moved-12.png b/SparkleShare/Linux/Pixmaps/icons/document-moved-12.png new file mode 100755 index 0000000..9306514 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/document-moved-12.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/gnome/Makefile.am b/SparkleShare/Linux/Pixmaps/icons/gnome/Makefile.am new file mode 100644 index 0000000..89edffb --- /dev/null +++ b/SparkleShare/Linux/Pixmaps/icons/gnome/Makefile.am @@ -0,0 +1,20 @@ +gnome_theme = gnome +gnome_themedir = /usr/share/icons/$(gnome_theme) + +gnome_theme_icons = apps,sparkleshare-symbolic.svg + +install_icon_exec = $(top_srcdir)/build/icon-theme-installer \ + -t "$(gnome_theme)" \ + -s "$(srcdir)" \ + -d "x$(DESTDIR)" \ + -m "$(mkinstalldirs)" \ + -x "$(INSTALL_DATA)" + +install-data-local: + @-$(install_icon_exec) -i -b "$(gnome_themedir)" $(gnome_theme_icons) + +uninstall-hook: + @-$(install_icon_exec) -u -b "$(gnome_themedir)" $(gnome_theme_icons) + +MAINTAINERCLEANFILES = Makefile.in +EXTRA_DIST = $(wildcard *.png *.svg) diff --git a/SparkleShare/Linux/Pixmaps/icons/gnome/sparkleshare-symbolic.svg b/SparkleShare/Linux/Pixmaps/icons/gnome/sparkleshare-symbolic.svg new file mode 100644 index 0000000..cf8b194 --- /dev/null +++ b/SparkleShare/Linux/Pixmaps/icons/gnome/sparkleshare-symbolic.svg @@ -0,0 +1,17 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + diff --git a/SparkleShare/Linux/Pixmaps/icons/list-point-16.png b/SparkleShare/Linux/Pixmaps/icons/list-point-16.png new file mode 100755 index 0000000..fa89d31 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/list-point-16.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-24.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-24.png new file mode 100644 index 0000000..55b836b Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-48.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-48.png new file mode 100644 index 0000000..46aef6a Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-48.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-down-24.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-down-24.png new file mode 100644 index 0000000..384e259 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-down-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-down-48.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-down-48.png new file mode 100644 index 0000000..8edbea1 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-down-48.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-error-24.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-error-24.png new file mode 100755 index 0000000..6e54ce4 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-error-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-error-48.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-error-48.png new file mode 100644 index 0000000..95e6b5a Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-error-48.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-up-24.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-up-24.png new file mode 100644 index 0000000..955cd6c Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-up-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-syncing-up-48.png b/SparkleShare/Linux/Pixmaps/icons/process-syncing-up-48.png new file mode 100644 index 0000000..95eeb03 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-syncing-up-48.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/process-working-22.png b/SparkleShare/Linux/Pixmaps/icons/process-working-22.png new file mode 100644 index 0000000..1b90a03 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/process-working-22.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/sparkleshare-16.png b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-16.png new file mode 100755 index 0000000..b344e26 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-16.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/sparkleshare-22.png b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-22.png new file mode 100755 index 0000000..a8264ed Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-22.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/sparkleshare-24.png b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-24.png new file mode 100755 index 0000000..b8d8c34 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/sparkleshare-256.png b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-256.png new file mode 100755 index 0000000..5f400dc Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-256.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/sparkleshare-32.png b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-32.png new file mode 100755 index 0000000..9280fd8 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-32.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/sparkleshare-48.png b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-48.png new file mode 100755 index 0000000..28a3d41 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/sparkleshare-48.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/Makefile.am b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/Makefile.am new file mode 100644 index 0000000..48bc9ee --- /dev/null +++ b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/Makefile.am @@ -0,0 +1,25 @@ +dark_theme = ubuntu-mono-dark +dark_themedir = /usr/share/icons/$(dark_theme) + +dark_theme_icons = \ + status,process-syncing-idle-24.png \ + status,process-syncing-up-24.png \ + status,process-syncing-down-24.png \ + status,process-syncing-24.png \ + status,process-syncing-error-24.png + +install_icon_exec = $(top_srcdir)/build/icon-theme-installer \ + -t "$(dark_theme)" \ + -s "$(srcdir)" \ + -d "x$(DESTDIR)" \ + -m "$(mkinstalldirs)" \ + -x "$(INSTALL_DATA)" + +install-data-local: + @-$(install_icon_exec) -i -b "$(dark_themedir)" $(dark_theme_icons) + +uninstall-hook: + @-$(install_icon_exec) -u -b "$(dark_themedir)" $(dark_theme_icons) + +MAINTAINERCLEANFILES = Makefile.in +EXTRA_DIST = $(wildcard *.png *.svg) diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-24.png new file mode 100644 index 0000000..3cb78b5 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-down-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-down-24.png new file mode 100644 index 0000000..6a00865 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-down-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-error-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-error-24.png new file mode 100644 index 0000000..cfe5261 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-error-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-idle-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-idle-24.png new file mode 100644 index 0000000..32da58b Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-idle-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-up-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-up-24.png new file mode 100644 index 0000000..6f129a6 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-dark/process-syncing-up-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/Makefile.am b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/Makefile.am new file mode 100644 index 0000000..a4e77c8 --- /dev/null +++ b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/Makefile.am @@ -0,0 +1,25 @@ +light_theme = ubuntu-mono-light +light_themedir = /usr/share/icons/$(light_theme) + +light_theme_icons = \ + status,process-syncing-idle-24.png \ + status,process-syncing-up-24.png \ + status,process-syncing-down-24.png \ + status,process-syncing-24.png \ + status,process-syncing-error-24.png + +install_icon_exec = $(top_srcdir)/build/icon-theme-installer \ + -t "$(light_theme)" \ + -s "$(srcdir)" \ + -d "x$(DESTDIR)" \ + -m "$(mkinstalldirs)" \ + -x "$(INSTALL_DATA)" + +install-data-local: + @-$(install_icon_exec) -i -b "$(light_themedir)" $(light_theme_icons) + +uninstall-hook: + @-$(install_icon_exec) -u -b "$(light_themedir)" $(light_theme_icons) + +MAINTAINERCLEANFILES = Makefile.in +EXTRA_DIST = $(wildcard *.png *.svg) diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-24.png new file mode 100644 index 0000000..59df796 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-down-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-down-24.png new file mode 100644 index 0000000..141243b Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-down-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-error-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-error-24.png new file mode 100644 index 0000000..1f2dab5 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-error-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-idle-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-idle-24.png new file mode 100644 index 0000000..b0fa246 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-idle-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-up-24.png b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-up-24.png new file mode 100644 index 0000000..79d5084 Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/icons/ubuntu-mono-light/process-syncing-up-24.png differ diff --git a/SparkleShare/Linux/Pixmaps/tutorial-slide-3.png b/SparkleShare/Linux/Pixmaps/tutorial-slide-3.png new file mode 100755 index 0000000..f3206ee Binary files /dev/null and b/SparkleShare/Linux/Pixmaps/tutorial-slide-3.png differ diff --git a/SparkleShare/Linux/README.md b/SparkleShare/Linux/README.md new file mode 100644 index 0000000..f98459c --- /dev/null +++ b/SparkleShare/Linux/README.md @@ -0,0 +1,93 @@ +## Building on Linux distributions + +You can choose to build SparkleShare from source or to get the package through your distribution's repositories. +To run SparkleShare, you'll need the following packages: + +**Note:** Git 1.9 changed the way local projects without a history are handled, and may cause protocol errors. Until a solution is found, it's recommended to use Git 1.8. + +``` +git 1.8.x +gtk-sharp3 +mono-core >= 2.8 +notify-sharp +webkitgtk-sharp +``` + +**Note:** These packages may not overlap with the packages required to perform a build, so please make sure that at least the above packages are installed. + +Optional packages: + +``` +gvfs (to change file/folder icons) +libappindicator (for Ubuntu integration) +curl (to make the "sparkleshare://" protocol handler work) +``` + + +### Installing common build requirements + +You will need the packages listed below for the most used Linux distributions: + +``` +desktop-file-utils +intltool +libtool +mono-devel +mono-gmcs +mono-mcs +monodevelop +nant +``` + + +### Installing additional source build requirements + +Install the `gtk-sharp3` bindings from: +https://github.com/mono/gtk-sharp +Or on Ubuntu, get it from this PPA: +https://launchpad.net/~meebey/+archive/mono-preview + +Install the `notify-sharp` bindings from: +https://download.gnome.org/sources/notify-sharp/3.0/ + +Install the `soup-sharp` and `webkitgtk-sharp` bindings from: +https://github.com/xDarkice/soup-sharp +https://github.com/xDarkice/webkitgtk-sharp + +All with the usual: + +``` +./autogen.sh +make +sudo make install +``` + +If you're using Ubuntu, also install the `appindicator-sharp` bindings from: +https://github.com/xDarkice/appindicator-sharp + + + +### Starting the build + +You can build and install SparkleShare like this: + +```bash +$ ./configure (or ./autogen.sh if you build from the repository) +$ make +$ sudo make install +``` + + +### Resetting SparkleShare settings + +``` +rm -Rf ~/SparkleShare +rm -Rf ~/.config/sparkleshare +``` + + +### Uninstalling + +``` +sudo make uninstall +``` diff --git a/SparkleShare/Linux/SparkleAbout.cs b/SparkleShare/Linux/SparkleAbout.cs new file mode 100755 index 0000000..cc15b4d --- /dev/null +++ b/SparkleShare/Linux/SparkleAbout.cs @@ -0,0 +1,182 @@ +// 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 Gtk; + +namespace SparkleShare { + + public class SparkleAbout : Window { + + public SparkleAboutController Controller = new SparkleAboutController (); + + private Label updates; + + + public SparkleAbout () : base ("About SparkleShare") + { + SetWmclass ("SparkleShare", "SparkleShare"); + + IconName = "sparkleshare"; + Resizable = false; + WindowPosition = WindowPosition.Center; + + SetSizeRequest (600, 260); + + + DeleteEvent += delegate (object o, DeleteEventArgs args) { + Controller.WindowClosed (); + args.RetVal = true; + }; + + KeyPressEvent += delegate (object o, KeyPressEventArgs args) { + if (args.Event.Key == Gdk.Key.Escape || + (args.Event.State == Gdk.ModifierType.ControlMask && args.Event.Key == Gdk.Key.w)) { + + Controller.WindowClosed (); + } + }; + + Controller.HideWindowEvent += delegate { + Application.Invoke (delegate { Hide (); }); + }; + + Controller.ShowWindowEvent += delegate { + Application.Invoke (delegate { + ShowAll (); + Present (); + }); + }; + + Controller.UpdateLabelEvent += delegate (string text) { + Application.Invoke (delegate { + this.updates.Text = text; + this.updates.ShowAll(); + }); + }; + + + CreateAbout (); + } + + + private void CreateAbout () + { + Gdk.RGBA white = new Gdk.RGBA (); + white.Parse ("#ffffff"); + + Gdk.RGBA highlight = new Gdk.RGBA (); + highlight.Parse ("#a8bbcf"); + + Pango.FontDescription font = StyleContext.GetFont (StateFlags.Normal); + font.Size = 9 * 1024; + + CssProvider css_provider = new CssProvider (); + string image_path = new string [] { SparkleUI.AssetsPath, "pixmaps", "about.png" }.Combine (); + + css_provider.LoadFromData ("GtkWindow {" + + "background-image: url('" + image_path + "');" + + "background-repeat: no-repeat;" + + "background-position: left bottom;" + + "}"); + + StyleContext.AddProvider (css_provider, 800); + + VBox layout_vertical = new VBox (false, 0); + HBox links_layout = new HBox (false, 16); + + + Label version = new Label () { + Text = "version " + Controller.RunningVersion, + Xalign = 0, Xpad = 0 + }; + + version.OverrideFont (font); + version.OverrideColor (StateFlags.Normal, white); + + + this.updates = new Label ("Checking for updates…") { + Xalign = 0, Xpad = 0 + }; + + this.updates.OverrideFont (font); + this.updates.OverrideColor (StateFlags.Normal, highlight); + + + Label copyright = new Label () { + Markup = string.Format ("Copyright © 2010–{0} Hylke Bons and others.", DateTime.Now.Year), + Xalign = 0, Xpad = 0 + }; + + copyright.OverrideFont (font); + copyright.OverrideColor (StateFlags.Normal, white); + + + TextView license = new TextView (); + TextBuffer license_buffer = license.Buffer; + license.WrapMode = WrapMode.Word; + license.Sensitive = false; + + license_buffer.Text = "SparkleShare is Open Source and you’re free to use, change, " + + "and share it under the GNU GPLv3."; + + license.OverrideBackgroundColor (StateFlags.Normal, new Gdk.RGBA () { Alpha = 0 }); + license.OverrideFont (font); + license.OverrideColor (StateFlags.Normal, white); + + + SparkleLink website_link = new SparkleLink ("Website", Controller.WebsiteLinkAddress); + SparkleLink credits_link = new SparkleLink ("Credits", Controller.CreditsLinkAddress); + SparkleLink report_problem_link = new SparkleLink ("Report a problem", Controller.ReportProblemLinkAddress); + SparkleLink debug_log_link = new SparkleLink ("Debug log", Controller.DebugLogLinkAddress); + + + layout_vertical.PackStart (new Label (""), true, true, 0); + layout_vertical.PackStart (version, false, false, 0); + layout_vertical.PackStart (this.updates, false, false, 0); + layout_vertical.PackStart (copyright, false, false, 6); + layout_vertical.PackStart (license, false, false, 6); + layout_vertical.PackStart (links_layout, false, false, 16); + + links_layout.PackStart (website_link, false, false, 0); + links_layout.PackStart (credits_link, false, false, 0); + links_layout.PackStart (report_problem_link, false, false, 0); + links_layout.PackStart (debug_log_link, false, false, 0); + + HBox layout_horizontal = new HBox (false, 0); + layout_horizontal.PackStart (new Label (""), false, false, 149); + layout_horizontal.PackStart (layout_vertical, false, false, 0); + + Add (layout_horizontal); + } + } + + + public class SparkleLink : Label { + + public SparkleLink (string text, string url) + { + Markup = string.Format ("{1}", url, text); + CanFocus = false; + + Pango.FontDescription font = StyleContext.GetFont (StateFlags.Normal); + font.Size = 9 * 1024; + + OverrideFont (font); + } + } +} diff --git a/SparkleShare/Linux/SparkleBubbles.cs b/SparkleShare/Linux/SparkleBubbles.cs new file mode 100755 index 0000000..8ec6dfb --- /dev/null +++ b/SparkleShare/Linux/SparkleBubbles.cs @@ -0,0 +1,65 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; + +using Gtk; +using Notifications; +using SparkleLib; + +namespace SparkleShare { + + public class SparkleBubbles { + + public SparkleBubblesController Controller = new SparkleBubblesController (); + + + public SparkleBubbles () + { + Controller.ShowBubbleEvent += ShowBubbleEvent; + } + + + private void ShowBubbleEvent (string title, string subtext, string image_path) + { + if (!Program.Controller.NotificationsEnabled) + return; + + Application.Invoke (delegate { + Notification notification = new Notification () { + Summary = title, + Body = subtext, + Timeout = 5 * 1000, + Urgency = Urgency.Low + }; + + if (image_path != null) + notification.Icon = new Gdk.Pixbuf (image_path); + else + notification.IconName = "folder-sparkleshare"; + + try { + notification.Show (); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Notification", "Error showing notification: ", e); + } + }); + } + } +} + diff --git a/SparkleShare/Linux/SparkleController.cs b/SparkleShare/Linux/SparkleController.cs new file mode 100755 index 0000000..3a68e39 --- /dev/null +++ b/SparkleShare/Linux/SparkleController.cs @@ -0,0 +1,205 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Diagnostics; +using System.IO; + +using Gtk; +using Mono.Unix.Native; +using SparkleLib; + +namespace SparkleShare { + + public class SparkleController : SparkleControllerBase { + + public SparkleController () : base () + { + } + + + public override string PluginsPath { + get { + return new string [] { Defines.INSTALL_DIR, "plugins" }.Combine (); + } + } + + + // Creates a .desktop entry in autostart folder to + // start SparkleShare automatically at login + public override void CreateStartupItem () + { + string autostart_path = Path.Combine ( + Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "autostart"); + + string desktopfile_path = Path.Combine (autostart_path, "sparkleshare.desktop"); + + if (!Directory.Exists (autostart_path)) + Directory.CreateDirectory (autostart_path); + + if (!File.Exists (desktopfile_path)) { + try { + File.WriteAllText (desktopfile_path, + "[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"); + + SparkleLogger.LogInfo ("Controller", "Added SparkleShare to login items"); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Controller", "Failed adding SparkleShare to login items: " + e.Message); + } + } + } + + + public override void InstallProtocolHandler () + { + // sparkleshare-invite-opener.desktop launches the handler on newer + // systems (like GNOME 3) that implement the last freedesktop.org specs. + // For GNOME 2 however we need to tell gconf about the protocol manually + + try { + // Add the handler to gconf... + Process process = new Process (); + process.StartInfo.FileName = "gconftool-2"; + process.StartInfo.Arguments = + "-s /desktop/gnome/url-handlers/sparkleshare/command 'sparkleshare open %s' --type String"; + + process.Start (); + process.WaitForExit (); + + // ...and enable it + process.StartInfo.Arguments = "-s /desktop/gnome/url-handlers/sparkleshare/enabled --type Boolean true"; + + process.Start (); + process.WaitForExit (); + + } catch { + // Pity... + } + } + + + // Adds the SparkleShare folder to the user's + // list of bookmarked places + public override void AddToBookmarks () + { + string bookmarks_file_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".gtk-bookmarks"); + string sparkleshare_bookmark = "file://" + FoldersPath + " SparkleShare"; + + if (File.Exists (bookmarks_file_path)) { + string bookmarks = File.ReadAllText (bookmarks_file_path); + + if (!bookmarks.Contains (sparkleshare_bookmark)) + File.AppendAllText (bookmarks_file_path, "file://" + FoldersPath + " SparkleShare"); + + } else { + File.WriteAllText (bookmarks_file_path, "file://" + FoldersPath + " SparkleShare"); + } + } + + + // Creates the SparkleShare folder in the user's home folder + public override bool CreateSparkleShareFolder () + { + bool folder_created = false; + + if (!Directory.Exists (SparkleConfig.DefaultConfig.FoldersPath)) { + Directory.CreateDirectory (SparkleConfig.DefaultConfig.FoldersPath); + Syscall.chmod (SparkleConfig.DefaultConfig.FoldersPath, (FilePermissions) 448); // 448 -> 700 + + SparkleLogger.LogInfo ("Controller", "Created '" + SparkleConfig.DefaultConfig.FoldersPath + "'"); + folder_created = true; + } + + string gvfs_command_path = new string [] { Path.VolumeSeparatorChar.ToString (), + "usr", "bin", "gvfs-set-attribute" }.Combine (); + + // Add a special icon to the SparkleShare folder + if (File.Exists (gvfs_command_path)) { + Process process = new Process (); + process.StartInfo.FileName = "gvfs-set-attribute"; + + // Give the SparkleShare folder an icon name, so that it scales + process.StartInfo.Arguments = SparkleConfig.DefaultConfig.FoldersPath + + " metadata::custom-icon-name 'sparkleshare'"; + + process.Start (); + process.WaitForExit (); + } + + return folder_created; + } + + + public override string EventLogHTML { + get { + string html_path = new string [] { Defines.INSTALL_DIR, "html", "event-log.html" }.Combine (); + string jquery_file_path = new string [] { Defines.INSTALL_DIR, "html", "jquery.js" }.Combine (); + + string html = File.ReadAllText (html_path); + string jquery = File.ReadAllText (jquery_file_path); + + return html.Replace ("", jquery); + } + } + + + public override string DayEntryHTML { + get { + string path = new string [] { Defines.INSTALL_DIR, "html", "day-entry.html" }.Combine (); + return File.ReadAllText (path); + } + } + + + public override string EventEntryHTML { + get { + string path = new string [] { Defines.INSTALL_DIR, "html", "event-entry.html" }.Combine (); + return File.ReadAllText (path); + } + } + + + public override void OpenFolder (string path) + { + OpenFile (path); + } + + + public override void OpenFile (string path) + { + Process process = new Process (); + process.StartInfo.FileName = "xdg-open"; + process.StartInfo.Arguments = "\"" + path + "\""; + process.Start (); + } + + + public override void CopyToClipboard (string text) + { + Clipboard clipboard = Clipboard.Get (Gdk.Atom.Intern ("CLIPBOARD", false)); + clipboard.Text = text; + } + } +} diff --git a/SparkleShare/Linux/SparkleEventLog.cs b/SparkleShare/Linux/SparkleEventLog.cs new file mode 100755 index 0000000..db6ff3f --- /dev/null +++ b/SparkleShare/Linux/SparkleEventLog.cs @@ -0,0 +1,289 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; + +using Gtk; +using WebKit; + +namespace SparkleShare { + + public class SparkleEventLog : Window { + + public SparkleEventLogController Controller = new SparkleEventLogController (); + + private Label size_label; + private Label history_label; + private ComboBox combo_box; + private EventBox content_wrapper; + private HBox combo_box_wrapper; + private HBox layout_horizontal; + private ScrolledWindow scrolled_window; + private VBox spinner_wrapper; + private Spinner spinner; + private WebView web_view; + + private int pos_x, pos_y; + + + public SparkleEventLog () : base ("Recent Changes") + { + SetWmclass ("SparkleShare", "SparkleShare"); + + Gdk.Rectangle monitor_0_rect = Gdk.Screen.Default.GetMonitorGeometry (0); + SetSizeRequest (480, (int) (monitor_0_rect.Height * 0.8)); + + IconName = "sparkleshare"; + this.pos_x = (int) (monitor_0_rect.Width * 0.61); + this.pos_y = (int) (monitor_0_rect.Height * 0.5 - (HeightRequest * 0.5)); + + this.size_label = new Label () { Xalign = 0, Markup = "Size: …" }; + this.history_label = new Label () { Xalign = 0, Markup = "History: …" }; + + this.size_label.SetSizeRequest (100, 24); + + HBox layout_sizes = new HBox (false, 0); + layout_sizes.PackStart (this.size_label, false, false, 12); + layout_sizes.PackStart (this.history_label, false, false, 0); + + VBox layout_vertical = new VBox (false, 0); + this.spinner = new Spinner (); + this.spinner_wrapper = new VBox (); + this.content_wrapper = new EventBox (); + this.scrolled_window = new ScrolledWindow (); + + this.content_wrapper.OverrideBackgroundColor (StateFlags.Normal, + new Gdk.RGBA () { Red = 1, Green = 1, Blue=1, Alpha = 1 }); + + this.web_view = new WebView () { Editable = false }; + this.web_view.NavigationRequested += WebViewNavigationRequested; + + this.scrolled_window.Add (this.web_view); + + this.spinner_wrapper = new VBox (false, 0); + this.spinner_wrapper.PackStart (new Label(""), true, true, 0); + this.spinner_wrapper.PackStart (this.spinner, false, false, 0); + this.spinner_wrapper.PackStart (new Label(""), true, true, 0); + this.spinner.SetSizeRequest (24, 24); + this.spinner.Start (); + + this.content_wrapper.Add (this.spinner_wrapper); + + this.layout_horizontal = new HBox (false, 0); + this.layout_horizontal.PackStart (layout_sizes, true, true, 12); + + layout_vertical.PackStart (this.layout_horizontal, false, false, 0); + layout_vertical.PackStart (new HSeparator (), false, false, 0); + layout_vertical.PackStart (this.content_wrapper, true, true, 0); + + Add (layout_vertical); + + + Controller.HideWindowEvent += delegate { + Application.Invoke (delegate { + Hide (); + + if (this.content_wrapper.Child != null) + this.content_wrapper.Remove (this.content_wrapper.Child); + }); + }; + + Controller.ShowWindowEvent += delegate { + Application.Invoke (delegate { + Move (this.pos_x, this.pos_y); + ShowAll (); + Present (); + }); + }; + + Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) { + Application.Invoke (delegate { + FileChooserDialog dialog = new FileChooserDialog ("Restore from History", this, + FileChooserAction.Save, "Cancel", ResponseType.Cancel, "Save", ResponseType.Ok); + + dialog.CurrentName = file_name; + dialog.DoOverwriteConfirmation = true; + dialog.SetCurrentFolder (target_folder_path); + + if (dialog.Run () == (int) ResponseType.Ok) + Controller.SaveDialogCompleted (dialog.Filename); + else + Controller.SaveDialogCancelled (); + + dialog.Destroy (); + }); + }; + + Controller.UpdateChooserEvent += delegate (string [] folders) { + Application.Invoke (delegate { UpdateChooser (folders); }); + }; + + Controller.UpdateChooserEnablementEvent += delegate (bool enabled) { + Application.Invoke (delegate { this.combo_box.Sensitive = enabled; }); + }; + + Controller.UpdateContentEvent += delegate (string html) { + Application.Invoke (delegate { UpdateContent (html); }); + }; + + Controller.ContentLoadingEvent += delegate { + Application.Invoke (delegate { + if (this.content_wrapper.Child != null) + this.content_wrapper.Remove (this.content_wrapper.Child); + + this.content_wrapper.Add (this.spinner_wrapper); + this.spinner.Start (); + }); + }; + + Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) { + Application.Invoke (delegate { + this.size_label.Markup = "Size " + size; + this.history_label.Markup = "History " + history_size; + }); + }; + + DeleteEvent += delegate (object o, DeleteEventArgs args) { + Controller.WindowClosed (); + args.RetVal = true; + }; + + KeyPressEvent += delegate (object o, KeyPressEventArgs args) { + if (args.Event.Key == Gdk.Key.Escape || + (args.Event.State == Gdk.ModifierType.ControlMask && args.Event.Key == Gdk.Key.w)) { + + Controller.WindowClosed (); + } + }; + } + + + public void UpdateChooser (string [] folders) + { + if (folders == null) + folders = Controller.Folders; + + if (this.combo_box_wrapper != null && this.combo_box_wrapper.Parent != null) { + this.layout_horizontal.Remove (this.combo_box_wrapper); + this.combo_box_wrapper.Remove (this.combo_box); + } + + this.combo_box_wrapper = new HBox (false, 0); + this.combo_box = new ComboBox (); + + CellRendererText cell = new CellRendererText(); + this.combo_box.PackStart (cell, false); + this.combo_box.AddAttribute (cell, "text", 0); + + ListStore store = new ListStore (typeof (string)); + + store.AppendValues ("Summary"); + store.AppendValues ("---"); + + this.combo_box.Model = store; + this.combo_box.Active = 0; + + int row = 2; + foreach (string folder in folders) { + store.AppendValues (folder); + + if (folder.Equals (Controller.SelectedFolder)) + this.combo_box.Active = row; + + row++; + } + + this.combo_box.RowSeparatorFunc = delegate (ITreeModel model, TreeIter iter) { + string item = (string) this.combo_box.Model.GetValue (iter, 0); + return (item == "---"); + }; + + this.combo_box.Changed += delegate { + TreeIter iter; + this.combo_box.GetActiveIter (out iter); + string selection = (string) this.combo_box.Model.GetValue (iter, 0); + TreePath path = this.combo_box.Model.GetPath (iter); + + if (path.Indices [0] == 0) + Controller.SelectedFolder = null; + else + Controller.SelectedFolder = selection; + }; + + this.combo_box_wrapper.Add (this.combo_box); + this.combo_box.GrabFocus (); + + this.layout_horizontal.BorderWidth = 6; + this.layout_horizontal.PackStart (this.combo_box_wrapper, false, false, 0); + this.layout_horizontal.ShowAll (); + } + + + public void UpdateContent (string html) + { + string pixmaps_path = new string [] {SparkleUI.AssetsPath, "pixmaps"}.Combine (); + string icons_path = new string [] {SparkleUI.AssetsPath, "icons", "hicolor", "12x12", "status"}.Combine (); + + html = html.Replace ("", "#009ff8"); + html = html.Replace ("", "#0085cf"); + + html = html.Replace ("", StyleContext.GetFont (StateFlags.Normal).Family); + html = html.Replace ("", (double) (StyleContext.GetFont (StateFlags.Normal).Size / 1024 + 3) + "px"); + html = html.Replace ("", SparkleUIHelpers.RGBAToHex (StyleContext.GetColor (StateFlags.Normal))); + html = html.Replace ("", + SparkleUIHelpers.RGBAToHex (new TreeView ().StyleContext.GetBackgroundColor (StateFlags.Normal))); + + html = html.Replace ("", (StyleContext.GetFont (StateFlags.Normal).Size / 1024 + 3) + "px"); + html = html.Replace ("", + SparkleUIHelpers.RGBAToHex (StyleContext.GetBackgroundColor (StateFlags.Normal))); + + html = html.Replace ("", SparkleUIHelpers.RGBAToHex (StyleContext.GetColor (StateFlags.Insensitive))); + + html = html.Replace ("", SparkleUIHelpers.RGBAToHex (StyleContext.GetColor (StateFlags.Insensitive))); + html = html.Replace ("", "90%"); + + html = html.Replace ("", pixmaps_path); + html = html.Replace ("", "file://" + new string [] {icons_path, "document-added.png"}.Combine ()); + html = html.Replace ("", "file://" + new string [] {icons_path, "document-edited.png"}.Combine ()); + html = html.Replace ("", "file://" + new string [] {icons_path, "document-deleted.png"}.Combine ()); + html = html.Replace ("", "file://" + new string [] {icons_path, "document-moved.png"}.Combine ()); + + this.spinner.Stop (); + this.scrolled_window.Remove (this.web_view); + this.web_view.Dispose (); + + this.web_view = new WebView () { Editable = false }; + this.web_view.LoadString (html, "text/html", "UTF-8", "file://"); + this.web_view.NavigationRequested += WebViewNavigationRequested; + this.scrolled_window.Add (this.web_view); + + this.content_wrapper.Remove (this.content_wrapper.Child); + this.content_wrapper.Add (this.scrolled_window); + this.scrolled_window.ShowAll (); + } + + + private void WebViewNavigationRequested (object o, WebKit.NavigationRequestedArgs args) { + Controller.LinkClicked (args.Request.Uri); + + // Don't follow HREFs (as this would cause a page refresh) + if (!args.Request.Uri.Equals ("file:")) + args.RetVal = 1; + } + } +} + diff --git a/SparkleShare/Linux/SparkleNote.cs b/SparkleShare/Linux/SparkleNote.cs new file mode 100755 index 0000000..410998b --- /dev/null +++ b/SparkleShare/Linux/SparkleNote.cs @@ -0,0 +1,141 @@ +// 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 Gtk; + +namespace SparkleShare { + + public class SparkleNote : Window { + + public SparkleNoteController Controller = new SparkleNoteController (); + + + public SparkleNote () : base ("Add Note") + { + SetWmclass ("SparkleShare", "SparkleShare"); + + IconName = "sparkleshare"; + Resizable = false; + WindowPosition = WindowPosition.Center; + BorderWidth = 16; + + SetSizeRequest (480, 120); + + + DeleteEvent += delegate (object o, DeleteEventArgs args) { + Controller.WindowClosed (); + args.RetVal = true; + }; + + KeyPressEvent += delegate (object o, KeyPressEventArgs args) { + if (args.Event.Key == Gdk.Key.Escape || + (args.Event.State == Gdk.ModifierType.ControlMask && args.Event.Key == Gdk.Key.w)) { + + Controller.WindowClosed (); + } + }; + + Controller.HideWindowEvent += delegate { + Application.Invoke (delegate { Hide (); }); + }; + + Controller.ShowWindowEvent += delegate { + Application.Invoke (delegate { + CreateNote (); + ShowAll (); + Present (); + }); + }; + + Controller.UpdateTitleEvent += delegate (string title) { + Application.Invoke (delegate { Title = title; }); + }; + + CreateNote (); + } + + + private void CreateNote () + { + Image user_image = new Image (Controller.AvatarFilePath); + + /* TODO: Style the entry neatly, multiple lines, and add placeholder text + string balloon_image_path = new string [] { SparkleUI.AssetsPath, "pixmaps", "text-balloon.png" }.Combine (); + Image balloon_image = new Image (balloon_image_path); + CssProvider balloon_css_provider = new CssProvider (); + + balloon_css_provider.LoadFromData ("GtkEntry {" + + "background-image: url('" + balloon_image_path + "');" + + "background-repeat: no-repeat;" + + "background-position: left top;" + + "}"); + + balloon.StyleContext.AddProvider (balloon_css_provider, 800); + */ + + Label balloon_label = new Label ("Anything to add?") { + Xalign = 0, + UseMarkup = true + }; + + Entry balloon = new Entry () { MaxLength = 144 }; + + + Button cancel_button = new Button ("Cancel"); + Button sync_button = new Button ("Sync"); // TODO: Make default button + + cancel_button.Clicked += delegate { Controller.CancelClicked (); }; + sync_button.Clicked += delegate { Controller.SyncClicked (balloon.Buffer.Text); }; + + + VBox layout_vertical = new VBox (false, 16); + HBox layout_horizontal = new HBox (false, 16); + + HBox buttons = new HBox () { + Homogeneous = false, + Spacing = 6 + }; + + Label user_label = new Label () { + Markup = "" + Program.Controller.CurrentUser.Name + "\n" + + "" + Program.Controller.CurrentUser.Email + + "" + }; + + + layout_horizontal.PackStart (user_image, false, false, 0); + layout_horizontal.PackStart (user_label, false, false, 0); + + buttons.PackStart (new Label (""), true, true, 0); + buttons.PackStart (cancel_button, false, false, 0); + buttons.PackStart (sync_button, false, false, 0); + + layout_vertical.PackStart (layout_horizontal, false, false, 0); + layout_vertical.PackStart (balloon_label, false, false, 0); + layout_vertical.PackStart (balloon, false, false, 0); + layout_vertical.PackStart (buttons, false, false, 0); + + // FIXME: Doesn't work + CanDefault = true; + Default = sync_button; + + Add (layout_vertical); + } + } +} + diff --git a/SparkleShare/Linux/SparkleSetup.cs b/SparkleShare/Linux/SparkleSetup.cs new file mode 100755 index 0000000..ad698c4 --- /dev/null +++ b/SparkleShare/Linux/SparkleSetup.cs @@ -0,0 +1,734 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General private 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 private License for more details. +// +// You should have received a copy of the GNU General private License +// along with this program. If not, see . + + +using System; + +using Gtk; +using Mono.Unix; + +namespace SparkleShare { + + public class SparkleSetup : SparkleSetupWindow { + + public SparkleSetupController Controller = new SparkleSetupController (); + + + public SparkleSetup () : base () + { + Controller.HideWindowEvent += delegate { + Application.Invoke (delegate { Hide (); }); + }; + + Controller.ShowWindowEvent += delegate { + Application.Invoke (delegate { + ShowAll (); + Present (); + }); + }; + + Controller.ChangePageEvent += delegate (PageType type, string [] warnings) { + Application.Invoke (delegate { + Reset (); + ShowPage (type, warnings); + ShowAll (); + }); + }; + } + + + public void ShowPage (PageType type, string [] warnings) + { + if (type == PageType.Setup) { + Header = "Welcome to SparkleShare!"; + Description = "First off, what’s your name and email?\n(visible only to team members)"; + + Table table = new Table (2, 3, true) { + RowSpacing = 6, + ColumnSpacing = 6 + }; + + Label name_label = new Label ("" + "Full Name:" + "") { + UseMarkup = true, + Xalign = 1 + }; + + Entry name_entry = new Entry () { + Xalign = 0, + ActivatesDefault = true + }; + + try { + UnixUserInfo user_info = UnixUserInfo.GetRealUser (); + + if (user_info != null && user_info.RealName != null) + // Some systems append a series of "," for some reason + name_entry.Text = user_info.RealName.TrimEnd (",".ToCharArray ()); + + } catch (ArgumentException) { + // No username, not a big deal + } + + Entry email_entry = new Entry () { + Xalign = 0, + ActivatesDefault = true + }; + + Label email_label = new Label ("" + "Email:" + "") { + UseMarkup = true, + Xalign = 1 + }; + + table.Attach (name_label, 0, 1, 0, 1); + table.Attach (name_entry, 1, 2, 0, 1); + table.Attach (email_label, 0, 1, 1, 2); + table.Attach (email_entry, 1, 2, 1, 2); + + VBox wrapper = new VBox (false, 9); + wrapper.PackStart (table, true, false, 0); + + Button cancel_button = new Button ("Cancel"); + Button continue_button = new Button ("Continue") { Sensitive = false }; + + + Controller.UpdateSetupContinueButtonEvent += delegate (bool button_enabled) { + Application.Invoke (delegate { continue_button.Sensitive = button_enabled; }); + }; + + name_entry.Changed += delegate { Controller.CheckSetupPage (name_entry.Text, email_entry.Text); }; + email_entry.Changed += delegate { Controller.CheckSetupPage (name_entry.Text, email_entry.Text); }; + cancel_button.Clicked += delegate { Controller.SetupPageCancelled (); }; + + continue_button.Clicked += delegate { + Controller.SetupPageCompleted (name_entry.Text, email_entry.Text); + }; + + + AddButton (cancel_button); + AddButton (continue_button); + Add (wrapper); + + Controller.CheckSetupPage (name_entry.Text, email_entry.Text); + + if (name_entry.Text.Equals ("")) + name_entry.GrabFocus (); + else + email_entry.GrabFocus (); + } + + if (type == PageType.Add) { + Header = "Where’s your project hosted?"; + + VBox layout_vertical = new VBox (false, 16); + HBox layout_fields = new HBox (true, 32); + VBox layout_address = new VBox (true, 0); + VBox layout_path = new VBox (true, 0); + + ListStore store = new ListStore (typeof (string), typeof (Gdk.Pixbuf), typeof (string), typeof (SparklePlugin)); + + SparkleTreeView tree_view = new SparkleTreeView (store) { HeadersVisible = false }; + ScrolledWindow scrolled_window = new ScrolledWindow () { ShadowType = ShadowType.In }; + scrolled_window.SetPolicy (PolicyType.Never, PolicyType.Automatic); + + // Padding column + tree_view.AppendColumn ("Padding", new Gtk.CellRendererText (), "text", 0); + tree_view.Columns [0].Cells [0].Xpad = 4; + + // Icon column + tree_view.AppendColumn ("Icon", new Gtk.CellRendererPixbuf (), "pixbuf", 1); + tree_view.Columns [1].Cells [0].Xpad = 4; + + // Service column + TreeViewColumn service_column = new TreeViewColumn () { Title = "Service" }; + CellRendererText service_cell = new CellRendererText () { Ypad = 8 }; + service_column.PackStart (service_cell, true); + service_column.SetCellDataFunc (service_cell, new TreeCellDataFunc (RenderServiceColumn)); + + foreach (SparklePlugin plugin in Controller.Plugins) { + store.AppendValues ("", new Gdk.Pixbuf (plugin.ImagePath), + "" + plugin.Name + "\n" + + "" + plugin.Description + "" + + "", plugin); + } + + tree_view.AppendColumn (service_column); + scrolled_window.Add (tree_view); + + Entry address_entry = new Entry () { + Text = Controller.PreviousAddress, + Sensitive = (Controller.SelectedPlugin.Address == null), + ActivatesDefault = true + }; + + Entry path_entry = new Entry () { + Text = Controller.PreviousPath, + Sensitive = (Controller.SelectedPlugin.Path == null), + ActivatesDefault = true + }; + + Label address_example = new Label () { + Xalign = 0, + UseMarkup = true, + Markup = "" + Controller.SelectedPlugin.AddressExample + "" + }; + + Label path_example = new Label () { + Xalign = 0, + UseMarkup = true, + Markup = "" + Controller.SelectedPlugin.PathExample + "" + }; + + + TreeSelection default_selection = tree_view.Selection; + TreePath default_path = new TreePath ("" + Controller.SelectedPluginIndex); + default_selection.SelectPath (default_path); + + tree_view.Model.Foreach (new TreeModelForeachFunc ( + delegate (ITreeModel 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.PreviousAddress)) { + + tree_view.SetCursor (path, service_column, false); + SparklePlugin plugin = (SparklePlugin) model.GetValue (iter, 2); + + if (plugin.Address != null) + address_entry.Sensitive = false; + + if (plugin.Path != null) + path_entry.Sensitive = false; + + return true; + + } else { + return false; + } + } + )); + + layout_address.PackStart (new Label () { + Markup = "" + "Address" + "", + Xalign = 0 + }, true, true, 0); + + layout_address.PackStart (address_entry, false, false, 0); + layout_address.PackStart (address_example, false, false, 0); + + path_entry.Changed += delegate { + Controller.CheckAddPage (address_entry.Text, path_entry.Text, tree_view.SelectedRow); + }; + + layout_path.PackStart (new Label () { + Markup = "" + "Remote Path" + "", + Xalign = 0 + }, true, true, 0); + + layout_path.PackStart (path_entry, false, false, 0); + layout_path.PackStart (path_example, false, false, 0); + + layout_fields.PackStart (layout_address, true, true, 0); + layout_fields.PackStart (layout_path, true, true, 0); + + layout_vertical.PackStart (new Label (""), false, false, 0); + layout_vertical.PackStart (scrolled_window, true, true, 0); + layout_vertical.PackStart (layout_fields, false, false, 0); + + tree_view.ScrollToCell (new TreePath ("" + Controller.SelectedPluginIndex), null, true, 0, 0); + + Add (layout_vertical); + + + if (string.IsNullOrEmpty (path_entry.Text)) { + address_entry.GrabFocus (); + address_entry.Position = -1; + } else { + path_entry.GrabFocus (); + path_entry.Position = -1; + } + + Button cancel_button = new Button ("Cancel"); + Button add_button = new Button ("Add") { Sensitive = false }; + + + Controller.ChangeAddressFieldEvent += delegate (string text, + string example_text, FieldState state) { + + Application.Invoke (delegate { + address_entry.Text = text; + address_entry.Sensitive = (state == FieldState.Enabled); + address_example.Markup = "" + example_text + ""; + }); + }; + + Controller.ChangePathFieldEvent += delegate (string text, + string example_text, FieldState state) { + + Application.Invoke (delegate { + path_entry.Text = text; + path_entry.Sensitive = (state == FieldState.Enabled); + path_example.Markup = "" + example_text + ""; + }); + }; + + Controller.UpdateAddProjectButtonEvent += delegate (bool button_enabled) { + Application.Invoke (delegate { add_button.Sensitive = button_enabled; }); + }; + + + tree_view.CursorChanged += delegate (object sender, EventArgs e) { + Controller.SelectedPluginChanged (tree_view.SelectedRow); + }; + + address_entry.Changed += delegate { + Controller.CheckAddPage (address_entry.Text, path_entry.Text, tree_view.SelectedRow); + }; + + cancel_button.Clicked += delegate { Controller.PageCancelled (); }; + add_button.Clicked += delegate { Controller.AddPageCompleted (address_entry.Text, path_entry.Text); }; + + + CheckButton check_button = new CheckButton ("Fetch prior revisions") { Active = true }; + check_button.Toggled += delegate { Controller.HistoryItemChanged (check_button.Active); }; + + AddOption (check_button); + AddButton (cancel_button); + AddButton (add_button); + + Controller.HistoryItemChanged (check_button.Active); + Controller.CheckAddPage (address_entry.Text, path_entry.Text, 1); + } + + if (type == PageType.Invite) { + Header = "You’ve received an invite!"; + Description = "Do you want to add this project to SparkleShare?"; + + Table table = new Table (2, 3, true) { + RowSpacing = 6, + ColumnSpacing = 6 + }; + + Label address_label = new Label ("Address:") { Xalign = 1 }; + Label path_label = new Label ("Remote Path:") { Xalign = 1 }; + + Label address_value = new Label ("" + Controller.PendingInvite.Address + "") { + UseMarkup = true, + Xalign = 0 + }; + + Label path_value = new Label ("" + Controller.PendingInvite.RemotePath + "") { + UseMarkup = true, + Xalign = 0 + }; + + table.Attach (address_label, 0, 1, 0, 1); + table.Attach (address_value, 1, 2, 0, 1); + table.Attach (path_label, 0, 1, 1, 2); + table.Attach (path_value, 1, 2, 1, 2); + + VBox wrapper = new VBox (false, 9); + wrapper.PackStart (table, true, false, 0); + + Button cancel_button = new Button ("Cancel"); + Button add_button = new Button ("Add"); + + + cancel_button.Clicked += delegate { Controller.PageCancelled (); }; + add_button.Clicked += delegate { Controller.InvitePageCompleted (); }; + + + AddButton (cancel_button); + AddButton (add_button); + Add (wrapper); + } + + if (type == PageType.Syncing) { + Header = String.Format ("Adding project ‘{0}’…", Controller.SyncingFolder); + Description = "This may take a while for large projects.\nIsn’t it coffee-o’clock?"; + + ProgressBar progress_bar = new ProgressBar (); + progress_bar.Fraction = Controller.ProgressBarPercentage / 100; + + Button cancel_button = new Button () { Label = "Cancel" }; + Button finish_button = new Button ("Finish") { Sensitive = false }; + + Label progress_label = new Label ("Preparing to fetch files…") { + Justify = Justification.Right, + Xalign = 1 + }; + + + Controller.UpdateProgressBarEvent += delegate (double percentage, string speed) { + Application.Invoke (delegate { + progress_bar.Fraction = percentage / 100; + progress_label.Text = speed; + }); + }; + + cancel_button.Clicked += delegate { Controller.SyncingCancelled (); }; + + + VBox bar_wrapper = new VBox (false, 0); + bar_wrapper.PackStart (progress_bar, false, false, 21); + bar_wrapper.PackStart (progress_label, false, true, 0); + + Add (bar_wrapper); + AddButton (cancel_button); + AddButton (finish_button); + } + + if (type == PageType.Error) { + Header = "Oops! Something went wrong" + "…"; + + VBox points = new VBox (false, 0); + Image list_point_one = new Image (SparkleUIHelpers.GetIcon ("list-point", 16)); + Image list_point_two = new Image (SparkleUIHelpers.GetIcon ("list-point", 16)); + Image list_point_three = new Image (SparkleUIHelpers.GetIcon ("list-point", 16)); + + Label label_one = new Label () { + Markup = "" + Controller.PreviousUrl + " is the address we’ve compiled. " + + "Does this look alright?", + Wrap = true, + Xalign = 0 + }; + + Label label_two = new Label () { + Text = "Is this computer’s Client ID known by the host?", + Wrap = true, + Xalign = 0 + }; + + points.PackStart (new Label ("Please check the following:") { Xalign = 0 }, false, false, 6); + + HBox point_one = new HBox (false, 0); + point_one.PackStart (list_point_one, false, false, 0); + point_one.PackStart (label_one, true, true, 12); + points.PackStart (point_one, false, false, 12); + + HBox point_two = new HBox (false, 0); + point_two.PackStart (list_point_two, false, false, 0); + point_two.PackStart (label_two, true, true, 12); + points.PackStart (point_two, false, false, 12); + + if (warnings.Length > 0) { + string warnings_markup = ""; + + foreach (string warning in warnings) + warnings_markup += "\n" + warning + ""; + + Label label_three = new Label () { + Markup = "Here’s the raw error message:" + warnings_markup, + Wrap = true, + Xalign = 0 + }; + + HBox point_three = new HBox (false, 0); + point_three.PackStart (list_point_three, false, false, 0); + point_three.PackStart (label_three, true, true, 12); + points.PackStart (point_three, false, false, 12); + } + + points.PackStart (new Label (""), true, true, 0); + + Button cancel_button = new Button ("Cancel"); + Button try_again_button = new Button ("Try Again…") { Sensitive = true }; + + + cancel_button.Clicked += delegate { Controller.PageCancelled (); }; + try_again_button.Clicked += delegate { Controller.ErrorPageCompleted (); }; + + + AddButton (cancel_button); + AddButton (try_again_button); + Add (points); + } + + if (type == PageType.CryptoSetup || type == PageType.CryptoPassword) { + if (type == PageType.CryptoSetup) { + Header = "Set up file encryption"; + Description = "Please a provide a strong password that you don’t use elsewhere."; + + } else { + Header = "This project contains encrypted files"; + Description = "Please enter the password to see their contents."; + } + + Label password_label = new Label ("" + "Password" + "") { + UseMarkup = true, + Xalign = 1 + }; + + Entry password_entry = new Entry () { + Xalign = 0, + Visibility = false, + ActivatesDefault = true + }; + + CheckButton show_password_check_button = new CheckButton ("Show password") { + Active = false, + Xalign = 0, + }; + + Table table = new Table (2, 3, true) { + RowSpacing = 6, + ColumnSpacing = 6 + }; + + table.Attach (password_label, 0, 1, 0, 1); + table.Attach (password_entry, 1, 2, 0, 1); + + table.Attach (show_password_check_button, 1, 2, 1, 2); + + VBox wrapper = new VBox (false, 9); + wrapper.PackStart (table, true, false, 0); + + Image warning_image = new Image ( + SparkleUIHelpers.GetIcon ("dialog-information", 24)); + + Label warning_label = new Label () { + Xalign = 0, + Wrap = true, + Text = "This password can’t be changed later, and your files can’t be recovered if it’s forgotten." + }; + + HBox warning_layout = new HBox (false, 0); + warning_layout.PackStart (warning_image, false, false, 15); + warning_layout.PackStart (warning_label, true, true, 0); + + VBox warning_wrapper = new VBox (false, 0); + warning_wrapper.PackStart (warning_layout, false, false, 15); + + if (type == PageType.CryptoSetup) + wrapper.PackStart (warning_wrapper, false, false, 0); + + Button cancel_button = new Button ("Cancel"); + Button continue_button = new Button ("Continue") { Sensitive = false }; + + + Controller.UpdateCryptoSetupContinueButtonEvent += delegate (bool button_enabled) { + Application.Invoke (delegate { continue_button.Sensitive = button_enabled; }); + }; + + Controller.UpdateCryptoPasswordContinueButtonEvent += delegate (bool button_enabled) { + Application.Invoke (delegate { continue_button.Sensitive = button_enabled; }); + }; + + show_password_check_button.Toggled += delegate { + password_entry.Visibility = !password_entry.Visibility; + }; + + password_entry.Changed += delegate { + if (type == PageType.CryptoSetup) + Controller.CheckCryptoSetupPage (password_entry.Text); + else + Controller.CheckCryptoPasswordPage (password_entry.Text); + }; + + cancel_button.Clicked += delegate { Controller.CryptoPageCancelled (); }; + + continue_button.Clicked += delegate { + if (type == PageType.CryptoSetup) + Controller.CryptoSetupPageCompleted (password_entry.Text); + else + Controller.CryptoPasswordPageCompleted (password_entry.Text); + }; + + + Add (wrapper); + + AddButton (cancel_button); + AddButton (continue_button); + + password_entry.GrabFocus (); + } + + if (type == PageType.Finished) { + Header = "Your shared project is ready!"; + Description = "You can find the files in your SparkleShare folder."; + + UrgencyHint = true; + + Button show_files_button = new Button ("Show Files…"); + Button finish_button = new Button ("Finish"); + + + show_files_button.Clicked += delegate { Controller.ShowFilesClicked (); }; + finish_button.Clicked += delegate { Controller.FinishPageCompleted (); }; + + + if (warnings.Length > 0) { + Image warning_image = new Image (SparkleUIHelpers.GetIcon ("dialog-information", 24)); + + Label warning_label = new Label (warnings [0]) { + Xalign = 0, + Wrap = true + }; + + HBox warning_layout = new HBox (false, 0); + warning_layout.PackStart (warning_image, false, false, 15); + warning_layout.PackStart (warning_label, true, true, 0); + + VBox warning_wrapper = new VBox (false, 0); + warning_wrapper.PackStart (warning_layout, false, false, 0); + + Add (warning_wrapper); + + } else { + Add (null); + } + + AddButton (show_files_button); + AddButton (finish_button); + } + + if (type == PageType.Tutorial) { + switch (Controller.TutorialPageNumber) { + case 1: { + Header = "What’s happening next?"; + Description = "SparkleShare creates a special folder on your computer " + + "that will keep track of your projects."; + + Button skip_tutorial_button = new Button ("Skip Tutorial"); + Button continue_button = new Button ("Continue"); + + skip_tutorial_button.Clicked += delegate { Controller.TutorialSkipped (); }; + continue_button.Clicked += delegate { Controller.TutorialPageCompleted (); }; + + AddButton (skip_tutorial_button); + AddButton (continue_button); + + break; + } + + case 2: { + Header = "Sharing files with others"; + Description = "All files added to your project folders are synced automatically with " + + "the host and your team members."; + + Button continue_button = new Button ("Continue"); + continue_button.Clicked += delegate { Controller.TutorialPageCompleted (); }; + AddButton (continue_button); + + break; + } + + case 3: { + Header = "The status icon helps you"; + Description = "It shows the syncing progress, provides easy access to " + + "your projects, and lets you view recent changes."; + + Button continue_button = new Button ("Continue"); + continue_button.Clicked += delegate { Controller.TutorialPageCompleted (); }; + AddButton (continue_button); + + break; + } + + case 4: { + Header = "Here’s your unique Client ID"; + Description = "You’ll need it whenever you want to link this computer to a host. " + + "You can also find it in the status icon menu."; + + Button finish_button = new Button ("Finish"); + VBox layout_vertical = new VBox (false, 0) { BorderWidth = 48 }; + HBox layout_horizontal = new HBox (false, 6); + + Entry link_code_entry = new Entry () { + Text = Program.Controller.CurrentUser.PublicKey, + Sensitive = false + }; + + Button copy_button = new Button (" Copy "); + + CheckButton check_button = new CheckButton ("Add SparkleShare to startup items"); + check_button.Active = true; + + + copy_button.Clicked += delegate { Controller.CopyToClipboardClicked (); }; + check_button.Toggled += delegate { Controller.StartupItemChanged (check_button.Active); }; + finish_button.Clicked += delegate { Controller.TutorialPageCompleted (); }; + + + layout_horizontal.PackStart (link_code_entry, true, true, 0); + layout_horizontal.PackStart (copy_button, false, false, 0); + + layout_vertical.PackStart (new Label (""), true, true, 0); + layout_vertical.PackStart (layout_horizontal, false, false, 0); + layout_vertical.PackStart (new Label (""), true, true, 18); + + Add (layout_vertical); + + AddOption (check_button); + AddButton (finish_button); + + break; + } + } + + if (Controller.TutorialPageNumber < 4) { + Image slide = SparkleUIHelpers.GetImage ("tutorial-slide-" + Controller.TutorialPageNumber + ".png"); + Add (slide); + } + } + } + + + private void RenderServiceColumn (TreeViewColumn column, CellRenderer cell, + ITreeModel model, TreeIter iter) + { + string markup = (string) model.GetValue (iter, 2); + TreeSelection selection = (column.TreeView as TreeView).Selection; + + if (selection.IterIsSelected (iter)) + markup = markup.Replace (Program.UI.SecondaryTextColor, Program.UI.SecondaryTextColorSelected); + else + markup = markup.Replace (Program.UI.SecondaryTextColorSelected, Program.UI.SecondaryTextColor); + + (cell as CellRendererText).Markup = markup; + } + + + private class SparkleTreeView : TreeView { + + public int SelectedRow + { + get { + TreeIter iter; + ITreeModel model; + + Selection.GetSelected (out model, out iter); + return int.Parse (model.GetPath (iter).ToString ()); + } + } + + + public SparkleTreeView (ListStore store) : base (store) + { + } + } + } +} diff --git a/SparkleShare/Linux/SparkleSetupWindow.cs b/SparkleShare/Linux/SparkleSetupWindow.cs new file mode 100755 index 0000000..77b69f8 --- /dev/null +++ b/SparkleShare/Linux/SparkleSetupWindow.cs @@ -0,0 +1,155 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using Gtk; + +namespace SparkleShare { + + public class SparkleSetupWindow : Window { + + private EventBox content_area; + private EventBox option_area; + private HBox buttons; + + public string Header; + public string Description; + + + public SparkleSetupWindow () : base ("SparkleShare Setup") + { + SetWmclass ("SparkleShare", "SparkleShare"); + + IconName = "sparkleshare"; + Resizable = false; + WindowPosition = WindowPosition.Center; + Deletable = false; + TypeHint = Gdk.WindowTypeHint.Dialog; + + + SetSizeRequest (680, 400); + + DeleteEvent += delegate (object sender, DeleteEventArgs args) { args.RetVal = true; }; + + HBox layout_horizontal = new HBox (false, 0); + + VBox layout_vertical = new VBox (false, 0); + + this.content_area = new EventBox (); + this.option_area = new EventBox (); + + this.buttons = CreateButtonBox (); + + HBox layout_actions = new HBox (false , 48); + + layout_actions.PackStart (this.option_area, true, true, 0); + layout_actions.PackStart (this.buttons, false, false, 0); + + layout_vertical.PackStart (this.content_area, true, true, 0); + layout_vertical.PackStart (layout_actions, false, false, 15); + + Image side_splash = SparkleUIHelpers.GetImage ("side-splash.png"); + side_splash.Yalign = 1; + + layout_horizontal.PackStart (side_splash, false, false, 0); + layout_horizontal.PackStart (layout_vertical, true, true, 30); + + base.Add (layout_horizontal); + } + + + private HBox CreateButtonBox () + { + return new HBox () { + BorderWidth = 0, + Homogeneous = false, + Spacing = 6 + }; + } + + + public void AddButton (Button button) + { + (button.Child as Label).Xpad = 15; + this.buttons.Add (button); + } + + + public void AddOption (Widget widget) + { + this.option_area.Add (widget); + } + + + new public void Add (Widget widget) + { + Label header = new Label ("" + Header + "") { + UseMarkup = true, + Xalign = 0, + }; + + VBox layout_vertical = new VBox (false, 0); + layout_vertical.PackStart (new Label (""), false, false, 6); + layout_vertical.PackStart (header, false, false, 0); + + if (!string.IsNullOrEmpty (Description)) { + Label description = new Label (Description) { + Xalign = 0, + LineWrap = true, + LineWrapMode = Pango.WrapMode.WordChar + }; + + layout_vertical.PackStart (description, false, false, 21); + } + + if (widget != null) + layout_vertical.PackStart (widget, true, true, 0); + + this.content_area.Add (layout_vertical); + } + + + public void Reset () + { + Header = ""; + Description = ""; + + if (this.option_area.Children.Length > 0) + this.option_area.Remove (this.option_area.Children [0]); + + if (this.content_area.Children.Length > 0) + this.content_area.Remove (this.content_area.Children [0]); + + foreach (Button button in this.buttons) + this.buttons.Remove (button); + } + + + new public void ShowAll () + { + if (this.buttons.Children.Length > 0) { + Button default_button = (Button) this.buttons.Children [this.buttons.Children.Length - 1]; + + default_button.CanDefault = true; + Default = default_button; + } + + Present (); + base.ShowAll (); + } + } +} diff --git a/SparkleShare/Linux/SparkleStatusIcon.cs b/SparkleShare/Linux/SparkleStatusIcon.cs new file mode 100644 index 0000000..1b7f2dd --- /dev/null +++ b/SparkleShare/Linux/SparkleStatusIcon.cs @@ -0,0 +1,297 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; + +using Gtk; +#if HAVE_APP_INDICATOR +using AppIndicator3; +#endif + +namespace SparkleShare { + + public class SparkleStatusIcon { + + public SparkleStatusIconController Controller = new SparkleStatusIconController (); + + private Menu menu; + private MenuItem recent_events_item; + private MenuItem quit_item; + private MenuItem state_item; + private SparkleMenuItem [] state_menu_items; + + #if HAVE_APP_INDICATOR + private Indicator indicator; + #else + private StatusIcon status_icon; + #endif + + + public SparkleStatusIcon () + { + #if HAVE_APP_INDICATOR + this.indicator = new Indicator ("sparkleshare", "sparkleshare", (int) IndicatorCategory.ApplicationStatus); + this.indicator.IconName = "process-syncing-idle"; + this.indicator.Status = (int) IndicatorStatus.Active; + #else + this.status_icon = new StatusIcon (); + this.status_icon.IconName = "sparkleshare"; + + this.status_icon.Activate += ShowMenu; // Primary mouse button click + this.status_icon.PopupMenu += ShowMenu; // Secondary mouse button click + #endif + + CreateMenu (); + + Controller.UpdateIconEvent += delegate (IconState state) { + Application.Invoke (delegate { + #if HAVE_APP_INDICATOR + string icon_name = "process-syncing-idle"; + #else + string icon_name = "sparkleshare"; + #endif + + if (state == IconState.SyncingUp) + icon_name = "process-syncing-up"; + else if (state == IconState.SyncingDown) + icon_name = "process-syncing-down"; + else if (state == IconState.Syncing) + icon_name = "process-syncing"; + else if (state == IconState.Error) + icon_name = "process-syncing-error"; + + #if HAVE_APP_INDICATOR + this.indicator.IconName = icon_name; + + // Force update of the status icon + this.indicator.Status = (int) IndicatorStatus.Attention; + this.indicator.Status = (int) IndicatorStatus.Active; + #else + this.status_icon.IconName = icon_name; + #endif + }); + }; + + Controller.UpdateStatusItemEvent += delegate (string state_text) { + Application.Invoke (delegate { + (this.state_item.Child as Label).Text = state_text; + this.state_item.ShowAll (); + + if (Controller.Projects.Length == this.state_menu_items.Length) { + for (int i = 0; i < Controller.Projects.Length; i++) { + (this.state_menu_items [i].Child as Label).Text = Controller.Projects [i].StatusMessage; + this.state_menu_items [i].ShowAll (); + } + } + }); + }; + + Controller.UpdateQuitItemEvent += delegate (bool item_enabled) { + Application.Invoke (delegate { + this.quit_item.Sensitive = item_enabled; + this.quit_item.ShowAll (); + }); + }; + + Controller.UpdateMenuEvent += delegate (IconState state) { + Application.Invoke (delegate { CreateMenu (); }); + }; + } + + + public void CreateMenu () + { + this.menu = new Menu (); + this.state_item = new MenuItem (Controller.StateText) { Sensitive = false }; + + ImageMenuItem folder_item = new SparkleMenuItem ("SparkleShare"); + folder_item.Image = new Image (SparkleUIHelpers.GetIcon ("sparkleshare", 16)); + + this.menu.Add (this.state_item); + this.menu.Add (new SeparatorMenuItem ()); + this.menu.Add (folder_item); + + + this.state_menu_items = new SparkleMenuItem [Controller.Projects.Length]; + + if (Controller.Projects.Length > 0) { + int i = 0; + foreach (ProjectInfo project in Controller.Projects) { + SparkleMenuItem item = new SparkleMenuItem (project.Name); + + Gdk.Pixbuf folder_icon; + folder_icon = IconTheme.Default.LoadIcon ("folder", 16, IconLookupFlags.GenericFallback); + + item.Submenu = new Menu (); + + this.state_menu_items [i] = new SparkleMenuItem (project.StatusMessage) { Sensitive = false }; + + (item.Submenu as Menu).Add (this.state_menu_items [i]); + (item.Submenu as Menu).Add (new SeparatorMenuItem ()); + + if (project.IsPaused) { + MenuItem resume_item; + + if (project.UnsyncedChangesInfo.Count > 0) { + string icons_path = new string [] { + SparkleUI.AssetsPath, "icons", "hicolor", "12x12", "status"}.Combine (); + + foreach (KeyValuePair pair in project.UnsyncedChangesInfo) { + string icon_path = new string [] { + icons_path, pair.Value.Replace ("-12", "")}.Combine (); + + (item.Submenu as Menu).Add (new SparkleMenuItem (pair.Key) { + Image = new Image (icon_path), + Sensitive = false + }); + } + + if (!string.IsNullOrEmpty (project.MoreUnsyncedChanges)) { + (item.Submenu as Menu).Add (new MenuItem (project.MoreUnsyncedChanges) { + Sensitive = false + }); + } + + (item.Submenu as Menu).Add (new SeparatorMenuItem ()); + resume_item = new MenuItem ("Sync and Resume…"); + + } else { + resume_item = new MenuItem ("Resume"); + } + + resume_item.Activated += Controller.ResumeDelegate (project.Name); + (item.Submenu as Menu).Add (resume_item); + + } else { + if (Controller.Projects [i].HasError) { + folder_icon = IconTheme.Default.LoadIcon ("dialog-warning", 16, IconLookupFlags.GenericFallback); + + MenuItem try_again_item = new MenuItem ("Try Again"); + try_again_item.Activated += Controller.TryAgainDelegate (project.Name); + (item.Submenu as Menu).Add (try_again_item); + + } else { + MenuItem pause_item = new MenuItem ("Pause"); + pause_item.Activated += Controller.PauseDelegate (project.Name); + (item.Submenu as Menu).Add (pause_item); + } + } + + (item.Child as Label).UseUnderline = false; + item.Image = new Image (folder_icon); + this.menu.Add (item); + + i++; + }; + } + + this.recent_events_item = new MenuItem ("Recent Changes…"); + this.recent_events_item.Sensitive = Controller.RecentEventsItemEnabled; + this.quit_item = new MenuItem ("Quit") { Sensitive = Controller.QuitItemEnabled }; + MenuItem add_item = new MenuItem ("Add Hosted Project…"); + + #if HAVE_APP_INDICATOR + MenuItem notify_item; + + if (Program.Controller.NotificationsEnabled) + notify_item = new MenuItem ("Turn Notifications Off"); + else + notify_item = new MenuItem ("Turn Notifications On"); + + notify_item.Activated += delegate { + Program.Controller.ToggleNotifications (); + + Application.Invoke (delegate { + if (Program.Controller.NotificationsEnabled) + (notify_item.Child as Label).Text = "Turn Notifications Off"; + else + (notify_item.Child as Label).Text = "Turn Notifications On"; + }); + }; + #endif + + MenuItem link_code_item = new MenuItem ("Client ID"); + + if (Controller.LinkCodeItemEnabled) { + link_code_item.Submenu = new Menu (); + + string link_code = Program.Controller.CurrentUser.PublicKey.Substring (0, 20) + "..."; + MenuItem code_item = new MenuItem (link_code) { Sensitive = false }; + + MenuItem copy_item = new MenuItem ("Copy to Clipboard"); + copy_item.Activated += delegate { Controller.CopyToClipboardClicked (); }; + + (link_code_item.Submenu as Menu).Add (code_item); + (link_code_item.Submenu as Menu).Add (new SeparatorMenuItem ()); + (link_code_item.Submenu as Menu).Add (copy_item); + } + + MenuItem about_item = new MenuItem ("About SparkleShare"); + + about_item.Activated += delegate { Controller.AboutClicked (); }; + add_item.Activated += delegate { Controller.AddHostedProjectClicked (); }; + this.recent_events_item.Activated += delegate { Controller.RecentEventsClicked (); }; + this.quit_item.Activated += delegate { Controller.QuitClicked (); }; + + folder_item.Submenu = new Menu (); + (folder_item.Submenu as Menu).Add (this.recent_events_item); + (folder_item.Submenu as Menu).Add (add_item); + #if HAVE_APP_INDICATOR + (folder_item.Submenu as Menu).Add (new SeparatorMenuItem ()); + (folder_item.Submenu as Menu).Add (notify_item); + #endif + (folder_item.Submenu as Menu).Add (new SeparatorMenuItem ()); + (folder_item.Submenu as Menu).Add (link_code_item); + (folder_item.Submenu as Menu).Add (new SeparatorMenuItem ()); + (folder_item.Submenu as Menu).Add (about_item); + + this.menu.Add (new SeparatorMenuItem ()); + this.menu.Add (this.quit_item); + this.menu.ShowAll (); + + #if HAVE_APP_INDICATOR + this.indicator.Menu = this.menu; + #endif + } + + + #if !HAVE_APP_INDICATOR + // Makes the menu visible + private void ShowMenu (object o, EventArgs args) + { + this.menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime); + } + + + // 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) + { + StatusIcon.PositionMenu (menu, out x, out y, out push_in, this.status_icon.Handle); + } + #endif + } + + + public class SparkleMenuItem : ImageMenuItem { + + public SparkleMenuItem (string text) : base (text) + { + SetProperty ("always-show-image", new GLib.Value (true)); + } + } +} diff --git a/SparkleShare/Linux/SparkleUI.cs b/SparkleShare/Linux/SparkleUI.cs new file mode 100644 index 0000000..4c5b27b --- /dev/null +++ b/SparkleShare/Linux/SparkleUI.cs @@ -0,0 +1,99 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; + +using GLib; +using Gtk; +using SparkleLib; + +namespace SparkleShare { + + public class SparkleUI { + + public static string AssetsPath = Defines.INSTALL_DIR; + + public SparkleStatusIcon StatusIcon; + public SparkleEventLog EventLog; + public SparkleBubbles Bubbles; + public SparkleSetup Setup; + public SparkleAbout About; + public SparkleNote Note; + + public readonly string SecondaryTextColor; + public readonly string SecondaryTextColorSelected; + + private Gtk.Application application; + + + public SparkleUI () + { + this.application = new Gtk.Application ("org.sparkleshare.sparkleshare", 0); + + this.application.Register (null); + this.application.Activated += ApplicationActivatedDelegate; + + Gdk.Color color = SparkleUIHelpers.RGBAToColor (new Label().StyleContext.GetColor (StateFlags.Insensitive)); + SecondaryTextColor = SparkleUIHelpers.ColorToHex (color); + + color = SparkleUIHelpers.MixColors ( + SparkleUIHelpers.RGBAToColor (new TreeView ().StyleContext.GetColor (StateFlags.Selected)), + SparkleUIHelpers.RGBAToColor (new TreeView ().StyleContext.GetBackgroundColor (StateFlags.Selected)), + 0.39); + + SecondaryTextColorSelected = SparkleUIHelpers.ColorToHex (color); + } + + + public void Run () + { + (this.application as GLib.Application).Run (null, null); + } + + + private void ApplicationActivatedDelegate (object sender, EventArgs args) + { + if (this.application.Windows.Length > 0) { + bool has_visible_windows = false; + + foreach (Window window in this.application.Windows) { + if (window.Visible) { + window.Present (); + has_visible_windows = true; + } + } + + if (!has_visible_windows) + Program.Controller.HandleReopen (); + + } else { + Setup = new SparkleSetup (); + EventLog = new SparkleEventLog (); + About = new SparkleAbout (); + Bubbles = new SparkleBubbles (); + StatusIcon = new SparkleStatusIcon (); + Note = new SparkleNote (); + + Setup.Application = this.application; + EventLog.Application = this.application; + About.Application = this.application; + + Program.Controller.UIHasLoaded (); + } + } + } +} diff --git a/SparkleShare/Linux/SparkleUIHelpers.cs b/SparkleShare/Linux/SparkleUIHelpers.cs new file mode 100755 index 0000000..d147b00 --- /dev/null +++ b/SparkleShare/Linux/SparkleUIHelpers.cs @@ -0,0 +1,93 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using Gtk; + +namespace SparkleShare { + + public static class SparkleUIHelpers { + + public static Gdk.Pixbuf GetIcon (string name, int size) + { + IconTheme icon_theme = new IconTheme (); + icon_theme.AppendSearchPath (new string [] {SparkleUI.AssetsPath, "icons"}.Combine ()); + + foreach (string search_path in IconTheme.Default.SearchPath) + icon_theme.AppendSearchPath (search_path); + + try { + return icon_theme.LoadIcon (name, size, IconLookupFlags.GenericFallback); + + } catch { + try { + return icon_theme.LoadIcon ("gtk-missing-image", size, IconLookupFlags.GenericFallback); + + } catch { + return null; + } + } + } + + + public static Image GetImage (string name) + { + string image_path = new string [] { SparkleUI.AssetsPath, "pixmaps", name }.Combine (); + return new Image (image_path); + } + + + // Converts a Gdk RGB color to a hex value. + // Example: from "rgb:0,0,0" to "#000000" + public static string ColorToHex (Gdk.Color color) + { + return String.Format ("#{0:X2}{1:X2}{2:X2}", + (int) Math.Truncate (color.Red / 256.00), + (int) Math.Truncate (color.Green / 256.00), + (int) Math.Truncate (color.Blue / 256.00)); + } + + + public static Gdk.Color RGBAToColor (Gdk.RGBA rgba) { + return new Gdk.Color () { + Red = (ushort) (rgba.Red * 65535), + Green = (ushort) (rgba.Green * 65535), + Blue = (ushort)(rgba.Blue * 65535) + }; + } + + + public static string RGBAToHex (Gdk.RGBA rgba) + { + return ColorToHex (RGBAToColor (rgba)); + } + + + public static Gdk.Color MixColors (Gdk.Color first_color, Gdk.Color second_color, double ratio) + { + return new Gdk.Color ( + Convert.ToByte ((255 * (Math.Min (65535, first_color.Red * (1.0 - ratio) + + second_color.Red * ratio))) / 65535), + Convert.ToByte ((255 * (Math.Min (65535, first_color.Green * (1.0 - ratio) + + second_color.Green * ratio))) / 65535), + Convert.ToByte ((255 * (Math.Min (65535, first_color.Blue * (1.0 - ratio) + + second_color.Blue * ratio))) / 65535) + ); + } + } +} + diff --git a/SparkleShare/Linux/sparkleshare-invite-opener.desktop b/SparkleShare/Linux/sparkleshare-invite-opener.desktop new file mode 100644 index 0000000..b2cc168 --- /dev/null +++ b/SparkleShare/Linux/sparkleshare-invite-opener.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=SparkleShareInviteOpener +Exec=sparkleshare open %U +Terminal=false +MimeType=application/x-sparkleshare;x-scheme-handler/sparkleshare; +NoDisplay=true diff --git a/SparkleShare/Linux/sparkleshare.appdata.xml b/SparkleShare/Linux/sparkleshare.appdata.xml new file mode 100644 index 0000000..3a451f1 --- /dev/null +++ b/SparkleShare/Linux/sparkleshare.appdata.xml @@ -0,0 +1,26 @@ + + + sparkleshare.desktop + CC0 + SparkleShare + Self hosted, instant, secure file sync + +

SparkleShare creates a special folder on your computer. You can add remotely hosted folders (or "projects") to this folder. These projects will be automatically kept in sync with both the host and all of your peers when someone adds, removes or edits a file.

+

SparkleShare was made to cover certain use cases, but doesn't handle every scenario well. To help you decide if SparkleShare is right for you, here's a few examples of what it does well and less well:

+

Great:

+
    +
  • Frequently changing project files, like text, office documents, and images
  • +
  • Tracking and syncing files edited by multiple people
  • +
  • Reverting a file to any point in its history
  • +
  • Preventing spying on your files on the server using encryption
  • +
+

Not so great:

+
    +
  • Full computer backups
  • +
  • Storing your photo or music collection
  • +
  • Large binary files that change often, like video editing projects
  • +
+

Have fun!

+
+ http://www.sparkleshare.org/ +
diff --git a/SparkleShare/Linux/sparkleshare.desktop b/SparkleShare/Linux/sparkleshare.desktop new file mode 100755 index 0000000..a8cf52c --- /dev/null +++ b/SparkleShare/Linux/sparkleshare.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=SparkleShare +Comment=Self hosted, instant, secure file sync +Exec=sparkleshare start +Icon=sparkleshare +Terminal=false +X-GNOME-Autostart-enabled=true +Categories=Network; diff --git a/SparkleShare/Linux/sparkleshare.in b/SparkleShare/Linux/sparkleshare.in new file mode 100755 index 0000000..5af417c --- /dev/null +++ b/SparkleShare/Linux/sparkleshare.in @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +if [[ $UID -eq 0 ]]; then + echo "SparkleShare can't be run as root. Things would go utterly wrong." + exit 1 +fi + +start() { + if [ -n "${SSH_AGENT_PID}" -o -n "${SSH_AUTH_SOCK}" ] ; then + mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" $2 & + else + ssh-agent mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" $2 & + fi +} + +case $1 in + start|--start) + start + ;; + open|--open) + invite=`date -u +%N` + open=`echo $2 | sed 's/sparkleshare:\/\/addProject\///'` + curl --insecure --output ~/SparkleShare/.$invite.xml $open + start + ;; + *) + mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --help + ;; +esac diff --git a/SparkleShare/Mac/AppDelegate.cs b/SparkleShare/Mac/AppDelegate.cs new file mode 100755 index 0000000..9e246c1 --- /dev/null +++ b/SparkleShare/Mac/AppDelegate.cs @@ -0,0 +1,31 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Drawing; + +using MonoMac.Foundation; +using MonoMac.AppKit; +using MonoMac.ObjCRuntime; + +namespace SparkleShare +{ + public partial class AppDelegate : NSApplicationDelegate + { + + } +} diff --git a/SparkleShare/Mac/Info.plist b/SparkleShare/Mac/Info.plist new file mode 100755 index 0000000..73f9a12 --- /dev/null +++ b/SparkleShare/Mac/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleIconFile + sparkleshare-app + CFBundleIdentifier + org.sparkleshare.sparkleshare + CFBundleName + SparkleShare + CFBundleShortVersionString + 1.5.0 + CFBundleVersion + 1.5.0 + LSApplicationCategoryType + public.app-category.productivity + LSMinimumSystemVersion + 10.6 + LSUIElement + 1 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/SparkleShare/Mac/MainMenu.xib b/SparkleShare/Mac/MainMenu.xib new file mode 100755 index 0000000..cdc8021 --- /dev/null +++ b/SparkleShare/Mac/MainMenu.xib @@ -0,0 +1,2195 @@ + + + + 1060 + 10J869 + 851 + 1038.35 + 461.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 851 + + + YES + + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + YES + + + SparkleShare + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + SparkleShare + + YES + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + YES + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide SparkleShare + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit SparkleShare + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + Edit + + YES + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + Find + + YES + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + Spelling and Grammar + + YES + + + Show Spelling and Grammar + : + 1048576 + 2147483647 + + + + + + Check Document Now + ; + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + Correct Spelling Automatically + + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + Substitutions + + YES + + + Show Substitutions + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Dashes + + 2147483647 + + + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + Text Replacement + + 2147483647 + + + + + + + + + Transformations + + 2147483647 + + + submenuAction: + + Transformations + + YES + + + Make Upper Case + + 2147483647 + + + + + + Make Lower Case + + 2147483647 + + + + + + Capitalize + + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + YES + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + YES + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + YES + + + SparkleShare Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + NSFontManager + + + AppDelegate + + + + + YES + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + terminate: + + + + 449 + + + + toggleAutomaticSpellingCorrection: + + + + 456 + + + + orderFrontSubstitutionsPanel: + + + + 458 + + + + toggleAutomaticDashSubstitution: + + + + 461 + + + + toggleAutomaticTextReplacement: + + + + 463 + + + + uppercaseWord: + + + + 464 + + + + capitalizeWord: + + + + 467 + + + + lowercaseWord: + + + + 468 + + + + pasteAsPlainText: + + + + 486 + + + + performFindPanelAction: + + + + 487 + + + + performFindPanelAction: + + + + 488 + + + + performFindPanelAction: + + + + 489 + + + + showHelp: + + + + 493 + + + + delegate + + + + 534 + + + + + YES + + 0 + + YES + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + YES + + + + + + + + + 19 + + + YES + + + + + + 56 + + + YES + + + + + + 217 + + + YES + + + + + + 205 + + + YES + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + YES + + + + + + 216 + + + YES + + + + + + 200 + + + YES + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + YES + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 57 + + + YES + + + + + + + + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 131 + + + YES + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + YES + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 211 + + + YES + + + + + + 212 + + + YES + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + YES + + + + + + 349 + + + YES + + + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 420 + + + + + 450 + + + YES + + + + + + 451 + + + YES + + + + + + + + 452 + + + + + 453 + + + + + 454 + + + + + 457 + + + + + 459 + + + + + 460 + + + + + 462 + + + + + 465 + + + + + 466 + + + + + 485 + + + + + 490 + + + YES + + + + + + 491 + + + YES + + + + + + 492 + + + + + 533 + + + + + + + YES + + YES + -3.IBPluginDependency + 130.IBEditorWindowLastContentRect + 130.IBPluginDependency + 130.ImportedFromIB2 + 130.editorWindowContentRectSynchronizationRect + 131.IBPluginDependency + 131.ImportedFromIB2 + 134.IBPluginDependency + 134.ImportedFromIB2 + 136.IBPluginDependency + 136.ImportedFromIB2 + 144.IBPluginDependency + 144.ImportedFromIB2 + 145.IBPluginDependency + 145.ImportedFromIB2 + 149.IBPluginDependency + 149.ImportedFromIB2 + 150.IBPluginDependency + 150.ImportedFromIB2 + 19.IBPluginDependency + 19.ImportedFromIB2 + 195.IBPluginDependency + 195.ImportedFromIB2 + 196.IBPluginDependency + 196.ImportedFromIB2 + 197.IBPluginDependency + 197.ImportedFromIB2 + 198.IBPluginDependency + 198.ImportedFromIB2 + 199.IBPluginDependency + 199.ImportedFromIB2 + 200.IBEditorWindowLastContentRect + 200.IBPluginDependency + 200.ImportedFromIB2 + 200.editorWindowContentRectSynchronizationRect + 201.IBPluginDependency + 201.ImportedFromIB2 + 202.IBPluginDependency + 202.ImportedFromIB2 + 203.IBPluginDependency + 203.ImportedFromIB2 + 204.IBPluginDependency + 204.ImportedFromIB2 + 205.IBEditorWindowLastContentRect + 205.IBPluginDependency + 205.ImportedFromIB2 + 205.editorWindowContentRectSynchronizationRect + 206.IBPluginDependency + 206.ImportedFromIB2 + 207.IBPluginDependency + 207.ImportedFromIB2 + 208.IBPluginDependency + 208.ImportedFromIB2 + 209.IBPluginDependency + 209.ImportedFromIB2 + 210.IBPluginDependency + 210.ImportedFromIB2 + 211.IBPluginDependency + 211.ImportedFromIB2 + 212.IBPluginDependency + 212.ImportedFromIB2 + 212.editorWindowContentRectSynchronizationRect + 213.IBPluginDependency + 213.ImportedFromIB2 + 214.IBPluginDependency + 214.ImportedFromIB2 + 215.IBPluginDependency + 215.ImportedFromIB2 + 216.IBPluginDependency + 216.ImportedFromIB2 + 217.IBPluginDependency + 217.ImportedFromIB2 + 218.IBPluginDependency + 218.ImportedFromIB2 + 219.IBPluginDependency + 219.ImportedFromIB2 + 220.IBEditorWindowLastContentRect + 220.IBPluginDependency + 220.ImportedFromIB2 + 220.editorWindowContentRectSynchronizationRect + 221.IBPluginDependency + 221.ImportedFromIB2 + 23.IBPluginDependency + 23.ImportedFromIB2 + 239.IBPluginDependency + 239.ImportedFromIB2 + 24.IBEditorWindowLastContentRect + 24.IBPluginDependency + 24.ImportedFromIB2 + 24.editorWindowContentRectSynchronizationRect + 29.IBEditorWindowLastContentRect + 29.IBPluginDependency + 29.ImportedFromIB2 + 29.WindowOrigin + 29.editorWindowContentRectSynchronizationRect + 346.IBPluginDependency + 346.ImportedFromIB2 + 348.IBPluginDependency + 348.ImportedFromIB2 + 349.IBEditorWindowLastContentRect + 349.IBPluginDependency + 349.ImportedFromIB2 + 349.editorWindowContentRectSynchronizationRect + 350.IBPluginDependency + 350.ImportedFromIB2 + 351.IBPluginDependency + 351.ImportedFromIB2 + 354.IBPluginDependency + 354.ImportedFromIB2 + 450.IBPluginDependency + 451.IBEditorWindowLastContentRect + 451.IBPluginDependency + 452.IBPluginDependency + 453.IBPluginDependency + 454.IBPluginDependency + 457.IBPluginDependency + 459.IBPluginDependency + 460.IBPluginDependency + 462.IBPluginDependency + 465.IBPluginDependency + 466.IBPluginDependency + 485.IBPluginDependency + 490.IBPluginDependency + 491.IBEditorWindowLastContentRect + 491.IBPluginDependency + 492.IBPluginDependency + 5.IBPluginDependency + 5.ImportedFromIB2 + 56.IBPluginDependency + 56.ImportedFromIB2 + 57.IBEditorWindowLastContentRect + 57.IBPluginDependency + 57.ImportedFromIB2 + 57.editorWindowContentRectSynchronizationRect + 92.IBPluginDependency + 92.ImportedFromIB2 + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + {{529, 686}, {64, 6}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{436, 809}, {64, 6}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{753, 187}, {275, 113}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {275, 83}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{470, 439}, {254, 283}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{187, 434}, {243, 243}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {167, 43}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{753, 217}, {238, 103}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {241, 103}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{514, 649}, {194, 73}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{525, 802}, {197, 73}} + {{346, 722}, {300, 20}} + com.apple.InterfaceBuilder.CocoaPlugin + + {74, 862} + {{6, 978}, {478, 20}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{746, 287}, {220, 133}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{608, 612}, {215, 63}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + {{724, 419}, {170, 63}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{585, 699}, {194, 23}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{358, 599}, {213, 123}} + com.apple.InterfaceBuilder.CocoaPlugin + + {{23, 794}, {245, 183}} + com.apple.InterfaceBuilder.CocoaPlugin + + + + + YES + + + YES + + + + + YES + + + YES + + + + 538 + + + + YES + + AppDelegate + NSResponder + + IBUserSource + + + + + + YES + + NSApplication + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSApplication.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSApplicationScripting.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSColorPanel.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSHelpManager.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSPageLayout.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSUserInterfaceItemSearching.h + + + + NSBrowser + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSBrowser.h + + + + NSControl + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSControl.h + + + + NSFontManager + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontManager.h + + + + NSFormatter + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFormatter.h + + + + NSMatrix + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSMatrix.h + + + + NSMenu + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenu.h + + + + NSMenuItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItem.h + + + + NSMovieView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSMovieView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSAccessibility.h + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDictionaryController.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDragging.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontPanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSKeyValueBinding.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSNibLoading.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSOutlineView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSPasteboard.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSSavePanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbarItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSView.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObjectScripting.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPortCoder.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptObjectSpecifiers.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptWhoseTests.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLDownload.h + + + + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSInterfaceStyle.h + + + + NSResponder + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSResponder.h + + + + NSTableView + NSControl + + + + NSText + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSText.h + + + + NSTextView + NSText + + IBFrameworkSource + AppKit.framework/Headers/NSTextView.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSClipView.h + + + + NSView + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSRulerView.h + + + + NSView + NSResponder + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSDrawer.h + + + + NSWindow + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSWindow.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSWindowScripting.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + ../MacCocoaApp.xcodeproj + 3 + + YES + + YES + NSMenuCheckmark + NSMenuMixedState + + + YES + {9, 8} + {7, 2} + + + + diff --git a/SparkleShare/Mac/MainMenu.xib.designer.cs b/SparkleShare/Mac/MainMenu.xib.designer.cs new file mode 100755 index 0000000..1ce6227 --- /dev/null +++ b/SparkleShare/Mac/MainMenu.xib.designer.cs @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Mono Runtime Version: 4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +namespace SparkleShare { + + + // Should subclass MonoMac.AppKit.NSResponder + [MonoMac.Foundation.Register("AppDelegate")] + public partial class AppDelegate { + } +} diff --git a/SparkleShare/Mac/README.md b/SparkleShare/Mac/README.md new file mode 100644 index 0000000..60fea68 --- /dev/null +++ b/SparkleShare/Mac/README.md @@ -0,0 +1,57 @@ +## Building on Mac + +You can build SparkleShare from source or download the SparkleShare bundle. + + +### Installing build requirements + + Install [Xcode](https://itunes.apple.com/gb/app/xcode/id497799835?mt=12) from the Mac App Store, or [download](https://developer.apple.com/xcode/) it manually. + Install [Xamarin Studio](http://monodevelop.com/download/). + +The required `git` binaries are now built automatically. For doing this and for building the distribution release, where Mono libraries are merged into SparkleShare, we need + the packes autoconf and pkg-config. You can install these in several ways, here's how it's done using [Homebrew](http://brew.sh/): + +```bash +brew install autoconf automake libtool pkg-config +``` + +### Building + +There are three build configurations available: + +* Debug + + with debug symbols and having the Symbol DEBUG defined. Requires an installed Mono framework. + +* Release + + without debug symbols. Requires an installed Mono framework. + +* ReleaseDist + + without debug symbols, the Mono framework is linked statically into the binary, so it does not require an installed Mono framework. + +To build any of these configurations, + +* open `./SparkleShare/Mac/SparkleShare.sln` +* select the required configuration +* select `Build`, then `"Build SparkleShare"` from the menu + +To build SparkleShare from a command line (e.g. for using a CI system), use this command: + +```bash +/Applications/Xamarin\ Studio.app/Contents/MacOS/mdtool -v build "--configuration:ReleaseDist" "./SparkleShare/Mac/SparkleShare.sln" +``` + + +### Resetting SparkleShare settings + +``` +rm -Rf ~/SparkleShare +rm -Rf ~/.config/sparkleshare +``` + + +### Uninstalling + +Simply remove the SparkleShare bundle. diff --git a/SparkleShare/Mac/Resources/process-syncing-down.png b/SparkleShare/Mac/Resources/process-syncing-down.png new file mode 100644 index 0000000..3841a78 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-down.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing-down@2x.png b/SparkleShare/Mac/Resources/process-syncing-down@2x.png new file mode 100644 index 0000000..9e4c575 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-down@2x.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing-error.png b/SparkleShare/Mac/Resources/process-syncing-error.png new file mode 100755 index 0000000..dec4784 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-error.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing-error@2x.png b/SparkleShare/Mac/Resources/process-syncing-error@2x.png new file mode 100644 index 0000000..df3f611 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-error@2x.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing-idle.png b/SparkleShare/Mac/Resources/process-syncing-idle.png new file mode 100755 index 0000000..b6f3ed1 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-idle.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing-idle@2x.png b/SparkleShare/Mac/Resources/process-syncing-idle@2x.png new file mode 100644 index 0000000..8849c66 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-idle@2x.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing-up.png b/SparkleShare/Mac/Resources/process-syncing-up.png new file mode 100644 index 0000000..bc6bd03 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-up.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing-up@2x.png b/SparkleShare/Mac/Resources/process-syncing-up@2x.png new file mode 100644 index 0000000..e9e6484 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing-up@2x.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing.png b/SparkleShare/Mac/Resources/process-syncing.png new file mode 100644 index 0000000..e7a1498 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing.png differ diff --git a/SparkleShare/Mac/Resources/process-syncing@2x.png b/SparkleShare/Mac/Resources/process-syncing@2x.png new file mode 100644 index 0000000..abc2ef6 Binary files /dev/null and b/SparkleShare/Mac/Resources/process-syncing@2x.png differ diff --git a/SparkleShare/Mac/Resources/sparkleshare-app.icns b/SparkleShare/Mac/Resources/sparkleshare-app.icns new file mode 100755 index 0000000..c550166 Binary files /dev/null and b/SparkleShare/Mac/Resources/sparkleshare-app.icns differ diff --git a/SparkleShare/Mac/Resources/sparkleshare-folder-yosemite.icns b/SparkleShare/Mac/Resources/sparkleshare-folder-yosemite.icns new file mode 100644 index 0000000..8694bb1 Binary files /dev/null and b/SparkleShare/Mac/Resources/sparkleshare-folder-yosemite.icns differ diff --git a/SparkleShare/Mac/Resources/sparkleshare-folder.icns b/SparkleShare/Mac/Resources/sparkleshare-folder.icns new file mode 100755 index 0000000..7d6c037 Binary files /dev/null and b/SparkleShare/Mac/Resources/sparkleshare-folder.icns differ diff --git a/SparkleShare/Mac/Resources/tutorial-slide-3.png b/SparkleShare/Mac/Resources/tutorial-slide-3.png new file mode 100644 index 0000000..1b74b50 Binary files /dev/null and b/SparkleShare/Mac/Resources/tutorial-slide-3.png differ diff --git a/SparkleShare/Mac/Resources/tutorial-slide-3@2x.png b/SparkleShare/Mac/Resources/tutorial-slide-3@2x.png new file mode 100644 index 0000000..0a1701f Binary files /dev/null and b/SparkleShare/Mac/Resources/tutorial-slide-3@2x.png differ diff --git a/SparkleShare/Mac/SparkleAbout.cs b/SparkleShare/Mac/SparkleAbout.cs new file mode 100755 index 0000000..448f7a1 --- /dev/null +++ b/SparkleShare/Mac/SparkleAbout.cs @@ -0,0 +1,219 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Drawing; +using System.IO; + +using MonoMac.AppKit; +using MonoMac.Foundation; + +namespace SparkleShare { + + public class SparkleAbout : NSWindow { + + public SparkleAboutController Controller = new SparkleAboutController (); + + private NSTextField version_text_field, updates_text_field, credits_text_field; + private SparkleLink website_link, credits_link, report_problem_link, debug_log_link; + private NSImage about_image; + private NSImageView about_image_view; + private NSButton hidden_close_button; + + + public SparkleAbout (IntPtr handle) : base (handle) { } + + public SparkleAbout () : base () + { + SetFrame (new RectangleF (0, 0, 640, 281), true); + Center (); + + Delegate = new SparkleAboutDelegate (); + StyleMask = (NSWindowStyle.Closable | NSWindowStyle.Titled); + Title = "About SparkleShare"; + MaxSize = new SizeF (640, 281); + MinSize = new SizeF (640, 281); + HasShadow = true; + BackingType = NSBackingStore.Buffered; + Level = NSWindowLevel.Floating; + + this.hidden_close_button = new NSButton () { + Frame = new RectangleF (0, 0, 0, 0), + KeyEquivalentModifierMask = NSEventModifierMask.CommandKeyMask, + KeyEquivalent = "w" + }; + + CreateAbout (); + + + this.hidden_close_button.Activated += delegate { Controller.WindowClosed (); }; + + Controller.HideWindowEvent += delegate { + Program.Controller.Invoke (() => PerformClose (this)); + }; + + Controller.ShowWindowEvent += delegate { + Program.Controller.Invoke (() => OrderFrontRegardless ()); + }; + + Controller.UpdateLabelEvent += delegate (string text) { + Program.Controller.Invoke (() => { this.updates_text_field.StringValue = text; }); + }; + + + ContentView.AddSubview (this.hidden_close_button); + } + + + private void CreateAbout () + { + this.about_image = NSImage.ImageNamed ("about"); + this.about_image.Size = new SizeF (720, 260); + + this.about_image_view = new NSImageView () { + Image = this.about_image, + Frame = new RectangleF (0, 0, 720, 260) + }; + + this.version_text_field = new SparkleLabel ("version " + Controller.RunningVersion, NSTextAlignment.Left) { + DrawsBackground = false, + Frame = new RectangleF (295, 140, 318, 22), + TextColor = NSColor.White + }; + + this.updates_text_field = new SparkleLabel ("Checking for updates...", NSTextAlignment.Left) { + DrawsBackground = false, + Frame = new RectangleF (295, Frame.Height - 232, 318, 98), + TextColor = NSColor.FromCalibratedRgba (1.0f, 1.0f, 1.0f, 0.5f) + }; + + this.credits_text_field = new SparkleLabel ( + @"Copyright © 2010–" + DateTime.Now.Year + " Hylke Bons and others." + + "\n\n" + + "SparkleShare is Open Source. You are free to use, modify, and redistribute it " + + "under the GNU GPLv3.", NSTextAlignment.Left) { + + DrawsBackground = false, + Frame = new RectangleF (295, Frame.Height - 260, 318, 98), + TextColor = NSColor.White + }; + + this.website_link = new SparkleLink ("Website", Controller.WebsiteLinkAddress); + this.website_link.Frame = new RectangleF (new PointF (295, 25), this.website_link.Frame.Size); + + this.credits_link = new SparkleLink ("Credits", Controller.CreditsLinkAddress); + this.credits_link.Frame = new RectangleF ( + new PointF (this.website_link.Frame.X + this.website_link.Frame.Width + 10, 25), + this.credits_link.Frame.Size); + + this.report_problem_link = new SparkleLink ("Report a problem", Controller.ReportProblemLinkAddress); + this.report_problem_link.Frame = new RectangleF ( + new PointF (this.credits_link.Frame.X + this.credits_link.Frame.Width + 10, 25), + this.report_problem_link.Frame.Size); + + this.debug_log_link = new SparkleLink ("Debug log", Controller.DebugLogLinkAddress); + this.debug_log_link.Frame = new RectangleF ( + new PointF (this.report_problem_link.Frame.X + this.report_problem_link.Frame.Width + 10, 25), + this.debug_log_link.Frame.Size); + + ContentView.AddSubview (this.about_image_view); + ContentView.AddSubview (this.version_text_field); + ContentView.AddSubview (this.updates_text_field); + ContentView.AddSubview (this.credits_text_field); + ContentView.AddSubview (this.website_link); + ContentView.AddSubview (this.credits_link); + ContentView.AddSubview (this.report_problem_link); + ContentView.AddSubview (this.debug_log_link); + } + + + public override void OrderFrontRegardless () + { + NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); + MakeKeyAndOrderFront (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + base.OrderFrontRegardless (); + } + + + public override void PerformClose (NSObject sender) + { + base.OrderOut (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + return; + } + + + private class SparkleAboutDelegate : NSWindowDelegate { + + public override bool WindowShouldClose (NSObject sender) + { + (sender as SparkleAbout).Controller.WindowClosed (); + return false; + } + } + + + private class SparkleLink : NSTextField { + + private NSUrl url; + + + public SparkleLink (string text, string address) : base () + { + this.url = new NSUrl (address); + + AllowsEditingTextAttributes = true; + BackgroundColor = NSColor.White; + Bordered = false; + DrawsBackground = false; + Editable = false; + Selectable = false; + + NSData name_data = NSData.FromString ("" + text + ""); + + NSDictionary name_dictionary = new NSDictionary(); + NSAttributedString name_attributes = new NSAttributedString (name_data, new NSUrl ("file://"), out name_dictionary); + + NSMutableAttributedString s = new NSMutableAttributedString (); + s.Append (name_attributes); + + Cell.AttributedStringValue = s; + SizeToFit (); + } + + + public override void MouseUp (NSEvent e) + { + Program.Controller.OpenWebsite (this.url.ToString ()); + } + + + public override void ResetCursorRects () + { + AddCursorRect (Bounds, NSCursor.PointingHandCursor); + } + } + } +} diff --git a/SparkleShare/Mac/SparkleBubbles.cs b/SparkleShare/Mac/SparkleBubbles.cs new file mode 100755 index 0000000..1ac44e4 --- /dev/null +++ b/SparkleShare/Mac/SparkleBubbles.cs @@ -0,0 +1,54 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; + +using MonoMac.AppKit; +using MonoMac.Foundation; + +namespace SparkleShare { + + public class SparkleBubbles : NSObject { + + public SparkleBubblesController Controller = new SparkleBubblesController (); + + + public SparkleBubbles () + { + // The notification center was introduced in Mountain Lion + if (Environment.OSVersion.Version.Major >= 12) + Controller.ShowBubbleEvent += ShowBubbleEvent; + } + + + private void ShowBubbleEvent (string title, string subtext, string image_path) { + InvokeOnMainThread (() => { + NSUserNotification notification = new NSUserNotification () { + Title = title, + InformativeText = subtext, + DeliveryDate = DateTime.Now + }; + + NSUserNotificationCenter center = NSUserNotificationCenter.DefaultUserNotificationCenter; + center.ShouldPresentNotification = delegate { return true; }; + center.DidActivateNotification += delegate { Controller.BubbleClicked (); }; + + center.ScheduleNotification (notification); + }); + } + } +} diff --git a/SparkleShare/Mac/SparkleController.cs b/SparkleShare/Mac/SparkleController.cs new file mode 100755 index 0000000..8f7a79e --- /dev/null +++ b/SparkleShare/Mac/SparkleController.cs @@ -0,0 +1,241 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; + +using MonoMac.Foundation; +using MonoMac.AppKit; + +using Mono.Unix.Native; +using SparkleLib; +using System.Collections.Generic; + +namespace SparkleShare { + + public class SparkleController : SparkleControllerBase { + + public override string PluginsPath { + get { + return Path.Combine (NSBundle.MainBundle.ResourcePath, "Plugins"); + } + } + + // We have to use our own custom made folder watcher, as + // System.IO.FileSystemWatcher fails watching subfolders on Mac + private SparkleMacWatcher watcher; + + + public SparkleController () : base () + { + NSApplication.Init (); + + // Let's use the bundled git first + SparkleLib.Git.SparkleGit.GitPath = Path.Combine (NSBundle.MainBundle.ResourcePath, "git", "libexec", "git-core", "git"); + SparkleLib.Git.SparkleGit.ExecPath = Path.Combine (NSBundle.MainBundle.ResourcePath, "git", "libexec", "git-core"); + } + + + public override void Initialize () + { + base.Initialize (); + + SparkleRepoBase.UseCustomWatcher = true; + this.watcher = new SparkleMacWatcher (Program.Controller.FoldersPath); + + this.watcher.Changed += OnFilesChanged; + } + + + private void OnFilesChanged (List changed_files_in_basedir) + { + List triggered_repos = new List (); + + foreach (string file in changed_files_in_basedir) { + string repo_name; + int path_sep_index = file.IndexOf (Path.DirectorySeparatorChar); + + if (path_sep_index >= 0) + repo_name = file.Substring (0, path_sep_index); + else + repo_name = file; + + repo_name = Path.GetFileNameWithoutExtension (repo_name); + SparkleRepoBase repo = GetRepoByName (repo_name); + + if (repo == null) + continue; + + if (!triggered_repos.Contains (repo_name)) { + triggered_repos.Add (repo_name); + + FileActivityTask task = MacActivityTask (repo, + new FileSystemEventArgs (WatcherChangeTypes.Changed, file, "Unknown")); + + task (); + } + + } + } + + private delegate void FileActivityTask (); + + private FileActivityTask MacActivityTask (SparkleRepoBase repo, FileSystemEventArgs fse_args) { + return delegate { new Thread (() => { repo.OnFileActivity (fse_args); }).Start (); }; + } + + + public override void CreateStartupItem () + { + // There aren't any bindings in MonoMac to support this yet, so + // we call out to an applescript to do the job + Process process = new Process (); + process.StartInfo.FileName = "osascript"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.Arguments = "-e 'tell application \"System Events\" to " + + "make login item at end with properties {path:\"" + NSBundle.MainBundle.BundlePath + "\", hidden:false}'"; + + process.Start (); + process.WaitForExit (); + + SparkleLogger.LogInfo ("Controller", "Added " + NSBundle.MainBundle.BundlePath + " to login items"); + } + + + public override void InstallProtocolHandler () + { + // We ship SparkleShareInviteHandler.app in the bundle + } + + + public override void AddToBookmarks () + { + // TODO + } + + + public override bool CreateSparkleShareFolder () + { + if (!Directory.Exists (Program.Controller.FoldersPath)) { + Directory.CreateDirectory (Program.Controller.FoldersPath); + + if (Environment.OSVersion.Version.Major >= 14) { + NSWorkspace.SharedWorkspace.SetIconforFile ( + NSImage.ImageNamed ("sparkleshare-folder-yosemite.icns"), + Program.Controller.FoldersPath, 0); + + } else { + NSWorkspace.SharedWorkspace.SetIconforFile ( + NSImage.ImageNamed ("sparkleshare-folder.icns"), + Program.Controller.FoldersPath, 0); + } + + Syscall.chmod (Program.Controller.FoldersPath, (FilePermissions) 448); // 448 -> 700 + + return true; + } + + return false; + } + + + public override void OpenFolder (string path) + { + path = Uri.UnescapeDataString (path); + NSWorkspace.SharedWorkspace.OpenFile (path); + } + + + public override void OpenFile (string path) + { + path = Uri.UnescapeDataString (path); + NSWorkspace.SharedWorkspace.OpenFile (path); + } + + + public override void OpenWebsite (string url) + { + NSWorkspace.SharedWorkspace.OpenUrl (new NSUrl (url)); + } + + + public override void CopyToClipboard (string text) + { + NSPasteboard.GeneralPasteboard.ClearContents (); + NSPasteboard.GeneralPasteboard.SetStringForType (text, "NSStringPboardType"); + } + + + private string event_log_html; + public override string EventLogHTML + { + get { + if (string.IsNullOrEmpty (this.event_log_html)) { + string html_file_path = Path.Combine (NSBundle.MainBundle.ResourcePath, "HTML", "event-log.html"); + string jquery_file_path = Path.Combine (NSBundle.MainBundle.ResourcePath, "HTML", "jquery.js"); + string html = File.ReadAllText (html_file_path); + string jquery = File.ReadAllText (jquery_file_path); + this.event_log_html = html.Replace ("", jquery); + } + + return this.event_log_html; + } + } + + + private string day_entry_html; + public override string DayEntryHTML + { + get { + if (string.IsNullOrEmpty (this.day_entry_html)) { + string html_file_path = Path.Combine (NSBundle.MainBundle.ResourcePath, "HTML", "day-entry.html"); + this.day_entry_html = File.ReadAllText (html_file_path); + } + + return this.day_entry_html; + } + } + + + private string event_entry_html; + public override string EventEntryHTML + { + get { + if (string.IsNullOrEmpty (this.event_entry_html)) { + string html_file_path = Path.Combine (NSBundle.MainBundle.ResourcePath, "HTML", "event-entry.html"); + this.event_entry_html = File.ReadAllText (html_file_path); + } + + return this.event_entry_html; + } + } + + + public delegate void Code (); + private NSObject obj = new NSObject (); + + public void Invoke (Code code) + { + using (var a = new NSAutoreleasePool ()) + { + obj.InvokeOnMainThread (() => code ()); + } + } + } +} diff --git a/SparkleShare/Mac/SparkleEventLog.cs b/SparkleShare/Mac/SparkleEventLog.cs new file mode 100755 index 0000000..6ea3c73 --- /dev/null +++ b/SparkleShare/Mac/SparkleEventLog.cs @@ -0,0 +1,419 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Drawing; +using System.IO; +using System.Threading; + +using MonoMac.Foundation; +using MonoMac.AppKit; +using MonoMac.ObjCRuntime; +using MonoMac.WebKit; + +namespace SparkleShare { + + public class SparkleEventLog : NSWindow { + + public SparkleEventLogController Controller = new SparkleEventLogController (); + public float TitlebarHeight; + + private WebView web_view; + private NSBox background; + private NSBox cover; + private NSPopUpButton popup_button; + private NSProgressIndicator progress_indicator; + private NSTextField size_label, size_label_value, history_label, history_label_value; + private NSButton hidden_close_button; + + + public SparkleEventLog (IntPtr handle) : base (handle) { } + + public SparkleEventLog () : base () + { + Title = "Recent Changes"; + Delegate = new SparkleEventsDelegate (); + + int min_width = 480; + int min_height = 640; + int height = (int) (NSScreen.MainScreen.Frame.Height * 0.85); + + float x = (float) (NSScreen.MainScreen.Frame.Width * 0.61); + float y = (float) (NSScreen.MainScreen.Frame.Height * 0.5 - (height * 0.5)); + + SetFrame ( + new RectangleF ( + new PointF (x, y), + new SizeF (min_width, height)), + true); + + StyleMask = (NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | + NSWindowStyle.Titled | NSWindowStyle.Resizable); + + MinSize = new SizeF (min_width, min_height); + HasShadow = true; + BackingType = NSBackingStore.Buffered; + TitlebarHeight = Frame.Height - ContentView.Frame.Height; + Level = NSWindowLevel.Floating; + + + this.web_view = new WebView (new RectangleF (0, 0, 481, 579), "", "") { + Frame = new RectangleF (new PointF (0, 0), + new SizeF (ContentView.Frame.Width, ContentView.Frame.Height - 39)) + }; + + this.cover = new NSBox () { + Frame = new RectangleF ( + new PointF (-1, -1), + new SizeF (Frame.Width + 2, this.web_view.Frame.Height + 1)), + FillColor = NSColor.White, + BorderType = NSBorderType.NoBorder, + BoxType = NSBoxType.NSBoxCustom + }; + + this.hidden_close_button = new NSButton () { + KeyEquivalentModifierMask = NSEventModifierMask.CommandKeyMask, + KeyEquivalent = "w" + }; + + this.hidden_close_button.Activated += delegate { + Controller.WindowClosed (); + }; + + + this.size_label = new NSTextField () { + Alignment = NSTextAlignment.Right, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF ( + new PointF (0, ContentView.Frame.Height - 31), + new SizeF (60, 20)), + StringValue = "Size:" + }; + + this.size_label_value = new NSTextField () { + Alignment = NSTextAlignment.Left, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF ( + new PointF (60, ContentView.Frame.Height - 27), + new SizeF (60, 20)), + StringValue = "…", + Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize) + }; + + + this.history_label = new NSTextField () { + Alignment = NSTextAlignment.Right, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF ( + new PointF (130, ContentView.Frame.Height - 31), + new SizeF (60, 20)), + StringValue = "History:" + }; + + this.history_label_value = new NSTextField () { + Alignment = NSTextAlignment.Left, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF ( + new PointF (190, ContentView.Frame.Height - 27), + new SizeF (60, 20) + ), + StringValue = "…", + Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize) + }; + + this.popup_button = new NSPopUpButton () { + Frame = new RectangleF ( + new PointF (ContentView.Frame.Width - 156 - 12, ContentView.Frame.Height - 33), + new SizeF (156, 26)), + PullsDown = false + }; + + this.background = new NSBox () { + Frame = new RectangleF ( + new PointF (-1, -1), + new SizeF (Frame.Width + 2, this.web_view.Frame.Height + 2)), + FillColor = NSColor.White, + BorderColor = NSColor.LightGray, + BoxType = NSBoxType.NSBoxCustom + }; + + this.progress_indicator = new NSProgressIndicator () { + Frame = new RectangleF ( + new PointF (Frame.Width / 2 - 10, this.web_view.Frame.Height / 2 + 10), + new SizeF (20, 20)), + Style = NSProgressIndicatorStyle.Spinning + }; + + this.progress_indicator.StartAnimation (this); + + ContentView.AddSubview (this.size_label); + ContentView.AddSubview (this.size_label_value); + ContentView.AddSubview (this.history_label); + ContentView.AddSubview (this.history_label_value); + ContentView.AddSubview (this.popup_button); + ContentView.AddSubview (this.progress_indicator); + ContentView.AddSubview (this.background); + ContentView.AddSubview (this.hidden_close_button); + + (Delegate as SparkleEventsDelegate).WindowResized += delegate (SizeF new_window_size) { + Program.Controller.Invoke (() => Relayout (new_window_size)); + }; + + + // Hook up the controller events + Controller.HideWindowEvent += delegate { + Program.Controller.Invoke (() => { + this.progress_indicator.Hidden = true; + PerformClose (this); + }); + }; + + Controller.ShowWindowEvent += delegate { + Program.Controller.Invoke (() => OrderFrontRegardless ()); + }; + + Controller.UpdateChooserEvent += delegate (string [] folders) { + Program.Controller.Invoke (() => UpdateChooser (folders)); + }; + + Controller.UpdateChooserEnablementEvent += delegate (bool enabled) { + Program.Controller.Invoke (() => { this.popup_button.Enabled = enabled; }); + }; + + Controller.UpdateContentEvent += delegate (string html) { + Program.Controller.Invoke (() => { + this.cover.RemoveFromSuperview (); + this.progress_indicator.Hidden = true; + UpdateContent (html); + }); + }; + + Controller.ContentLoadingEvent += delegate { + Program.Controller.Invoke (() => { + this.web_view.RemoveFromSuperview (); + // FIXME: Hack to hide that the WebView sometimes doesn't disappear + ContentView.AddSubview (this.cover); + this.progress_indicator.Hidden = false; + this.progress_indicator.StartAnimation (this); + }); + }; + + Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) { + Program.Controller.Invoke (() => { + this.size_label_value.StringValue = size; + this.history_label_value.StringValue = history_size; + }); + }; + + Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) { + Program.Controller.Invoke (() => { + NSSavePanel panel = new NSSavePanel () { + DirectoryUrl = new NSUrl (target_folder_path, true), + NameFieldStringValue = file_name, + ParentWindow = this, + Title = "Restore from History", + PreventsApplicationTerminationWhenModal = false + }; + + if ((NSPanelButtonType) panel.RunModal () == NSPanelButtonType.Ok) { + string target_file_path = Path.Combine (panel.DirectoryUrl.RelativePath, panel.NameFieldStringValue); + Controller.SaveDialogCompleted (target_file_path); + + } else { + Controller.SaveDialogCancelled (); + } + }); + }; + } + + + public void Relayout (SizeF new_window_size) + { + this.web_view.Frame = new RectangleF (this.web_view.Frame.Location, + new SizeF (new_window_size.Width, new_window_size.Height - TitlebarHeight - 39)); + + this.cover.Frame = new RectangleF (this.cover.Frame.Location, + new SizeF (new_window_size.Width, new_window_size.Height - TitlebarHeight - 39)); + + this.background.Frame = new RectangleF (this.background.Frame.Location, + new SizeF (new_window_size.Width, new_window_size.Height - TitlebarHeight - 37)); + + this.size_label.Frame = new RectangleF ( + new PointF (this.size_label.Frame.X, new_window_size.Height - TitlebarHeight - 30), + this.size_label.Frame.Size); + + this.size_label_value.Frame = new RectangleF ( + new PointF (this.size_label_value.Frame.X, new_window_size.Height - TitlebarHeight - 27), + this.size_label_value.Frame.Size); + + this.history_label.Frame = new RectangleF ( + new PointF (this.history_label.Frame.X, new_window_size.Height - TitlebarHeight - 30), + this.history_label.Frame.Size); + + this.history_label_value.Frame = new RectangleF ( + new PointF (this.history_label_value.Frame.X, new_window_size.Height - TitlebarHeight - 27), + this.history_label_value.Frame.Size); + + this.progress_indicator.Frame = new RectangleF ( + new PointF (new_window_size.Width / 2 - 10, this.web_view.Frame.Height / 2 + 10), + this.progress_indicator.Frame.Size); + + this.popup_button.RemoveFromSuperview (); // Needed to prevent redraw glitches + + this.popup_button.Frame = new RectangleF ( + new PointF (new_window_size.Width - this.popup_button.Frame.Width - 12, new_window_size.Height - TitlebarHeight - 33), + this.popup_button.Frame.Size); + + ContentView.AddSubview (this.popup_button); + } + + + public void UpdateChooser (string [] folders) + { + if (folders == null) + folders = Controller.Folders; + + this.popup_button.RemoveAllItems (); + + this.popup_button.AddItem ("Summary"); + this.popup_button.Menu.AddItem (NSMenuItem.SeparatorItem); + + int row = 2; + foreach (string folder in folders) { + this.popup_button.AddItem (folder); + + if (folder.Equals (Controller.SelectedFolder)) + this.popup_button.SelectItem (row); + + row++; + } + + this.popup_button.AddItems (folders); + + this.popup_button.Activated += delegate { + Program.Controller.Invoke (() => { + if (this.popup_button.IndexOfSelectedItem == 0) + Controller.SelectedFolder = null; + else + Controller.SelectedFolder = this.popup_button.SelectedItem.Title; + }); + }; + } + + + public void UpdateContent (string html) + { + string pixmaps_path = "file://" + NSBundle.MainBundle.ResourcePath; + + html = html.Replace ("", "Helvetica Neue"); + html = html.Replace ("", "13.6px"); + html = html.Replace ("", "13.4px"); + html = html.Replace ("", "#bbb"); + html = html.Replace ("", "#ddd"); + html = html.Replace ("", "10px"); + html = html.Replace ("", "#f5f5f5"); + html = html.Replace ("", "#009ff8"); + html = html.Replace ("", "#009ff8"); + html = html.Replace ("", pixmaps_path); + html = html.Replace ("", pixmaps_path + "/document-added-12.png"); + html = html.Replace ("", pixmaps_path + "/document-deleted-12.png"); + html = html.Replace ("", pixmaps_path + "/document-edited-12.png"); + html = html.Replace ("", pixmaps_path + "/document-moved-12.png"); + + this.web_view = new WebView (new RectangleF (0, 0, 481, 579), "", "") { + Frame = new RectangleF (new PointF (0, 0), new SizeF (ContentView.Frame.Width, ContentView.Frame.Height - 39)) + }; + + this.web_view.MainFrame.LoadHtmlString (html, new NSUrl ("")); + + this.web_view.PolicyDelegate = new SparkleWebPolicyDelegate (); + ContentView.AddSubview (this.web_view); + + (this.web_view.PolicyDelegate as SparkleWebPolicyDelegate).LinkClicked += delegate (string href) { + if (href.StartsWith ("file:///")) + href = href.Substring (7); + + Controller.LinkClicked (href); + }; + + this.progress_indicator.Hidden = true; + } + + + public override void OrderFrontRegardless () + { + NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); + MakeKeyAndOrderFront (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + base.OrderFrontRegardless (); + } + + + public override void PerformClose (NSObject sender) + { + base.OrderOut (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + return; + } + } + + + public class SparkleEventsDelegate : NSWindowDelegate { + + public event WindowResizedHandler WindowResized = delegate { }; + public delegate void WindowResizedHandler (SizeF new_window_size); + + public override SizeF WillResize (NSWindow sender, SizeF to_frame_size) + { + WindowResized (to_frame_size); + return to_frame_size; + } + + public override bool WindowShouldClose (NSObject sender) + { + (sender as SparkleEventLog).Controller.WindowClosed (); + return false; + } + } + + + public class SparkleWebPolicyDelegate : WebPolicyDelegate { + + public event LinkClickedHandler LinkClicked = delegate { }; + public delegate void LinkClickedHandler (string href); + + public override void DecidePolicyForNavigation (WebView web_view, NSDictionary action_info, + NSUrlRequest request, WebFrame frame, NSObject decision_token) + { + LinkClicked (request.Url.ToString ()); + } + } +} diff --git a/SparkleShare/Mac/SparkleMacWatcher.cs b/SparkleShare/Mac/SparkleMacWatcher.cs new file mode 100755 index 0000000..0046cb3 --- /dev/null +++ b/SparkleShare/Mac/SparkleMacWatcher.cs @@ -0,0 +1,196 @@ +// Originally taken from: +// https://github.com/jesse99/Continuum/blob/master/source/shared/DirectoryWatcher.cs +// Modified to use MonoMac and integrate into SparkleShare +// +// Copyright (C) 2008 Jesse Jones +// Copyright (C) 2012 Hylke Bons +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.IO; +using System.Threading; +using System.Timers; + +using MonoMac.AppKit; +using MonoMac.Foundation; + +namespace SparkleShare { + + public sealed class SparkleMacWatcher : IDisposable { + + public delegate void ChangedEventHandler (List paths); + public event ChangedEventHandler Changed; + + public string BasePath { get; private set; } + + + [Flags] + [Serializable] + private enum FSEventStreamCreateFlags : uint + { + kFSEventStreamCreateFlagNone = 0x00000000, + kFSEventStreamCreateFlagUseCFTypes = 0x00000001, + kFSEventStreamCreateFlagNoDefer = 0x00000002, + kFSEventStreamCreateFlagWatchRoot = 0x00000004, + } + + private DateTime last_found_timestamp; + private IntPtr m_stream; + private FSEventStreamCallback m_callback; // need to keep a reference around so that it isn't GC'ed + private static readonly IntPtr kCFRunLoopDefaultMode = new NSString ("kCFRunLoopDefaultMode").Handle; + private ulong kFSEventStreamEventIdSinceNow = 0xFFFFFFFFFFFFFFFFUL; + + private delegate void FSEventStreamCallback (IntPtr streamRef, IntPtr clientCallBackInfo, + int numEvents, IntPtr eventPaths, IntPtr eventFlags, IntPtr eventIds); + + + ~SparkleMacWatcher () + { + Dispose (false); + } + + + public SparkleMacWatcher (string path) + { + BasePath = path; + m_callback = DoCallback; + + NSString [] s = new NSString [1]; + s [0] = new NSString (path); + NSArray path_p = NSArray.FromNSObjects (s); + + m_stream = FSEventStreamCreate ( // note that the stream will always be valid + IntPtr.Zero, // allocator + m_callback, // callback + IntPtr.Zero, // context + path_p.Handle, // pathsToWatch + kFSEventStreamEventIdSinceNow, // sinceWhen + 2, // latency (in seconds) + FSEventStreamCreateFlags.kFSEventStreamCreateFlagNone); // flags + + FSEventStreamScheduleWithRunLoop ( + m_stream, // streamRef + CFRunLoopGetMain(), // runLoop + kCFRunLoopDefaultMode); // runLoopMode + + bool started = FSEventStreamStart (m_stream); + if (!started) { + GC.SuppressFinalize (this); + throw new InvalidOperationException ("Failed to start FSEvent stream for " + path); + } + } + + + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); + } + + + private void Dispose (bool disposing) + { + if (m_stream != IntPtr.Zero) { + FSEventStreamStop (m_stream); + FSEventStreamInvalidate (m_stream); + FSEventStreamRelease (m_stream); + + m_stream = IntPtr.Zero; + } + } + + + private void checkDirectory (string dir) + { + if (dir == null) + return; + + DirectoryInfo parent = new DirectoryInfo (dir); + + if (!parent.FullName.Contains ("/.") && + DateTime.Compare (parent.LastWriteTime, this.last_found_timestamp) > 0) { + + last_found_timestamp = parent.LastWriteTime; + } + } + + + private void DoCallback (IntPtr streamRef, IntPtr clientCallBackInfo, + int numEvents, IntPtr eventPaths, IntPtr eventFlags, IntPtr eventIds) + { + int bytes = Marshal.SizeOf (typeof (IntPtr)); + string [] paths = new string [numEvents]; + + for (int i = 0; i < numEvents; ++i) { + IntPtr p = Marshal.ReadIntPtr (eventPaths, i * bytes); + paths [i] = Marshal.PtrToStringAnsi (p); + checkDirectory (paths [i]); + } + + var handler = Changed; + if (handler != null) { + List filtered_paths = new List (); + foreach (var path in paths) { + if (path.Length > BasePath.Length) { + var t = path.Substring (BasePath.Length); + t = t.Trim ("/".ToCharArray ()); + + if (!string.IsNullOrWhiteSpace (t)) + filtered_paths.Add(t); + } + } + + if(filtered_paths.Count > 0) + handler (filtered_paths); + } + + GC.KeepAlive (this); + } + + + [DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")] + private extern static IntPtr CFRunLoopGetMain (); + + [DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")] + private extern static IntPtr FSEventStreamCreate (IntPtr allocator, FSEventStreamCallback callback, + IntPtr context, IntPtr pathsToWatch, ulong sinceWhen, double latency, FSEventStreamCreateFlags flags); + + [DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")] + private extern static void FSEventStreamScheduleWithRunLoop (IntPtr streamRef, IntPtr runLoop, IntPtr runLoopMode); + + [return: MarshalAs (UnmanagedType.U1)] + [DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")] + private extern static bool FSEventStreamStart (IntPtr streamRef); + + [DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")] + private extern static void FSEventStreamStop (IntPtr streamRef); + + [DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")] + private extern static void FSEventStreamInvalidate (IntPtr streamRef); + + [DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")] + private extern static void FSEventStreamRelease (IntPtr streamRef); + } +} diff --git a/SparkleShare/Mac/SparkleNote.cs b/SparkleShare/Mac/SparkleNote.cs new file mode 100755 index 0000000..9b9cbf2 --- /dev/null +++ b/SparkleShare/Mac/SparkleNote.cs @@ -0,0 +1,233 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Drawing; + +using MonoMac.AppKit; +using MonoMac.Foundation; + +namespace SparkleShare { + + public class SparkleNote : NSWindow { + + public SparkleNoteController Controller = new SparkleNoteController (); + + private NSImage user_image, balloon_image; + private NSImageView user_image_view, balloon_image_view; + private NSButton hidden_close_button, cancel_button, sync_button; + private NSBox cover; + private NSTextField user_name_text_field, user_email_text_field, balloon_text_field; + + + public SparkleNote (IntPtr handle) : base (handle) { } + + public SparkleNote () : base () + { + SetFrame (new RectangleF (0, 0, 480, 240), true); + Center (); + + Delegate = new SparkleNoteDelegate (); + StyleMask = (NSWindowStyle.Closable | NSWindowStyle.Titled); + Title = "Add Note"; + MaxSize = new SizeF (480, 240); + MinSize = new SizeF (480, 240); + HasShadow = true; + BackingType = NSBackingStore.Buffered; + Level = NSWindowLevel.Floating; + + this.hidden_close_button = new NSButton () { + Frame = new RectangleF (0, 0, 0, 0), + KeyEquivalentModifierMask = NSEventModifierMask.CommandKeyMask, + KeyEquivalent = "w" + }; + + CreateNote (); + + + this.hidden_close_button.Activated += delegate { Controller.WindowClosed (); }; + + Controller.HideWindowEvent += delegate { + Program.Controller.Invoke (() => PerformClose (this)); + }; + + Controller.ShowWindowEvent += delegate { + Program.Controller.Invoke (() => OrderFrontRegardless ()); + CreateNote (); + }; + + Controller.UpdateTitleEvent += delegate (string title) { + Program.Controller.Invoke (() => { Title = title; }); + }; + + + ContentView.AddSubview (this.hidden_close_button); + } + + + private void CreateNote () + { + this.cover = new NSBox () { + Frame = new RectangleF ( + new PointF (-1, 58), + new SizeF (Frame.Width + 2, this.ContentView.Frame.Height + 1)), + FillColor = NSColor.FromCalibratedRgba (0.77f, 0.77f, 0.75f, 1.0f), + BorderColor = NSColor.LightGray, + BoxType = NSBoxType.NSBoxCustom + }; + + + this.user_name_text_field = new NSTextField () { + Alignment = NSTextAlignment.Left, + BackgroundColor = NSColor.FromCalibratedRgba (0.77f, 0.77f, 0.75f, 1.0f), + Bordered = false, + Editable = false, + Frame = new RectangleF ( + new PointF (85, ContentView.Frame.Height - 41), + new SizeF (320, 22)), + StringValue = Program.Controller.CurrentUser.Name, + Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize) + }; + + this.user_email_text_field = new NSTextField () { + Alignment = NSTextAlignment.Left, + BackgroundColor = NSColor.FromCalibratedRgba (0.77f, 0.77f, 0.75f, 1.0f), + TextColor = NSColor.DisabledControlText, + Bordered = false, + Editable = false, + Frame = new RectangleF ( + new PointF (85, ContentView.Frame.Height - 60), + new SizeF (320, 20)), + StringValue = Program.Controller.CurrentUser.Email, + }; + + + this.balloon_text_field = new NSTextField () { + Alignment = NSTextAlignment.Left, + BackgroundColor = NSColor.White, + Bordered = false, + Editable = true, + Frame = new RectangleF ( + new PointF (30, ContentView.Frame.Height - 137), + new SizeF (418, 48)) + }; + + (this.balloon_text_field.Cell as NSTextFieldCell).PlaceholderString = "Anything to add?"; + (this.balloon_text_field.Cell as NSTextFieldCell).LineBreakMode = NSLineBreakMode.ByWordWrapping; + (this.balloon_text_field.Cell as NSTextFieldCell).UsesSingleLineMode = false; + + this.balloon_text_field.Cell.FocusRingType = NSFocusRingType.None; + + + this.cancel_button = new NSButton () { + Title = "Cancel", + BezelStyle = NSBezelStyle.Rounded, + Frame = new RectangleF (Frame.Width - 15 - 105 * 2, 12, 105, 32), + }; + + this.sync_button = new NSButton () { + Title = "Sync", + BezelStyle = NSBezelStyle.Rounded, + Frame = new RectangleF (Frame.Width - 15 - 105, 12, 105, 32), + }; + + this.cancel_button.Activated += delegate { Controller.CancelClicked (); }; + this.sync_button.Activated += delegate { Controller.SyncClicked (this.balloon_text_field.StringValue); }; + + DefaultButtonCell = this.sync_button.Cell; + + + if (BackingScaleFactor >= 2) + this.balloon_image = NSImage.ImageNamed ("text-balloon@2x"); + else + this.balloon_image = NSImage.ImageNamed ("text-balloon"); + + this.balloon_image.Size = new SizeF (438, 72); + this.balloon_image_view = new NSImageView () { + Image = this.balloon_image, + Frame = new RectangleF (21, ContentView.Frame.Height - 145, 438, 72) + }; + + + if (!string.IsNullOrEmpty (Controller.AvatarFilePath)) + this.user_image = new NSImage (Controller.AvatarFilePath); + else + this.user_image = NSImage.ImageNamed ("user-icon-default"); + + this.user_image.Size = new SizeF (48, 48); + this.user_image_view = new NSImageView () { + Image = this.user_image, + Frame = new RectangleF (21, ContentView.Frame.Height - 65, 48, 48) + }; + + this.user_image_view.WantsLayer = true; + this.user_image_view.Layer.CornerRadius = 5.0f; + this.user_image_view.Layer.MasksToBounds = true; + + + ContentView.AddSubview (this.cover); + ContentView.AddSubview (this.cancel_button); + ContentView.AddSubview (this.sync_button); + ContentView.AddSubview (this.user_name_text_field); + ContentView.AddSubview (this.user_email_text_field); + + ContentView.AddSubview (this.user_image_view); + ContentView.AddSubview (this.balloon_image_view); + ContentView.AddSubview (this.balloon_text_field); + + MakeFirstResponder ((NSResponder) this.balloon_text_field); + } + + + public override void OrderFrontRegardless () + { + NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); + MakeKeyAndOrderFront (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + base.OrderFrontRegardless (); + } + + + public override void PerformClose (NSObject sender) + { + base.OrderOut (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + return; + } + + public override bool AcceptsFirstResponder () + { + return true; + } + + + private class SparkleNoteDelegate : NSWindowDelegate { + + public override bool WindowShouldClose (NSObject sender) + { + (sender as SparkleNote).Controller.WindowClosed (); + return false; + } + } + } +} diff --git a/SparkleShare/Mac/SparkleSetup.cs b/SparkleShare/Mac/SparkleSetup.cs new file mode 100755 index 0000000..d544627 --- /dev/null +++ b/SparkleShare/Mac/SparkleSetup.cs @@ -0,0 +1,878 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +using MonoMac.Foundation; +using MonoMac.AppKit; +using MonoMac.WebKit; + +using Mono.Unix; + +namespace SparkleShare { + + public class SparkleSetup : SparkleSetupWindow { + + public SparkleSetupController Controller = new SparkleSetupController (); + + private NSButton ContinueButton, AddButton, CopyButton, TryAgainButton, CancelButton, + SkipTutorialButton, FinishButton, ShowFilesButton; + + private NSTextField FullNameTextField, FullNameLabel, EmailLabel, EmailTextField, + LinkCodeTextField, AddressTextField, AddressLabel, AddressHelpLabel, PathTextField, PathLabel, + PathHelpLabel, ProgressLabel, PasswordTextField, VisiblePasswordTextField, PasswordLabel, WarningTextField; + + private NSButton StartupCheckButton, HistoryCheckButton, ShowPasswordCheckButton; + private NSProgressIndicator ProgressIndicator; + private NSImage WarningImage, SlideImage; + private NSImageView WarningImageView, SlideImageView; + private NSTableColumn IconColumn, DescriptionColumn; + private NSTableView TableView; + private NSScrollView ScrollView; + private SparkleDataSource DataSource; + + + public SparkleSetup () : base () + { + Controller.HideWindowEvent += delegate { + Program.Controller.Invoke (() => PerformClose (this)); + }; + + Controller.ShowWindowEvent += delegate { + Program.Controller.Invoke (() => OrderFrontRegardless ()); + }; + + Controller.ChangePageEvent += delegate (PageType type, string [] warnings) { + Program.Controller.Invoke (() => { + Reset (); + ShowPage (type, warnings); + ShowAll (); + }); + }; + } + + + public void ShowPage (PageType type, string [] warnings) + { + if (type == PageType.Setup) { + Header = "Welcome to SparkleShare!"; + Description = "First off, what’s your name and email?\n(visible only to team members)"; + + FullNameLabel = new SparkleLabel ("Full Name:", NSTextAlignment.Right); + FullNameLabel.Frame = new RectangleF (165, Frame.Height - 234, 160, 17); + + FullNameTextField = new NSTextField () { + Frame = new RectangleF (330, Frame.Height - 238, 196, 22), + StringValue = UnixUserInfo.GetRealUser ().RealName, + Delegate = new SparkleTextFieldDelegate () + }; + + EmailLabel = new SparkleLabel ("Email:", NSTextAlignment.Right); + EmailLabel.Frame = new RectangleF (165, Frame.Height - 264, 160, 17); + + EmailTextField = new NSTextField () { + Frame = new RectangleF (330, Frame.Height - 268, 196, 22), + Delegate = new SparkleTextFieldDelegate () + }; + + CancelButton = new NSButton () { Title = "Cancel" }; + + ContinueButton = new NSButton () { + Title = "Continue", + Enabled = false + }; + + + (FullNameTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { + Controller.CheckSetupPage (FullNameTextField.StringValue, EmailTextField.StringValue); + }; + + (EmailTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { + Controller.CheckSetupPage (FullNameTextField.StringValue, EmailTextField.StringValue); + }; + + ContinueButton.Activated += delegate { + string full_name = FullNameTextField.StringValue.Trim (); + string email = EmailTextField.StringValue.Trim (); + + Controller.SetupPageCompleted (full_name, email); + }; + + CancelButton.Activated += delegate { Controller.SetupPageCancelled (); }; + + Controller.UpdateSetupContinueButtonEvent += delegate (bool button_enabled) { + Program.Controller.Invoke (() => { + ContinueButton.Enabled = button_enabled; + }); + }; + + + ContentView.AddSubview (FullNameLabel); + ContentView.AddSubview (FullNameTextField); + ContentView.AddSubview (EmailLabel); + ContentView.AddSubview (EmailTextField); + + Buttons.Add (ContinueButton); + Buttons.Add (CancelButton); + + Controller.CheckSetupPage (FullNameTextField.StringValue, EmailTextField.StringValue); + + if (FullNameTextField.StringValue.Equals ("")) + MakeFirstResponder ((NSResponder) FullNameTextField); + else + MakeFirstResponder ((NSResponder) EmailTextField); + } + + if (type == PageType.Invite) { + Header = "You’ve received an invite!"; + Description = "Do you want to add this project to SparkleShare?"; + + AddressLabel = new SparkleLabel ("Address:", NSTextAlignment.Right); + AddressLabel.Frame = new RectangleF (165, Frame.Height - 238, 160, 17); + AddressLabel.Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize); + + AddressTextField = new SparkleLabel (Controller.PendingInvite.Address, NSTextAlignment.Left) { + Frame = new RectangleF (330, Frame.Height - 240, 260, 17) + }; + + PathLabel = new SparkleLabel ("Remote Path:", NSTextAlignment.Right); + PathLabel.Frame = new RectangleF (165, Frame.Height - 262, 160, 17); + PathLabel.Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize); + + + PathTextField = new SparkleLabel (Controller.PendingInvite.RemotePath, NSTextAlignment.Left) { + Frame = new RectangleF (330, Frame.Height - 264, 260, 17) + }; + + CancelButton = new NSButton () { Title = "Cancel" }; + AddButton = new NSButton () { Title = "Add" }; + + + CancelButton.Activated += delegate { Controller.PageCancelled (); }; + AddButton.Activated += delegate { Controller.InvitePageCompleted (); }; + + + ContentView.AddSubview (AddressLabel); + ContentView.AddSubview (PathLabel); + ContentView.AddSubview (AddressTextField); + ContentView.AddSubview (PathTextField); + + Buttons.Add (AddButton); + Buttons.Add (CancelButton); + } + + if (type == PageType.Add) { + Header = "Where’s your project hosted?"; + Description = ""; + + AddressLabel = new SparkleLabel ("Address:", NSTextAlignment.Left) { + Frame = new RectangleF (190, Frame.Height - 308, 160, 17), + Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize) + }; + + AddressTextField = new NSTextField () { + Frame = new RectangleF (190, Frame.Height - 336, 196, 22), + Enabled = (Controller.SelectedPlugin.Address == null), + Delegate = new SparkleTextFieldDelegate (), + StringValue = "" + Controller.PreviousAddress + }; + + AddressTextField.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail; + + PathLabel = new SparkleLabel ("Remote Path:", NSTextAlignment.Left) { + Frame = new RectangleF (190 + 196 + 16, Frame.Height - 308, 160, 17), + Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize) + }; + + PathTextField = new NSTextField () { + Frame = new RectangleF (190 + 196 + 16, Frame.Height - 336, 196, 22), + Enabled = (Controller.SelectedPlugin.Path == null), + Delegate = new SparkleTextFieldDelegate (), + StringValue = "" + Controller.PreviousPath + }; + + PathTextField.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail; + + PathHelpLabel = new SparkleLabel (Controller.SelectedPlugin.PathExample, NSTextAlignment.Left) { + TextColor = NSColor.DisabledControlText, + Frame = new RectangleF (190 + 196 + 16, Frame.Height - 358, 204, 19) + }; + + AddressHelpLabel = new SparkleLabel (Controller.SelectedPlugin.AddressExample, NSTextAlignment.Left) { + TextColor = NSColor.DisabledControlText, + Frame = new RectangleF (190, Frame.Height - 358, 204, 19) + }; + + if (TableView == null || TableView.RowCount != Controller.Plugins.Count) { + TableView = new NSTableView () { + Frame = new RectangleF (0, 0, 0, 0), + RowHeight = 38, + IntercellSpacing = new SizeF (8, 12), + HeaderView = null, + Delegate = new SparkleTableViewDelegate () + }; + + ScrollView = new NSScrollView () { + Frame = new RectangleF (190, Frame.Height - 280, 408, 185), + DocumentView = TableView, + HasVerticalScroller = true, + BorderType = NSBorderType.BezelBorder + }; + + IconColumn = new NSTableColumn () { + Width = 36, + HeaderToolTip = "Icon", + DataCell = new NSImageCell () { ImageAlignment = NSImageAlignment.Right } + }; + + DescriptionColumn = new NSTableColumn () { + Width = 350, + HeaderToolTip = "Description", + Editable = false + }; + + DescriptionColumn.DataCell.Font = NSFontManager.SharedFontManager.FontWithFamily ( + SparkleUI.FontName, NSFontTraitMask.Condensed, 0, 11); + + TableView.AddColumn (IconColumn); + TableView.AddColumn (DescriptionColumn); + + // Hi-res display support was added after Snow Leopard + if (Environment.OSVersion.Version.Major < 11) + DataSource = new SparkleDataSource (1, Controller.Plugins); + else + DataSource = new SparkleDataSource (BackingScaleFactor, Controller.Plugins); + + TableView.DataSource = DataSource; + TableView.ReloadData (); + + (TableView.Delegate as SparkleTableViewDelegate).SelectionChanged += delegate { + Controller.SelectedPluginChanged (TableView.SelectedRow); + Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow); + }; + } + + TableView.SelectRow (Controller.SelectedPluginIndex, false); + TableView.ScrollRowToVisible (Controller.SelectedPluginIndex); + MakeFirstResponder ((NSResponder) TableView); + + HistoryCheckButton = new NSButton () { + Frame = new RectangleF (190, Frame.Height - 400, 300, 18), + Title = "Fetch prior revisions" + }; + + if (Controller.FetchPriorHistory) + HistoryCheckButton.State = NSCellStateValue.On; + + HistoryCheckButton.SetButtonType (NSButtonType.Switch); + + AddButton = new NSButton () { + Title = "Add", + Enabled = false + }; + + CancelButton = new NSButton () { Title = "Cancel" }; + + + Controller.ChangeAddressFieldEvent += delegate (string text, string example_text, FieldState state) { + Program.Controller.Invoke (() => { + AddressTextField.StringValue = text; + AddressTextField.Enabled = (state == FieldState.Enabled); + AddressHelpLabel.StringValue = example_text; + }); + }; + + Controller.ChangePathFieldEvent += delegate (string text, string example_text, FieldState state) { + Program.Controller.Invoke (() => { + PathTextField.StringValue = text; + PathTextField.Enabled = (state == FieldState.Enabled); + PathHelpLabel.StringValue = example_text; + }); + }; + + + (AddressTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { + Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow); + }; + + (PathTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { + Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow); + }; + + + HistoryCheckButton.Activated += delegate { + Controller.HistoryItemChanged (HistoryCheckButton.State == NSCellStateValue.On); + }; + + AddButton.Activated += delegate { + Controller.AddPageCompleted (AddressTextField.StringValue, PathTextField.StringValue); + }; + + CancelButton.Activated += delegate { Controller.PageCancelled (); }; + + Controller.UpdateAddProjectButtonEvent += delegate (bool button_enabled) { + Program.Controller.Invoke (() => { + AddButton.Enabled = button_enabled; + }); + }; + + ContentView.AddSubview (ScrollView); + ContentView.AddSubview (AddressLabel); + ContentView.AddSubview (AddressTextField); + ContentView.AddSubview (AddressHelpLabel); + ContentView.AddSubview (PathLabel); + ContentView.AddSubview (PathTextField); + ContentView.AddSubview (PathHelpLabel); + ContentView.AddSubview (HistoryCheckButton); + + Buttons.Add (AddButton); + Buttons.Add (CancelButton); + + Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow); + } + + if (type == PageType.Syncing) { + Header = "Adding project ‘" + Controller.SyncingFolder + "’…"; + Description = "This may take a while for large projects.\nIsn’t it coffee-o’clock?"; + + ProgressIndicator = new NSProgressIndicator () { + Frame = new RectangleF (190, Frame.Height - 200, 640 - 150 - 80, 20), + Style = NSProgressIndicatorStyle.Bar, + MinValue = 0.0, + MaxValue = 100.0, + Indeterminate = false, + DoubleValue = Controller.ProgressBarPercentage + }; + + ProgressIndicator.StartAnimation (this); + + CancelButton = new NSButton () { Title = "Cancel" }; + + FinishButton = new NSButton () { + Title = "Finish", + Enabled = false + }; + + ProgressLabel = new SparkleLabel ("Preparing to fetch files…", NSTextAlignment.Right); + ProgressLabel.Frame = new RectangleF (Frame.Width - 40 - 250, 185, 250, 25); + + + Controller.UpdateProgressBarEvent += delegate (double percentage, string speed) { + Program.Controller.Invoke (() => { + ProgressIndicator.DoubleValue = percentage; + ProgressLabel.StringValue = speed; + }); + }; + + + CancelButton.Activated += delegate { Controller.SyncingCancelled (); }; + + + ContentView.AddSubview (ProgressLabel); + ContentView.AddSubview (ProgressIndicator); + + Buttons.Add (FinishButton); + Buttons.Add (CancelButton); + } + + if (type == PageType.Error) { + Header = "Oops! Something went wrong…"; + Description = "Please check the following:"; + + // Displaying marked up text with Cocoa is + // a pain, so we just use a webview instead + WebView web_view = new WebView (); + web_view.Frame = new RectangleF (190, Frame.Height - 525, 375, 400); + + string html = "" + + "
    " + + "
  • " + Controller.PreviousUrl + " is the address we’ve compiled. Does this look alright?
  • " + + "
  • Is this computer’s Client ID known by the host?
  • " + + "
"; + + if (warnings.Length > 0) { + string warnings_markup = ""; + + foreach (string warning in warnings) + warnings_markup += "
" + warning + ""; + + html = html.Replace ("", "
  • Here’s the raw error message: " + warnings_markup + "
  • "); + } + + web_view.MainFrame.LoadHtmlString (html, new NSUrl ("")); + web_view.DrawsBackground = false; + + CancelButton = new NSButton () { Title = "Cancel" }; + TryAgainButton = new NSButton () { Title = "Try Again…" }; + + + CancelButton.Activated += delegate { Controller.PageCancelled (); }; + TryAgainButton.Activated += delegate { Controller.ErrorPageCompleted (); }; + + + ContentView.AddSubview (web_view); + + Buttons.Add (TryAgainButton); + Buttons.Add (CancelButton); + } + + if (type == PageType.CryptoSetup || type == PageType.CryptoPassword) { + if (type == PageType.CryptoSetup) { + Header = "Set up file encryption"; + Description = "Please a provide a strong password that you don’t use elsewhere."; + + } else { + Header = "This project contains encrypted files"; + Description = "Please enter the password to see their contents."; + } + + int extra_pos_y = 0; + + if (type == PageType.CryptoPassword) + extra_pos_y = 20; + + PasswordLabel = new SparkleLabel ("Password:", NSTextAlignment.Right) { + Frame = new RectangleF (155, Frame.Height - 202 - extra_pos_y, 160, 17), + Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize) + }; + + PasswordTextField = new NSSecureTextField () { + Frame = new RectangleF (320, Frame.Height - 208 - extra_pos_y, 196, 22), + Delegate = new SparkleTextFieldDelegate () + }; + + VisiblePasswordTextField = new NSTextField () { + Frame = new RectangleF (320, Frame.Height - 208 - extra_pos_y, 196, 22), + Delegate = new SparkleTextFieldDelegate () + }; + + ShowPasswordCheckButton = new NSButton () { + Frame = new RectangleF (318, Frame.Height - 235 - extra_pos_y, 300, 18), + Title = "Show password", + State = NSCellStateValue.Off + }; + + ShowPasswordCheckButton.SetButtonType (NSButtonType.Switch); + + WarningImage = NSImage.ImageNamed ("NSInfo"); + WarningImage.Size = new SizeF (24, 24); + + WarningImageView = new NSImageView () { + Image = WarningImage, + Frame = new RectangleF (200, Frame.Height - 320, 24, 24) + }; + + WarningTextField = new SparkleLabel ("This password can’t be changed later, and your files can’t be recovered if it’s forgotten.", NSTextAlignment.Left) { + Frame = new RectangleF (235, Frame.Height - 390, 325, 100), + }; + + CancelButton = new NSButton () { Title = "Cancel" }; + + ContinueButton = new NSButton () { + Title = "Continue", + Enabled = false + }; + + + Controller.UpdateCryptoPasswordContinueButtonEvent += delegate (bool button_enabled) { + Program.Controller.Invoke (() => { ContinueButton.Enabled = button_enabled; }); + }; + + Controller.UpdateCryptoSetupContinueButtonEvent += delegate (bool button_enabled) { + Program.Controller.Invoke (() => { ContinueButton.Enabled = button_enabled; }); + }; + + ShowPasswordCheckButton.Activated += delegate { + if (PasswordTextField.Superview == ContentView) { + PasswordTextField.RemoveFromSuperview (); + ContentView.AddSubview (VisiblePasswordTextField); + + } else { + VisiblePasswordTextField.RemoveFromSuperview (); + ContentView.AddSubview (PasswordTextField); + } + }; + + (PasswordTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { + VisiblePasswordTextField.StringValue = PasswordTextField.StringValue; + + if (type == PageType.CryptoSetup) + Controller.CheckCryptoSetupPage (PasswordTextField.StringValue); + else + Controller.CheckCryptoPasswordPage (PasswordTextField.StringValue); + }; + + (VisiblePasswordTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { + PasswordTextField.StringValue = VisiblePasswordTextField.StringValue; + + if (type == PageType.CryptoSetup) + Controller.CheckCryptoSetupPage (PasswordTextField.StringValue); + else + Controller.CheckCryptoPasswordPage (PasswordTextField.StringValue); + }; + + ContinueButton.Activated += delegate { + if (type == PageType.CryptoSetup) + Controller.CryptoSetupPageCompleted (PasswordTextField.StringValue); + else + Controller.CryptoPasswordPageCompleted (PasswordTextField.StringValue); + }; + + CancelButton.Activated += delegate { Controller.CryptoPageCancelled (); }; + + + ContentView.AddSubview (PasswordLabel); + ContentView.AddSubview (PasswordTextField); + ContentView.AddSubview (ShowPasswordCheckButton); + + if (type == PageType.CryptoSetup) { + ContentView.AddSubview (WarningImageView); + ContentView.AddSubview (WarningTextField); + } + + Buttons.Add (ContinueButton); + Buttons.Add (CancelButton); + + MakeFirstResponder ((NSResponder) PasswordTextField); + NSApplication.SharedApplication.RequestUserAttention (NSRequestUserAttentionType.CriticalRequest); + } + + + if (type == PageType.Finished) { + Header = "Your shared project is ready!"; + Description = "You can find the files in your SparkleShare folder."; + + if (warnings.Length > 0) { + WarningImage = NSImage.ImageNamed ("NSInfo"); + WarningImage.Size = new SizeF (24, 24); + + WarningImageView = new NSImageView () { + Image = WarningImage, + Frame = new RectangleF (200, Frame.Height - 175, 24, 24) + }; + + WarningTextField = new SparkleLabel (warnings [0], NSTextAlignment.Left); + WarningTextField.Frame = new RectangleF (235, Frame.Height - 245, 325, 100); + + ContentView.AddSubview (WarningImageView); + ContentView.AddSubview (WarningTextField); + } + + ShowFilesButton = new NSButton () { Title = "Show Files…" }; + FinishButton = new NSButton () { Title = "Finish" }; + + + ShowFilesButton.Activated += delegate { Controller.ShowFilesClicked (); }; + FinishButton.Activated += delegate { Controller.FinishPageCompleted (); }; + + + Buttons.Add (FinishButton); + Buttons.Add (ShowFilesButton); + + NSApplication.SharedApplication.RequestUserAttention (NSRequestUserAttentionType.CriticalRequest); + } + + if (type == PageType.Tutorial) { + SlideImage = NSImage.ImageNamed ("tutorial-slide-" + Controller.TutorialPageNumber); + if (SlideImage != null) { + SlideImage.Size = new SizeF (324, 200); + + SlideImageView = new NSImageView () { + Image = SlideImage, + Frame = new RectangleF (228, Frame.Height - 350, 324, 200) + }; + + ContentView.AddSubview (SlideImageView); + } + + switch (Controller.TutorialPageNumber) { + case 1: { + Header = "What’s happening next?"; + Description = "SparkleShare creates a special folder on your computer " + + "that will keep track of your projects."; + + SkipTutorialButton = new NSButton () { Title = "Skip Tutorial" }; + ContinueButton = new NSButton () { Title = "Continue" }; + + + SkipTutorialButton.Activated += delegate { Controller.TutorialSkipped (); }; + ContinueButton.Activated += delegate { Controller.TutorialPageCompleted (); }; + + + ContentView.AddSubview (SlideImageView); + + Buttons.Add (ContinueButton); + Buttons.Add (SkipTutorialButton); + + break; + } + + case 2: { + Header = "Sharing files with others"; + Description = "All files added to your project folders are synced automatically with " + + "the host and your team members."; + + ContinueButton = new NSButton () { Title = "Continue" }; + ContinueButton.Activated += delegate { Controller.TutorialPageCompleted (); }; + Buttons.Add (ContinueButton); + + break; + } + + case 3: { + Header = "The status icon helps you"; + Description = "It shows the syncing progress, provides easy access to " + + "your projects, and lets you view recent changes."; + + ContinueButton = new NSButton () { Title = "Continue" }; + ContinueButton.Activated += delegate { Controller.TutorialPageCompleted (); }; + Buttons.Add (ContinueButton); + + break; + } + + case 4: { + Header = "Here’s your unique Client ID"; + Description = "You’ll need it whenever you want to link this computer to a host. " + + "You can also find it in the status icon menu."; + + LinkCodeTextField = new NSTextField () { + StringValue = Program.Controller.CurrentUser.PublicKey, + Enabled = false, + Selectable = false, + Frame = new RectangleF (230, Frame.Height - 238, 246, 22) + }; + + LinkCodeTextField.Cell.UsesSingleLineMode = true; + LinkCodeTextField.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail; + + CopyButton = new NSButton () { + Title = "Copy", + BezelStyle = NSBezelStyle.RoundRect, + Frame = new RectangleF (480, Frame.Height - 238, 60, 22) + }; + + StartupCheckButton = new NSButton () { + Frame = new RectangleF (190, Frame.Height - 400, 300, 18), + Title = "Add SparkleShare to startup items", + State = NSCellStateValue.On + }; + + StartupCheckButton.SetButtonType (NSButtonType.Switch); + + FinishButton = new NSButton () { Title = "Finish" }; + + + StartupCheckButton.Activated += delegate { + Controller.StartupItemChanged (StartupCheckButton.State == NSCellStateValue.On); + }; + + CopyButton.Activated += delegate { Controller.CopyToClipboardClicked (); }; + FinishButton.Activated += delegate { Controller.TutorialPageCompleted (); }; + + + ContentView.AddSubview (LinkCodeTextField); + ContentView.AddSubview (CopyButton); + ContentView.AddSubview (StartupCheckButton); + + Buttons.Add (FinishButton); + + break; + } + } + } + } + } + + + [Register("SparkleDataSource")] + public class SparkleDataSource : NSTableViewDataSource { + + public List Items; + public NSAttributedString [] Cells, SelectedCells; + + int backing_scale_factor; + + public SparkleDataSource (float backing_scale_factor, List plugins) + { + Items = new List (); + Cells = new NSAttributedString [plugins.Count]; + SelectedCells = new NSAttributedString [plugins.Count]; + + this.backing_scale_factor = (int) backing_scale_factor; + + int i = 0; + foreach (SparklePlugin plugin in plugins) { + Items.Add (plugin); + + NSTextFieldCell cell = new NSTextFieldCell (); + + NSData name_data = NSData.FromString ("" + plugin.Name + ""); + + NSDictionary name_dictionary = new NSDictionary(); + NSAttributedString name_attributes = new NSAttributedString ( + name_data, new NSUrl ("file://"), out name_dictionary); + + NSData description_data = NSData.FromString ( + "" + plugin.Description + ""); + + NSDictionary description_dictionary = new NSDictionary(); + NSAttributedString description_attributes = new NSAttributedString ( + description_data, new NSUrl ("file://"), out description_dictionary); + + NSMutableAttributedString mutable_attributes = new NSMutableAttributedString (name_attributes); + mutable_attributes.Append (new NSAttributedString ("\n")); + mutable_attributes.Append (description_attributes); + + cell.AttributedStringValue = mutable_attributes; + Cells [i] = (NSAttributedString) cell.ObjectValue; + + NSTextFieldCell selected_cell = new NSTextFieldCell (); + + NSData selected_name_data = NSData.FromString ( + "" + plugin.Name + ""); + + NSDictionary selected_name_dictionary = new NSDictionary (); + NSAttributedString selected_name_attributes = new NSAttributedString ( + selected_name_data, new NSUrl ("file://"), out selected_name_dictionary); + + NSData selected_description_data = NSData.FromString ( + "" + + plugin.Description + ""); + + NSDictionary selected_description_dictionary = new NSDictionary (); + NSAttributedString selected_description_attributes = new NSAttributedString ( + selected_description_data, new NSUrl ("file://"), out selected_description_dictionary); + + NSMutableAttributedString selected_mutable_attributes = + new NSMutableAttributedString (selected_name_attributes); + + selected_mutable_attributes.Append (new NSAttributedString ("\n")); + selected_mutable_attributes.Append (selected_description_attributes); + + selected_cell.AttributedStringValue = selected_mutable_attributes; + SelectedCells [i] = (NSAttributedString) selected_cell.ObjectValue; + + i++; + } + } + + + [Export("numberOfRowsInTableView:")] + public int numberOfRowsInTableView (NSTableView table_view) + { + if (Items == null) + return 0; + else + return Items.Count; + } + + + [Export("tableView:objectValueForTableColumn:row:")] + public NSObject objectValueForTableColumn (NSTableView table_view, + NSTableColumn table_column, int row_index) + { + if (table_column.HeaderToolTip.Equals ("Description")) { + if (table_view.SelectedRow == row_index && + Program.UI.Setup.IsKeyWindow && + Program.UI.Setup.FirstResponder == table_view) { + + return SelectedCells [row_index]; + + } else { + return Cells [row_index]; + } + + } else { + SparklePlugin plugin = (SparklePlugin) Items [row_index]; + string path = plugin.ImagePath; + + if (backing_scale_factor >= 2) { + string hi_path = String.Format ("{0}@{1}x{2}", + Path.Combine (Path.GetDirectoryName (path), Path.GetFileNameWithoutExtension (path)), + backing_scale_factor, Path.GetExtension (path) + ); + + if (File.Exists (hi_path)) + path = hi_path; + } + + return new NSImage (path) { Size = new SizeF (24, 24) }; + } + } + } + + + public class SparkleTextFieldDelegate : NSTextFieldDelegate { + + public event Action StringValueChanged = delegate { }; + + public override void Changed (NSNotification notification) + { + StringValueChanged (); + } + } + + + public class SparkleTableViewDelegate : NSTableViewDelegate { + + public event Action SelectionChanged = delegate { }; + + public override void SelectionDidChange (NSNotification notification) + { + SelectionChanged (); + } + } + + + public class SparkleLabel : NSTextField { + + public SparkleLabel (string label, NSTextAlignment alignment) + { + if (!string.IsNullOrEmpty (label)) + StringValue = label; + + Alignment = alignment; + BackgroundColor = NSColor.WindowBackground; + Bordered = false; + Editable = false; + } + } +} diff --git a/SparkleShare/Mac/SparkleSetupWindow.cs b/SparkleShare/Mac/SparkleSetupWindow.cs new file mode 100755 index 0000000..a0dcb8a --- /dev/null +++ b/SparkleShare/Mac/SparkleSetupWindow.cs @@ -0,0 +1,156 @@ +// SparkleShare, an instant update workflow to Git. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +using MonoMac.Foundation; +using MonoMac.AppKit; + +namespace SparkleShare { + + public class SparkleSetupWindow : NSWindow { + + public List Buttons = new List (); + public string Header; + new public string Description; + + private NSImage side_splash; + private NSImageView side_splash_view; + private NSTextField header_text_field, description_text_field; + + + public SparkleSetupWindow (IntPtr handle) : base (handle) { } + + public SparkleSetupWindow () : base () + { + SetFrame (new RectangleF (0, 0, 640, 420), true); + + StyleMask = NSWindowStyle.Titled; + MaxSize = new SizeF (640, 420); + MinSize = new SizeF (640, 420); + HasShadow = true; + BackingType = NSBackingStore.Buffered; + Level = NSWindowLevel.Floating; + + Center (); + + this.side_splash = NSImage.ImageNamed ("side-splash"); + this.side_splash.Size = new SizeF (150, 482); + + this.side_splash_view = new NSImageView () { + Image = this.side_splash, + Frame = new RectangleF (0, 0, 150, 482) + }; + + this.header_text_field = new SparkleLabel ("", NSTextAlignment.Left) { + Frame = new RectangleF (190, Frame.Height - 80, Frame.Width, 24), + Font = NSFontManager.SharedFontManager.FontWithFamily ( + SparkleUI.FontName, NSFontTraitMask.Bold, 0, 16) + }; + + this.description_text_field = new SparkleLabel ("", NSTextAlignment.Left) { + Frame = new RectangleF (190, Frame.Height - 130, 640 - 240, 44) + }; + + this.header_text_field.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail; + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + } + + + public void Reset () + { + ContentView.Subviews = new NSView [0]; + Buttons = new List (); + Header = ""; + Description = ""; + } + + + public void ShowAll () + { + this.header_text_field.StringValue = Header; + this.description_text_field.StringValue = Description; + + ContentView.AddSubview (this.side_splash_view); + ContentView.AddSubview (this.header_text_field); + + if (!string.IsNullOrEmpty (Description)) + ContentView.AddSubview (this.description_text_field); + + int i = 1; + int x = 0; + if (Buttons.Count > 0) { + DefaultButtonCell = Buttons [0].Cell; + + foreach (NSButton button in Buttons) { + button.BezelStyle = NSBezelStyle.Rounded; + button.Frame = new RectangleF (Frame.Width - 15 - x - (105 * i), 12, 105, 32); + + // Make the button a bit wider if the text is likely to be longer + if (button.Title.Contains (" ")) { + button.SizeToFit (); + button.Frame = new RectangleF (Frame.Width - 30 - 15 - (105 * (i - 1)) - button.Frame.Width, + 12, button.Frame.Width + 30, 32); + + x += 22; + } + + ContentView.AddSubview (button); + i++; + } + } + + RecalculateKeyViewLoop (); + } + + + public override void OrderFrontRegardless () + { + NSApplication.SharedApplication.AddWindowsItem (this, "SparkleShare Setup", false); + NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); + MakeKeyAndOrderFront (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + base.OrderFrontRegardless (); + } + + + public override void PerformClose (NSObject sender) + { + base.OrderOut (this); + NSApplication.SharedApplication.RemoveWindowsItem (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + return; + } + + + public override bool AcceptsFirstResponder () + { + return true; + } + } +} diff --git a/SparkleShare/Mac/SparkleShare.csproj b/SparkleShare/Mac/SparkleShare.csproj new file mode 100644 index 0000000..04b8cbb --- /dev/null +++ b/SparkleShare/Mac/SparkleShare.csproj @@ -0,0 +1,296 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC} + {948B3504-5B70-4649-8FE4-BDE1FB46EC69};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + SparkleShare + SparkleShare + + + True + True + + + none + False + bin\Release + prompt + 4 + + + + + + False + False + False + false + False + false + false + + + False + bin\Debug + DEBUG + prompt + 4 + + + + + + False + False + False + false + False + true + false + false + + + false + bin\ReleaseDist + 4 + false + false + false + + + + + + + false + false + + + + + + + + + ..\..\..\monomac\src\MonoMac.dll + + + + + MainMenu.xib + + + MainMenu.xib + + + SparkleControllerBase.cs + + + + + Program.cs + + + + + + + + SparkleBubblesController.cs + + + SparkleEventLogController.cs + + + SparkleSetupController.cs + + + SparkleStatusIconController.cs + + + SparkleAboutController.cs + + + + SparklePlugin.cs + + + + SparkleInvite.cs + + + SparkleKeys.cs + + + + SparkleNoteController.cs + + + + + + + + + + + + + + HTML\day-entry.html + + + HTML\event-entry.html + + + HTML\event-log.html + + + sparkleshare-folder.icns + + + sparkleshare-app.icns + + + HTML\jquery.js + + + sparkleshare-folder-yosemite.icns + + + + + + + + + + {2C914413-B31C-4362-93C7-1AE34F09112A} + SparkleLib + + + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE} + SparkleLib.Git + + + + + Resources\side-splash.png + + + Resources\document-added-12.png + + + Resources\document-edited-12.png + + + Resources\document-deleted-12.png + + + Resources\document-moved-12.png + + + Resources\about.png + + + Resources\tutorial-slide-3.png + + + + + + + + Resources\user-icon-default.png + + + Resources\side-splash%402x.png + + + + + + + + Resources\about%402x.png + + + Resources\tutorial-slide-1.png + + + Resources\tutorial-slide-1%402x.png + + + Resources\tutorial-slide-2.png + + + Resources\tutorial-slide-2%402x.png + + + Plugins\bitbucket%402x.png + + + Plugins\github%402x.png + + + Plugins\gitorious%402x.png + + + Plugins\own-server%402x.png + + + Plugins\ssnet%402x.png + + + Plugins\bitbucket.xml + + + Plugins\github.xml + + + Plugins\gitorious.xml + + + Plugins\own-server.xml + + + Plugins\bitbucket.png + + + Plugins\github.png + + + Plugins\gitorious.png + + + Plugins\own-server.png + + + Plugins\ssnet.png + + + Plugins\ssnet.xml + + + + Plugins\planio.png + + + Plugins\planio.xml + + + Plugins\planio%402x.png + + + Resources\text-balloon.png + + + Resources\text-balloon%402x.png + + + diff --git a/SparkleShare/Mac/SparkleShare.sln b/SparkleShare/Mac/SparkleShare.sln new file mode 100644 index 0000000..8920b7f --- /dev/null +++ b/SparkleShare/Mac/SparkleShare.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare", "SparkleShare.csproj", "{CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleLib", "..\..\SparkleLib\SparkleLib.csproj", "{2C914413-B31C-4362-93C7-1AE34F09112A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleLib.Git", "..\..\SparkleLib\Git\SparkleLib.Git.csproj", "{009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|Any CPU = Release|Any CPU + Debug|Any CPU = Debug|Any CPU + ReleaseDist|Any CPU = ReleaseDist|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|Any CPU.Build.0 = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.Build.0 = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU + {CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Release|Any CPU.Build.0 = Release|Any CPU + {CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.ReleaseDist|Any CPU.ActiveCfg = ReleaseDist|Any CPU + {CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.ReleaseDist|Any CPU.Build.0 = ReleaseDist|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = SparkleShare.csproj + Policies = $0 + $0.DotNetNamingPolicy = $1 + $1.DirectoryNamespaceAssociation = None + $1.ResourceNamePolicy = FileFormatDefault + $0.TextStylePolicy = $2 + $2.inheritsSet = null + $2.scope = text/x-csharp + $0.CSharpFormattingPolicy = $3 + $3.inheritsSet = Mono + $3.inheritsScope = text/x-csharp + $3.scope = text/x-csharp + $0.TextStylePolicy = $4 + $4.FileWidth = 120 + $4.inheritsSet = VisualStudio + $4.inheritsScope = text/plain + $4.scope = text/plain + version = + EndGlobalSection +EndGlobal diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Info.plist b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Info.plist new file mode 100644 index 0000000..5532c56 --- /dev/null +++ b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleAllowMixedLocalizations + + CFBundleDevelopmentRegion + English + CFBundleExecutable + applet + CFBundleIconFile + applet + CFBundleIdentifier + org.sparkleshare.SparkleShareInviteOpener + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + SparkleShareInviteOpen + CFBundlePackageType + APPL + CFBundleSignature + aplt + CFBundleURLTypes + + + CFBundleURLName + SparkleShareInviteOpener + CFBundleURLSchemes + + sparkleshare + + + + LSMinimumSystemVersionByArchitecture + + x86_64 + 10.6 + + LSRequiresCarbon + + WindowState + + dividerCollapsed + + eventLogLevel + -1 + name + ScriptWindowState + positionOfDivider + 333 + savedFrame + 758 93 773 597 0 0 1920 1058 + selectedTabView + event log + + + diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/MacOS/applet b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/MacOS/applet new file mode 100755 index 0000000..0079f4b Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/MacOS/applet differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/PkgInfo b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/PkgInfo new file mode 100644 index 0000000..3253614 --- /dev/null +++ b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPLaplt \ No newline at end of file diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/Scripts/main.scpt b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/Scripts/main.scpt new file mode 100644 index 0000000..2ffb96e Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/Scripts/main.scpt differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.icns b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.icns new file mode 100644 index 0000000..fcc1f09 Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.icns differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.rsrc b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.rsrc new file mode 100644 index 0000000..2015dcc Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.rsrc differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/description.rtfd/TXT.rtf b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/description.rtfd/TXT.rtf new file mode 100644 index 0000000..d868171 --- /dev/null +++ b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/description.rtfd/TXT.rtf @@ -0,0 +1,4 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +{\fonttbl} +{\colortbl;\red255\green255\blue255;} +} \ No newline at end of file diff --git a/SparkleShare/Mac/SparkleStatusIcon.cs b/SparkleShare/Mac/SparkleStatusIcon.cs new file mode 100755 index 0000000..a925366 --- /dev/null +++ b/SparkleShare/Mac/SparkleStatusIcon.cs @@ -0,0 +1,288 @@ +// SparkleShare, an instant update workflow to Git. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +using MonoMac.Foundation; +using MonoMac.AppKit; + +namespace SparkleShare { + + public class SparkleStatusIcon { + + public SparkleStatusIconController Controller = new SparkleStatusIconController (); + + private NSStatusItem status_item = NSStatusBar.SystemStatusBar.CreateStatusItem (28); + private NSMenu menu, submenu, link_code_submenu; + private SparkleMenuDelegate menu_delegate; + + private NSMenuItem state_item, folder_item, add_item, about_item, recent_events_item, quit_item, + code_item, copy_item, link_code_item; + + private NSMenuItem [] folder_menu_items, try_again_menu_items, pause_menu_items, + resume_menu_items, state_menu_items; + + private NSImage syncing_idle_image = NSImage.ImageNamed ("process-syncing-idle"); + private NSImage syncing_up_image = NSImage.ImageNamed ("process-syncing-up"); + private NSImage syncing_down_image = NSImage.ImageNamed ("process-syncing-down"); + private NSImage syncing_image = NSImage.ImageNamed ("process-syncing"); + private NSImage syncing_error_image = NSImage.ImageNamed ("process-syncing-error"); + + private NSImage folder_image = NSImage.ImageNamed ("NSFolder"); + private NSImage caution_image = NSImage.ImageNamed ("NSCaution"); + private NSImage sparkleshare_image; + + + public SparkleStatusIcon () + { + this.status_item.HighlightMode = true; + this.status_item.Image = this.syncing_idle_image; + this.status_item.Image.Template = true; + + if (Environment.OSVersion.Version.Major >= 14) + this.sparkleshare_image = (NSImage)NSImage.ImageNamed ("sparkleshare-folder-yosemite.icns").Copy(); + else + this.sparkleshare_image = (NSImage)NSImage.ImageNamed ("sparkleshare-folder.icns").Copy(); + + CreateMenu (); + + Controller.UpdateIconEvent += delegate (IconState state) { + Program.Controller.Invoke (() => { + switch (state) { + case IconState.Idle: { this.status_item.Image = this.syncing_idle_image; break; } + case IconState.SyncingUp: { this.status_item.Image = this.syncing_up_image; break; } + case IconState.SyncingDown: { this.status_item.Image = this.syncing_down_image; break; } + case IconState.Syncing: { this.status_item.Image = this.syncing_image; break; } + case IconState.Error: { this.status_item.Image = this.syncing_error_image; break; } + } + + this.status_item.Image.Template = true; + }); + }; + + Controller.UpdateStatusItemEvent += delegate (string state_text) { + Program.Controller.Invoke (() => { + this.state_item.Title = state_text; + + if (Controller.Projects.Length == this.state_menu_items.Length) { + for (int i = 0; i < Controller.Projects.Length; i++) + this.state_menu_items [i].Title = Controller.Projects [i].StatusMessage; + } + }); + }; + + Controller.UpdateMenuEvent += delegate { + while (this.menu_delegate.MenuIsOpen) + System.Threading.Thread.Sleep (100); + + Program.Controller.Invoke (() => CreateMenu ()); + }; + + Controller.UpdateQuitItemEvent += delegate (bool quit_item_enabled) { + Program.Controller.Invoke (() => { this.quit_item.Enabled = quit_item_enabled; }); + }; + } + + + public void CreateMenu () + { + this.menu = new NSMenu () { AutoEnablesItems = false }; + + this.state_item = new NSMenuItem () { + Title = Controller.StateText, + Enabled = false + }; + + this.folder_item = new NSMenuItem () { + Title = "SparkleShare", + Enabled = true + }; + + this.folder_item.Image = this.sparkleshare_image; + this.folder_item.Image.Size = new SizeF (16, 16); + + this.add_item = new NSMenuItem () { + Title = "Add Hosted Project…", + Enabled = true + }; + + this.recent_events_item = new NSMenuItem () { + Title = "Recent Changes…", + Enabled = Controller.RecentEventsItemEnabled + }; + + this.link_code_item = new NSMenuItem (); + this.link_code_item.Title = "Client ID"; + + if (Controller.LinkCodeItemEnabled) { + this.link_code_submenu = new NSMenu (); + + this.code_item = new NSMenuItem (); + this.code_item.Title = Program.Controller.CurrentUser.PublicKey.Substring (0, 20) + "..."; + + this.copy_item = new NSMenuItem (); + this.copy_item.Title = "Copy to Clipboard"; + this.copy_item.Activated += delegate { Controller.CopyToClipboardClicked (); }; + + this.link_code_submenu.AddItem (this.code_item); + this.link_code_submenu.AddItem (NSMenuItem.SeparatorItem); + this.link_code_submenu.AddItem (this.copy_item); + + this.link_code_item.Submenu = this.link_code_submenu; + } + + this.about_item = new NSMenuItem () { + Title = "About SparkleShare", + Enabled = true + }; + + this.quit_item = new NSMenuItem () { + Title = "Quit", + Enabled = Controller.QuitItemEnabled + }; + + this.folder_menu_items = new NSMenuItem [Controller.Projects.Length]; + this.try_again_menu_items = new NSMenuItem [Controller.Projects.Length]; + this.pause_menu_items = new NSMenuItem [Controller.Projects.Length]; + this.resume_menu_items = new NSMenuItem [Controller.Projects.Length]; + this.state_menu_items = new NSMenuItem [Controller.Projects.Length]; + + if (Controller.Projects.Length > 0) { + int i = 0; + foreach (ProjectInfo project in Controller.Projects) { + NSMenuItem item = new NSMenuItem () { Title = project.Name }; + this.folder_menu_items [i] = item; + + item.Submenu = new NSMenu (); + item.Image = this.folder_image; + + this.state_menu_items [i] = new NSMenuItem (project.StatusMessage); + + item.Submenu.AddItem (this.state_menu_items [i]); + item.Submenu.AddItem (NSMenuItem.SeparatorItem); + + if (project.IsPaused) { + if (project.UnsyncedChangesInfo.Count > 0) { + foreach (KeyValuePair pair in project.UnsyncedChangesInfo) + item.Submenu.AddItem (new NSMenuItem (pair.Key) { + Image = NSImage.ImageNamed (pair.Value) + }); + + if (!string.IsNullOrEmpty (project.MoreUnsyncedChanges)) + item.Submenu.AddItem (new NSMenuItem (project.MoreUnsyncedChanges)); + + item.Submenu.AddItem (NSMenuItem.SeparatorItem); + this.resume_menu_items [i] = new NSMenuItem ("Sync and Resume…"); + + } else { + this.resume_menu_items [i] = new NSMenuItem ("Resume"); + } + + this.resume_menu_items [i].Activated += Controller.ResumeDelegate (project.Name); + item.Submenu.AddItem (this.resume_menu_items [i]); + + } else { + if (Controller.Projects [i].HasError) { + item.Image = this.caution_image; + + this.try_again_menu_items [i] = new NSMenuItem (); + this.try_again_menu_items [i].Title = "Try Again"; + this.try_again_menu_items [i].Activated += Controller.TryAgainDelegate (project.Name); + + item.Submenu.AddItem (this.try_again_menu_items [i]); + + } else { + this.pause_menu_items [i] = new NSMenuItem ("Pause"); + this.pause_menu_items [i].Activated += Controller.PauseDelegate (project.Name); + + item.Submenu.AddItem (this.pause_menu_items [i]); + } + } + + if (!Controller.Projects [i].HasError) + this.folder_menu_items [i].Activated += Controller.OpenFolderDelegate (project.Name); + + item.Image.Size = new SizeF (16, 16); + i++; + }; + } + + + if (Controller.RecentEventsItemEnabled) + this.recent_events_item.Activated += delegate { Controller.RecentEventsClicked (); }; + + this.add_item.Activated += delegate { Controller.AddHostedProjectClicked (); }; + this.about_item.Activated += delegate { Controller.AboutClicked (); }; + this.quit_item.Activated += delegate { Controller.QuitClicked (); }; + + + this.menu.AddItem (this.state_item); + this.menu.AddItem (NSMenuItem.SeparatorItem); + this.menu.AddItem (this.folder_item); + + this.submenu = new NSMenu (); + + this.submenu.AddItem (this.recent_events_item); + this.submenu.AddItem (this.add_item); + this.submenu.AddItem (NSMenuItem.SeparatorItem); + this.submenu.AddItem (link_code_item); + this.submenu.AddItem (NSMenuItem.SeparatorItem); + this.submenu.AddItem (this.about_item); + + this.folder_item.Submenu = this.submenu; + + foreach (NSMenuItem item in this.folder_menu_items) + this.menu.AddItem (item); + + this.menu.AddItem (NSMenuItem.SeparatorItem); + this.menu.AddItem (this.quit_item); + + this.menu_delegate = new SparkleMenuDelegate (); + this.menu.Delegate = this.menu_delegate; + this.status_item.Menu = this.menu; + } + + + private class SparkleMenuDelegate : NSMenuDelegate { + + public SparkleMenuDelegate (IntPtr handle) : base (handle) { } + public SparkleMenuDelegate () { } + + public bool MenuIsOpen { get; private set; } + + + public override void MenuWillHighlightItem (NSMenu menu, NSMenuItem item) + { + } + + + public override void MenuWillOpen (NSMenu menu) + { + MenuIsOpen = true; + } + + + public override void MenuDidClose (NSMenu menu) + { + MenuIsOpen = false; + } + } + } +} diff --git a/SparkleShare/Mac/SparkleUI.cs b/SparkleShare/Mac/SparkleUI.cs new file mode 100755 index 0000000..508055a --- /dev/null +++ b/SparkleShare/Mac/SparkleUI.cs @@ -0,0 +1,97 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; + +using MonoMac.Foundation; +using MonoMac.AppKit; + +namespace SparkleShare { + + public class SparkleUI : AppDelegate { + + public SparkleStatusIcon StatusIcon; + public SparkleEventLog EventLog; + public SparkleSetup Setup; + public SparkleBubbles Bubbles; + public SparkleAbout About; + public SparkleNote Note; + + public static string FontName = "Helvetica Neue"; + + public SparkleUI () + { + if (Environment.OSVersion.Version.Major < 14) + FontName = "Lucida Grande"; + + Program.Controller.Invoke (() => { + if (Environment.OSVersion.Version.Major >= 14) { + NSWorkspace.SharedWorkspace.SetIconforFile ( + NSImage.ImageNamed ("sparkleshare-folder-yosemite.icns"), + Program.Controller.FoldersPath, 0); + + } else { + NSWorkspace.SharedWorkspace.SetIconforFile ( + NSImage.ImageNamed ("sparkleshare-folder.icns"), + Program.Controller.FoldersPath, 0); + } + + NSApplication.SharedApplication.ApplicationIconImage = NSImage.ImageNamed ("sparkleshare-app.icns"); + + Setup = new SparkleSetup (); + EventLog = new SparkleEventLog (); + About = new SparkleAbout (); + Note = new SparkleNote (); + Bubbles = new SparkleBubbles (); + StatusIcon = new SparkleStatusIcon (); + }); + + Program.Controller.UIHasLoaded (); + } + + + public void Run () + { + NSApplication.Main (Program.Arguments); + } + + + public void UpdateDockIconVisibility () + { +// if (Setup.IsVisible || EventLog.IsVisible || About.IsVisible) +// NSApplication.SharedApplication.ActivationPolicy = NSApplicationActivationPolicy.Regular; + } + } + + + public partial class AppDelegate : NSApplicationDelegate { + + public override void WillTerminate (NSNotification notification) + { + Program.Controller.Quit (); + } + + + public override bool ApplicationShouldHandleReopen (NSApplication sender, bool has_visible_windows) + { + if (!has_visible_windows) + Program.Controller.HandleReopen (); + + return true; + } + } +} diff --git a/SparkleShare/Mac/checkGit.sh b/SparkleShare/Mac/checkGit.sh new file mode 100755 index 0000000..d64a083 --- /dev/null +++ b/SparkleShare/Mac/checkGit.sh @@ -0,0 +1,37 @@ +#!/bin/sh +function abspath() +{ + case "${1}" in + [./]*) + echo "$(cd ${1%/*}; pwd)/${1##*/}" + ;; + *) + echo "${PWD}/${1}" + ;; + esac +} + +export projectFolder=$(dirname $0) +export projectFolder=$(abspath ${projectFolder}) + +export gitVersion=$(cat ${projectFolder}/git.version) + +set -e + +if [ ! -f ${projectFolder}/git-${gitVersion}.tar.gz ] +then + curl -s https://codeload.github.com/git/git/zip/v${gitVersion} > git.zip + unzip -q git.zip + + cd git-${gitVersion} + + make configure + ./configure --prefix=${projectFolder}/git + make install + cd .. + + tar cfz git-${gitVersion}.tar.gz git + rm -rf git + rm -rf git-${gitVersion} + rm git.zip +fi diff --git a/SparkleShare/Mac/config b/SparkleShare/Mac/config new file mode 100644 index 0000000..e15ba99 --- /dev/null +++ b/SparkleShare/Mac/config @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Mac/git.version b/SparkleShare/Mac/git.version new file mode 100644 index 0000000..05fc3da --- /dev/null +++ b/SparkleShare/Mac/git.version @@ -0,0 +1 @@ +1.8.5.5 diff --git a/SparkleShare/Mac/packReleaseDist.sh b/SparkleShare/Mac/packReleaseDist.sh new file mode 100755 index 0000000..171811d --- /dev/null +++ b/SparkleShare/Mac/packReleaseDist.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# expect path to app bundle argument +export bundle=$1 +export projectFolder=$(dirname $0) + +echo packing ${bundle} for release without Mono framework dependency + +export MONO_PATH=`readlink /Library/Frameworks/Mono.framework/Versions/Current` +export PKG_CONFIG_PATH=/usr/lib/pkgconfig:${MONO_PATH}/lib/pkgconfig +export AS="as -arch i386" +export CC="cc -arch i386 -lobjc -liconv -framework Foundation" +export PATH=/usr/local/bin:/opt/local/bin:/Library/Frameworks/Mono.framework/Versions/Current/bin:/usr/bin:/bin + +cd ${bundle}/Contents/MonoBundle/ + +# add / fix dependency libMonoPosixHelper +cp ${MONO_PATH}/lib/libMonoPosixHelper.dylib ../MacOS/ +sed -i .bak 's/libMonoPosixHelper.dylib/@executable_path\/libMonoPosixHelper.dylib/' ./config + +# merge all Assemblies into one Mac binary +mkbundle --static --deps --config ./config -o ../MacOS/SparkleShare SparkleShare.exe SparkleLib.dll MonoMac.dll SparkleLib.Git.dll +rm *.dll *.exe + diff --git a/SparkleShare/Mac/postBuild.sh b/SparkleShare/Mac/postBuild.sh new file mode 100755 index 0000000..643f33a --- /dev/null +++ b/SparkleShare/Mac/postBuild.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# expect path to app bundle argument +export bundle=$1 +export projectFolder=$(dirname $0) +export gitVersion=$(cat ${projectFolder}/git.version) + +echo postprocessing ${bundle} + +export PATH=/usr/local/bin:/opt/local/bin:/Library/Frameworks/Mono.framework/Versions/Current/bin:/usr/bin:/bin + +${projectFolder}/checkGit.sh +tar -x -f ${projectFolder}/git-${gitVersion}.tar.gz -C ${bundle}/Contents/Resources +cp -R SparkleShareInviteOpener.app ${bundle}/Contents/Resources +cp config ${bundle}/Contents/MonoBundle diff --git a/SparkleShare/Makefile.am b/SparkleShare/Makefile.am new file mode 100755 index 0000000..a53148d --- /dev/null +++ b/SparkleShare/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = Linux \ + Common diff --git a/SparkleShare/Program.cs b/SparkleShare/Program.cs new file mode 100644 index 0000000..db3431b --- /dev/null +++ b/SparkleShare/Program.cs @@ -0,0 +1,96 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Threading; + +using SparkleLib; + +namespace SparkleShare { + + // This is SparkleShare! + public class Program { + + public static SparkleController Controller; + public static SparkleUI UI; + public static string [] Arguments; + + private static Mutex program_mutex = new Mutex (false, "SparkleShare"); + + + #if !__MonoCS__ + [STAThread] + #endif + public static void Main (string [] args) + { + Arguments = args; + + if (args.Length != 0 && !args [0].Equals ("help") && + SparkleBackend.Platform != PlatformID.MacOSX && + SparkleBackend.Platform != PlatformID.Win32NT) { + + string n = Environment.NewLine; + + Console.WriteLine (n + + "SparkleShare is a collaboration and sharing tool that is" + n + + "designed to keep things simple and to stay out of your way." + n + + n + + "Version: " + SparkleLib.SparkleBackend.Version + n + + "Copyright (C) 2010 Hylke Bons and others" + n + + "This program comes with ABSOLUTELY NO WARRANTY." + n + + n + + "This is free software, and you are welcome to redistribute it" + n + + "under certain conditions. Please read the GNU GPLv3 for details." + n + + n + + "Usage: sparkleshare [start|open]"); + + Environment.Exit (-1); + } + + // Only allow one instance of SparkleShare (on Windows) + if (!program_mutex.WaitOne (0, false)) { + Console.WriteLine ("SparkleShare is already running."); + Environment.Exit (-1); + } + + AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; + + Controller = new SparkleController (); + Controller.Initialize (); + + UI = new SparkleUI (); + UI.Run (); + + #if !__MonoCS__ + // Suppress assertion messages in debug mode + GC.Collect (GC.MaxGeneration, GCCollectionMode.Forced); + GC.WaitForPendingFinalizers (); + #endif + } + + private static void OnUnhandledException (object sender, UnhandledExceptionEventArgs exception_args) + { + try { + Exception e = (Exception) exception_args.ExceptionObject; + SparkleLogger.WriteCrashReport (e); + + } finally { + Environment.Exit (-1); + } + } + } +} diff --git a/SparkleShare/SparkleAboutController.cs b/SparkleShare/SparkleAboutController.cs new file mode 100755 index 0000000..58a4c8d --- /dev/null +++ b/SparkleShare/SparkleAboutController.cs @@ -0,0 +1,78 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Net; +using System.Threading; + +namespace SparkleShare { + + public class SparkleAboutController { + + public event Action ShowWindowEvent = delegate { }; + public event Action HideWindowEvent = delegate { }; + + public event UpdateLabelEventDelegate UpdateLabelEvent = delegate { }; + public delegate void UpdateLabelEventDelegate (string text); + + public readonly string WebsiteLinkAddress = "http://www.sparkleshare.org/"; + public readonly string CreditsLinkAddress = "http://github.com/hbons/SparkleShare/blob/master/legal/Authors.txt"; + public readonly string ReportProblemLinkAddress = "http://www.github.com/hbons/SparkleShare/issues"; + public readonly string DebugLogLinkAddress = "file://" + Program.Controller.Config.LogFilePath; + + public string RunningVersion; + + + public SparkleAboutController () + { + RunningVersion = SparkleLib.SparkleBackend.Version; + + Program.Controller.ShowAboutWindowEvent += delegate { + ShowWindowEvent (); + new Thread (() => CheckForNewVersion ()).Start (); + }; + } + + + public void WindowClosed () + { + HideWindowEvent (); + } + + + private void CheckForNewVersion () + { + UpdateLabelEvent ("Checking for updates..."); + Thread.Sleep (500); + + WebClient web_client = new WebClient (); + Uri uri = new Uri ("http://www.sparkleshare.org/version"); + + try { + string latest_version = web_client.DownloadString (uri).Trim (); + + if (new Version (latest_version) > new Version (RunningVersion)) + UpdateLabelEvent ("A newer version (" + latest_version + ") is available!"); + else + UpdateLabelEvent ("You are running the latest version."); + + } catch { + UpdateLabelEvent ("Version check failed."); + } + } + } +} diff --git a/SparkleShare/SparkleAvatars.cs b/SparkleShare/SparkleAvatars.cs new file mode 100644 index 0000000..2562e9f --- /dev/null +++ b/SparkleShare/SparkleAvatars.cs @@ -0,0 +1,131 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.IO; +using System.Collections.Generic; +using System.Net; +using System.Net.Mime; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; + +using SparkleLib; + +namespace SparkleShare +{ + public static class SparkleAvatars + { + private static List skipped_avatars = new List (); + + + public static string GetAvatar (string email, int size, string target_path) + { + #if __MonoCS__ + ServicePointManager.ServerCertificateValidationCallback = GetAvatarValidationCallBack; + #endif + + email = email.ToLower (); + + if (skipped_avatars.Contains (email)) + return null; + + string avatars_path = new string [] { Path.GetDirectoryName (target_path), + "avatars", size + "x" + size }.Combine (); + + // Search avatars by file name, ignore extension + // Delete files over a day old + // Return first matching file + if (Directory.Exists (avatars_path)) { + foreach (string file_path in Directory.GetFiles (avatars_path, email.MD5 () + "*")) { + if (new FileInfo (file_path).LastWriteTime < DateTime.Now.AddDays (-1)) + File.Delete (file_path); + else + return file_path; + } + } + + string avatar_file_path; + + try { + avatar_file_path = Path.Combine (avatars_path, email.MD5 ()); + + } catch (InvalidOperationException e) { + SparkleLogger.LogInfo ("Avatars", "Error fetching avatar for " + email, e); + return null; + } + + WebClient client = new WebClient (); + string url = "https://gravatar.com/avatar/" + email.MD5 () + ".png?s=" + size + "&d=404"; + + try { + byte [] buffer = client.DownloadData (url); + + if (client.ResponseHeaders ["content-type"].Equals (MediaTypeNames.Image.Jpeg, StringComparison.InvariantCultureIgnoreCase)) { + avatar_file_path += ".jpg"; + + } else if (client.ResponseHeaders ["content-type"].Equals (MediaTypeNames.Image.Gif, StringComparison.InvariantCultureIgnoreCase)) { + avatar_file_path += ".gif"; + + } else { + avatar_file_path += ".png"; + } + + if (buffer.Length > 255) { + if (!Directory.Exists (avatars_path)) { + Directory.CreateDirectory (avatars_path); + SparkleLogger.LogInfo ("Avatars", "Created '" + avatars_path + "'"); + } + + File.WriteAllBytes (avatar_file_path, buffer); + SparkleLogger.LogInfo ("Avatars", "Fetched " + size + "x" + size + " avatar for " + email); + + return avatar_file_path; + + } else { + return null; + } + + } catch (Exception e) { + SparkleLogger.LogInfo ("Avatars", "Error fetching avatar for " + email, e); + skipped_avatars.Add (email); + + return null; + } + } + + + private static bool GetAvatarValidationCallBack (Object sender, + X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) + { + X509Certificate2 certificate2 = new X509Certificate2 (certificate.GetRawCertData ()); + + // On some systems (mostly Linux) we can't assume the needed certificates are + // available, so we have to check the certificate's SHA-1 fingerprint manually. + // + // SHA1 fingerprinter obtained from https://www.gravatar.com/ on Oct 16 2015 + // Set to expire on Oct 14 2018 + string gravatar_cert_fingerprint = "1264B3F00814C6077D3853238771EE67FB6321C9"; + + if (!certificate2.Thumbprint.Equals (gravatar_cert_fingerprint)) { + SparkleLogger.LogInfo ("Avatars", "Invalid certificate for https://www.gravatar.com/"); + return false; + } + + return true; + } + } +} diff --git a/SparkleShare/SparkleBubblesController.cs b/SparkleShare/SparkleBubblesController.cs new file mode 100755 index 0000000..b3eca17 --- /dev/null +++ b/SparkleShare/SparkleBubblesController.cs @@ -0,0 +1,59 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Text; + +using SparkleLib; + +namespace SparkleShare { + + public class SparkleBubblesController { + + public event ShowBubbleEventHandler ShowBubbleEvent = delegate { }; + public delegate void ShowBubbleEventHandler (string title, string subtext, string image_path); + + + public SparkleBubblesController () + { + Program.Controller.AlertNotificationRaised += delegate (string title, string message) { + ShowBubble (title, message, null); + }; + + Program.Controller.NotificationRaised += delegate (SparkleChangeSet change_set) { + ShowBubble (change_set.User.Name, change_set.ToMessage (), change_set.User.AvatarFilePath); + }; + } + + + public void ShowBubble (string title, string subtext, string image_path) + { + byte [] title_bytes = Encoding.Default.GetBytes (title); + byte [] subtext_bytes = Encoding.Default.GetBytes (subtext); + title = Encoding.UTF8.GetString (title_bytes); + subtext = Encoding.UTF8.GetString (subtext_bytes); + + ShowBubbleEvent (title, subtext, image_path); + } + + + public void BubbleClicked () + { + Program.Controller.ShowEventLogWindow (); + } + } +} diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs new file mode 100644 index 0000000..2f7e95f --- /dev/null +++ b/SparkleShare/SparkleControllerBase.cs @@ -0,0 +1,796 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; + +using SparkleLib; + +namespace SparkleShare { + + public abstract class SparkleControllerBase { + + public SparkleRepoBase [] Repositories { + get { + lock (this.repo_lock) + return this.repositories.GetRange (0, this.repositories.Count).ToArray (); + } + } + + + private void AddRepository (SparkleRepoBase repo) + { + lock (this.repo_lock) { + this.repositories.Add (repo); + this.repositories.Sort ((x, y) => string.Compare (x.Name, y.Name)); + } + } + + + private void RemoveRepository (SparkleRepoBase repo) + { + lock (this.repo_lock) + this.repositories.Remove (repo); + } + + + public SparkleRepoBase GetRepoByName (string name) + { + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in this.repositories) + if (repo.Name.Equals (name)) + return repo; + } + + return null; + } + + + public SparkleConfig Config { get; private set; } + public bool RepositoriesLoaded { get; private set; } + public string FoldersPath { get; private set; } + + public double ProgressPercentage = 0.0; + public double ProgressSpeedUp = 0.0; + public double ProgressSpeedDown = 0.0; + + + public event ShowSetupWindowEventHandler ShowSetupWindowEvent = delegate { }; + public delegate void ShowSetupWindowEventHandler (PageType page_type); + + public event ShowNoteWindowEventHandler ShowNoteWindowEvent = delegate { }; + public delegate void ShowNoteWindowEventHandler (string project); + + public event Action ShowAboutWindowEvent = delegate { }; + public event Action ShowEventLogWindowEvent = delegate { }; + + public event FolderFetchedEventHandler FolderFetched = delegate { }; + public delegate void FolderFetchedEventHandler (string remote_url, string [] warnings); + + public event FolderFetchErrorHandler FolderFetchError = delegate { }; + public delegate void FolderFetchErrorHandler (string remote_url, string [] errors); + + public event FolderFetchingHandler FolderFetching = delegate { }; + public delegate void FolderFetchingHandler (double percentage, double speed); + + + public event Action FolderListChanged = delegate { }; + public event Action OnIdle = delegate { }; + public event Action OnSyncing = delegate { }; + public event Action OnError = delegate { }; + + + public event InviteReceivedHandler InviteReceived = delegate { }; + public delegate void InviteReceivedHandler (SparkleInvite invite); + + public event NotificationRaisedEventHandler NotificationRaised = delegate { }; + public delegate void NotificationRaisedEventHandler (SparkleChangeSet change_set); + + public event AlertNotificationRaisedEventHandler AlertNotificationRaised = delegate { }; + public delegate void AlertNotificationRaisedEventHandler (string title, string message); + + + public bool FirstRun { + get { return Config.User.Email.Equals ("Unknown"); } + } + + public List Folders { + get { + List folders = Config.Folders; + return folders; + } + } + + public SparkleUser CurrentUser { + get { return Config.User; } + set { Config.User = value; } + } + + public bool NotificationsEnabled { + get { + string notifications_enabled = Config.GetConfigOption ("notifications"); + + if (string.IsNullOrEmpty (notifications_enabled)) { + Config.SetConfigOption ("notifications", bool.TrueString); + return true; + + } else { + return notifications_enabled.Equals (bool.TrueString); + } + } + } + + public bool AvatarsEnabled { + get { + string fetch_avatars_option = Config.GetConfigOption ("fetch_avatars"); + + if (fetch_avatars_option == null || fetch_avatars_option.Equals (bool.FalseString)) + return false; + + return true; + } + } + + + // Path where the plugins are kept + public abstract string PluginsPath { get; } + + // Enables SparkleShare to start automatically at login + public abstract void CreateStartupItem (); + + // Installs the sparkleshare:// protocol handler + public abstract void InstallProtocolHandler (); + + // Adds the SparkleShare folder to the user's + // list of bookmarked places + public abstract void AddToBookmarks (); + + // Creates the SparkleShare folder in the user's home folder + public abstract bool CreateSparkleShareFolder (); + + // Opens the SparkleShare folder or an (optional) subfolder + public abstract void OpenFolder (string path); + + // Opens a file with the appropriate application + public abstract void OpenFile (string path); + + // Opens a file with the appropriate application + public virtual void OpenWebsite (string url) { } + + // Copies text to the clipboard + public abstract void CopyToClipboard (string text); + + public abstract string EventLogHTML { get; } + public abstract string DayEntryHTML { get; } + public abstract string EventEntryHTML { get; } + + + private SparkleFetcherBase fetcher; + private FileSystemWatcher watcher; + private Object repo_lock = new Object (); + private Object check_repos_lock = new Object (); + private List repositories = new List (); + private bool lost_folders_path = false; + + + public SparkleControllerBase () + { + + string app_data_path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); + string config_path = Path.Combine (app_data_path, "sparkleshare"); + + Config = new SparkleConfig (config_path, "config.xml"); + SparkleConfig.DefaultConfig = Config; + FoldersPath = Config.FoldersPath; + } + + + public virtual void Initialize () + { + SparkleLogger.LogInfo ("Environment", "SparkleShare version: " + SparkleLib.SparkleBackend.Version + + ", Operating system: " + SparkleLib.SparkleBackend.Platform + " (" + Environment.OSVersion + ")"); + + SparklePlugin.PluginsPath = PluginsPath; + InstallProtocolHandler (); + + try { + if (CreateSparkleShareFolder ()) + AddToBookmarks (); + + } catch (DirectoryNotFoundException) { + this.lost_folders_path = true; + } + + bool keys_imported = false; + + if (FirstRun) { + Config.SetConfigOption ("notifications", bool.TrueString); + + } else { + string keys_path = Path.GetDirectoryName (Config.FullPath); + string key_file_path = ""; + + foreach (string file_path in Directory.GetFiles (keys_path)) { + string file_name = Path.GetFileName(file_path); + if (file_name.EndsWith (".key")) { + key_file_path = Path.Combine (keys_path, file_name); + + // Replace spaces with underscores in old keys + if (file_name.Contains (" ")) { + string new_file_name = file_name.Replace (" ", "_"); + File.Move (key_file_path, Path.Combine (keys_path, new_file_name)); + File.Move (key_file_path + ".pub", Path.Combine (keys_path, new_file_name + ".pub")); + key_file_path = Path.Combine (keys_path, new_file_name); + } + + SparkleKeys.ImportPrivateKey (key_file_path); + keys_imported = true; + + break; + } + } + + if (keys_imported) { + CurrentUser.PublicKey = File.ReadAllText (key_file_path + ".pub"); + + } else { + string [] key_pair = CreateKeys (); + + SparkleKeys.ImportPrivateKey (key_pair [0]); + CurrentUser.PublicKey = File.ReadAllText (key_pair [1]); + } + + SparkleKeys.ListPrivateKeys (); + FolderListChanged (); // FIXME: Hacky way to update status icon menu to show the key + } + + // Watch the SparkleShare folder + this.watcher = new FileSystemWatcher () { + Filter = "*", + IncludeSubdirectories = false, + Path = FoldersPath + }; + + watcher.Created += OnFolderActivity; + // FIXME watcher.Deleted += OnFolderActivity; + // FIXME watcher.Renamed += OnFolderActivity; + + watcher.EnableRaisingEvents = true; + } + + + private int reopen_attempt_counts = 0; + + public void HandleReopen () + { + if (Repositories.Length > 0) { + ShowEventLogWindow (); + + } else if (reopen_attempt_counts > 1) { + AlertNotificationRaised ("Hello!", "SparkleShare sits right here, as a status icon."); + reopen_attempt_counts = 0; + + } else { + reopen_attempt_counts++; + } + } + + + public void UIHasLoaded () + { + if (this.lost_folders_path) { + Program.UI.Bubbles.Controller.ShowBubble ("Where's your SparkleShare folder?", + "Did you put it on a detached drive?", null); + + Environment.Exit (-1); + } + + if (FirstRun) { + ShowSetupWindow (PageType.Setup); + + new Thread (() => { + string [] key_pair = CreateKeys (); + + SparkleKeys.ImportPrivateKey (key_pair [0]); + CurrentUser.PublicKey = File.ReadAllText (key_pair [1]); + + FolderListChanged (); // FIXME: Hacky way to update status icon menu to show the key + + }).Start (); + + } else { + new Thread (() => { + StartupInviteScan (); + CheckRepositories (); + RepositoriesLoaded = true; + UpdateState (); + + }).Start (); + } + } + + + public void ShowSetupWindow (PageType page_type) + { + ShowSetupWindowEvent (page_type); + } + + + public void ShowAboutWindow () + { + ShowAboutWindowEvent (); + } + + + public void ShowNoteWindow (string project) + { + ShowNoteWindowEvent (project); + } + + + public void ShowEventLogWindow () + { + ShowEventLogWindowEvent (); + } + + + public void OpenSparkleShareFolder () + { + OpenFolder (Config.FoldersPath); + } + + + public void OpenSparkleShareFolder (string name) + { + OpenFolder (new SparkleFolder (name).FullPath); + } + + + public void ToggleNotifications () + { + bool notifications_enabled = Config.GetConfigOption ("notifications").Equals (bool.TrueString); + Config.SetConfigOption ("notifications", (!notifications_enabled).ToString ()); + } + + + private void CheckRepositories () + { + lock (this.check_repos_lock) { + string path = Config.FoldersPath; + + // Detect any renames + foreach (string folder_path in Directory.GetDirectories (path)) { + string folder_name = Path.GetFileName (folder_path); + + if (folder_name.Equals (".tmp")) + continue; + + if (Config.GetIdentifierForFolder (folder_name) == null) { + string identifier_file_path = Path.Combine (folder_path, ".sparkleshare"); + + if (!File.Exists (identifier_file_path)) + continue; + + string identifier = File.ReadAllText (identifier_file_path).Trim (); + + if (Config.IdentifierExists (identifier)) { + RemoveRepository (GetRepoByName (folder_name)); + Config.RenameFolder (identifier, folder_name); + + string new_folder_path = Path.Combine (path, folder_name); + AddRepository (new_folder_path); + + SparkleLogger.LogInfo ("Controller", + "Renamed folder with identifier " + identifier + " to '" + folder_name + "'"); + } + } + } + + // Remove any deleted folders + foreach (string folder_name in Config.Folders) { + string folder_path = new SparkleFolder (folder_name).FullPath; + + if (!Directory.Exists (folder_path)) { + Config.RemoveFolder (folder_name); + RemoveRepository (GetRepoByName (folder_name)); + + SparkleLogger.LogInfo ("Controller", "Removed folder '" + folder_name + "' from config"); + + } else { + AddRepository (folder_path); + } + } + + // Remove any duplicate folders + string previous_name = ""; + foreach (string folder_name in Config.Folders) { + if (!string.IsNullOrEmpty (previous_name) && folder_name.Equals (previous_name)) + Config.RemoveFolder (folder_name); + else + previous_name = folder_name; + } + + FolderListChanged (); + } + } + + + private void AddRepository (string folder_path) + { + SparkleRepoBase repo = null; + string folder_name = Path.GetFileName (folder_path); + string backend = Config.GetBackendForFolder (folder_name); + + try { + repo = (SparkleRepoBase) Activator.CreateInstance ( + Type.GetType ("SparkleLib." + backend + ".SparkleRepo, SparkleLib." + backend), + new object [] { folder_path, Config }); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Controller", "Failed to load backend '" + backend + "' for '" + folder_name + "': ", e); + return; + } + + repo.ChangesDetected += delegate { + UpdateState (); + }; + + repo.SyncStatusChanged += delegate (SyncStatus status) { + if (status == SyncStatus.Idle) { + ProgressPercentage = 0.0; + ProgressSpeedUp = 0.0; + ProgressSpeedDown = 0.0; + } + + UpdateState (); + }; + + repo.ProgressChanged += delegate { + ProgressPercentage = 0.0; + ProgressSpeedUp = 0.0; + ProgressSpeedDown = 0.0; + + double percentage = 0.0; + int repo_count = 0; + + foreach (SparkleRepoBase rep in Repositories) { + if (rep.ProgressPercentage > 0) { + percentage += rep.ProgressPercentage; + repo_count++; + } + + if (rep.Status == SyncStatus.SyncUp) + ProgressSpeedUp += rep.ProgressSpeed; + + if (rep.Status == SyncStatus.SyncDown) + ProgressSpeedDown += rep.ProgressSpeed; + } + + if (repo_count > 0) + ProgressPercentage = percentage / repo_count; + + UpdateState (); + }; + + repo.NewChangeSet += delegate (SparkleChangeSet change_set) { + if (AvatarsEnabled) + change_set.User.AvatarFilePath = SparkleAvatars.GetAvatar (change_set.User.Email, 48, Config.FullPath); + + NotificationRaised (change_set); + }; + + repo.ConflictResolved += delegate { + AlertNotificationRaised ("Resolved a file collision", + "Local and server versions were kept."); + }; + + AddRepository (repo); + repo.Initialize (); + } + + + private void OnFolderActivity (object o, FileSystemEventArgs args) + { + if (args != null && args.FullPath.EndsWith (".xml") && + args.ChangeType == WatcherChangeTypes.Created) { + + HandleInvite (args); + return; + + }/* else { FIXME: on the fly folder removal doesn't always work. disabling for now + Thread.Sleep (1000); + + if (Directory.Exists (args.FullPath) && args.ChangeType == WatcherChangeTypes.Created) + return; + + CheckRepositories (); + }*/ + } + + + private void StartupInviteScan () + { + foreach (string invite in Directory.GetFiles (FoldersPath, "*.xml")) { + HandleInvite (invite); + } + } + + + private void HandleInvite (FileSystemEventArgs args) + { + HandleInvite (args.FullPath); + } + + + private void HandleInvite (string path) + { + if (this.fetcher != null && + this.fetcher.IsActive) { + + AlertNotificationRaised ("SparkleShare Setup seems busy", "Please wait for it to finish"); + + } else { + SparkleInvite invite = new SparkleInvite (path); + + // It may be that the invite we received a path to isn't + // fully downloaded yet, so we try to read it several times + int tries = 0; + while (!invite.IsValid) { + Thread.Sleep (100); + invite = new SparkleInvite (path); + tries++; + + if (tries > 10) { + AlertNotificationRaised ("Oh noes!", "This invite seems screwed up..."); + break; + } + } + + if (invite.IsValid) + InviteReceived (invite); + + File.Delete (path); + } + } + + + // Fires events for the current syncing state + private void UpdateState () + { + bool has_unsynced_repos = false; + bool has_syncing_repos = false; + + foreach (SparkleRepoBase repo in Repositories) { + if (repo.Status == SyncStatus.SyncDown || repo.Status == SyncStatus.SyncUp || repo.IsBuffering) { + has_syncing_repos = true; + break; + + } else if (repo.Status == SyncStatus.Idle && repo.HasUnsyncedChanges) { + has_unsynced_repos = true; + } + } + + if (has_syncing_repos) + OnSyncing (); + else if (has_unsynced_repos) + OnError (); + else + OnIdle (); + } + + + public void StartFetcher (SparkleFetcherInfo info) + { + string tmp_path = Config.TmpPath; + + if (!Directory.Exists (tmp_path)) { + Directory.CreateDirectory (tmp_path); + File.SetAttributes (tmp_path, File.GetAttributes (tmp_path) | FileAttributes.Hidden); + } + + string canonical_name = Path.GetFileName (info.RemotePath); + string backend = info.Backend; + + if (string.IsNullOrEmpty (backend)) + backend = SparkleFetcherBase.GetBackend (info.Address); + + info.TargetDirectory = Path.Combine (tmp_path, canonical_name); + + try { + this.fetcher = (SparkleFetcherBase) Activator.CreateInstance ( + Type.GetType ("SparkleLib." + backend + ".SparkleFetcher, SparkleLib." + backend), info); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Controller", + "Failed to load '" + backend + "' backend for '" + canonical_name + "' " + e.Message); + + FolderFetchError (Path.Combine (info.Address, info.RemotePath).Replace (@"\", "/"), + new string [] {"Failed to load \"" + backend + "\" backend for \"" + canonical_name + "\""}); + + return; + } + + this.fetcher.Finished += delegate (bool repo_is_encrypted, bool repo_is_empty, string [] warnings) { + if (repo_is_encrypted && repo_is_empty) { + ShowSetupWindowEvent (PageType.CryptoSetup); + + } else if (repo_is_encrypted) { + ShowSetupWindowEvent (PageType.CryptoPassword); + + } else { + FinishFetcher (); + } + }; + + this.fetcher.Failed += delegate { + FolderFetchError (this.fetcher.RemoteUrl.ToString (), this.fetcher.Errors); + StopFetcher (); + }; + + this.fetcher.ProgressChanged += delegate (double percentage, double speed) { + FolderFetching (percentage, speed); + }; + + this.fetcher.Start (); + } + + + public void StopFetcher () + { + this.fetcher.Stop (); + this.fetcher.Dispose (); + + this.fetcher = null; + this.watcher.EnableRaisingEvents = true; + } + + + public bool CheckPassword (string password) + { + return this.fetcher.IsFetchedRepoPasswordCorrect (password); + } + + + public void FinishFetcher (string password) + { + this.fetcher.EnableFetchedRepoCrypto (password); + FinishFetcher (); + } + + + public void FinishFetcher () + { + this.watcher.EnableRaisingEvents = false; + + this.fetcher.Complete (); + string canonical_name = Path.GetFileName (this.fetcher.RemoteUrl.AbsolutePath); + + if (canonical_name.EndsWith (".git")) + canonical_name = canonical_name.Replace (".git", ""); + + canonical_name = canonical_name.Replace ("-crypto", ""); + canonical_name = canonical_name.ReplaceUnderscoreWithSpace (); + canonical_name = canonical_name.Replace ("%20", " "); + + bool target_folder_exists = Directory.Exists ( + Path.Combine (Config.FoldersPath, canonical_name)); + + // Add a numbered suffix to the name if a folder with the same name + // already exists. Example: "Folder (2)" + int suffix = 1; + while (target_folder_exists) { + suffix++; + target_folder_exists = Directory.Exists ( + Path.Combine (Config.FoldersPath, canonical_name + " (" + suffix + ")")); + } + + string target_folder_name = canonical_name; + + if (suffix > 1) + target_folder_name += " (" + suffix + ")"; + + string target_folder_path = Path.Combine (Config.FoldersPath, target_folder_name); + + try { + Directory.Move (this.fetcher.TargetFolder, target_folder_path); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Controller", "Error moving directory, trying again...", e); + + try { + ClearDirectoryAttributes (this.fetcher.TargetFolder); + Directory.Move (this.fetcher.TargetFolder, target_folder_path); + + } catch (Exception x) { + SparkleLogger.LogInfo ("Controller", "Error moving directory", x); + + this.fetcher.Dispose (); + this.fetcher = null; + this.watcher.EnableRaisingEvents = true; + return; + } + } + + string backend = SparkleFetcherBase.GetBackend (this.fetcher.RemoteUrl.ToString ()); + + Config.AddFolder (target_folder_name, this.fetcher.Identifier, + this.fetcher.RemoteUrl.ToString (), backend); + + if (this.fetcher.OriginalFetcherInfo.AnnouncementsUrl != null) { + Config.SetFolderOptionalAttribute (target_folder_name, "announcements_url", + this.fetcher.OriginalFetcherInfo.AnnouncementsUrl); + } + + RepositoriesLoaded = true; + FolderFetched (this.fetcher.RemoteUrl.ToString (), this.fetcher.Warnings.ToArray ()); + + AddRepository (target_folder_path); + FolderListChanged (); + + this.fetcher.Dispose (); + this.fetcher = null; + + this.watcher.EnableRaisingEvents = true; + } + + + public virtual void Quit () + { + foreach (SparkleRepoBase repo in Repositories) + repo.Dispose (); + + Environment.Exit (0); + } + + + private void ClearDirectoryAttributes (string path) + { + if (!Directory.Exists (path)) + return; + + string [] folders = Directory.GetDirectories (path); + + foreach (string folder in folders) + ClearDirectoryAttributes (folder); + + string [] files = Directory.GetFiles(path); + + foreach (string file in files) + if (!IsSymlink (file)) + File.SetAttributes (file, FileAttributes.Normal); + } + + + private string [] CreateKeys () + { + string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath); + string key_file_name = DateTime.Now.ToString ("yyyy-MM-dd_HH\\hmm"); + + return SparkleKeys.GenerateKeyPair (keys_path, key_file_name); + } + + + private bool IsSymlink (string file) + { + FileAttributes attributes = File.GetAttributes (file); + return ((attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint); + } + } +} diff --git a/SparkleShare/SparkleEventLogController.cs b/SparkleShare/SparkleEventLogController.cs new file mode 100755 index 0000000..fea2e65 --- /dev/null +++ b/SparkleShare/SparkleEventLogController.cs @@ -0,0 +1,643 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; + +using SparkleLib; + +namespace SparkleShare { + + public class SparkleEventLogController { + + public event Action ShowWindowEvent = delegate { }; + public event Action HideWindowEvent = delegate { }; + public event Action ContentLoadingEvent = delegate { }; + + public event UpdateContentEventEventHandler UpdateContentEvent = delegate { }; + public delegate void UpdateContentEventEventHandler (string html); + + public event UpdateChooserEventHandler UpdateChooserEvent = delegate { }; + public delegate void UpdateChooserEventHandler (string [] folders); + + public event UpdateChooserEnablementEventHandler UpdateChooserEnablementEvent = delegate { }; + public delegate void UpdateChooserEnablementEventHandler (bool enabled); + + public event UpdateSizeInfoEventHandler UpdateSizeInfoEvent = delegate { }; + public delegate void UpdateSizeInfoEventHandler (string size, string history_size); + + public event ShowSaveDialogEventHandler ShowSaveDialogEvent = delegate { }; + public delegate void ShowSaveDialogEventHandler (string file_name, string target_folder_path); + + + private string selected_folder; + private RevisionInfo restore_revision_info; + private bool history_view_active; + + + public bool WindowIsOpen { get; private set; } + + public string SelectedFolder { + get { + return this.selected_folder; + } + + set { + this.selected_folder = value; + + ContentLoadingEvent (); + UpdateSizeInfoEvent ("…", "…"); + + new Thread (() => { + SparkleDelay delay = new SparkleDelay (); + string html = HTML; + delay.Stop (); + + if (!string.IsNullOrEmpty (html)) + UpdateContentEvent (html); + + UpdateSizeInfoEvent (Size, HistorySize); + + }).Start (); + } + } + + public string HTML { + get { + List change_sets = GetLog (this.selected_folder); + string html = GetHTMLLog (change_sets); + + return html; + } + } + + public string [] Folders { + get { + return Program.Controller.Folders.ToArray (); + } + } + + public string Size { + get { + double size = 0; + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + if (this.selected_folder == null) { + size += repo.Size; + + } else if (this.selected_folder.Equals (repo.Name)) { + if (repo.Size == 0) + return "???"; + else + return repo.Size.ToSize (); + } + } + + if (size == 0) + return "???"; + else + return size.ToSize (); + } + } + + public string HistorySize { + get { + double size = 0; + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + if (this.selected_folder == null) { + size += repo.HistorySize; + + } else if (this.selected_folder.Equals (repo.Name)) { + if (repo.HistorySize == 0) + return "???"; + else + return repo.HistorySize.ToSize (); + } + } + + if (size == 0) + return "???"; + else + return size.ToSize (); + } + } + + + public SparkleEventLogController () + { + Program.Controller.ShowEventLogWindowEvent += delegate { + if (!WindowIsOpen) { + ContentLoadingEvent (); + UpdateSizeInfoEvent ("…", "…"); + + if (this.selected_folder == null) { + new Thread (() => { + SparkleDelay delay = new SparkleDelay (); + string html = HTML; + delay.Stop (); + + UpdateChooserEvent (Folders); + UpdateChooserEnablementEvent (true); + + if (!string.IsNullOrEmpty (html)) + UpdateContentEvent (html); + + UpdateSizeInfoEvent (Size, HistorySize); + + }).Start (); + } + } + + WindowIsOpen = true; + ShowWindowEvent (); + }; + + Program.Controller.OnIdle += delegate { + if (this.history_view_active) + return; + + ContentLoadingEvent (); + UpdateSizeInfoEvent ("…", "…"); + + SparkleDelay delay = new SparkleDelay (); + string html = HTML; + delay.Stop (); + + if (!string.IsNullOrEmpty (html)) + UpdateContentEvent (html); + + UpdateSizeInfoEvent (Size, HistorySize); + }; + + Program.Controller.FolderListChanged += delegate { + if (this.selected_folder != null && !Program.Controller.Folders.Contains (this.selected_folder)) + this.selected_folder = null; + + UpdateChooserEvent (Folders); + UpdateSizeInfoEvent (Size, HistorySize); + }; + } + + + public void WindowClosed () + { + WindowIsOpen = false; + HideWindowEvent (); + this.selected_folder = null; + } + + + public void LinkClicked (string url) + { + if (url.StartsWith ("about:") || string.IsNullOrEmpty (url)) + return; + + url = url.Replace ("%20", " "); + + if (url.StartsWith ("http")) { + Program.Controller.OpenWebsite (url); + + } else if (url.StartsWith ("restore://") && this.restore_revision_info == null) { + Regex regex = new Regex ("restore://(.+)/([a-f0-9]+)/(.+)/(.{3} [0-9]+ [0-9]+h[0-9]+)/(.+)"); + Match match = regex.Match (url); + + if (match.Success) { + string author_name = match.Groups [3].Value; + string timestamp = match.Groups [4].Value; + + this.restore_revision_info = new RevisionInfo () { + Folder = new SparkleFolder (match.Groups [1].Value), + Revision = match.Groups [2].Value, + FilePath = Uri.UnescapeDataString (match.Groups [5].Value) + }; + + string file_name = Path.GetFileNameWithoutExtension (this.restore_revision_info.FilePath) + + " (" + author_name + " " + timestamp + ")" + Path.GetExtension (this.restore_revision_info.FilePath); + + string target_folder_path = Path.Combine (this.restore_revision_info.Folder.FullPath, + Path.GetDirectoryName (this.restore_revision_info.FilePath)); + + ShowSaveDialogEvent (file_name, target_folder_path); + } + + } else if (url.StartsWith ("back://")) { + this.history_view_active = false; + SelectedFolder = this.selected_folder; // TODO: Return to the same position on the page + + UpdateChooserEnablementEvent (true); + + } else if (url.StartsWith ("history://")) { + this.history_view_active = true; + + ContentLoadingEvent (); + UpdateSizeInfoEvent ("…", "…"); + UpdateChooserEnablementEvent (false); + + string folder = url.Replace ("history://", "").Split ("/".ToCharArray ()) [0]; + string file_path = url.Replace ("history://" + folder + "/", ""); + + byte [] file_path_bytes = Encoding.Default.GetBytes (file_path); + file_path = Encoding.UTF8.GetString (file_path_bytes); + + file_path = Uri.UnescapeDataString (file_path); + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + if (!repo.Name.Equals (folder)) + continue; + + new Thread (() => { + SparkleDelay delay = new SparkleDelay (); + List change_sets = repo.GetChangeSets (file_path); + string html = GetHistoryHTMLLog (change_sets, file_path); + delay.Stop (); + + if (!string.IsNullOrEmpty (html)) + UpdateContentEvent (html); + + }).Start (); + + break; + } + + } else { + Program.Controller.OpenFile (url); + } + } + + + public void SaveDialogCompleted (string target_file_path) + { + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + if (repo.Name.Equals (this.restore_revision_info.Folder.Name)) { + repo.RestoreFile (this.restore_revision_info.FilePath, + this.restore_revision_info.Revision, target_file_path); + + break; + } + } + + this.restore_revision_info = null; + Program.Controller.OpenFolder (Path.GetDirectoryName (target_file_path)); + } + + + public void SaveDialogCancelled () + { + this.restore_revision_info = null; + } + + + private List GetLog () + { + List list = new List (); + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + List change_sets = repo.ChangeSets; + + if (change_sets != null) + list.AddRange (change_sets); + else + SparkleLogger.LogInfo ("Log", "Could not create log for " + repo.Name); + } + + list.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); + list.Reverse (); + + if (list.Count > 100) + return list.GetRange (0, 100); + else + return list.GetRange (0, list.Count); + } + + + private List GetLog (string name) + { + if (name == null) + return GetLog (); + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + if (repo.Name.Equals (name)) { + List change_sets = repo.ChangeSets; + + if (change_sets != null) + return change_sets; + else + break; + } + } + + return new List (); + } + + + public string GetHistoryHTMLLog (List change_sets, string file_path) + { + string html = "
    " + + "« Back  |  "; + + if (change_sets.Count > 1) + html += "Revisions for “"; + else + html += "No revisions for “"; + + html += Path.GetFileName (file_path) + "”"; + html += "
    "; + + if (change_sets.Count > 0) + change_sets.RemoveAt (0); + + foreach (SparkleChangeSet change_set in change_sets) { + html += "" + + "" + + "" + + "" + + "" + + "" + + ""; + } + + html += "
    " + change_set.User.Name + "" + + change_set.Timestamp.ToString ("d MMM yyyy", CultureInfo.InvariantCulture) + + "" + change_set.Timestamp.ToString ("HH:mm") + "" + + "Restore…" + + "
    "; + html = Program.Controller.EventLogHTML.Replace ("", html); + + return html.Replace ("", "100000000"); + } + + + public string GetHTMLLog (List change_sets) + { + if (change_sets == null || change_sets.Count == 0) + return Program.Controller.EventLogHTML.Replace ("", + "
    This project does not keep a history.
    "); + + List activity_days = new List (); + + change_sets.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); + change_sets.Reverse (); + + foreach (SparkleChangeSet change_set in change_sets) { + bool change_set_inserted = false; + + foreach (ActivityDay stored_activity_day in activity_days) { + if (stored_activity_day.Date.Year == change_set.Timestamp.Year && + stored_activity_day.Date.Month == change_set.Timestamp.Month && + stored_activity_day.Date.Day == change_set.Timestamp.Day) { + + stored_activity_day.Add (change_set); + + change_set_inserted = true; + break; + } + } + + if (!change_set_inserted) { + ActivityDay activity_day = new ActivityDay (change_set.Timestamp); + activity_day.Add (change_set); + activity_days.Add (activity_day); + } + } + + string event_log_html = Program.Controller.EventLogHTML; + string day_entry_html = Program.Controller.DayEntryHTML; + string event_entry_html = Program.Controller.EventEntryHTML; + string event_log = ""; + + foreach (ActivityDay activity_day in activity_days) { + string event_entries = ""; + + foreach (SparkleChangeSet change_set in activity_day) { + string event_entry = "
    "; + + foreach (SparkleChange change in change_set.Changes) { + if (change.Type != SparkleChangeType.Moved) { + event_entry += "
    "; + + if (!change.IsFolder) { + event_entry += "" + change.Timestamp.ToString ("HH:mm") + + " ▾  "; + + } else { + event_entry += "" + change.Timestamp.ToString ("HH:mm") + "  "; + } + + event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path); + event_entry += "
    "; + + } else { + event_entry += "
    "; + event_entry += "" + change.Timestamp.ToString ("HH:mm") +"  "; + event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path); + event_entry += "
    "; + event_entry += "" + change.Timestamp.ToString ("HH:mm") +"  "; + event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.MovedToPath); + event_entry += "
    "; + } + } + + event_entry += "
    "; + + string timestamp = change_set.Timestamp.ToString ("H:mm"); + + if (!change_set.FirstTimestamp.Equals (new DateTime ()) && + !change_set.Timestamp.ToString ("H:mm").Equals (change_set.FirstTimestamp.ToString ("H:mm"))) { + + timestamp = change_set.FirstTimestamp.ToString ("H:mm") + " – " + timestamp; + } + + // TODO: List commit messages if there are any + event_entries += event_entry_html.Replace ("", event_entry) + .Replace ("", change_set.User.Name) + .Replace ("", change_set.User.Email) + .Replace ("", GetAvatarFilePath (change_set.User)) + .Replace ("", change_set.RemoteUrl.ToString ()) + .Replace ("", change_set.Revision); + + if (this.selected_folder == null) { + event_entries = event_entries.Replace ("", " @ " + change_set.Folder.Name); + event_entries = event_entries.Replace ("", change_set.Folder.FullPath); + } + } + + string day_entry = ""; + DateTime today = DateTime.Now; + DateTime yesterday = DateTime.Now.AddDays (-1); + + if (today.Day == activity_day.Date.Day && + today.Month == activity_day.Date.Month && + today.Year == activity_day.Date.Year) { + + day_entry = day_entry_html.Replace ("", + "" + "Today" + + ""); + + } else if (yesterday.Day == activity_day.Date.Day && + yesterday.Month == activity_day.Date.Month && + yesterday.Year == activity_day.Date.Year) { + + day_entry = day_entry_html.Replace ("", + "" + + "Yesterday" + + ""); + + } else { + if (activity_day.Date.Year != DateTime.Now.Year) { + day_entry = day_entry_html.Replace ("", + activity_day.Date.ToString ("dddd, MMMM d, yyyy", CultureInfo.InvariantCulture)); + + } else { + day_entry = day_entry_html.Replace ("", + activity_day.Date.ToString ("dddd, MMMM d", CultureInfo.InvariantCulture)); + } + } + + event_log += day_entry.Replace ("", event_entries); + } + + int midnight = (int) (DateTime.Today.AddDays (1) - new DateTime (1970, 1, 1)).TotalSeconds; + + string html = event_log_html.Replace ("", event_log); + html = html.Replace ("", midnight.ToString ()); + + return html; + } + + + private string FormatBreadCrumbs (string path_root, string path) + { + byte [] path_root_bytes = Encoding.Default.GetBytes (path_root); + byte [] path_bytes = Encoding.Default.GetBytes (path); + path_root = Encoding.UTF8.GetString (path_root_bytes); + path = Encoding.UTF8.GetString (path_bytes); + + path_root = path_root.Replace ("/", Path.DirectorySeparatorChar.ToString ()); + path = path.Replace ("/", Path.DirectorySeparatorChar.ToString ()); + string new_path_root = path_root; + string [] crumbs = path.Split (Path.DirectorySeparatorChar); + string link = ""; + bool previous_was_folder = false; + + int i = 0; + foreach (string crumb in crumbs) { + if (string.IsNullOrEmpty (crumb)) + continue; + + string crumb_path = SafeCombine (new_path_root, crumb); + + if (Directory.Exists (crumb_path)) { + link += "" + crumb + Path.DirectorySeparatorChar + ""; + previous_was_folder = true; + + } else if (File.Exists (crumb_path)) { + link += "" + crumb + ""; + previous_was_folder = false; + + } else { + if (i > 0 && !previous_was_folder) + link += Path.DirectorySeparatorChar; + + link += crumb; + previous_was_folder = false; + } + + new_path_root = SafeCombine (new_path_root, crumb); + i++; + } + + return link; + } + + + private string SafeCombine (string path1, string path2) + { + string result = path1; + + if (!result.EndsWith (Path.DirectorySeparatorChar.ToString ())) + result += Path.DirectorySeparatorChar; + + if (path2.StartsWith (Path.DirectorySeparatorChar.ToString ())) + path2 = path2.Substring (1); + + return result + path2; + } + + + private string GetAvatarFilePath (SparkleUser user) + { + if (!Program.Controller.AvatarsEnabled) + return "/user-icon-default.png"; + + string fetched_avatar = SparkleAvatars.GetAvatar (user.Email, 48, Program.Controller.Config.FullPath); + + if (!string.IsNullOrEmpty (fetched_avatar)) + return "file://" + fetched_avatar.Replace ("\\", "/"); + else + return "/user-icon-default.png"; + } + + + // All change sets that happened on a day + private class ActivityDay : List + { + public DateTime Date; + + public ActivityDay (DateTime date_time) + { + Date = new DateTime (date_time.Year, date_time.Month, date_time.Day); + } + } + + + private class RevisionInfo { + public SparkleFolder Folder; + public string FilePath; + public string Revision; + } + + + private class SparkleDelay : Stopwatch { + + public SparkleDelay () : base () + { + Start (); + } + + + new public void Stop () + { + base.Stop (); + + if (ElapsedMilliseconds < 500) + Thread.Sleep (500 - (int) ElapsedMilliseconds); + } + } + } +} diff --git a/SparkleShare/SparkleExtensions.cs b/SparkleShare/SparkleExtensions.cs new file mode 100644 index 0000000..2ae8660 --- /dev/null +++ b/SparkleShare/SparkleExtensions.cs @@ -0,0 +1,35 @@ +// 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; + +namespace SparkleShare { + + public static class Extensions { + + public static string Combine (this string [] parts) + { + string new_path = ""; + + foreach (string part in parts) + new_path = Path.Combine (new_path, part); + + return new_path; + } + } +} diff --git a/SparkleShare/SparkleInvite.cs b/SparkleShare/SparkleInvite.cs new file mode 100644 index 0000000..7ce67eb --- /dev/null +++ b/SparkleShare/SparkleInvite.cs @@ -0,0 +1,120 @@ +// 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.Net; +using System.Text; +using System.Xml; + +using SparkleLib; + +namespace SparkleShare { + + public class SparkleInvite : XmlDocument { + + public string Address { get; private set; } + public string RemotePath { get; private set; } + public string Fingerprint { get; private set; } + public string AcceptUrl { get; private set; } + public string AnnouncementsUrl { get; private set; } + + public bool IsValid { + get { + return (!string.IsNullOrEmpty (Address) && !string.IsNullOrEmpty (RemotePath)); + } + } + + + public SparkleInvite (string xml_file_path) : base () + { + try { + Load (xml_file_path); + + } catch (XmlException e) { + SparkleLogger.LogInfo ("Invite", "Error parsing XML", e); + return; + } + + Address = ReadField ("address"); + RemotePath = ReadField ("remote_path"); + AcceptUrl = ReadField ("accept_url"); + AnnouncementsUrl = ReadField ("announcements_url"); + Fingerprint = ReadField ("fingerprint"); + } + + + public bool Accept (string public_key) + { + #if __MonoCS__ + ServicePointManager.ServerCertificateValidationCallback = delegate { + return true; + }; + #endif + + if (string.IsNullOrEmpty (AcceptUrl)) + return true; + + string post_data = "public_key=" + Uri.EscapeDataString (public_key); + byte [] post_bytes = Encoding.UTF8.GetBytes (post_data); + + WebRequest request = WebRequest.Create (AcceptUrl); + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + request.ContentLength = post_bytes.Length; + + Stream data_stream = request.GetRequestStream (); + data_stream.Write (post_bytes, 0, post_bytes.Length); + data_stream.Close (); + + HttpWebResponse response = null; + + try { + response = (HttpWebResponse) request.GetResponse (); + response.Close (); + + } catch (WebException e) { + SparkleLogger.LogInfo ("Invite", "Failed uploading public key to " + AcceptUrl + "", e); + return false; + } + + if (response != null && response.StatusCode == HttpStatusCode.OK) { + SparkleLogger.LogInfo ("Invite", "Uploaded public key to " + AcceptUrl); + return true; + } + + return false; + } + + + private string ReadField (string name) + { + try { + XmlNode node = SelectSingleNode ("/sparkleshare/invite/" + name + "/text()"); + + if (node != null) + return node.Value; + else + return ""; + + } catch (XmlException e) { + SparkleLogger.LogInfo ("Invite", "Error reading field '" + name + "'", e); + return ""; + } + } + } +} \ No newline at end of file diff --git a/SparkleShare/SparkleKeys.cs b/SparkleShare/SparkleKeys.cs new file mode 100644 index 0000000..c30b575 --- /dev/null +++ b/SparkleShare/SparkleKeys.cs @@ -0,0 +1,105 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Diagnostics; +using System.IO; + +using SparkleLib; + +namespace SparkleShare { + + public static class SparkleKeys { + + public static string [] GenerateKeyPair (string output_path, string key_name) + { + key_name += ".key"; + string key_file_path = Path.Combine (output_path, key_name); + + if (File.Exists (key_file_path)) { + SparkleLogger.LogInfo ("Auth", "A key pair exists ('" + key_name + "'), leaving it untouched"); + return new string [] { key_file_path, key_file_path + ".pub" }; + } + + string computer_name = System.Net.Dns.GetHostName (); + + if (computer_name.EndsWith (".local")) + computer_name = computer_name.Substring (0, computer_name.Length - 6); + + string arguments = "-t rsa " + // crypto type + "-b 4096 " + // key size + "-P \"\" " + // empty password + "-C \"" + computer_name + " (SparkleShare)\" " + // key comment + "-f \"" + key_name + "\""; // file name + + SparkleKeyProcess process = new SparkleKeyProcess ("ssh-keygen", arguments); + process.StartInfo.WorkingDirectory = output_path; + process.Start (); + process.WaitForExit (); + + if (process.ExitCode == 0) + SparkleLogger.LogInfo ("Auth", "Created keypair '" + key_file_path + "'"); + else + SparkleLogger.LogInfo ("Auth", "Could not create key pair '" + key_file_path + "'"); + + return new string [] { key_file_path, key_file_path + ".pub" }; + } + + + public static void ImportPrivateKey (string key_file_path) + { + // Use forward slashes when dealing with Windows domain accounts + if (key_file_path.StartsWith ("\\\\")) + key_file_path = key_file_path.Replace ("\\", "/"); + + SparkleKeyProcess process = new SparkleKeyProcess ("ssh-add", "\"" + key_file_path + "\""); + process.Start (); + process.WaitForExit (); + + if (process.ExitCode == 0) + SparkleLogger.LogInfo ("Auth", "Imported key '" + key_file_path + "'"); + else + SparkleLogger.LogInfo ("Auth", "Could not import key '" + key_file_path + "', " + + process.StandardError.ReadToEnd ()); + } + + + public static void ListPrivateKeys () + { + SparkleKeyProcess process = new SparkleKeyProcess ("ssh-add", "-l"); + process.Start (); + string keys_in_use = process.StandardOutput.ReadToEnd (); + process.WaitForExit (); + + SparkleLogger.LogInfo ("Auth", "The following keys may be used:\n" + keys_in_use.Trim ()); + } + + + private class SparkleKeyProcess : Process { + + public SparkleKeyProcess (string command, string arguments) : base () + { + StartInfo.FileName = command; + StartInfo.Arguments = arguments; + StartInfo.UseShellExecute = false; + StartInfo.RedirectStandardOutput = true; + StartInfo.RedirectStandardError = true; + StartInfo.CreateNoWindow = true; + } + } + } +} diff --git a/SparkleShare/SparkleNoteController.cs b/SparkleShare/SparkleNoteController.cs new file mode 100755 index 0000000..47809d2 --- /dev/null +++ b/SparkleShare/SparkleNoteController.cs @@ -0,0 +1,67 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Net; +using System.Threading; + +namespace SparkleShare { + + public class SparkleNoteController { + + public event Action ShowWindowEvent = delegate { }; + public event Action HideWindowEvent = delegate { }; + + public event UpdateTitleEventDelegate UpdateTitleEvent = delegate { }; + public delegate void UpdateTitleEventDelegate (string title); + + public string AvatarFilePath = ""; + public string CurrentProject { get; private set; } + + + public SparkleNoteController () + { + Program.Controller.ShowNoteWindowEvent += delegate (string project) { + CurrentProject = project; + ShowWindowEvent (); + UpdateTitleEvent (CurrentProject); + }; + + AvatarFilePath = SparkleAvatars.GetAvatar (Program.Controller.CurrentUser.Email, + 48, Program.Controller.Config.FullPath); + } + + + public void CancelClicked () + { + HideWindowEvent (); + } + + + public void SyncClicked (string note) + { + HideWindowEvent (); + new Thread (() => Program.Controller.GetRepoByName (CurrentProject).Resume (note)).Start (); + } + + + public void WindowClosed () + { + HideWindowEvent (); + } + } +} diff --git a/SparkleShare/SparklePlugin.cs b/SparkleShare/SparklePlugin.cs new file mode 100644 index 0000000..c80d2d8 --- /dev/null +++ b/SparkleShare/SparklePlugin.cs @@ -0,0 +1,123 @@ +// 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.Xml; + +using IO = System.IO; + +namespace SparkleShare { + + public class SparklePlugin : XmlDocument { + + public static string PluginsPath = ""; + + public static string LocalPluginsPath = IO.Path.Combine ( + Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "sparkleshare", "plugins"); + + new public string Name { get { return GetValue ("info", "name"); } } + public string Description { get { return GetValue ("info", "description"); } } + public string Backend { get { return GetValue ("info", "backend"); } } + public string Fingerprint { get { return GetValue ("info", "fingerprint"); } } + public string AnnouncementsUrl { get { return GetValue ("info", "announcements_url"); } } + public string Address { get { return GetValue ("address", "value"); } } + public string AddressExample { get { return GetValue ("address", "example"); } } + public string Path { get { return GetValue ("path", "value"); } } + public string PathExample { get { return GetValue ("path", "example"); } } + + public string ImagePath { + get { + string image_file_name = GetValue ("info", "icon"); + string image_path = IO.Path.Combine (this.plugin_directory, image_file_name); + + if (IO.File.Exists (image_path)) + return image_path; + else + return IO.Path.Combine (PluginsPath, image_file_name); + } + } + + public bool PathUsesLowerCase { + get { + string uses_lower_case = GetValue ("path", "uses_lower_case"); + + if (!string.IsNullOrEmpty (uses_lower_case)) + return uses_lower_case.Equals (bool.TrueString); + else + return false; + } + } + + private string plugin_directory; + + + public SparklePlugin (string plugin_path) + { + this.plugin_directory = System.IO.Path.GetDirectoryName (plugin_path); + Load (plugin_path); + } + + + public static SparklePlugin Create (string name, string description, string address_value, + string address_example, string path_value, string path_example) + { + string plugin_path = System.IO.Path.Combine (LocalPluginsPath, name + ".xml"); + + if (IO.File.Exists (plugin_path)) + return null; + + string plugin_xml = "" + + "" + + " " + + " " + + " " + name + "" + + " " + description + "" + + " own-server.png" + + " " + + "
    " + + " " + address_value + "" + + " " + address_example + "" + + "
    " + + " " + + " " + path_value + "" + + " " + path_example + "" + + " " + + "
    " + + "
    "; + + plugin_xml = plugin_xml.Replace ("", ""); + plugin_xml = plugin_xml.Replace ("", ""); + + if (!IO.Directory.Exists (LocalPluginsPath)) + IO.Directory.CreateDirectory (LocalPluginsPath); + + IO.File.WriteAllText (plugin_path, plugin_xml); + return new SparklePlugin (plugin_path); + } + + + private string GetValue (string a, string b) + { + XmlNode node = SelectSingleNode ("/sparkleshare/plugin/" + a + "/" + b + "/text()"); + + if (node != null && !string.IsNullOrEmpty (node.Value)) + return node.Value; + else + return null; + } + } +} \ No newline at end of file diff --git a/SparkleShare/SparkleSetupController.cs b/SparkleShare/SparkleSetupController.cs new file mode 100755 index 0000000..574da27 --- /dev/null +++ b/SparkleShare/SparkleSetupController.cs @@ -0,0 +1,594 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Threading; + +using SparkleLib; + +namespace SparkleShare { + + public enum PageType { + None, + Setup, + Add, + Invite, + Syncing, + Error, + Finished, + Tutorial, + CryptoSetup, + CryptoPassword + } + + public enum FieldState { + Enabled, + Disabled + } + + + public class SparkleSetupController { + + public event Action ShowWindowEvent = delegate { }; + public event Action HideWindowEvent = delegate { }; + + public event ChangePageEventHandler ChangePageEvent = delegate { }; + public delegate void ChangePageEventHandler (PageType page, string [] warnings); + + public event UpdateProgressBarEventHandler UpdateProgressBarEvent = delegate { }; + public delegate void UpdateProgressBarEventHandler (double percentage, string speed); + + public event UpdateSetupContinueButtonEventHandler UpdateSetupContinueButtonEvent = delegate { }; + public delegate void UpdateSetupContinueButtonEventHandler (bool button_enabled); + + public event UpdateCryptoSetupContinueButtonEventHandler UpdateCryptoSetupContinueButtonEvent = delegate { }; + public delegate void UpdateCryptoSetupContinueButtonEventHandler (bool button_enabled); + + public event UpdateCryptoPasswordContinueButtonEventHandler UpdateCryptoPasswordContinueButtonEvent = delegate { }; + public delegate void UpdateCryptoPasswordContinueButtonEventHandler (bool button_enabled); + + public event UpdateAddProjectButtonEventHandler UpdateAddProjectButtonEvent = delegate { }; + public delegate void UpdateAddProjectButtonEventHandler (bool button_enabled); + + public event ChangeAddressFieldEventHandler ChangeAddressFieldEvent = delegate { }; + public delegate void ChangeAddressFieldEventHandler (string text, string example_text, FieldState state); + + public event ChangePathFieldEventHandler ChangePathFieldEvent = delegate { }; + public delegate void ChangePathFieldEventHandler (string text, string example_text, FieldState state); + + public readonly List Plugins = new List (); + public SparklePlugin SelectedPlugin; + + public bool WindowIsOpen { get; private set; } + public SparkleInvite PendingInvite { get; private set; } + public int TutorialPageNumber { get; private set; } + public string PreviousUrl { get; private set; } + public string PreviousAddress { get; private set; } + public string PreviousPath { get; private set; } + public string SyncingFolder { get; private set; } + public double ProgressBarPercentage { get; private set; } + + + public int SelectedPluginIndex { + get { + return Plugins.IndexOf (SelectedPlugin); + } + } + + public bool FetchPriorHistory { + get { + return this.fetch_prior_history; + } + } + + private PageType current_page; + private string saved_address = ""; + private string saved_remote_path = ""; + private bool create_startup_item = true; + private bool fetch_prior_history = false; + + + public SparkleSetupController () + { + ChangePageEvent += delegate (PageType page_type, string [] warnings) { + this.current_page = page_type; + }; + + TutorialPageNumber = 0; + PreviousAddress = ""; + PreviousPath = ""; + PreviousUrl = ""; + SyncingFolder = ""; + + string local_plugins_path = SparklePlugin.LocalPluginsPath; + int local_plugins_count = 0; + + // Import all of the plugins + if (Directory.Exists (local_plugins_path)) + // Local plugins go first... + foreach (string xml_file_path in Directory.GetFiles (local_plugins_path, "*.xml")) { + Plugins.Add (new SparklePlugin (xml_file_path)); + local_plugins_count++; + } + + // ...system plugins after that... + if (Directory.Exists (Program.Controller.PluginsPath)) { + foreach (string xml_file_path in Directory.GetFiles (Program.Controller.PluginsPath, "*.xml")) { + // ...and "Own server" at the very top + if (xml_file_path.EndsWith ("own-server.xml")) { + Plugins.Insert (0, new SparklePlugin (xml_file_path)); + + } else if (xml_file_path.EndsWith ("ssnet.xml")) { + // Plugins.Insert ((local_plugins_count + 1), new SparklePlugin (xml_file_path)); + // TODO: Skip this plugin for now + + } else { + Plugins.Add (new SparklePlugin (xml_file_path)); + } + } + } + + SelectedPlugin = Plugins [0]; + + Program.Controller.InviteReceived += delegate (SparkleInvite invite) { + PendingInvite = invite; + + ChangePageEvent (PageType.Invite, null); + ShowWindowEvent (); + }; + + Program.Controller.ShowSetupWindowEvent += delegate (PageType page_type) { + if (page_type == PageType.CryptoSetup || page_type == PageType.CryptoPassword) { + ChangePageEvent (page_type, null); + return; + } + + if (PendingInvite != null) { + WindowIsOpen = true; + ShowWindowEvent (); + return; + } + + if (this.current_page == PageType.Syncing || + this.current_page == PageType.Finished || + this.current_page == PageType.CryptoSetup || + this.current_page == PageType.CryptoPassword) { + + ShowWindowEvent (); + return; + } + + if (page_type == PageType.Add) { + if (WindowIsOpen) { + if (this.current_page == PageType.Error || + this.current_page == PageType.Finished || + this.current_page == PageType.None) { + + ChangePageEvent (PageType.Add, null); + } + + } else if (!Program.Controller.FirstRun && TutorialPageNumber == 0) { + WindowIsOpen = true; + ChangePageEvent (PageType.Add, null); + } + + ShowWindowEvent (); + return; + } + + WindowIsOpen = true; + ChangePageEvent (page_type, null); + ShowWindowEvent (); + }; + } + + + public void PageCancelled () + { + PendingInvite = null; + SelectedPlugin = Plugins [0]; + + PreviousAddress = ""; + PreviousPath = ""; + PreviousUrl = ""; + + this.saved_address = ""; + this.saved_remote_path = ""; + this.fetch_prior_history = false; + + WindowIsOpen = false; + HideWindowEvent (); + } + + + public void CheckSetupPage (string full_name, string email) + { + full_name = full_name.Trim (); + email = email.Trim (); + + bool fields_valid = (!string.IsNullOrEmpty (full_name) && IsValidEmail (email)); + UpdateSetupContinueButtonEvent (fields_valid); + } + + + public void SetupPageCancelled () + { + Program.Controller.Quit (); + } + + + public void SetupPageCompleted (string full_name, string email) + { + Program.Controller.CurrentUser = new SparkleUser (full_name, email); + + TutorialPageNumber = 1; + ChangePageEvent (PageType.Tutorial, null); + } + + + public void TutorialSkipped () + { + TutorialPageNumber = 4; + ChangePageEvent (PageType.Tutorial, null); + } + + + public void HistoryItemChanged (bool fetch_prior_history) + { + this.fetch_prior_history = fetch_prior_history; + } + + + public void TutorialPageCompleted () + { + TutorialPageNumber++; + + if (TutorialPageNumber == 5) { + TutorialPageNumber = 0; + + WindowIsOpen = false; + HideWindowEvent (); + + if (this.create_startup_item) + new Thread (() => Program.Controller.CreateStartupItem ()).Start (); + + } else { + ChangePageEvent (PageType.Tutorial, null); + } + } + + + public void SelectedPluginChanged (int plugin_index) + { + SelectedPlugin = Plugins [plugin_index]; + + if (SelectedPlugin.Address != null) { + ChangeAddressFieldEvent (SelectedPlugin.Address, "", FieldState.Disabled); + + } else if (SelectedPlugin.AddressExample != null) { + ChangeAddressFieldEvent (this.saved_address, SelectedPlugin.AddressExample, FieldState.Enabled); + + } else { + ChangeAddressFieldEvent (this.saved_address, "", FieldState.Enabled); + } + + if (SelectedPlugin.Path != null) { + ChangePathFieldEvent (SelectedPlugin.Path, "", FieldState.Disabled); + + } else if (SelectedPlugin.PathExample != null) { + ChangePathFieldEvent (this.saved_remote_path, SelectedPlugin.PathExample, FieldState.Enabled); + + } else { + ChangePathFieldEvent (this.saved_remote_path, "", FieldState.Enabled); + } + } + + + public void StartupItemChanged (bool create_startup_item) + { + this.create_startup_item = create_startup_item; + } + + + public void CheckAddPage (string address, string remote_path, int selected_plugin) + { + address = address.Trim (); + remote_path = remote_path.Trim (); + + if (selected_plugin == 0) + this.saved_address = address; + + this.saved_remote_path = remote_path; + + bool fields_valid = (!string.IsNullOrEmpty (address) && + !string.IsNullOrEmpty (remote_path) && !remote_path.Contains ("\"")); + + UpdateAddProjectButtonEvent (fields_valid); + } + + + public void AddPageCompleted (string address, string remote_path) + { + SyncingFolder = Path.GetFileName (remote_path); + + if (remote_path.EndsWith (".git")) + SyncingFolder = remote_path.Substring (0, remote_path.Length - 4); + + SyncingFolder = SyncingFolder.Replace ("-crypto", ""); + SyncingFolder = SyncingFolder.ReplaceUnderscoreWithSpace (); + ProgressBarPercentage = 1.0; + + ChangePageEvent (PageType.Syncing, null); + + address = Uri.EscapeUriString (address.Trim ()); + remote_path = remote_path.Trim (); + remote_path = remote_path.TrimEnd ("/".ToCharArray ()); + + if (SelectedPlugin.PathUsesLowerCase) + remote_path = remote_path.ToLower (); + + PreviousAddress = address; + PreviousPath = remote_path; + + Program.Controller.FolderFetched += AddPageFetchedDelegate; + Program.Controller.FolderFetchError += AddPageFetchErrorDelegate; + Program.Controller.FolderFetching += SyncingPageFetchingDelegate; + + SparkleFetcherInfo info = new SparkleFetcherInfo { + Address = address, + Fingerprint = SelectedPlugin.Fingerprint, + RemotePath = remote_path, + FetchPriorHistory = this.fetch_prior_history, + AnnouncementsUrl = SelectedPlugin.AnnouncementsUrl, + Backend = SelectedPlugin.Backend + }; + + new Thread (() => { Program.Controller.StartFetcher (info); }).Start (); + } + + // The following private methods are + // delegates used by the previous method + + private void AddPageFetchedDelegate (string remote_url, string [] warnings) + { + SyncingFolder = ""; + + // Create a local plugin for succesfully added projects, so + // so the user can easily use the same host again + if (SelectedPluginIndex == 0) { + SparklePlugin new_plugin; + Uri uri = new Uri (remote_url); + + try { + string address = remote_url.Replace (uri.AbsolutePath, ""); + new_plugin = SparklePlugin.Create (uri.Host, address, address, "", "", "/path/to/project"); + + if (new_plugin != null) { + Plugins.Insert (1, new_plugin); + SparkleLogger.LogInfo ("Controller", "Added plugin for " + uri.Host); + } + + } catch { + SparkleLogger.LogInfo ("Controller", "Failed adding plugin for " + uri.Host); + } + } + + ChangePageEvent (PageType.Finished, warnings); + + Program.Controller.FolderFetched -= AddPageFetchedDelegate; + Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate; + Program.Controller.FolderFetching -= SyncingPageFetchingDelegate; + } + + private void AddPageFetchErrorDelegate (string remote_url, string [] errors) + { + SyncingFolder = ""; + PreviousUrl = remote_url; + + ChangePageEvent (PageType.Error, errors); + + Program.Controller.FolderFetched -= AddPageFetchedDelegate; + Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate; + Program.Controller.FolderFetching -= SyncingPageFetchingDelegate; + } + + private void SyncingPageFetchingDelegate (double percentage, double speed) + { + ProgressBarPercentage = percentage; + + if (speed == 0.0) + UpdateProgressBarEvent (ProgressBarPercentage, ""); + else + UpdateProgressBarEvent (ProgressBarPercentage, "Fetching files… " + speed.ToSize () + "/s"); + } + + + public void InvitePageCompleted () + { + SyncingFolder = Path.GetFileName (PendingInvite.RemotePath); + + if (PendingInvite.RemotePath.EndsWith (".git")) + SyncingFolder = PendingInvite.RemotePath.Substring (0, PendingInvite.RemotePath.Length - 4); + + SyncingFolder = SyncingFolder.Replace ("-crypto", ""); + SyncingFolder = SyncingFolder.ReplaceUnderscoreWithSpace (); + PreviousAddress = PendingInvite.Address; + PreviousPath = PendingInvite.RemotePath; + + ChangePageEvent (PageType.Syncing, null); + + new Thread (() => { + if (!PendingInvite.Accept (Program.Controller.CurrentUser.PublicKey)) { + PreviousUrl = PendingInvite.Address + PendingInvite.RemotePath.TrimStart ("/".ToCharArray ()); + ChangePageEvent (PageType.Error, new string [] { "error: Failed to upload the public key" }); + return; + } + + Program.Controller.FolderFetched += InvitePageFetchedDelegate; + Program.Controller.FolderFetchError += InvitePageFetchErrorDelegate; + Program.Controller.FolderFetching += SyncingPageFetchingDelegate; + + SparkleFetcherInfo info = new SparkleFetcherInfo { + Address = PendingInvite.Address, + Fingerprint = PendingInvite.Fingerprint, + RemotePath = PendingInvite.RemotePath, + FetchPriorHistory = false, // TODO: checkbox on invite page + AnnouncementsUrl = PendingInvite.AnnouncementsUrl + }; + + Program.Controller.StartFetcher (info); + + }).Start (); + } + + // The following private methods are + // delegates used by the previous method + + private void InvitePageFetchedDelegate (string remote_url, string [] warnings) + { + SyncingFolder = ""; + PendingInvite = null; + + ChangePageEvent (PageType.Finished, warnings); + + Program.Controller.FolderFetched -= AddPageFetchedDelegate; + Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate; + Program.Controller.FolderFetching -= SyncingPageFetchingDelegate; + } + + private void InvitePageFetchErrorDelegate (string remote_url, string [] errors) + { + SyncingFolder = ""; + PreviousUrl = remote_url; + + ChangePageEvent (PageType.Error, errors); + + Program.Controller.FolderFetched -= AddPageFetchedDelegate; + Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate; + Program.Controller.FolderFetching -= SyncingPageFetchingDelegate; + } + + + public void SyncingCancelled () + { + Program.Controller.StopFetcher (); + + if (PendingInvite != null) + ChangePageEvent (PageType.Invite, null); + else + ChangePageEvent (PageType.Add, null); + } + + + public void ErrorPageCompleted () + { + if (PendingInvite != null) + ChangePageEvent (PageType.Invite, null); + else + ChangePageEvent (PageType.Add, null); + } + + + public void CheckCryptoSetupPage (string password) + { + new Thread (() => { + bool is_valid_password = (password.Length > 0 && !password.StartsWith (" ") && !password.EndsWith (" ")); + UpdateCryptoSetupContinueButtonEvent (is_valid_password); + }).Start (); + } + + + public void CheckCryptoPasswordPage (string password) + { + bool is_password_correct = Program.Controller.CheckPassword (password); + UpdateCryptoPasswordContinueButtonEvent (is_password_correct); + } + + + public void CryptoPageCancelled () + { + SyncingCancelled (); + } + + + public void CryptoSetupPageCompleted (string password) + { + CryptoPasswordPageCompleted (password); + } + + + public void CryptoPasswordPageCompleted (string password) + { + ProgressBarPercentage = 100.0; + ChangePageEvent (PageType.Syncing, null); + + new Thread (() => { + Thread.Sleep (1000); + Program.Controller.FinishFetcher (password); + + }).Start (); + } + + + public void CopyToClipboardClicked () + { + Program.Controller.CopyToClipboard (Program.Controller.CurrentUser.PublicKey); + } + + + public void ShowFilesClicked () + { + string folder_name = Path.GetFileName (PreviousPath); + folder_name = folder_name.ReplaceUnderscoreWithSpace (); + + if (PreviousPath.EndsWith ("-crypto")) + folder_name = folder_name.Replace ("-crypto", ""); + + if (PreviousPath.EndsWith ("-crypto.git")) + folder_name = folder_name.Replace ("-crypto.git", ""); + + Program.Controller.OpenSparkleShareFolder (folder_name); + FinishPageCompleted (); + } + + + public void FinishPageCompleted () + { + SelectedPlugin = Plugins [0]; + PreviousUrl = ""; + PreviousAddress = ""; + PreviousPath = ""; + + this.fetch_prior_history = false; + this.saved_address = ""; + this.saved_remote_path = ""; + this.current_page = PageType.None; + + WindowIsOpen = false; + HideWindowEvent (); + } + + + private bool IsValidEmail (string email) + { + return new Regex (@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+$", RegexOptions.IgnoreCase).IsMatch (email); + } + } +} diff --git a/SparkleShare/SparkleStatusIconController.cs b/SparkleShare/SparkleStatusIconController.cs new file mode 100755 index 0000000..486104f --- /dev/null +++ b/SparkleShare/SparkleStatusIconController.cs @@ -0,0 +1,408 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.Threading; +using Timers = System.Timers; + +using SparkleLib; + +namespace SparkleShare { + + public enum IconState { + Idle, + SyncingUp, + SyncingDown, + Syncing, + Error + } + + + public class ProjectInfo { + + private SparkleRepoBase repo; + + public string Name { get { return this.repo.Name; }} + public string Path { get { return this.repo.LocalPath; }} + + public bool IsPaused { get { return this.repo.Status == SyncStatus.Paused; }} + public bool HasError { get { return this.repo.Status == SyncStatus.Error; }} + + + public string StatusMessage { + get { + string status_message = "Waiting to sync"; + + if (!this.repo.LastSync.Equals (DateTime.MinValue)) + status_message = string.Format ("Synced {0}", this.repo.LastSync.ToPrettyDate ()); + + if (this.repo.Status == SyncStatus.SyncUp) + status_message = "Sending changes… " + this.repo.ProgressPercentage + "%"; + + if (this.repo.Status == SyncStatus.SyncDown) + status_message = "Receiving changes… " + this.repo.ProgressPercentage + "%"; + + if (this.repo.Status == SyncStatus.SyncUp || this.repo.Status == SyncStatus.SyncDown) { + if (this.repo.ProgressSpeed > 0) + status_message += " " + this.repo.ProgressSpeed.ToSize () + "/s"; + } + + if (IsPaused) { + return "Paused"; + + } else if (HasError) { + switch (this.repo.Error) { + case ErrorStatus.HostUnreachable: return "Can’t reach the host"; + case ErrorStatus.HostIdentityChanged: return "The host’s identity has changed"; + case ErrorStatus.AuthenticationFailed: return "Authentication failed"; + case ErrorStatus.DiskSpaceExceeded: return "Host is out of disk space"; + case ErrorStatus.UnreadableFiles: return "Some local files are unreadable or in use"; + case ErrorStatus.NotFound: return "Project doesn’t exist on host"; + case ErrorStatus.IncompatibleClientServer: return "Incompatible client/server versions"; + } + } + + return status_message; + } + } + + + public string MoreUnsyncedChanges = ""; + + public Dictionary UnsyncedChangesInfo { + get { + Dictionary changes_info = new Dictionary (); + + int changes_count = 0; + foreach (SparkleChange change in repo.UnsyncedChanges) { + changes_count++; + + if (changes_count > 10) + continue; + + switch (change.Type) { + case SparkleChangeType.Added: changes_info [change.Path] = "document-added-12.png"; break; + case SparkleChangeType.Edited: changes_info [change.Path] = "document-edited-12.png"; break; + case SparkleChangeType.Deleted: changes_info [change.Path] = "document-deleted-12.png"; break; + case SparkleChangeType.Moved: changes_info [change.MovedToPath] = "document-moved-12.png"; break; + } + } + + if (changes_count > 10) + MoreUnsyncedChanges = string.Format ("and {0} more", changes_count - 10); + + return changes_info; + } + } + + + public ProjectInfo (SparkleRepoBase repo) + { + this.repo = repo; + } + } + + + public class SparkleStatusIconController { + + public event UpdateIconEventHandler UpdateIconEvent = delegate { }; + public delegate void UpdateIconEventHandler (IconState state); + + public event UpdateMenuEventHandler UpdateMenuEvent = delegate { }; + public delegate void UpdateMenuEventHandler (IconState state); + + public event UpdateStatusItemEventHandler UpdateStatusItemEvent = delegate { }; + public delegate void UpdateStatusItemEventHandler (string state_text); + + public event UpdateQuitItemEventHandler UpdateQuitItemEvent = delegate { }; + public delegate void UpdateQuitItemEventHandler (bool quit_item_enabled); + + public IconState CurrentState = IconState.Idle; + public string StateText = "Welcome to SparkleShare!"; + + public ProjectInfo [] Projects = new ProjectInfo [0]; + + + public int ProgressPercentage { + get { + return (int) Program.Controller.ProgressPercentage; + } + } + + public string ProgressSpeed { + get { + string progress_speed = ""; + + if (Program.Controller.ProgressSpeedDown == 0 && Program.Controller.ProgressSpeedUp > 0) { + progress_speed = Program.Controller.ProgressSpeedUp.ToSize () + "/s "; + + } else if (Program.Controller.ProgressSpeedUp == 0 && Program.Controller.ProgressSpeedDown > 0) { + progress_speed = Program.Controller.ProgressSpeedDown.ToSize () + "/s "; + + } else if (Program.Controller.ProgressSpeedUp > 0 && + Program.Controller.ProgressSpeedDown > 0) { + + progress_speed = "Up: " + Program.Controller.ProgressSpeedUp.ToSize () + "/s " + + "Down: " + Program.Controller.ProgressSpeedDown.ToSize () + "/s"; + } + + return progress_speed; + } + } + + public bool RecentEventsItemEnabled { + get { + return (Program.Controller.Repositories.Length > 0); + } + } + + public bool LinkCodeItemEnabled { + get { + return !string.IsNullOrEmpty (Program.Controller.CurrentUser.PublicKey); + } + } + + public bool QuitItemEnabled { + get { + return (CurrentState == IconState.Idle || CurrentState == IconState.Error); + } + } + + + public SparkleStatusIconController () + { + UpdateFolders (); + + Program.Controller.FolderListChanged += delegate { + if (CurrentState != IconState.Error) { + CurrentState = IconState.Idle; + + UpdateStateText (); + } + + UpdateFolders (); + + UpdateStatusItemEvent (StateText); + UpdateMenuEvent (CurrentState); + }; + + Program.Controller.OnIdle += delegate { + if (CurrentState != IconState.Error) { + CurrentState = IconState.Idle; + + UpdateStateText (); + } + + UpdateFolders (); + + UpdateIconEvent (CurrentState); + UpdateStatusItemEvent (StateText); + UpdateQuitItemEvent (QuitItemEnabled); + UpdateMenuEvent (CurrentState); + }; + + Program.Controller.OnSyncing += delegate { + int repos_syncing_up = 0; + int repos_syncing_down = 0; + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + if (repo.Status == SyncStatus.SyncUp) + repos_syncing_up++; + + if (repo.Status == SyncStatus.SyncDown) + repos_syncing_down++; + } + + if (repos_syncing_up > 0 && + repos_syncing_down > 0) { + + CurrentState = IconState.Syncing; + StateText = "Syncing changes…"; + + } else if (repos_syncing_down == 0) { + CurrentState = IconState.SyncingUp; + StateText = "Sending changes…"; + + } else { + CurrentState = IconState.SyncingDown; + StateText = "Receiving changes…"; + } + + if (ProgressPercentage > 0) + StateText += " " + ProgressPercentage + "% " + ProgressSpeed; + + UpdateIconEvent (CurrentState); + UpdateStatusItemEvent (StateText); + UpdateQuitItemEvent (QuitItemEnabled); + }; + + Program.Controller.OnError += delegate { + CurrentState = IconState.Error; + StateText = "Some changes weren’t synced"; + + UpdateFolders (); + + UpdateIconEvent (CurrentState); + UpdateStatusItemEvent (StateText); + UpdateQuitItemEvent (QuitItemEnabled); + UpdateMenuEvent (CurrentState); + }; + + + // FIXME: Work around a race condition causing + // the icon to not always show the right state + Timers.Timer timer = new Timers.Timer () { Interval = 30 * 1000 }; + + timer.Elapsed += delegate { + UpdateIconEvent (CurrentState); + UpdateStatusItemEvent (StateText); + }; + + timer.Start (); + } + + + private string UpdateStateText () + { + if (Projects.Length == 0) + return StateText = "Welcome to SparkleShare!"; + else + return StateText = "Projects up to date " + GetPausedCount (); + } + + + private string GetPausedCount () + { + int paused_projects = 0; + + foreach (ProjectInfo project in Projects) + if (project.IsPaused) + paused_projects++; + + if (paused_projects > 0) + return string.Format ("— {0} paused", paused_projects); + else + return ""; + } + + + // Main menu items + public void RecentEventsClicked () + { + new Thread (() => { + while (!Program.Controller.RepositoriesLoaded) + Thread.Sleep (100); + + Program.Controller.ShowEventLogWindow (); + + }).Start (); + } + + public void AddHostedProjectClicked () + { + new Thread (() => Program.Controller.ShowSetupWindow (PageType.Add)).Start (); + } + + public void CopyToClipboardClicked () + { + Program.Controller.CopyToClipboard (Program.Controller.CurrentUser.PublicKey); + } + + public void AboutClicked () + { + Program.Controller.ShowAboutWindow (); + } + + public void QuitClicked () + { + Program.Controller.Quit (); + } + + + // Project items + public void ProjectClicked (string project) + { + Program.Controller.OpenSparkleShareFolder (project); + } + + public void PauseClicked (string project) + { + Program.Controller.GetRepoByName (project).Pause (); + UpdateStateText (); + UpdateMenuEvent (CurrentState); + } + + public void ResumeClicked (string project) + { + if (Program.Controller.GetRepoByName (project).UnsyncedChanges.Count > 0) { + Program.Controller.ShowNoteWindow (project); + + } else { + new Thread (() => { + Program.Controller.GetRepoByName (project).Resume (""); + + UpdateStateText (); + UpdateMenuEvent (CurrentState); + + }).Start (); + } + } + + public void TryAgainClicked (string project) + { + new Thread (() => Program.Controller.GetRepoByName (project).ForceRetry ()).Start (); + } + + + // Helper delegates + public EventHandler OpenFolderDelegate (string project) + { + return delegate { ProjectClicked (project); }; + } + + public EventHandler TryAgainDelegate (string project) + { + return delegate { TryAgainClicked (project); }; + } + + public EventHandler PauseDelegate (string project) + { + return delegate { PauseClicked (project); }; + } + + public EventHandler ResumeDelegate (string project) + { + return delegate { ResumeClicked (project); }; + } + + + private Object projects_lock = new Object (); + + private void UpdateFolders () + { + lock (this.projects_lock) { + List projects = new List (); + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) + projects.Add (new ProjectInfo (repo)); + + Projects = projects.ToArray (); + } + } + } +} diff --git a/SparkleShare/Windows/LICENSE.rtf b/SparkleShare/Windows/LICENSE.rtf new file mode 100644 index 0000000..f679cc6 --- /dev/null +++ b/SparkleShare/Windows/LICENSE.rtf @@ -0,0 +1,115 @@ +{\rtf1\ansi\ansicpg1252\deff0\deflang2077{\fonttbl{\f0\froman\fcharset0 Times New Roman;}{\f1\fnil\fcharset0 Calibri;}{\f2\fnil\fcharset2 Symbol;}} +{\colortbl ;\red0\green0\blue255;} +{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\keepn\sb100\sa100\lang1053\b\f0\fs28 GNU GENERAL PUBLIC LICENSE\par +\pard\sb100\sa100\b0\fs24 Version 3, 29 June 2007\par +Copyright \'a9 2007 Free Software Foundation, Inc. <{\field{\*\fldinst{HYPERLINK "http://fsf.org/"}}{\fldrslt{\ul\cf1 http://fsf.org/}}}\f0\fs24 >\par +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\par +\pard\keepn\sb100\sa100\b\fs28 Preamble\par +\pard\sb100\sa100\b0\fs24 The GNU General Public License is a free, copyleft license for software and other kinds of works.\par +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.\par +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.\par +To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.\par +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\par +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.\par +For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.\par +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.\par +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.\par +The precise terms and conditions for copying, distribution and modification follow.\par +\pard\keepn\sb100\sa100\b\fs28 TERMS AND CONDITIONS\par +\fs24 0. Definitions.\par +\pard\sb100\sa100\b0\ldblquote This License\rdblquote refers to version 3 of the GNU General Public License.\par +\ldblquote Copyright\rdblquote also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.\par +\ldblquote The Program\rdblquote refers to any copyrightable work licensed under this License. Each licensee is addressed as \ldblquote you\rdblquote . \ldblquote Licensees\rdblquote and \ldblquote recipients\rdblquote may be individuals or organizations.\par +To \ldblquote modify\rdblquote a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a \ldblquote modified version\rdblquote of the earlier work or a work \ldblquote based on\rdblquote the earlier work.\par +A \ldblquote covered work\rdblquote means either the unmodified Program or a work based on the Program.\par +To \ldblquote propagate\rdblquote a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.\par +To \ldblquote convey\rdblquote a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.\par +An interactive user interface displays \ldblquote Appropriate Legal Notices\rdblquote to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.\par +\pard\keepn\sb100\sa100\b 1. Source Code.\par +\pard\sb100\sa100\b0 The \ldblquote source code\rdblquote for a work means the preferred form of the work for making modifications to it. \ldblquote Object code\rdblquote means any non-source form of a work.\par +A \ldblquote Standard Interface\rdblquote means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.\par +The \ldblquote System Libraries\rdblquote of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A \ldblquote Major Component\rdblquote , in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.\par +The \ldblquote Corresponding Source\rdblquote for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.\par +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.\par +The Corresponding Source for a work in source code form is that same work.\par +\pard\keepn\sb100\sa100\b 2. Basic Permissions.\par +\pard\sb100\sa100\b0 All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.\par +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.\par +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.\par +\pard\keepn\sb100\sa100\b 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\par +\pard\sb100\sa100\b0 No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.\par +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.\par +\pard\keepn\sb100\sa100\b 4. Conveying Verbatim Copies.\par +\pard\sb100\sa100\b0 You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.\par +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.\par +\pard\keepn\sb100\sa100\b 5. Conveying Modified Source Versions.\par +\pard\sb100\sa100\b0 You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:\par +\pard{\pntext\f2\'B7\tab}{\*\pn\pnlvlblt\pnf2\pnindent360{\pntxtb\'B7}}\fi-360\li720\sb100\sa100 a) The work must carry prominent notices stating that you modified it, and giving a relevant date. \par +{\pntext\f2\'B7\tab}b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to \ldblquote keep intact all notices\rdblquote . \par +{\pntext\f2\'B7\tab}c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. \par +{\pntext\f2\'B7\tab}d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. \par +\pard\sb100\sa100 A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an \ldblquote aggregate\rdblquote if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.\par +\pard\keepn\sb100\sa100\b 6. Conveying Non-Source Forms.\par +\pard\sb100\sa100\b0 You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:\par +\pard{\pntext\f2\'B7\tab}{\*\pn\pnlvlblt\pnf2\pnindent360{\pntxtb\'B7}}\fi-360\li720\sb100\sa100 a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. \par +{\pntext\f2\'B7\tab}b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. \par +{\pntext\f2\'B7\tab}c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. \par +{\pntext\f2\'B7\tab}d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. \par +{\pntext\f2\'B7\tab}e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. \par +\pard\sb100\sa100 A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.\par +A \ldblquote User Product\rdblquote is either (1) a \ldblquote consumer product\rdblquote , which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, \ldblquote normally used\rdblquote refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.\par +\ldblquote Installation Information\rdblquote for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.\par +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).\par +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.\par +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.\par +\pard\keepn\sb100\sa100\b 7. Additional Terms.\par +\pard\sb100\sa100\b0\ldblquote Additional permissions\rdblquote are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.\par +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.\par +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:\par +\pard{\pntext\f2\'B7\tab}{\*\pn\pnlvlblt\pnf2\pnindent360{\pntxtb\'B7}}\fi-360\li720\sb100\sa100 a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or \par +{\pntext\f2\'B7\tab}b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or \par +{\pntext\f2\'B7\tab}c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or \par +{\pntext\f2\'B7\tab}d) Limiting the use for publicity purposes of names of licensors or authors of the material; or \par +{\pntext\f2\'B7\tab}e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or \par +{\pntext\f2\'B7\tab}f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. \par +\pard\sb100\sa100 All other non-permissive additional terms are considered \ldblquote further restrictions\rdblquote within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.\par +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.\par +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.\par +\pard\keepn\sb100\sa100\b 8. Termination.\par +\pard\sb100\sa100\b0 You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).\par +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.\par +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.\par +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.\par +\pard\keepn\sb100\sa100\b 9. Acceptance Not Required for Having Copies.\par +\pard\sb100\sa100\b0 You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.\par +\pard\keepn\sb100\sa100\b 10. Automatic Licensing of Downstream Recipients.\par +\pard\sb100\sa100\b0 Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.\par +An \ldblquote entity transaction\rdblquote is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.\par +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.\par +\pard\keepn\sb100\sa100\b 11. Patents.\par +\pard\sb100\sa100\b0 A \ldblquote contributor\rdblquote is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's \ldblquote contributor version\rdblquote .\par +A contributor's \ldblquote essential patent claims\rdblquote are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, \ldblquote control\rdblquote includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.\par +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.\par +In the following three paragraphs, a \ldblquote patent license\rdblquote is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To \ldblquote grant\rdblquote such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.\par +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. \ldblquote Knowingly relying\rdblquote means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.\par +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.\par +A patent license is \ldblquote discriminatory\rdblquote if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.\par +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.\par +\pard\keepn\sb100\sa100\b 12. No Surrender of Others' Freedom.\par +\pard\sb100\sa100\b0 If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.\par +\pard\keepn\sb100\sa100\b 13. Use with the GNU Affero General Public License.\par +\pard\sb100\sa100\b0 Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.\par +\pard\keepn\sb100\sa100\b 14. Revised Versions of this License.\par +\pard\sb100\sa100\b0 The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\par +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License \ldblquote or any later version\rdblquote applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.\par +If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.\par +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.\par +\pard\keepn\sb100\sa100\b 15. Disclaimer of Warranty.\par +\pard\sb100\sa100\b0 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \ldblquote AS IS\rdblquote WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\par +\pard\keepn\sb100\sa100\b 16. Limitation of Liability.\par +\pard\sb100\sa100\b0 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\par +\pard\keepn\sb100\sa100\b 17. Interpretation of Sections 15 and 16.\par +\pard\sb100\sa100\b0 If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.\par +END OF TERMS AND CONDITIONS\lang29\f1\fs22\par +} + \ No newline at end of file diff --git a/SparkleShare/Windows/Pixmaps/folder.png b/SparkleShare/Windows/Pixmaps/folder.png new file mode 100644 index 0000000..46fa475 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/folder.png differ diff --git a/SparkleShare/Windows/Pixmaps/process-syncing-down.png b/SparkleShare/Windows/Pixmaps/process-syncing-down.png new file mode 100644 index 0000000..f5bd436 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/process-syncing-down.png differ diff --git a/SparkleShare/Windows/Pixmaps/process-syncing-error.png b/SparkleShare/Windows/Pixmaps/process-syncing-error.png new file mode 100644 index 0000000..ee81060 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/process-syncing-error.png differ diff --git a/SparkleShare/Windows/Pixmaps/process-syncing-idle.png b/SparkleShare/Windows/Pixmaps/process-syncing-idle.png new file mode 100644 index 0000000..7856e12 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/process-syncing-idle.png differ diff --git a/SparkleShare/Windows/Pixmaps/process-syncing-up.png b/SparkleShare/Windows/Pixmaps/process-syncing-up.png new file mode 100644 index 0000000..56b8f23 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/process-syncing-up.png differ diff --git a/SparkleShare/Windows/Pixmaps/process-syncing.png b/SparkleShare/Windows/Pixmaps/process-syncing.png new file mode 100644 index 0000000..9f9df04 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/process-syncing.png differ diff --git a/SparkleShare/Windows/Pixmaps/sparkleshare-app.ico b/SparkleShare/Windows/Pixmaps/sparkleshare-app.ico new file mode 100644 index 0000000..73917b1 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/sparkleshare-app.ico differ diff --git a/SparkleShare/Windows/Pixmaps/sparkleshare-folder.ico b/SparkleShare/Windows/Pixmaps/sparkleshare-folder.ico new file mode 100644 index 0000000..e00ebf4 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/sparkleshare-folder.ico differ diff --git a/SparkleShare/Windows/Pixmaps/sparkleshare-folder.png b/SparkleShare/Windows/Pixmaps/sparkleshare-folder.png new file mode 100644 index 0000000..f44e363 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/sparkleshare-folder.png differ diff --git a/SparkleShare/Windows/Pixmaps/tutorial-slide-3.png b/SparkleShare/Windows/Pixmaps/tutorial-slide-3.png new file mode 100644 index 0000000..be651b0 Binary files /dev/null and b/SparkleShare/Windows/Pixmaps/tutorial-slide-3.png differ diff --git a/SparkleShare/Windows/README.md b/SparkleShare/Windows/README.md new file mode 100644 index 0000000..17ff4a6 --- /dev/null +++ b/SparkleShare/Windows/README.md @@ -0,0 +1,43 @@ +## Windows +You can choose to build SparkleShare from source or to run the Windows installer. + + +### Installing build requirements + +Install version 4.0 of the [.NET Framework](http://www.microsoft.com/download/en/details.aspx?id=17851) if you haven't already. + +Install [msysGit](http://msysgit.github.io/) and copy the contents of the install folder +(`C:\Program Files (x86)\Git` by default) to `C:\path\to\SparkleShare-sources\bin\msysgit\` (create the "bin"-folder in the SparkleShare source directory). + +Open a command prompt and execute the following: + +``` +cd C:\path\to\SparkleShare-sources +cd SparkleShare\Windows +build +``` + +`C:\path\to\SparkleShare-sources\bin` should now contain `SparkleShare.exe`, which you can run. + + +### Creating a Windows installer + +To create an installer package, install [WiX 3.7](http://wix.codeplex.com/releases/view/99514), restart Windows and run: + +``` +cd C:\path\to\SparkleShare-sources\SparkleShare\Windows\ +build installer +``` + +This will create `SparkleShare.msi` in the same directory. + + +### Resetting SparkleShare settings + +Remove `My Documents\SparkleShare` and `AppData\Roaming\sparkleshare` (`AppData` is hidden by default). + + +### Uninstalling + +You can uninstall SparkleShare through the Windows Control Panel. + diff --git a/SparkleShare/Windows/Settings.StyleCop b/SparkleShare/Windows/Settings.StyleCop new file mode 100644 index 0000000..bf20b44 --- /dev/null +++ b/SparkleShare/Windows/Settings.StyleCop @@ -0,0 +1,379 @@ + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + \ No newline at end of file diff --git a/SparkleShare/Windows/SparkleAbout.cs b/SparkleShare/Windows/SparkleAbout.cs new file mode 100644 index 0000000..1e19fc9 --- /dev/null +++ b/SparkleShare/Windows/SparkleAbout.cs @@ -0,0 +1,186 @@ +// 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.ComponentModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Input; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Xaml; + +namespace SparkleShare { + + public class SparkleAbout : Window { + + public SparkleAboutController Controller = new SparkleAboutController (); + + private Label updates; + + + public SparkleAbout () + { + Title = "About SparkleShare"; + ResizeMode = ResizeMode.NoResize; + Height = 288; + Width = 720; + Icon = SparkleUIHelpers.GetImageSource("sparkleshare-app", "ico"); + + WindowStartupLocation = WindowStartupLocation.CenterScreen; + Closing += Close; + + CreateAbout (); + + Controller.ShowWindowEvent += delegate { + Dispatcher.BeginInvoke ((Action) delegate { + Show (); + Activate (); + BringIntoView (); + }); + }; + + Controller.HideWindowEvent += delegate { + Dispatcher.BeginInvoke ((Action) delegate { + Hide (); + }); + }; + + Controller.UpdateLabelEvent += delegate (string text) { + Dispatcher.BeginInvoke ((Action) delegate { + this.updates.Content = text; + this.updates.UpdateLayout (); + }); + }; + } + + + private void CreateAbout () + { + Image image = new Image () { + Width = 720, + Height = 260 + }; + + image.Source = SparkleUIHelpers.GetImageSource ("about"); + + + Label version = new Label () { + Content = "version " + Controller.RunningVersion, + FontSize = 11, + Foreground = new SolidColorBrush (Colors.White) + }; + + this.updates = new Label () { + Content = "Checking for updates...", + FontSize = 11, + Foreground = new SolidColorBrush (Color.FromArgb (128, 255, 255, 255)) + }; + + TextBlock credits = new TextBlock () { + FontSize = 11, + Foreground = new SolidColorBrush (Colors.White), + Text = "Copyright © 2010–" + DateTime.Now.Year + " Hylke Bons and others.\n" + + "\n" + + "SparkleShare is Open Source software. You are free to use, modify, " + + "and redistribute it under the GNU General Public License version 3 or later.", + TextWrapping = TextWrapping.Wrap, + Width = 318 + }; + + SparkleLink website_link = new SparkleLink ("Website", Controller.WebsiteLinkAddress); + SparkleLink credits_link = new SparkleLink ("Credits", Controller.CreditsLinkAddress); + SparkleLink report_problem_link = new SparkleLink ("Report a problem", Controller.ReportProblemLinkAddress); + SparkleLink debug_log_link = new SparkleLink ("Debug log", Controller.DebugLogLinkAddress); + + Canvas canvas = new Canvas (); + + canvas.Children.Add (image); + Canvas.SetLeft (image, 0); + Canvas.SetTop (image, 0); + + canvas.Children.Add (version); + Canvas.SetLeft (version, 289); + Canvas.SetTop (version, 92); + + canvas.Children.Add (this.updates); + Canvas.SetLeft (this.updates, 289); + Canvas.SetTop (this.updates, 109); + + canvas.Children.Add (credits); + Canvas.SetLeft (credits, 294); + Canvas.SetTop (credits, 142); + + canvas.Children.Add (website_link); + Canvas.SetLeft (website_link, 289); + Canvas.SetTop (website_link, 222); + + canvas.Children.Add (credits_link); + Canvas.SetLeft (credits_link, 289 + website_link.ActualWidth + 60); + Canvas.SetTop (credits_link, 222); + + canvas.Children.Add (report_problem_link); + Canvas.SetLeft (report_problem_link, 289 + website_link.ActualWidth + credits_link.ActualWidth + 115); + Canvas.SetTop (report_problem_link, 222); + + canvas.Children.Add (debug_log_link); + Canvas.SetLeft (debug_log_link, 289 + website_link.ActualWidth + credits_link.ActualWidth + + report_problem_link.ActualWidth + 220); + Canvas.SetTop (debug_log_link, 222); + + Content = canvas; + } + + + private void Close (object sender, CancelEventArgs args) + { + Controller.WindowClosed (); + args.Cancel = true; + } + } + + + public class SparkleLink : Label { + + public SparkleLink (string title, string url) + { + FontSize = 11; + Cursor = Cursors.Hand; + Foreground = new SolidColorBrush (Color.FromRgb (135, 178, 227)); + + TextDecoration underline = new TextDecoration () { + Pen = new Pen (new SolidColorBrush (Color.FromRgb (135, 178, 227)), 1), + PenThicknessUnit = TextDecorationUnit.FontRecommended + }; + + TextDecorationCollection collection = new TextDecorationCollection (); + collection.Add (underline); + + TextBlock text_block = new TextBlock () { + Text = title, + TextDecorations = collection + }; + + Content = text_block; + + MouseUp += delegate { + Program.Controller.OpenWebsite (url); + }; + } + } +} diff --git a/SparkleShare/Windows/SparkleBubbles.cs b/SparkleShare/Windows/SparkleBubbles.cs new file mode 100644 index 0000000..cbae16d --- /dev/null +++ b/SparkleShare/Windows/SparkleBubbles.cs @@ -0,0 +1,37 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; + +namespace SparkleShare { + + public class SparkleBubbles { + + public SparkleBubblesController Controller = new SparkleBubblesController (); + + + public SparkleBubbles () + { + Controller.ShowBubbleEvent += delegate (string title, string subtext, string image_path) { + if (!Program.Controller.NotificationsEnabled) + return; + + Program.UI.StatusIcon.ShowBalloon (title, subtext, image_path); + }; + } + } +} diff --git a/SparkleShare/Windows/SparkleController.cs b/SparkleShare/Windows/SparkleController.cs new file mode 100644 index 0000000..ed9a65f --- /dev/null +++ b/SparkleShare/Windows/SparkleController.cs @@ -0,0 +1,270 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using Forms = System.Windows.Forms; + +using Microsoft.Win32; +using SparkleLib; +using System.Windows; + + +namespace SparkleShare { + + public class SparkleController : SparkleControllerBase { + + private int ssh_agent_pid; + + + public SparkleController () : base () + { + } + + + public override string PluginsPath + { + get { + return Path.Combine (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location), "plugins"); + } + } + + + public override void Initialize () + { + // Add msysgit to path, as we cannot asume it is added to the path + // Asume it is installed in @"\msysgit\bin" + string executable_path = Path.GetDirectoryName (Forms.Application.ExecutablePath); + string msysgit_path = Path.Combine (executable_path, "msysgit"); + + + string new_PATH = msysgit_path + @"\bin" + ";" + + msysgit_path + @"\mingw\bin" + ";" + + msysgit_path + @"\cmd" + ";" + + Environment.ExpandEnvironmentVariables ("%PATH%"); + + Environment.SetEnvironmentVariable ("PATH", new_PATH); + Environment.SetEnvironmentVariable ("HOME", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)); + + StartSSH (); + SparkleLib.Git.SparkleGit.SSHPath = Path.Combine (msysgit_path, "bin", "ssh.exe"); + + base.Initialize (); + } + + + public override string EventLogHTML { + get { + string html = SparkleUIHelpers.GetHTML ("event-log.html"); + return html.Replace ("", SparkleUIHelpers.GetHTML ("jquery.js")); + } + } + + + public override string DayEntryHTML { + get { + return SparkleUIHelpers.GetHTML ("day-entry.html"); + } + } + + + public override string EventEntryHTML { + get { + return SparkleUIHelpers.GetHTML ("event-entry.html"); + } + } + + + public override void CreateStartupItem () + { + string startup_folder_path = Environment.GetFolderPath (Environment.SpecialFolder.Startup); + string shortcut_path = Path.Combine (startup_folder_path, "SparkleShare.lnk"); + + if (File.Exists (shortcut_path)) + File.Delete (shortcut_path); + + string shortcut_target = Forms.Application.ExecutablePath; + + Shortcut shortcut = new Shortcut (); + shortcut.Create (shortcut_path, shortcut_target); + } + + + public override void InstallProtocolHandler () + { + // We ship a separate .exe for this + } + + + public override void AddToBookmarks () + { + string user_profile_path = Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); + string shortcut_path = Path.Combine (user_profile_path, "Links", "SparkleShare.lnk"); + + if (File.Exists (shortcut_path)) + File.Delete (shortcut_path); + + Shortcut shortcut = new Shortcut (); + shortcut.Create (FoldersPath, shortcut_path); + } + + + public override bool CreateSparkleShareFolder () + { + if (Directory.Exists (FoldersPath)) + return false; + + Directory.CreateDirectory (FoldersPath); + + File.SetAttributes (FoldersPath, File.GetAttributes (FoldersPath) | FileAttributes.System); + SparkleLogger.LogInfo ("Config", "Created '" + FoldersPath + "'"); + + string app_path = Path.GetDirectoryName (Forms.Application.ExecutablePath); + string icon_file_path = Path.Combine (app_path, "Pixmaps", "sparkleshare-folder.ico"); + + if (!File.Exists (icon_file_path)) { + string ini_file_path = Path.Combine (FoldersPath, "desktop.ini"); + string n = Environment.NewLine; + + string ini_file = "[.ShellClassInfo]" + n + + "IconFile=" + icon_file_path + n + + "IconIndex=0" + n + + "InfoTip=SparkleShare"; + + try { + File.Create (ini_file_path).Close (); + File.WriteAllText (ini_file_path, ini_file); + + File.SetAttributes (ini_file_path, + File.GetAttributes (ini_file_path) | FileAttributes.Hidden | FileAttributes.System); + + } catch (IOException e) { + SparkleLogger.LogInfo ("Config", "Failed setting icon for '" + FoldersPath + "': " + e.Message); + } + + return true; + } + + return false; + } + + + public override void OpenFile (string path) + { + Process.Start (path); + } + + + public override void OpenFolder (string path) + { + Process.Start (path); + } + + + public override void OpenWebsite (string url) + { + Process.Start (new ProcessStartInfo (url)); + } + + + public override void CopyToClipboard (string text) + { + try { + Clipboard.SetData (DataFormats.Text, text); + + } catch (COMException e) { + SparkleLogger.LogInfo ("Controller", "Copy to clipboard failed", e); + } + } + + + public override void Quit () + { + StopSSH (); + base.Quit (); + } + + + private void StartSSH () + { + string auth_agent_pid = Environment.GetEnvironmentVariable ("SSH_AGENT_PID"); + + if (!string.IsNullOrEmpty (auth_agent_pid)) { + SparkleLogger.LogInfo ("Controller", "Trying to use existing ssh-agent with PID=" + auth_agent_pid + "..."); + this.ssh_agent_pid = Convert.ToInt32 (auth_agent_pid); + + try { + Process ssh_agent = Process.GetProcessById (this.ssh_agent_pid); + SparkleLogger.LogInfo ("Controller", "Using existing ssh-agent with PID=" + this.ssh_agent_pid); + + return; + + } catch (ArgumentException) { + SparkleLogger.LogInfo ("Controller", "ssh-agent with PID=" + auth_agent_pid + " does not exist. Starting a new one..."); + } + } + + Process process = new Process (); + process.StartInfo.FileName = "ssh-agent"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.CreateNoWindow = true; + + process.Start (); + + string output = process.StandardOutput.ReadToEnd (); + process.WaitForExit (); + + Match auth_sock_match = new Regex (@"SSH_AUTH_SOCK=([^;\n\r]*)").Match (output); + Match ssh_pid_match = new Regex (@"SSH_AGENT_PID=([^;\n\r]*)").Match (output); + + if (auth_sock_match.Success) + Environment.SetEnvironmentVariable ("SSH_AUTH_SOCK", auth_sock_match.Groups [1].Value); + + if (ssh_pid_match.Success) { + Int32.TryParse (ssh_pid_match.Groups [1].Value, out this.ssh_agent_pid); + Environment.SetEnvironmentVariable ("SSH_AGENT_PID", "" + this.ssh_agent_pid); + + SparkleLogger.LogInfo ("Controller", "ssh-agent started, PID=" + this.ssh_agent_pid); + + } else { + SparkleLogger.LogInfo ("Controller", "Could not start ssh-agent:" + output); + } + } + + + private void StopSSH () + { + if (this.ssh_agent_pid == 0) + return; + + try { + Process.GetProcessById (this.ssh_agent_pid).Kill (); + + } catch (ArgumentException e) { + SparkleLogger.LogInfo ("SSH", "Could not stop ssh-agent: " + e.Message); + } + } + } +} diff --git a/SparkleShare/Windows/SparkleEventLog.cs b/SparkleShare/Windows/SparkleEventLog.cs new file mode 100644 index 0000000..7938d77 --- /dev/null +++ b/SparkleShare/Windows/SparkleEventLog.cs @@ -0,0 +1,372 @@ +// 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.ComponentModel; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +using Microsoft.Win32; +using Shapes = System.Windows.Shapes; + +using SparkleLib; + +namespace SparkleShare { + + public class SparkleEventLog : Window { + + public SparkleEventLogController Controller = new SparkleEventLogController (); + + private Canvas canvas; + private Label size_label_value; + private Label history_label_value; + private ComboBox combo_box; + private WebBrowser web_browser; + private SparkleSpinner spinner; + + + public SparkleEventLog () + { + Title = "Recent Changes"; + Height = 640; + Width = 480; + ResizeMode = ResizeMode.NoResize; // TODO + Background = new SolidColorBrush (Color.FromRgb (240, 240, 240)); + AllowsTransparency = false; + Icon = SparkleUIHelpers.GetImageSource ("sparkleshare-app", "ico"); + + int x = (int) (SystemParameters.PrimaryScreenWidth * 0.61); + int y = (int) (SystemParameters.PrimaryScreenHeight * 0.5 - (Height * 0.5)); + + WindowStartupLocation = WindowStartupLocation.Manual; + Left = x; + Top = y; + + WriteOutImages (); + + Label size_label = new Label () { + Content = "Size:", + FontWeight = FontWeights.Bold + }; + + this.size_label_value = new Label () { + Content = Controller.Size + }; + + size_label.Measure (new Size (Double.PositiveInfinity, Double.PositiveInfinity)); + Rect size_label_rect = new Rect (size_label.DesiredSize); + + Label history_label = new Label () { + Content = "History:", + FontWeight = FontWeights.Bold + }; + + this.history_label_value = new Label () { + Content = Controller.HistorySize, + }; + + history_label.Measure (new Size (Double.PositiveInfinity, Double.PositiveInfinity)); + Rect history_label_rect = new Rect (history_label.DesiredSize); + + Shapes.Rectangle line = new Shapes.Rectangle () { + Width = Width, + Height = 1, + Fill = new SolidColorBrush (Color.FromRgb (223, 223, 223)) + }; + + Shapes.Rectangle background = new Shapes.Rectangle () { + Width = Width, + Height = Height, + Fill = new SolidColorBrush (Color.FromRgb (250, 250, 250)) + }; + + this.web_browser = new WebBrowser () { + Width = Width - 6, + Height = Height - 64 + }; + + this.web_browser.ObjectForScripting = new SparkleScriptingObject (); + + + spinner = new SparkleSpinner (22); + + // Disable annoying IE clicking sound + CoInternetSetFeatureEnabled (21, 0x00000002, true); + + + this.canvas = new Canvas (); + Content = this.canvas; + + this.canvas.Children.Add (size_label); + Canvas.SetLeft (size_label, 24); + Canvas.SetTop (size_label, 4); + + this.canvas.Children.Add (this.size_label_value); + Canvas.SetLeft (this.size_label_value, 22 + size_label_rect.Width); + Canvas.SetTop (this.size_label_value, 4); + + this.canvas.Children.Add (history_label); + Canvas.SetLeft (history_label, 130); + Canvas.SetTop (history_label, 4); + + this.canvas.Children.Add (this.history_label_value); + Canvas.SetLeft (this.history_label_value, 130 + history_label_rect.Width); + Canvas.SetTop (this.history_label_value, 4); + + this.canvas.Children.Add (background); + Canvas.SetLeft (background, 0); + Canvas.SetTop (background, 36); + + this.canvas.Children.Add (spinner); + Canvas.SetLeft (spinner, (Width / 2) - 15); + Canvas.SetTop (spinner, (Height / 2) - 22); + + this.canvas.Children.Add (line); + Canvas.SetLeft (line, 0); + Canvas.SetTop (line, 35); + + + Closing += Close; + + Controller.ShowWindowEvent += delegate { + Dispatcher.BeginInvoke ((Action) delegate { + Show (); + Activate (); + BringIntoView (); + }); + }; + + Controller.HideWindowEvent += delegate { + Dispatcher.BeginInvoke ((Action) delegate { + Hide (); + + if (this.canvas.Children.Contains (this.web_browser)) + this.canvas.Children.Remove (this.web_browser); + }); + }; + + Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) { + Dispatcher.BeginInvoke ((Action) delegate { + this.size_label_value.Content = size; + this.size_label_value.UpdateLayout (); + + this.history_label_value.Content = history_size; + this.history_label_value.UpdateLayout (); + }); + }; + + Controller.UpdateChooserEvent += delegate (string [] folders) { + Dispatcher.BeginInvoke ((Action) delegate { + UpdateChooser (folders); + }); + }; + + Controller.UpdateChooserEnablementEvent += delegate (bool enabled) { + Dispatcher.BeginInvoke ((Action) delegate { + this.combo_box.IsEnabled = enabled; + }); + }; + + Controller.UpdateContentEvent += delegate (string html) { + Dispatcher.BeginInvoke ((Action) delegate { + UpdateContent (html); + }); + }; + + Controller.ContentLoadingEvent += delegate { + Dispatcher.BeginInvoke ((Action) delegate { + this.spinner.Start (); + + if (this.canvas.Children.Contains (this.web_browser)) + this.canvas.Children.Remove (this.web_browser); + }); + }; + + Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) { + Dispatcher.BeginInvoke ((Action) delegate { + SaveFileDialog dialog = new SaveFileDialog () { + FileName = file_name, + InitialDirectory = target_folder_path, + Title = "Restore from History", + DefaultExt = "." + Path.GetExtension (file_name), + Filter = "All Files|*.*" + }; + + Nullable result = dialog.ShowDialog (this); + + if (result == true) + Controller.SaveDialogCompleted (dialog.FileName); + else + Controller.SaveDialogCancelled (); + }); + }; + } + + + public void UpdateChooser (string [] folders) + { + if (folders == null) + folders = Controller.Folders; + + if (this.combo_box != null) + this.canvas.Children.Remove (this.combo_box); + + this.combo_box = new ComboBox () { + Width = 160 + }; + + ComboBoxItem item = new ComboBoxItem () { + Content = "Summary" + }; + + this.combo_box.Items.Add (item); + this.combo_box.Items.Add (new Separator ()); + + this.combo_box.SelectedItem = combo_box.Items [0]; + + int row = 2; + foreach (string folder in folders) { + this.combo_box.Items.Add ( + new ComboBoxItem () { Content = folder } + ); + + if (folder.Equals (Controller.SelectedFolder)) + this.combo_box.SelectedItem = combo_box.Items [row]; + + row++; + } + + this.combo_box.SelectionChanged += delegate { + Dispatcher.BeginInvoke ((Action) delegate { + int index = this.combo_box.SelectedIndex; + + if (index == 0) + Controller.SelectedFolder = null; + else + Controller.SelectedFolder = (string) + (this.combo_box.Items [index] as ComboBoxItem).Content; + }); + }; + + this.canvas.Children.Add (combo_box); + Canvas.SetLeft (this.combo_box, Width - 24 - this.combo_box.Width); + Canvas.SetTop (this.combo_box, 6); + } + + + public void UpdateContent (string html) + { + string pixmaps_path = Path.Combine (SparkleLib.SparkleConfig.DefaultConfig.TmpPath, "Pixmaps".SHA1 ()); + pixmaps_path = pixmaps_path.Replace ("\\", "/"); + + html = html.Replace ("", "'Segoe UI', sans-serif"); + html = html.Replace ("", "13px"); + html = html.Replace ("", "12px"); + html = html.Replace ("", "#bbb"); + html = html.Replace ("", "#ddd"); + html = html.Replace ("", "90%"); + html = html.Replace ("", "#f5f5f5"); + html = html.Replace ("", "#0085cf"); + html = html.Replace ("", "#009ff8"); + html = html.Replace ("", pixmaps_path); + html = html.Replace ("", pixmaps_path + "/document-added-12.png"); + html = html.Replace ("", pixmaps_path + "/document-edited-12.png"); + html = html.Replace ("", pixmaps_path + "/document-deleted-12.png"); + html = html.Replace ("", pixmaps_path + "/document-moved-12.png"); + + this.spinner.Stop (); + + this.web_browser.ObjectForScripting = new SparkleScriptingObject (); + this.web_browser.NavigateToString (html); + + if (!this.canvas.Children.Contains (this.web_browser)) { + this.canvas.Children.Add (this.web_browser); + Canvas.SetLeft (this.web_browser, 0); + Canvas.SetTop (this.web_browser, 36); + } + } + + + private void WriteOutImages () + { + string tmp_path = SparkleLib.SparkleConfig.DefaultConfig.TmpPath; + string pixmaps_path = Path.Combine (tmp_path, "Pixmaps".SHA1 ()); + + if (!Directory.Exists (pixmaps_path)) { + Directory.CreateDirectory (pixmaps_path); + + File.SetAttributes (tmp_path, + File.GetAttributes (tmp_path) | FileAttributes.Hidden); + } + + BitmapSource image = SparkleUIHelpers.GetImageSource ("user-icon-default"); + string file_path = Path.Combine (pixmaps_path, "user-icon-default.png"); + + using (FileStream stream = new FileStream (file_path, FileMode.Create)) + { + BitmapEncoder encoder = new PngBitmapEncoder (); + encoder.Frames.Add (BitmapFrame.Create (image)); + encoder.Save (stream); + } + + string [] actions = new string [] {"added", "deleted", "edited", "moved"}; + + foreach (string action in actions) { + image = SparkleUIHelpers.GetImageSource ("document-" + action + "-12"); + file_path = Path.Combine (pixmaps_path, "document-" + action + "-12.png"); + + using (FileStream stream = new FileStream (file_path, FileMode.Create)) + { + BitmapEncoder encoder = new PngBitmapEncoder (); + encoder.Frames.Add (BitmapFrame.Create (image)); + encoder.Save (stream); + } + } + } + + + private void Close (object sender, CancelEventArgs args) + { + Controller.WindowClosed (); + args.Cancel = true; + } + + + [DllImport ("urlmon.dll")] + [PreserveSig] + [return:MarshalAs (UnmanagedType.Error)] + static extern int CoInternetSetFeatureEnabled (int feature, + [MarshalAs (UnmanagedType.U4)] int flags, bool enable); + } + + + [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] + [ComVisible(true)] + public class SparkleScriptingObject { + + public void LinkClicked (string url) + { + Program.UI.EventLog.Controller.LinkClicked (url); + } + } +} diff --git a/SparkleShare/Windows/SparkleEventLogWindow.xaml b/SparkleShare/Windows/SparkleEventLogWindow.xaml new file mode 100644 index 0000000..a43d38f --- /dev/null +++ b/SparkleShare/Windows/SparkleEventLogWindow.xaml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SparkleShare/Windows/SparkleEventLogWindow.xaml.cs b/SparkleShare/Windows/SparkleEventLogWindow.xaml.cs new file mode 100644 index 0000000..ac6b581 --- /dev/null +++ b/SparkleShare/Windows/SparkleEventLogWindow.xaml.cs @@ -0,0 +1,262 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 . + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Security.Permissions; +using System.Text; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +using Microsoft.Win32; + +namespace SparkleShare +{ + public partial class SparkleEventLogWindow : Window + { + public SparkleEventLogController Controller = new SparkleEventLogController (); + + [DllImport("urlmon.dll")] + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + static extern int CoInternetSetFeatureEnabled (int feature, [MarshalAs(UnmanagedType.U4)] int flags, bool enable); + + + public SparkleEventLogWindow () + { + InitializeComponent (); + + + Background = new SolidColorBrush (Color.FromRgb(240, 240, 240)); + AllowsTransparency = false; + Icon = SparkleUIHelpers.GetImageSource ("sparkleshare-app", "ico"); + WindowStartupLocation = WindowStartupLocation.CenterScreen; + + WriteOutImages (); + + this.label_Size.Content = "Size: " + Controller.Size; + this.label_History.Content = "History: " + Controller.HistorySize; + + this.webbrowser.ObjectForScripting = new SparkleScriptingObject (); + + // Disable annoying IE clicking sound + CoInternetSetFeatureEnabled (21, 0x00000002, true); + + Closing += this.OnClosing; + + Controller.ShowWindowEvent += delegate { + Dispatcher.BeginInvoke ((Action) (() => { + Show (); + Activate (); + BringIntoView (); + })); + }; + + Controller.HideWindowEvent += delegate { + Dispatcher.BeginInvoke ((Action) (() => { + Hide (); + this.spinner.Visibility = Visibility.Visible; + this.webbrowser.Visibility = Visibility.Collapsed; + })); + }; + + Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) { + Dispatcher.BeginInvoke ((Action) (() => { + this.label_Size.Content = "Size: " + size; + this.label_History.Content = "History: " + history_size; + })); + }; + + Controller.UpdateChooserEvent += delegate (string [] folders) { + Dispatcher.BeginInvoke ((Action) (() => + UpdateChooser (folders)) + ); + }; + + Controller.UpdateChooserEnablementEvent += delegate (bool enabled) { + Dispatcher.BeginInvoke ((Action) (() => + this.combobox.IsEnabled = enabled + )); + }; + + Controller.UpdateContentEvent += delegate (string html) { + Dispatcher.BeginInvoke ((Action) (() => { + UpdateContent (html); + + this.spinner.Visibility = Visibility.Collapsed; + this.webbrowser.Visibility = Visibility.Visible; + })); + }; + + Controller.ContentLoadingEvent += () => this.Dispatcher.BeginInvoke ( + (Action)(() => { + this.spinner.Visibility = Visibility.Visible; + this.spinner.Start (); + this.webbrowser.Visibility = Visibility.Collapsed; + })); + + Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) { + Dispatcher.BeginInvoke ((Action) (() => { + SaveFileDialog dialog = new SaveFileDialog () { + FileName = file_name, + InitialDirectory = target_folder_path, + Title = "Restore from History", + DefaultExt = "." + Path.GetExtension (file_name), + Filter = "All Files|*.*" + }; + + bool? result = dialog.ShowDialog (this); + + if (result == true) + Controller.SaveDialogCompleted (dialog.FileName); + else + Controller.SaveDialogCancelled (); + })); + }; + } + + + private void OnClosing (object sender, CancelEventArgs cancel_event_args) + { + Controller.WindowClosed (); + cancel_event_args.Cancel = true; + } + + + private void UpdateContent (string html) + { + string pixmaps_path = Path.Combine (SparkleLib.SparkleConfig.DefaultConfig.TmpPath, "Pixmaps"); + pixmaps_path = pixmaps_path.Replace ("\\", "/"); + + html = html.Replace ("", "Segoe UI"); + html = html.Replace ("", "13px"); + html = html.Replace ("", "12px"); + html = html.Replace ("", "#bbb"); + html = html.Replace ("", "#ddd"); + html = html.Replace ("", "90%"); + html = html.Replace ("", "#f5f5f5"); + html = html.Replace ("", "#0085cf"); + html = html.Replace ("", "#009ff8"); + html = html.Replace ("", pixmaps_path); + html = html.Replace ("", pixmaps_path + "/document-added-12.png"); + html = html.Replace ("", pixmaps_path + "/document-edited-12.png"); + html = html.Replace ("", pixmaps_path + "/document-deleted-12.png"); + html = html.Replace ("", pixmaps_path + "/document-moved-12.png"); + + this.spinner.Stop (); + + this.webbrowser.ObjectForScripting = new SparkleScriptingObject (); + this.webbrowser.NavigateToString (html); + } + + + public void UpdateChooser (string [] folders) + { + if (folders == null) { + folders = Controller.Folders; + } + + this.combobox.Items.Clear (); + this.combobox.Items.Add (new ComboBoxItem () { Content = "Summary" }); + this.combobox.Items.Add (new Separator ()); + this.combobox.SelectedItem = combobox.Items [0]; + + int row = 2; + foreach (string folder in folders) { + this.combobox.Items.Add (new ComboBoxItem () { Content = folder } ); + + if (folder.Equals (Controller.SelectedFolder)) + this.combobox.SelectedItem = this.combobox.Items [row]; + + row++; + } + + this.combobox.SelectionChanged += delegate { + Dispatcher.BeginInvoke ((Action) delegate { + int index = this.combobox.SelectedIndex; + + if (index == 0) + Controller.SelectedFolder = null; + else + Controller.SelectedFolder = (string) ((ComboBoxItem) this.combobox.Items [index]).Content; + }); + }; + } + + + private void WriteOutImages () + { + string tmp_path = SparkleLib.SparkleConfig.DefaultConfig.TmpPath; + string pixmaps_path = Path.Combine (tmp_path, "Pixmaps"); + + if (!Directory.Exists (pixmaps_path)) + { + Directory.CreateDirectory (pixmaps_path); + + File.SetAttributes (tmp_path, File.GetAttributes (tmp_path) | FileAttributes.Hidden); + } + + BitmapSource image = SparkleUIHelpers.GetImageSource ("user-icon-default"); + string file_path = Path.Combine (pixmaps_path, "user-icon-default.png"); + + using (FileStream stream = new FileStream (file_path, FileMode.Create)) + { + BitmapEncoder encoder = new PngBitmapEncoder (); + encoder.Frames.Add (BitmapFrame.Create (image)); + encoder.Save (stream); + } + + string[] actions = new string [] { "added", "deleted", "edited", "moved" }; + + foreach (string action in actions) + { + image = SparkleUIHelpers.GetImageSource ("document-" + action + "-12"); + file_path = Path.Combine (pixmaps_path, "document-" + action + "-12.png"); + + using (FileStream stream = new FileStream (file_path, FileMode.Create)) + { + BitmapEncoder encoder = new PngBitmapEncoder (); + encoder.Frames.Add (BitmapFrame.Create(image)); + encoder.Save (stream); + } + } + } + } + + + + + + [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] + [ComVisible(true)] + public class SparkleScriptingObject + { + public void LinkClicked(string url) + { + Program.UI.EventLog.Controller.LinkClicked(url); + } + } + + +} diff --git a/SparkleShare/Windows/SparkleLib/Git/SparkleLib.Git.csproj b/SparkleShare/Windows/SparkleLib/Git/SparkleLib.Git.csproj new file mode 100644 index 0000000..473b4dc --- /dev/null +++ b/SparkleShare/Windows/SparkleLib/Git/SparkleLib.Git.csproj @@ -0,0 +1,71 @@ + + + + + Debug + AnyCPU + {7F0DB8D0-E278-4955-8204-FC391B99F7C1} + Library + Properties + SparkleLib.Git + SparkleLib.Git + v4.0 + 512 + + + + true + full + false + ..\..\..\..\bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\bin\ + TRACE + prompt + 4 + + + + + + + + + + + + + SparkleFetcherGit.cs + + + SparkleGit.cs + Component + + + SparkleRepoGit.cs + + + + + + + + {748f6316-37b4-46fd-a011-af073bc7c02d} + SparkleLib + + + + + \ No newline at end of file diff --git a/SparkleShare/Windows/SparkleLib/SparkleLib.csproj b/SparkleShare/Windows/SparkleLib/SparkleLib.csproj new file mode 100644 index 0000000..4c5eaff --- /dev/null +++ b/SparkleShare/Windows/SparkleLib/SparkleLib.csproj @@ -0,0 +1,97 @@ + + + + + Debug + AnyCPU + {748F6316-37B4-46FD-A011-AF073BC7C02D} + Library + Properties + SparkleLib + SparkleLib + v4.0 + 512 + + + + true + full + false + ..\..\..\bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\bin\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + Defines.cs + + + SparkleBackend.cs + + + SparkleConfig.cs + + + SparkleExtensions.cs + + + SparkleFetcherBase.cs + + + SparkleFetcherSSH.cs + + + SparkleListenerBase.cs + + + SparkleListenerFactory.cs + + + SparkleListenerTcp.cs + + + SparkleLogger.cs + + + SparkleRepoBase.cs + + + SparkleUser.cs + + + SparkleWatcher.cs + + + SparkleWrappers.cs + + + + + \ No newline at end of file diff --git a/SparkleShare/Windows/SparkleNote.xaml b/SparkleShare/Windows/SparkleNote.xaml new file mode 100644 index 0000000..22f2b24 --- /dev/null +++ b/SparkleShare/Windows/SparkleNote.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +