diff --git a/OnTopReplica/AppStrings.resx b/OnTopReplica/AppStrings.resx
new file mode 100644
index 0000000..376870a
--- /dev/null
+++ b/OnTopReplica/AppStrings.resx
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ http://ontopreplica.codeplex.com
+
+
+ http://lorenz.klopfenstein.net
+
+
+ http://ontopreplica.codeplex.com/SourceControl/list/changesets
+
+
+ http://opensource.org/licenses/ms-rl.html
+
+
+ http://ontopreplica.codeplex.com/project/feeds/rss?ProjectRSSFeed=codeplex%3a%2f%2frelease%2fontopreplica
+
+
\ No newline at end of file
diff --git a/OnTopReplica/OnTopReplica.csproj b/OnTopReplica/OnTopReplica.csproj
index 6205031..971ba9a 100644
--- a/OnTopReplica/OnTopReplica.csproj
+++ b/OnTopReplica/OnTopReplica.csproj
@@ -102,6 +102,11 @@
+
+ True
+ True
+ AppStrings.resx
+
Form
@@ -154,6 +159,7 @@
True
Settings.settings
+
Form
@@ -201,6 +207,10 @@
+
+ ResXFileCodeGenerator
+ AppStrings.Designer.cs
+
SidePanelContainer.cs
diff --git a/OnTopReplica/Program.cs b/OnTopReplica/Program.cs
index ad90306..73b0846 100644
--- a/OnTopReplica/Program.cs
+++ b/OnTopReplica/Program.cs
@@ -116,7 +116,7 @@ namespace OnTopReplica {
if (e.Success && e.Information != null) {
Log.Write("Updated check successful (latest version is {0})", e.Information.LatestVersion);
- if (e.Information.IsNewVersion) {
+ if (e.Information.IsNewVersionAvailable) {
Update.ConfirmAndInstall();
}
}
diff --git a/OnTopReplica/Shell.cs b/OnTopReplica/Shell.cs
new file mode 100644
index 0000000..7ace07c
--- /dev/null
+++ b/OnTopReplica/Shell.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+
+namespace OnTopReplica {
+
+ static class Shell {
+
+ ///
+ /// Executes a filename via Windows shell.
+ ///
+ /// Filename to execute.
+ public static void Execute(string filename){
+ if (filename == null)
+ throw new ArgumentNullException();
+
+ Process.Start(new ProcessStartInfo {
+ FileName = filename,
+ UseShellExecute = true
+ });
+ }
+
+ }
+
+}
diff --git a/OnTopReplica/SidePanel.cs b/OnTopReplica/SidePanel.cs
index d66f010..296cff2 100644
--- a/OnTopReplica/SidePanel.cs
+++ b/OnTopReplica/SidePanel.cs
@@ -23,7 +23,7 @@ namespace OnTopReplica {
///
/// Gets the panel's parent form.
///
- protected MainForm ParentForm { get; private set; }
+ protected MainForm ParentMainForm { get; private set; }
///
/// Raised when the side panel requests to be closed.
@@ -41,7 +41,7 @@ namespace OnTopReplica {
///
/// Parent form that is embedding the side panel.
public virtual void OnFirstShown(MainForm form) {
- ParentForm = form;
+ ParentMainForm = form;
}
///
diff --git a/OnTopReplica/SidePanels/AboutPanelContents.cs b/OnTopReplica/SidePanels/AboutPanelContents.cs
index 84738b2..1ffccc7 100644
--- a/OnTopReplica/SidePanels/AboutPanelContents.cs
+++ b/OnTopReplica/SidePanels/AboutPanelContents.cs
@@ -54,18 +54,18 @@ namespace OnTopReplica.SidePanels {
}
private void LinkHomepage_clicked(object sender, LinkLabelLinkClickedEventArgs e) {
- Process.Start("http://ontopreplica.codeplex.com");
+ Shell.Execute(AppStrings.ApplicationWebsite);
}
private void LinkAuthor_clicked(object sender, LinkLabelLinkClickedEventArgs e) {
- Process.Start("http://lorenz.klopfenstein.net");
+ Shell.Execute(AppStrings.AuthorWebsite);
}
private void LinkCredits_click(object sender, LinkLabelLinkClickedEventArgs e) {
var exeDir = Path.GetDirectoryName(Application.ExecutablePath);
var filePath = Path.Combine(exeDir, "CREDITS.txt");
- Process.Start(filePath);
+ Shell.Execute(filePath);
}
void UpdateButton_click(object sender, System.EventArgs e) {
@@ -80,7 +80,7 @@ namespace OnTopReplica.SidePanels {
//TODO
MessageBox.Show("Failed to download update info.");
}
- else if (!e.Information.IsNewVersion) {
+ else if (!e.Information.IsNewVersionAvailable) {
Program.Update.DisplayInfo();
}
@@ -89,11 +89,11 @@ namespace OnTopReplica.SidePanels {
}
private void LinkLicense_click(object sender, LinkLabelLinkClickedEventArgs e) {
- Process.Start("http://opensource.org/licenses/ms-rl.html");
+ Shell.Execute(AppStrings.MsRlLicenseLink);
}
private void LinkContribute_clicked(object sender, LinkLabelLinkClickedEventArgs e) {
- Process.Start("http://ontopreplica.codeplex.com/SourceControl/list/changesets");
+ Shell.Execute(AppStrings.LatestCommitsLink);
}
}
}
diff --git a/OnTopReplica/SidePanels/GroupSwitchPanel.cs b/OnTopReplica/SidePanels/GroupSwitchPanel.cs
index 66183f5..a168d53 100644
--- a/OnTopReplica/SidePanels/GroupSwitchPanel.cs
+++ b/OnTopReplica/SidePanels/GroupSwitchPanel.cs
@@ -29,7 +29,7 @@ namespace OnTopReplica.SidePanels {
LoadWindowList();
- labelStatus.Text = (ParentForm.MessagePumpManager.Get().IsActive) ?
+ labelStatus.Text = (ParentMainForm.MessagePumpManager.Get().IsActive) ?
Strings.GroupSwitchModeStatusEnabled :
Strings.GroupSwitchModeStatusDisabled;
}
diff --git a/OnTopReplica/SidePanels/RegionPanel.cs b/OnTopReplica/SidePanels/RegionPanel.cs
index 3d4dcbd..9ef4983 100644
--- a/OnTopReplica/SidePanels/RegionPanel.cs
+++ b/OnTopReplica/SidePanels/RegionPanel.cs
@@ -217,7 +217,7 @@ namespace OnTopReplica.SidePanels {
/// Region bounds.
protected virtual void OnRegionSet(ThumbnailRegion region) {
//Forward region to thumbnail
- ParentForm.SelectedThumbnailRegion = region;
+ ParentMainForm.SelectedThumbnailRegion = region;
//Have region, allowed to save
buttonSave.Enabled = true;
@@ -231,7 +231,7 @@ namespace OnTopReplica.SidePanels {
private void Reset_click(object sender, EventArgs e) {
Reset();
- ParentForm.SelectedThumbnailRegion = null;
+ ParentMainForm.SelectedThumbnailRegion = null;
}
private void Delete_click(object sender, EventArgs e) {
@@ -305,9 +305,9 @@ namespace OnTopReplica.SidePanels {
var region = ConstructCurrentRegion();
region.Relative = !region.Relative; //this must be reversed because the GUI has already switched state when calling ConstructCurrentRegion()
if (checkRelative.Checked)
- region.SwitchToRelative(ParentForm.ThumbnailPanel.ThumbnailOriginalSize);
+ region.SwitchToRelative(ParentMainForm.ThumbnailPanel.ThumbnailOriginalSize);
else
- region.SwitchToAbsolute(ParentForm.ThumbnailPanel.ThumbnailOriginalSize);
+ region.SwitchToAbsolute(ParentMainForm.ThumbnailPanel.ThumbnailOriginalSize);
//Update GUI
SetRegion(region);
diff --git a/OnTopReplica/Update/UpdateInformation.cs b/OnTopReplica/Update/UpdateInformation.cs
index de46168..5ab3165 100644
--- a/OnTopReplica/Update/UpdateInformation.cs
+++ b/OnTopReplica/Update/UpdateInformation.cs
@@ -1,9 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Xml.Serialization;
-using System.IO;
-using System.Xml;
+using System.Globalization;
using System.Reflection;
namespace OnTopReplica.Update {
@@ -13,79 +9,62 @@ namespace OnTopReplica.Update {
///
public class UpdateInformation {
- Version _latestVersion;
+ ///
+ /// Construct update information from raw data.
+ ///
+ /// Latest available version.
+ /// Direct link to the download page (has URL form).
+ /// Publication date of latest version, in standard RTF/RSS format.
+ public UpdateInformation(Version latestVersion, string downloadLink, string publicationDate) {
+ LatestVersion = latestVersion;
+ DownloadPage = downloadLink;
+
+ //RSS date formatted as in: Thu, 29 Nov 2012 12:55:04 GMT
+ DateTime parsedPublicationDate;
+ if (DateTime.TryParseExact(publicationDate, "R", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out parsedPublicationDate)) {
+ LatestVersionRelease = parsedPublicationDate;
+ }
+ }
///
- /// Gets the latest available version of the software.
+ /// Gets or sets the latest available version of the software.
///
- [XmlIgnore]
- public Version LatestVersion {
- get {
- return _latestVersion;
- }
- set {
- _latestVersion = value;
- }
- }
-
- [XmlElement("latestVersion")]
- public string LatestVersionInternal {
- get {
- return _latestVersion.ToString();
- }
- set {
- _latestVersion = new Version(value);
- }
- }
+ public Version LatestVersion { get; private set; }
///
/// Returns whether this update information instance represents data about
/// a new available version.
///
- public bool IsNewVersion {
+ public bool IsNewVersionAvailable {
get {
- var currentVersion = CurrentVersion;
-
- return (LatestVersion > currentVersion);
+ return (LatestVersion > CurrentVersion);
}
}
+ private Version _currentVersion = null;
+
///
/// Gets the currently installed version.
///
public Version CurrentVersion {
get {
- return Assembly.GetExecutingAssembly().GetName().Version;
+ if (_currentVersion == null) {
+ _currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
+ }
+
+ return _currentVersion;
}
}
///
/// Indicates when the latest version was released.
///
- [XmlElement("latestVersionRelease")]
- public DateTime LatestVersionRelease { get; set; }
+ public DateTime LatestVersionRelease { get; private set; }
///
/// Gets the URL of the page that allows the user to download the updated installer.
///
- [XmlElement("downloadPage")]
- public string DownloadPage { get; set; }
-
- ///
- /// Gets the URL of the installer executable.
- ///
- /// New after version 3.3.1.
- [XmlElement("downloadInstaller")]
- public string DownloadInstaller { get; set; }
-
- ///
- /// Deserializes an UpdateInformation object from a stream.
- ///
- public static UpdateInformation Deserialize(Stream source) {
- var serializer = new XmlSerializer(typeof(UpdateInformation));
- var info = serializer.Deserialize(source) as UpdateInformation;
- return info;
- }
+ public string DownloadPage { get; private set; }
}
diff --git a/OnTopReplica/Update/UpdateManager.cs b/OnTopReplica/Update/UpdateManager.cs
index a2fcd9b..de14199 100644
--- a/OnTopReplica/Update/UpdateManager.cs
+++ b/OnTopReplica/Update/UpdateManager.cs
@@ -34,8 +34,6 @@ namespace OnTopReplica.Update {
#region Checking
- const string UpdateFeedUrl = "https://ontopreplica.codeplex.com/project/feeds/rss?ProjectRSSFeed=codeplex%3a%2f%2frelease%2fontopreplica";
-
///
/// Gets the latest update information available.
///
@@ -53,7 +51,7 @@ namespace OnTopReplica.Update {
}
//Build web request
- _checkRequest = (HttpWebRequest)HttpWebRequest.Create(UpdateFeedUrl);
+ _checkRequest = (HttpWebRequest)HttpWebRequest.Create(AppStrings.UpdateFeed);
_checkRequest.AllowAutoRedirect = true;
_checkRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
_checkRequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
@@ -90,11 +88,13 @@ namespace OnTopReplica.Update {
let title = item.Element("title").Value
let match = _versionExtractor.Match(title)
where match.Success
- let versionNumber = match.Groups["version"].Value
+ let versionNumber = new Version(match.Groups["version"].Value)
orderby versionNumber descending
- select new { versionNumber, item.Element("link").Value };
+ select new { Version = versionNumber, Link = item.Element("link").Value, Date = item.Element("pubDate").Value };
- return new UpdateInformation();
+ var lastRelease = releases.FirstOrDefault();
+
+ return new UpdateInformation(lastRelease.Version, lastRelease.Link, lastRelease.Date);
}
#endregion
@@ -127,15 +127,11 @@ namespace OnTopReplica.Update {
#region Updating
- HttpWebRequest _downloadRequest;
- TaskDialog _updateDialog;
- bool _updateDownloaded = false;
-
///
- /// Asks confirmation for an update and installs the update.
+ /// Asks confirmation for an update and installs the update (if available).
///
public void ConfirmAndInstall() {
- if (LastInformation == null || !LastInformation.IsNewVersion)
+ if (LastInformation == null || !LastInformation.IsNewVersionAvailable)
return;
AttachedForm.SafeInvoke(new Action(ConfirmAndInstallCore));
@@ -145,7 +141,7 @@ namespace OnTopReplica.Update {
/// Core delegate that asks for update confirmation and installs. Must be called from GUI thread.
///
private void ConfirmAndInstallCore() {
- _updateDialog = new TaskDialog {
+ var updateDialog = new TaskDialog {
Title = Strings.UpdateTitle,
Instruction = string.Format(Strings.UpdateAvailableInstruction, LastInformation.LatestVersion),
Content = Strings.UpdateAvailableContent,
@@ -157,111 +153,11 @@ namespace OnTopReplica.Update {
CommonIcon = TaskDialogIcon.Information,
ExpandedInformation = string.Format(Strings.UpdateAvailableExpanded, LastInformation.CurrentVersion, LastInformation.LatestVersion),
};
- _updateDialog.ButtonClick += delegate(object sender, ClickEventArgs args) {
- if (args.ButtonID == (int)Result.OK) {
- args.PreventClosing = true;
-
- if (_updateDownloaded) {
- //Terminate application
- AttachedForm.Close();
-
- //Launch updater
- Process.Start(UpdateInstallerPath);
- }
- else {
- var downDlg = new TaskDialog {
- Title = Strings.UpdateTitle,
- Instruction = Strings.UpdateDownloadingInstruction,
- ShowProgressBar = true,
- ProgressBarMinRange = 0,
- ProgressBarMaxRange = 100,
- ProgressBarPosition = 0,
- CommonButtons = TaskDialogButton.Cancel
- };
- _updateDialog.Navigate(downDlg);
-
- _downloadRequest = (HttpWebRequest)HttpWebRequest.Create(LastInformation.DownloadInstaller);
- _downloadRequest.BeginGetResponse(DownloadAsyncCallback, null);
- }
- }
- };
-
- _updateDialog.Show(AttachedForm);
- }
-
- ///
- /// Gets the target filename used when downloading the update from the Internet.
- ///
- private string UpdateInstallerPath {
- get {
- var downloadPath = Native.FilesystemMethods.DownloadsPath;
-
- string versionName = (LastInformation != null) ?
- LastInformation.LatestVersion.ToString() : string.Empty;
- string filename = string.Format("OnTopReplica-Update-{0}.exe", versionName);
-
- return Path.Combine(downloadPath, filename);
+ if (updateDialog.Show(AttachedForm).CommonButton == Result.OK) {
+ Shell.Execute(LastInformation.DownloadPage);
}
}
- ///
- /// Handles background downloading.
- ///
- private void DownloadAsyncCallback(IAsyncResult result) {
- if (_downloadRequest == null || _updateDialog == null)
- return;
-
- try {
- var response = _downloadRequest.EndGetResponse(result);
- var responseStream = response.GetResponseStream();
- long total = response.ContentLength;
-
- byte[] buffer = new byte[1024];
-
- using (var stream = new FileStream(UpdateInstallerPath, FileMode.Create)) {
- int readTotal = 0;
- while (true) {
- int read = responseStream.Read(buffer, 0, buffer.Length);
- readTotal += read;
-
- if (read <= 0) //EOF
- break;
-
- stream.Write(buffer, 0, read);
-
- _updateDialog.Content = string.Format(Strings.UpdateDownloadingContent, readTotal, total);
- _updateDialog.ProgressBarPosition = (int)((readTotal * 100.0) / total);
- }
- }
- }
- catch (Exception ex) {
- DownloadShowError(ex.Message);
- return;
- }
-
- _updateDownloaded = true;
-
- var okDlg = new TaskDialog {
- Title = Strings.UpdateTitle,
- Instruction = Strings.UpdateReadyInstruction,
- Content = string.Format(Strings.UpdateReadyContent, LastInformation.LatestVersion),
- UseCommandLinks = true,
- CommonButtons = TaskDialogButton.Cancel,
- CustomButtons = new CustomButton[] {
- new CustomButton(Result.OK, Strings.UpdateReadyCommandOk)
- }
- };
- _updateDialog.Navigate(okDlg);
- }
-
- private void DownloadShowError(string msg) {
- if (_updateDialog == null)
- return;
-
- _updateDialog.ProgressBarState = WindowsFormsAero.ProgressBar.States.Error;
- _updateDialog.Content = msg;
- }
-
///
/// Displays some information about the current installation and available updates.
///
@@ -285,8 +181,9 @@ namespace OnTopReplica.Update {
Footer = string.Format(Strings.UpdateInfoFooter, LastInformation.LatestVersionRelease.ToLongDateString())
};
dlg.HyperlinkClick += delegate(object sender, HyperlinkEventArgs args) {
- Process.Start("http://ontopreplica.codeplex.com");
+ Shell.Execute(AppStrings.ApplicationWebsite);
};
+
dlg.Show(AttachedForm);
}
diff --git a/OnTopReplica/WindowHandle.cs b/OnTopReplica/WindowHandle.cs
index d2b2cc6..34720b3 100644
--- a/OnTopReplica/WindowHandle.cs
+++ b/OnTopReplica/WindowHandle.cs
@@ -113,16 +113,6 @@ namespace OnTopReplica {
}
return sb.ToString();
-
- if (string.IsNullOrWhiteSpace(_title)) {
- return string.Format("#{0}", _handle.ToInt64());
- }
- else if (string.IsNullOrWhiteSpace(_class)) {
- return string.Format("#{0} ({1})", _handle.ToInt64(), _title);
- }
- else {
- return string.Format("#{0} ({1}, class {2})", _handle.ToInt64(), _title, _class);
- }
}
public override bool Equals(object obj) {