Update mechanism updated radically (with integrated download and update start).

Little code clean-up.
Strings updated.
This commit is contained in:
Lorenz Cuno Klopfenstein 2011-04-14 23:52:55 +02:00
parent 81a74d0afe
commit 42608bddc2
19 changed files with 897 additions and 491 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -23,7 +23,6 @@ namespace OnTopReplica {
SkipNotVisibleWindows = true
};
MessagePumpManager _msgPumpManager = new MessagePumpManager();
UpdateManager _updateManager = new UpdateManager();
Options _startupOptions;
@ -54,17 +53,6 @@ namespace OnTopReplica {
this.KeyPreview = true;
}
void UpdateManager_CheckCompleted(object sender, UpdateCheckCompletedEventArgs e) {
this.Invoke(new Action(() => {
if (e.Success) {
_updateManager.HandleUpdateCheck(this, e.Information, false);
}
else {
Console.WriteLine("Failed to check for updates: {0}", e.Error);
}
}));
}
#region Event override
protected override CreateParams CreateParams {
@ -97,10 +85,6 @@ namespace OnTopReplica {
//Apply startup options
_startupOptions.Apply(this);
//Check for updates
_updateManager.UpdateCheckCompleted += new EventHandler<UpdateCheckCompletedEventArgs>(UpdateManager_CheckCompleted);
_updateManager.CheckForUpdate();
}
protected override void OnClosing(CancelEventArgs e) {

View file

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace OnTopReplica.Native {
/// <summary>
/// Native methods for filesystem interop.
/// </summary>
static class FilesystemMethods {
/// <summary>
/// Gets the path to the current user's download path.
/// </summary>
/// <remarks>
/// Code taken from http://stackoverflow.com/questions/3795023/downloads-folder-not-special-enough
/// </remarks>
public static string DownloadsPath {
get {
string path = null;
//Requires Vista or superior
if (Environment.OSVersion.Version.Major >= 6) {
IntPtr pathPtr;
Guid folderId = FolderDownloads;
int hr = SHGetKnownFolderPath(ref folderId, 0, IntPtr.Zero, out pathPtr);
if (hr == 0) {
path = Marshal.PtrToStringUni(pathPtr);
Marshal.FreeCoTaskMem(pathPtr);
return path;
}
}
//Fallback code
path = Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
path = Path.Combine(path, "Downloads");
return path;
}
}
static readonly Guid FolderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int SHGetKnownFolderPath(ref Guid id, int flags, IntPtr token, out IntPtr path);
}
}

View file

@ -134,6 +134,7 @@
<Compile Include="MessagePumpProcessors\ShellInterceptProcessor.cs" />
<Compile Include="MessagePumpProcessors\WindowKeeper.cs" />
<Compile Include="Native\ErrorMethods.cs" />
<Compile Include="Native\FilesystemMethods.cs" />
<Compile Include="Native\HookMethods.cs" />
<Compile Include="Native\HotKeyMethods.cs" />
<Compile Include="Native\HT.cs" />
@ -178,6 +179,7 @@
<Compile Include="WindowSeekers\ByTitleWindowSeeker.cs" />
<Compile Include="WindowSeekers\RestoreWindowSeeker.cs" />
<Compile Include="WindowSeekers\TaskWindowSeeker.cs" />
<Compile Include="WindowsFormsExtensions.cs" />
<EmbeddedResource Include="SidePanelContainer.resx">
<DependentUpon>SidePanelContainer.cs</DependentUpon>
</EmbeddedResource>
@ -187,8 +189,18 @@
<EmbeddedResource Include="SidePanels\AboutPanelContents.resx">
<DependentUpon>AboutPanelContents.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Strings.pl.resx" />
<EmbeddedResource Include="Strings.ru.resx" />
<EmbeddedResource Include="Strings.pl.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.pl.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.ru.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.ru.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Native\ITaskBarList.cs" />
<Compile Include="Native\InputMethods.cs" />
<Compile Include="Native\MessagingMethods.cs" />
@ -256,9 +268,18 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.da.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.de.resx" />
<EmbeddedResource Include="Strings.es.resx" />
<EmbeddedResource Include="Strings.fi.resx" />
<EmbeddedResource Include="Strings.de.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.de.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.es.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.es.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.fi.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.fi.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.it.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.it.Designer.cs</LastGenOutput>
@ -277,13 +298,17 @@
<DependentUpon>RegionPanel.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Strings.no.resx" />
<EmbeddedResource Include="Strings.pt-BR.resx" />
<EmbeddedResource Include="Strings.pt.resx" />
<EmbeddedResource Include="Strings.resx">
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
<EmbeddedResource Include="Strings.no.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.no.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.pt-BR.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.pt-BR.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings.pt.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.pt.Designer.cs</LastGenOutput>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
@ -406,7 +431,6 @@
<None Include="Assets\x-oblique.png" />
<None Include="Assets\xiao_up.png" />
<None Include="Assets\xiao_down.png" />
<None Include="Assets\thumbs_up.png" />
<None Include="Assets\pos_null.png" />
<None Include="Assets\pos_topright.png" />
<None Include="Assets\pos_topleft.png" />

View file

@ -13,7 +13,7 @@ namespace OnTopReplica {
public static PlatformSupport Platform { get; private set; }
static UpdateManager _updateManager;
public static UpdateManager Update { get; private set; }
static MainForm _mainForm;
@ -55,6 +55,19 @@ namespace OnTopReplica {
//Show form
using (_mainForm = new MainForm(options)) {
//Start up update manager
Update = new UpdateManager(_mainForm);
Update.UpdateCheckCompleted += new EventHandler<UpdateCheckCompletedEventArgs>(UpdateManager_CheckCompleted);
bool doneCheck = false;
_mainForm.Shown += delegate {
if (doneCheck) return;
doneCheck = true;
//Delay first update check to when form is visible
Update.CheckForUpdate();
};
//Enter GUI loop
Application.Run(_mainForm);
//Persist settings
@ -64,6 +77,20 @@ namespace OnTopReplica {
}
}
/// <summary>
/// Callback that handles update checking.
/// </summary>
static void UpdateManager_CheckCompleted(object sender, UpdateCheckCompletedEventArgs e) {
if (e.Success && e.Information != null) {
if (e.Information.IsNewVersion) {
Update.ConfirmAndInstall();
}
}
else {
Console.Error.WriteLine("Failed to check updates. {0}", e.Error);
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
string dump = string.Format("OnTopReplica-dump-{0}{1}{2}{3}{4}.txt",
DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day,

View file

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
// Runtime Version:4.0.30319.225
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -228,13 +228,6 @@ namespace OnTopReplica.Properties {
}
}
internal static System.Drawing.Bitmap thumbs_up {
get {
object obj = ResourceManager.GetObject("thumbs_up", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
internal static System.Drawing.Bitmap window_border16 {
get {
object obj = ResourceManager.GetObject("window_border16", resourceCulture);

View file

@ -148,9 +148,6 @@
<data name="window_opacity" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\window_opacity_new.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="thumbs_up" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\thumbs_up.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="pos_topleft" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\pos_topleft.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@ -232,7 +229,6 @@
<data name="flag_spanish" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\flag_spanish.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="flag_poland" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\flag_poland.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

View file

@ -34,7 +34,7 @@
this.labelVersion.Location = new System.Drawing.Point(0, 270);
this.labelVersion.Name = "labelVersion";
this.labelVersion.Padding = new System.Windows.Forms.Padding(0, 0, 0, 3);
this.labelVersion.Size = new System.Drawing.Size(255, 20);
this.labelVersion.Size = new System.Drawing.Size(265, 20);
this.labelVersion.TabIndex = 0;
this.labelVersion.Text = "Version";
this.labelVersion.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
@ -49,7 +49,7 @@
this.panelContents.Location = new System.Drawing.Point(6, 6);
this.panelContents.Margin = new System.Windows.Forms.Padding(6);
this.panelContents.Name = "panelContents";
this.panelContents.Size = new System.Drawing.Size(243, 255);
this.panelContents.Size = new System.Drawing.Size(253, 255);
this.panelContents.TabIndex = 1;
//
// AboutPanel
@ -58,9 +58,9 @@
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panelContents);
this.Controls.Add(this.labelVersion);
this.MinimumSize = new System.Drawing.Size(255, 290);
this.MinimumSize = new System.Drawing.Size(265, 290);
this.Name = "AboutPanel";
this.Size = new System.Drawing.Size(255, 290);
this.Size = new System.Drawing.Size(265, 290);
this.ResumeLayout(false);
}

View file

@ -13,40 +13,42 @@ using System.IO;
namespace OnTopReplica.SidePanels {
public partial class AboutPanelContents : UserControl {
UpdateManager _updater;
EventHandler<UpdateCheckCompletedEventArgs> _updateHandler;
public AboutPanelContents() {
InitializeComponent();
//Localized strings
lblSlogan.Text = Strings.AboutSlogan;
InternationalizeLinkLabel(linkAuthor, Strings.AboutAuthor, Strings.AboutAuthorContent);
linkAuthor.Internationalize(Strings.AboutAuthor, Strings.AboutAuthorContent);
labeledDivider1.Text = Strings.AboutDividerUpdates;
lblUpdateDisclaimer.Text = Strings.AboutUpdatesDisclaimer;
buttonUpdate.Text = Strings.AboutUpdatesCheckNow;
labeledDivider2.Text = Strings.AboutDividerCredits;
InternationalizeLinkLabel(linkCredits, Strings.AboutCreditsSources, Strings.AboutCreditsSourcesContent);
linkCredits.Internationalize(Strings.AboutCreditsSources, Strings.AboutCreditsSourcesContent);
labelTranslators.Text = string.Format(Strings.AboutTranslators, Strings.AboutTranslatorsContent);
labeledDivider3.Text = Strings.AboutDividerLicense;
InternationalizeLinkLabel(linkLicense, Strings.AboutLicense, Strings.AboutLicenseContent);
linkLicense.Internationalize(Strings.AboutLicense, Strings.AboutLicenseContent);
labeledDivider4.Text = Strings.AboutDividerContribute;
InternationalizeLinkLabel(linkContribute, Strings.AboutContribute, Strings.AboutContributeContent);
//Updating
_updater = new UpdateManager();
_updater.UpdateCheckCompleted += new EventHandler<UpdateCheckCompletedEventArgs>(UpdateCheckCompleted);
linkContribute.Internationalize(Strings.AboutContribute, Strings.AboutContributeContent);
}
private void InternationalizeLinkLabel(LinkLabel label, string text, string linkText) {
int linkIndex = text.IndexOf('%');
if (linkIndex == -1) {
//Shouldn't happen, but try to fail with meaningful text
label.Text = text;
return;
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
label.Text = text.Substring(0, linkIndex) + linkText + text.Substring(linkIndex + 1);
label.LinkArea = new LinkArea(linkIndex, linkText.Length);
if (!DesignMode) {
//Updating
_updateHandler = new EventHandler<UpdateCheckCompletedEventArgs>(UpdateCheckCompleted);
Program.Update.UpdateCheckCompleted += _updateHandler;
}
}
protected override void OnHandleDestroyed(EventArgs e) {
base.OnHandleDestroyed(e);
if (!DesignMode) {
Program.Update.UpdateCheckCompleted -= _updateHandler;
}
}
private void LinkHomepage_clicked(object sender, LinkLabelLinkClickedEventArgs e) {
@ -67,22 +69,17 @@ namespace OnTopReplica.SidePanels {
void UpdateButton_click(object sender, System.EventArgs e) {
progressUpdate.Visible = true;
_updater.CheckForUpdate();
Program.Update.CheckForUpdate();
}
void UpdateCheckCompleted(object sender, UpdateCheckCompletedEventArgs e) {
this.Invoke(new Action(() => {
var topForm = this.TopLevelControl as Form;
if (e.Success) {
_updater.HandleUpdateCheck(topForm, e.Information, true);
if (!e.Success || e.Information == null) {
//TODO
MessageBox.Show("Failed to download update info.");
}
else {
var dlg = new TaskDialog(Strings.ErrorUpdate, Strings.ErrorUpdate, Strings.ErrorUpdateContentGeneric) {
CommonIcon = TaskDialogIcon.Stop,
CommonButtons = TaskDialogButton.OK
};
dlg.Show(topForm);
else if (!e.Information.IsNewVersion) {
Program.Update.DisplayInfo();
}
progressUpdate.Visible = false;

View file

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
// Runtime Version:4.0.30319.225
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -232,7 +232,7 @@ namespace OnTopReplica {
}
/// <summary>
/// Looks up a localized string similar to Christian Olaechea M., Daniel Zeus.EX, Federico Lorenzo, Goran Brecelj, Marco Kraxner, Patrik (batupata), Raúl Morillo, René Mihula, Roberto Leiro, Rodrigo Lourenço, Thomas Amundsen..
/// Looks up a localized string similar to Christian Olaechea M., Daniel Zeus.EX, Federico Lorenzo, Goran Brecelj, Jan Romanczyk, Marco Kraxner, Patrik (batupata), Raúl Morillo, René Mihula, Roberto Leiro, Rodrigo Lourenço, Thomas Amundsen..
/// </summary>
internal static string AboutTranslatorsContent {
get {
@ -340,63 +340,6 @@ namespace OnTopReplica {
}
}
/// <summary>
/// Looks up a localized string similar to Download OnTopReplica {0}?.
/// </summary>
internal static string AskUpdate {
get {
return ResourceManager.GetString("AskUpdate", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cancel update
///OnTopReplica will prompt you the next time it is started..
/// </summary>
internal static string AskUpdateButtonCancel {
get {
return ResourceManager.GetString("AskUpdateButtonCancel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Download
///Install OnTopReplica {0}..
/// </summary>
internal static string AskUpdateButtonOk {
get {
return ResourceManager.GetString("AskUpdateButtonOk", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The new version can be downloaded and installed from the official website..
/// </summary>
internal static string AskUpdateContent {
get {
return ResourceManager.GetString("AskUpdateContent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Installed version: {0}
///Available version: {1}.
/// </summary>
internal static string AskUpdateExpanded {
get {
return ResourceManager.GetString("AskUpdateExpanded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Update available.
/// </summary>
internal static string AskUpdateTitle {
get {
return ResourceManager.GetString("AskUpdateTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &amp;Cancel.
/// </summary>
@ -1511,5 +1454,137 @@ namespace OnTopReplica {
return ResourceManager.GetString("SettingsTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cancel update
///OnTopReplica will prompt you the next time it is started..
/// </summary>
internal static string UpdateAvailableCommandCancel {
get {
return ResourceManager.GetString("UpdateAvailableCommandCancel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Download
///Install OnTopReplica {0}..
/// </summary>
internal static string UpdateAvailableCommandOk {
get {
return ResourceManager.GetString("UpdateAvailableCommandOk", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The new version can be downloaded and installed from the official website..
/// </summary>
internal static string UpdateAvailableContent {
get {
return ResourceManager.GetString("UpdateAvailableContent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Installed version: {0}
///Available version: {1}.
/// </summary>
internal static string UpdateAvailableExpanded {
get {
return ResourceManager.GetString("UpdateAvailableExpanded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version {0} available.
/// </summary>
internal static string UpdateAvailableInstruction {
get {
return ResourceManager.GetString("UpdateAvailableInstruction", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0}/{1} bytes downloaded..
/// </summary>
internal static string UpdateDownloadingContent {
get {
return ResourceManager.GetString("UpdateDownloadingContent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Downloading....
/// </summary>
internal static string UpdateDownloadingInstruction {
get {
return ResourceManager.GetString("UpdateDownloadingInstruction", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The latest version of OnTopReplica is already installed. The program automatically checks for updates at every start.
///
///You can keep up to date about OnTopReplica&apos;s development, suggest improvements and new features by &lt;a href=&quot;website&quot;&gt;visiting the official website&lt;/a&gt;..
/// </summary>
internal static string UpdateInfoContent {
get {
return ResourceManager.GetString("UpdateInfoContent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Latest stable version: {0}..
/// </summary>
internal static string UpdateInfoFooter {
get {
return ResourceManager.GetString("UpdateInfoFooter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OnTopReplica is up to date.
/// </summary>
internal static string UpdateInfoInstruction {
get {
return ResourceManager.GetString("UpdateInfoInstruction", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Install
///OnTopReplica will be closed and the update installed..
/// </summary>
internal static string UpdateReadyCommandOk {
get {
return ResourceManager.GetString("UpdateReadyCommandOk", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OnTopReplica version {0} is ready to be installed on your computer..
/// </summary>
internal static string UpdateReadyContent {
get {
return ResourceManager.GetString("UpdateReadyContent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Update ready.
/// </summary>
internal static string UpdateReadyInstruction {
get {
return ResourceManager.GetString("UpdateReadyInstruction", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OnTopReplica updates.
/// </summary>
internal static string UpdateTitle {
get {
return ResourceManager.GetString("UpdateTitle", resourceCulture);
}
}
}
}

View file

@ -24,8 +24,18 @@
<data name="AboutButtonUpdateTT" xml:space="preserve">
<value>Aktualizovat OnTopReplica.</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>Nenáročný a instantní náhled libovolného otevřeného okna (nebo jeho výřezu) v systému.</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Zkontroluj aktualizace</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>Aplikace OnTopReplica automaticky kontroluje dostupné aktualizace.</value>
</data>
<data name="ApplicationName" xml:space="preserve">
<value>OnTopReplica</value>
<comment>Probably doesn't need localization. :)</comment>
</data>
<data name="AskReset" xml:space="preserve">
<value>Resetovat nastavení okna?</value>
@ -49,36 +59,17 @@ Všechna nastavení budou ztracena.</value>
<data name="AskSettingResetTitle" xml:space="preserve">
<value>Resetovat nastavení</value>
</data>
<data name="AskUpdate" xml:space="preserve">
<value>Instalovat OnTopReplica {0}?</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateButtonCancel" xml:space="preserve">
<value>Zrušit aktualizaci
Aplikace OnTopReplica vás vyzve k aktualizaci při dalším startu.</value>
</data>
<data name="AskUpdateButtonOk" xml:space="preserve">
<data name="UpdateAvailableCommandOk" xml:space="preserve">
<value>Pokračovat
Instalovat OnTopReplica {0}.</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateContent" xml:space="preserve">
<value>Nová verze bude automaticky stažena a nainstalována.</value>
</data>
<data name="AskUpdateExpanded" xml:space="preserve">
<value>Nainstalovaná verze: {0}
Dostupná verze: {1}</value>
<comment>{0} installed version number
{1} online available version number</comment>
</data>
<data name="AskUpdateTitle" xml:space="preserve">
<value>Nové aktualizace jsou k dispozici</value>
</data>
<data name="ButtonCancel" xml:space="preserve">
<value>&amp;Storno</value>
<comment>&amp; marks the ALT+[] shortcut</comment>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Autor: Lorenz Cuno Klopfenstein.</value>
<data name="UpdateAvailableCommandCancel" xml:space="preserve">
<value>Zrušit aktualizaci
Aplikace OnTopReplica vás vyzve k aktualizaci při dalším startu.</value>
</data>
<data name="DrawRegions" xml:space="preserve">
<value>Označte výřez pomocí myši.</value>
@ -385,13 +376,11 @@ Režim "Proklikávání" je možné zvolit později v menu</value>
<data name="RightClick" xml:space="preserve">
<value>Začněte klepnutím sem pravým tlačítkem myši...</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>Aplikace OnTopReplica automaticky kontroluje dostupné aktualizace.</value>
<data name="UpdateAvailableContent" xml:space="preserve">
<value>Nová verze bude automaticky stažena a nainstalována.</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Zkontroluj aktualizace</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>Nenáročný a instantní náhled libovolného otevřeného okna (nebo jeho výřezu) v systému.</value>
<data name="UpdateAvailableExpanded" xml:space="preserve">
<value>Nainstalovaná verze: {0}
Dostupná verze: {1}</value>
</data>
</root>

View file

@ -24,8 +24,18 @@
<data name="AboutButtonUpdateTT" xml:space="preserve">
<value>Opdater OnTopReplica nu.</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>En letvægts, live, miniature udgave af et vindue du vælger, der altid er øverst.</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Opdater nu!</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica checker automatiskt for opdateringer.</value>
</data>
<data name="ApplicationName" xml:space="preserve">
<value>OnTopReplica</value>
<comment>Probably doesn't need localization. :)</comment>
</data>
<data name="AskReset" xml:space="preserve">
<value>Nulstil vinduet helt?</value>
@ -48,34 +58,15 @@
<data name="AskSettingResetTitle" xml:space="preserve">
<value>Nulstil indstillingerne</value>
</data>
<data name="AskUpdate" xml:space="preserve">
<value>Installer OnTopReplica {0}?</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateButtonCancel" xml:space="preserve">
<value>Annuller opdateringenOnTopReplica påminder dig igen næste gang det startes.</value>
</data>
<data name="AskUpdateButtonOk" xml:space="preserve">
<data name="UpdateAvailableCommandOk" xml:space="preserve">
<value>FortsætInstaller OnTopReplica</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateContent" xml:space="preserve">
<value>Den nye version vil automatiskt blive downloaded og installeret.</value>
</data>
<data name="AskUpdateExpanded" xml:space="preserve">
<value>Installeret version: {0}
Tilgængelig version: {1}</value>
<comment>{0} installed version number
{1} online available version number</comment>
</data>
<data name="AskUpdateTitle" xml:space="preserve">
<value>Opdatering tilgængelig.</value>
</data>
<data name="ButtonCancel" xml:space="preserve">
<value>&amp;Annuller</value>
<comment>&amp; marks the ALT+[] shortcut</comment>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Lavet af: Lorenz Cuno Klopfenstein.</value>
<data name="UpdateAvailableCommandCancel" xml:space="preserve">
<value>Annuller opdateringenOnTopReplica påminder dig igen næste gang det startes.</value>
</data>
<data name="DrawRegions" xml:space="preserve">
<value>Tegn områder med musen</value>
@ -380,13 +371,11 @@ Du kan aktivere gennem klik senere.</value>
<data name="RightClick" xml:space="preserve">
<value>Højreklik her for at starte...</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica checker automatiskt for opdateringer.</value>
<data name="UpdateAvailableContent" xml:space="preserve">
<value>Den nye version vil automatiskt blive downloaded og installeret.</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Opdater nu!</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>En letvægts, live, miniature udgave af et vindue du vælger, der altid er øverst.</value>
<data name="UpdateAvailableExpanded" xml:space="preserve">
<value>Installeret version: {0}
Tilgængelig version: {1}</value>
</data>
</root>

View file

@ -24,8 +24,18 @@
<data name="AboutButtonUpdateTT" xml:space="preserve">
<value>Actualiza OnTopReplica ahora.</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>Una copia liviana, en tiempo real y siempre encima de cualquier ventana.</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Actualizar ahora!</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica busca actualizaciones automáticamente.</value>
</data>
<data name="ApplicationName" xml:space="preserve">
<value>OnTopReplica</value>
<comment>Probably doesn't need localization. :)</comment>
</data>
<data name="AskReset" xml:space="preserve">
<value>¿Reiniciar la ventana?</value>
@ -49,36 +59,17 @@ Todos los ajustes se perderán.</value>
<data name="AskSettingResetTitle" xml:space="preserve">
<value>Reiniciar ajustes</value>
</data>
<data name="AskUpdate" xml:space="preserve">
<value>Descargar OnTopReplica {0}?</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateButtonCancel" xml:space="preserve">
<value>Cancelar actualización
OnTopReplica le preguntará la próxima vez que se ejecute.</value>
</data>
<data name="AskUpdateButtonOk" xml:space="preserve">
<data name="UpdateAvailableCommandOk" xml:space="preserve">
<value>Descargar
Instalar OnTopReplica {0}</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateContent" xml:space="preserve">
<value>La nueva versión puede ser descargada e instalada del sitio oficial.</value>
</data>
<data name="AskUpdateExpanded" xml:space="preserve">
<value>Versión instalada: {0}
Versión disponible: {1}</value>
<comment>{0} installed version number
{1} online available version number</comment>
</data>
<data name="AskUpdateTitle" xml:space="preserve">
<value>Actualización disponible</value>
</data>
<data name="ButtonCancel" xml:space="preserve">
<value>&amp;Cancelar</value>
<comment>&amp; marks the ALT+[] shortcut</comment>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Creado por: Lorenz Cuno Klopfenstein.</value>
<data name="UpdateAvailableCommandCancel" xml:space="preserve">
<value>Cancelar actualización
OnTopReplica le preguntará la próxima vez que se ejecute.</value>
</data>
<data name="DrawRegions" xml:space="preserve">
<value>Crea una región utilizando el ratón.</value>
@ -413,13 +404,11 @@ Se podrá activar Click a través más tarde</value>
<data name="RightClick" xml:space="preserve">
<value>Click derecho para empezar...</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica busca actualizaciones automáticamente.</value>
<data name="UpdateAvailableContent" xml:space="preserve">
<value>La nueva versión puede ser descargada e instalada del sitio oficial.</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Actualizar ahora!</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>Una copia liviana, en tiempo real y siempre encima de cualquier ventana.</value>
<data name="UpdateAvailableExpanded" xml:space="preserve">
<value>Versión instalada: {0}
Versión disponible: {1}</value>
</data>
</root>

View file

@ -12,6 +12,10 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutAuthor" xml:space="preserve">
<value>Creato da: %.</value>
<comment>Link % is replaced by string AboutAuthorContent.</comment>
</data>
<data name="AboutButtonCancelTT" xml:space="preserve">
<value>Annulla il processo di aggiornamento.</value>
</data>
@ -24,11 +28,56 @@
<data name="AboutButtonUpdateTT" xml:space="preserve">
<value>Aggiorna OnTopReplica ora.</value>
</data>
<data name="AboutContribute" xml:space="preserve">
<value>T'interessa partecipare? Ogni aiuto è ben accetto, sia che tu voglia migliorare una traduzione, aggiungerne una nuova oppure dare un'occhiata al % su CodePlex.</value>
</data>
<data name="AboutContributeContent" xml:space="preserve">
<value>codice sorgente</value>
</data>
<data name="AboutCreditsSources" xml:space="preserve">
<value>OnTopReplica è basato sulla libreria WindowsFormsAero ed il codice di altri progetti open-source. %.</value>
<comment>Link % is replaced by string AboutCreditsSourcesContent.</comment>
</data>
<data name="AboutCreditsSourcesContent" xml:space="preserve">
<value>Leggi tutti i riferimenti</value>
</data>
<data name="AboutDividerContribute" xml:space="preserve">
<value>Contribuisci</value>
</data>
<data name="AboutDividerCredits" xml:space="preserve">
<value>Ringraziamenti</value>
</data>
<data name="AboutDividerLicense" xml:space="preserve">
<value>Licenza d'uso</value>
</data>
<data name="AboutDividerUpdates" xml:space="preserve">
<value>Aggiornamenti</value>
</data>
<data name="AboutLicense" xml:space="preserve">
<value>Questa applicazione è rilasciata sotto la licenza %, che rientra nella definizione di "open-source" data dal consorzio OSI.</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>Una copia in tempo reale e sempre in primo piano di una finestra a tua scelta.</value>
</data>
<data name="AboutTitle" xml:space="preserve">
<value>A proposito di OnTopReplica</value>
</data>
<data name="AboutTranslators" xml:space="preserve">
<value>Traduttori: {0}</value>
<comment>{0} translators (do not end with period)</comment>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Controlla!</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica controlla automaticamente la presenza di aggiornamenti ad ogni avvio.</value>
</data>
<data name="AboutVersion" xml:space="preserve">
<value>Versione {0}</value>
</data>
<data name="ApplicationName" xml:space="preserve">
<value>OnTopReplica</value>
<comment>Probably doesn't need localization. :)</comment>
</data>
<data name="AskReset" xml:space="preserve">
<value>Ripristinare completamente la finestra?</value>
@ -52,36 +101,13 @@ Tutte le impostazioni saranno perse.</value>
<data name="AskSettingResetTitle" xml:space="preserve">
<value>Reimposta</value>
</data>
<data name="AskUpdate" xml:space="preserve">
<value>Scaricare OnTopReplica {0}?</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateButtonCancel" xml:space="preserve">
<value>Annulla aggiornamento
OnTopReplica si aggiornerà in un secondo momento.</value>
</data>
<data name="AskUpdateButtonOk" xml:space="preserve">
<value>Continua
Scarica OnTopReplica {0}.</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateContent" xml:space="preserve">
<value>Sarà possibile scaricare la nuova versione ed installarla.</value>
</data>
<data name="AskUpdateExpanded" xml:space="preserve">
<value>Versione installata: {0}
Versione disponibile: {1}</value>
<comment>{0} installed version number
{1} online available version number</comment>
</data>
<data name="AskUpdateTitle" xml:space="preserve">
<value>Aggiornamento disponibile</value>
</data>
<data name="ButtonCancel" xml:space="preserve">
<value>&amp;Annulla</value>
<comment>&amp; marks the ALT+[] shortcut</comment>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Creato da: Lorenz Cuno Klopfenstein.</value>
<data name="UpdateAvailableCommandCancel" xml:space="preserve">
<value>Annulla aggiornamento
OnTopReplica si aggiornerà in un secondo momento.</value>
</data>
<data name="DrawRegions" xml:space="preserve">
<value>Disegna una regione usando il mouse.</value>
@ -284,12 +310,6 @@ Puoi abilitare il Click-Through in futuro</value>
<data name="MenuFitQuarter" xml:space="preserve">
<value>1:4 Quarto</value>
</data>
<data name="SettingsHotKeyDescription" xml:space="preserve">
<value>Queste scorciatoie possono essere usate quando OnTopReplica non è attivo.</value>
</data>
<data name="SettingsHotKeyClone" xml:space="preserve">
<value>Clona finestra corrente</value>
</data>
<data name="MenuGroupSwitch" xml:space="preserve">
<value>Modalità Gruppo di finestre</value>
</data>
@ -335,6 +355,9 @@ Puoi abilitare il Click-Through in futuro</value>
<data name="MenuPosBottomRight" xml:space="preserve">
<value>In basso a destra</value>
</data>
<data name="MenuPosCenter" xml:space="preserve">
<value>Centrato</value>
</data>
<data name="MenuPosDisabled" xml:space="preserve">
<value>Disabilitato</value>
</data>
@ -380,6 +403,18 @@ Puoi abilitare il Click-Through in futuro</value>
<data name="MenuResize" xml:space="preserve">
<value>Ridimensionamento</value>
</data>
<data name="MenuRestoreLast" xml:space="preserve">
<value>Ripristina ultima finestra</value>
</data>
<data name="MenuRestoreLastTT" xml:space="preserve">
<value>Se abilitato, all'avvio OnTopReplica tenterà di ripristinare l'ultima finestra precedentemente clonata.</value>
</data>
<data name="MenuSettings" xml:space="preserve">
<value>Impostazioni...</value>
</data>
<data name="MenuSettingsTT" xml:space="preserve">
<value>Mostra il pannello delle impostazioni.</value>
</data>
<data name="MenuSwitch" xml:space="preserve">
<value>Vai alla finestra originale</value>
</data>
@ -408,7 +443,7 @@ Puoi abilitare il Click-Through in futuro</value>
<value>Chiudi</value>
</data>
<data name="RegionsHeight" xml:space="preserve">
<value>Altezz.</value>
<value>Altezza</value>
</data>
<data name="RegionsResetButton" xml:space="preserve">
<value>Reset</value>
@ -423,19 +458,16 @@ Puoi abilitare il Click-Through in futuro</value>
<value>Regioni:</value>
</data>
<data name="RegionsWidth" xml:space="preserve">
<value>Largh.</value>
<value>Larghezza</value>
</data>
<data name="RightClick" xml:space="preserve">
<value>Clic destro qui per iniziare...</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica controlla automaticamente la presenza di aggiornamenti ad ogni avvio.</value>
<data name="SettingsHotKeyClone" xml:space="preserve">
<value>Clona finestra corrente</value>
</data>
<data name="AboutTitle" xml:space="preserve">
<value>A proposito di OnTopReplica</value>
</data>
<data name="AboutVersion" xml:space="preserve">
<value>Versione {0}</value>
<data name="SettingsHotKeyDescription" xml:space="preserve">
<value>Queste scorciatoie possono essere usate quando OnTopReplica non è attivo.</value>
</data>
<data name="SettingsHotKeyShowHide" xml:space="preserve">
<value>Nascondi</value>
@ -449,61 +481,54 @@ Puoi abilitare il Click-Through in futuro</value>
<data name="SettingsRestartRequired" xml:space="preserve">
<value>Richiede un riavvio.</value>
</data>
<data name="UpdateAvailableCommandOk" xml:space="preserve">
<value>Continua
Scarica OnTopReplica {0}.</value>
</data>
<data name="SettingsTitle" xml:space="preserve">
<value>Impostazioni</value>
</data>
<data name="MenuRestoreLast" xml:space="preserve">
<value>Ripristina ultima finestra</value>
<data name="UpdateAvailableContent" xml:space="preserve">
<value>Sarà possibile scaricare la nuova versione ed installarla.</value>
</data>
<data name="MenuRestoreLastTT" xml:space="preserve">
<value>Se abilitato, all'avvio OnTopReplica tenterà di ripristinare l'ultima finestra precedentemente clonata.</value>
<data name="UpdateAvailableExpanded" xml:space="preserve">
<value>Versione installata: {0}
Versione disponibile: {1}</value>
</data>
<data name="MenuSettings" xml:space="preserve">
<value>Impostazioni...</value>
<data name="UpdateAvailableInstruction" xml:space="preserve">
<value>Disponibile la versione {0}</value>
</data>
<data name="MenuSettingsTT" xml:space="preserve">
<value>Mostra il pannello delle impostazioni.</value>
<data name="UpdateDownloadingContent" xml:space="preserve">
<value>Scaricati {0} byte su {1}.</value>
<comment>{0} downloaded bytes {1} total bytes</comment>
</data>
<data name="MenuPosCenter" xml:space="preserve">
<value>Centrato</value>
<data name="UpdateDownloadingInstruction" xml:space="preserve">
<value>Download in corso...</value>
</data>
<data name="AboutAuthor" xml:space="preserve">
<value>Creato da: %.</value>
<comment>Link % is replaced by string AboutAuthorContent.</comment>
<data name="UpdateInfoContent" xml:space="preserve">
<value>L'ultima versione di OnTopReplica è già installata. Il programma controllo automaticamente la presenza di aggiornamenti ad ogni avvio.
Per tenersi aggiornati sullo sviluppo di OnTopReplica o suggerire miglioramenti, &lt;a href="website"&gt;visitare il sito ufficiale&lt;/a&gt;.</value>
<comment>The website link should be enclosed in &lt;a href="website"&gt;&lt;/a&gt; tags.</comment>
</data>
<data name="AboutCreditsSources" xml:space="preserve">
<value>OnTopReplica è basato sulla libreria WindowsFormsAero ed il codice di altri progetti open-source. %.</value>
<comment>Link % is replaced by string AboutCreditsSourcesContent.</comment>
<data name="UpdateInfoFooter" xml:space="preserve">
<value>Ultima versione stabile rilasciata il {0}.</value>
<comment>{0} last version release date</comment>
</data>
<data name="AboutCreditsSourcesContent" xml:space="preserve">
<value>Leggi tutti i riferimenti</value>
<data name="UpdateInfoInstruction" xml:space="preserve">
<value>OnTopReplica è aggiornato</value>
</data>
<data name="AboutDividerCredits" xml:space="preserve">
<value>Ringraziamenti</value>
<data name="UpdateReadyCommandOk" xml:space="preserve">
<value>Installa
OnTopReplica verrà chiuso e l'aggiornamento sarà installato.</value>
</data>
<data name="AboutDividerUpdates" xml:space="preserve">
<value>Aggiornamenti</value>
<data name="UpdateReadyContent" xml:space="preserve">
<value>La versione {0} di OnTopReplica è pronta ad essere installata sul tuo computer.</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>Una copia in tempo reale e sempre in primo piano di una finestra a tua scelta.</value>
<data name="UpdateReadyInstruction" xml:space="preserve">
<value>Aggiornamento pronto</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Controlla!</value>
</data>
<data name="AboutDividerLicense" xml:space="preserve">
<value>Licenza d'uso</value>
</data>
<data name="AboutLicense" xml:space="preserve">
<value>Questa applicazione è rilasciata sotto la licenza %, che rientra nella definizione di "open-source" data dal consorzio OSI.</value>
</data>
<data name="AboutTranslators" xml:space="preserve">
<value>Traduttori: {0}</value>
<comment>{0} translators</comment>
</data>
<data name="AboutContribute" xml:space="preserve">
<value>T'interessa partecipare? Ogni aiuto è ben accetto, sia che tu voglia migliorare una traduzione, aggiungerne una nuova oppure dare un'occhiata al % su CodePlex.</value>
</data>
<data name="AboutContributeContent" xml:space="preserve">
<value>codice sorgente</value>
<data name="UpdateTitle" xml:space="preserve">
<value>Aggiornamenti di OnTopReplica</value>
</data>
</root>

View file

@ -16,9 +16,6 @@
<value>Autor: %.</value>
<comment>Link % is replaced by string AboutAuthorContent.</comment>
</data>
<data name="AboutAuthorContent" xml:space="preserve">
<value>Lorenz Cuno Klopfenstein</value>
</data>
<data name="AboutButtonCancelTT" xml:space="preserve">
<value>Przerwij proces aktualizacji.</value>
</data>
@ -60,7 +57,8 @@
<value>Aplikacja jest licencjonowana na warunkach licencji %, która spełnia warunki definicji "open-source" definiowane przez OSI.</value>
</data>
<data name="AboutLicenseContent" xml:space="preserve">
<value>Microsoft Reciprocal (MS-RL)</value>
<value />
<comment>Can be left blank.</comment>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>Miniatura "zawsze na wierzchu" przedstawiająca w czasie rzeczywistym podgląd wybranego okna.</value>
@ -70,11 +68,7 @@
</data>
<data name="AboutTranslators" xml:space="preserve">
<value>Tłumaczenie: {0}</value>
<comment>{0} translators</comment>
</data>
<data name="AboutTranslatorsContent" xml:space="preserve">
<value>Christian Olaechea M., Daniel Zeus.EX, Federico Lorenzo, Goran Brecelj, Marco Kraxner, Patrik (batupata), Raúl Morillo, René Mihula, Roberto Leiro, Rodrigo Lourenço, Thomas Amundsen</value>
<comment>Must not be localized. In order to be added, contact author.</comment>
<comment>{0} translators (do not end with period)</comment>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Sprawdź teraz!</value>
@ -87,6 +81,7 @@
</data>
<data name="ApplicationName" xml:space="preserve">
<value>OnTopReplica</value>
<comment>Probably doesn't need localization. :)</comment>
</data>
<data name="AskReset" xml:space="preserve">
<value>Całkowicie zresetować okno?</value>
@ -110,33 +105,9 @@ Wszystkie ustawienia zostaną utracone.</value>
<data name="AskSettingResetTitle" xml:space="preserve">
<value>Zresetuj ustawienia</value>
</data>
<data name="AskUpdate" xml:space="preserve">
<value>Pobrać OnTopReplica {0}?</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateButtonCancel" xml:space="preserve">
<value>Anuluj aktualizację
OnTopReplica zapyta Cię przy następnym uruchomieniu.</value>
</data>
<data name="AskUpdateButtonOk" xml:space="preserve">
<value>Pobierz
Zainstaluj OnTopReplica {0}.</value>
<comment>{0} update version</comment>
</data>
<data name="AskUpdateContent" xml:space="preserve">
<value>Nowa wersja może zostać pobrana i zainstalowana z oficjalnej strony programu.</value>
</data>
<data name="AskUpdateExpanded" xml:space="preserve">
<value>Zainstalowana wersja: {0}
Dostępna wersja: {1}</value>
<comment>{0} installed version number
{1} online available version number</comment>
</data>
<data name="AskUpdateTitle" xml:space="preserve">
<value>Aktualizacja jest dostępna</value>
</data>
<data name="ButtonCancel" xml:space="preserve">
<value>&amp;Anuluj</value>
<comment>&amp; marks the ALT+[] shortcut</comment>
</data>
<data name="DrawRegions" xml:space="preserve">
<value>Utwórz region używając myszy.</value>
@ -510,7 +481,22 @@ Możesz włączyć kliknij-przez później</value>
<data name="SettingsRestartRequired" xml:space="preserve">
<value>Wymaga restartu.</value>
</data>
<data name="UpdateAvailableCommandOk" xml:space="preserve">
<value>Pobierz
Zainstaluj OnTopReplica {0}.</value>
</data>
<data name="UpdateAvailableCommandCancel" xml:space="preserve">
<value>Anuluj aktualizację
OnTopReplica zapyta Cię przy następnym uruchomieniu.</value>
</data>
<data name="SettingsTitle" xml:space="preserve">
<value>Ustawienia</value>
</data>
<data name="UpdateAvailableContent" xml:space="preserve">
<value>Nowa wersja może zostać pobrana i zainstalowana z oficjalnej strony programu.</value>
</data>
<data name="UpdateAvailableExpanded" xml:space="preserve">
<value>Zainstalowana wersja: {0}
Dostępna wersja: {1}</value>
</data>
</root>

View file

@ -12,6 +12,14 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutAuthor" xml:space="preserve">
<value>Created by: %.</value>
<comment>Link % is replaced by string AboutAuthorContent.</comment>
</data>
<data name="AboutAuthorContent" xml:space="preserve">
<value>Lorenz Cuno Klopfenstein</value>
<comment>Must not be localized. Leave blank in non-default languages.</comment>
</data>
<data name="AboutButtonCancelTT" xml:space="preserve">
<value>Abort update process.</value>
</data>
@ -24,8 +32,64 @@
<data name="AboutButtonUpdateTT" xml:space="preserve">
<value>Update OnTopReplica now.</value>
</data>
<data name="AboutContribute" xml:space="preserve">
<value>Care to contribute to the project? You are welcome to improve available translations, start a new one for your native language or to check out the % from CodePlex.</value>
</data>
<data name="AboutContributeContent" xml:space="preserve">
<value>source code</value>
</data>
<data name="AboutCreditsSources" xml:space="preserve">
<value>OnTopReplica is based upon the WindowsFormsAero library and some other libraries and code sources. %.</value>
<comment>Link % is replaced by string AboutCreditsSourcesContent.</comment>
</data>
<data name="AboutCreditsSourcesContent" xml:space="preserve">
<value>Read the full credits</value>
</data>
<data name="AboutDividerContribute" xml:space="preserve">
<value>Contribute</value>
</data>
<data name="AboutDividerCredits" xml:space="preserve">
<value>Credits</value>
</data>
<data name="AboutDividerLicense" xml:space="preserve">
<value>License</value>
</data>
<data name="AboutDividerUpdates" xml:space="preserve">
<value>Updates</value>
</data>
<data name="AboutLicense" xml:space="preserve">
<value>The application is licensed under the % license, which meets the terms of the "open-source" definition specified by OSI.</value>
</data>
<data name="AboutLicenseContent" xml:space="preserve">
<value>Microsoft Reciprocal (MS-RL)</value>
<comment>Can be left blank.</comment>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>A lightweight, real-time, always on top thumbnail of a window of your choice.</value>
</data>
<data name="AboutTitle" xml:space="preserve">
<value>About OnTopReplica</value>
</data>
<data name="AboutTranslators" xml:space="preserve">
<value>Translators: {0}</value>
<comment>{0} translators (do not end with period)</comment>
</data>
<data name="AboutTranslatorsContent" xml:space="preserve">
<value>Christian Olaechea M., Daniel Zeus.EX, Federico Lorenzo, Goran Brecelj, Jan Romanczyk, Marco Kraxner, Patrik (batupata), Raúl Morillo, René Mihula, Roberto Leiro, Rodrigo Lourenço, Thomas Amundsen.</value>
<comment>Must not be localized. Leave blank in non-default languages.</comment>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Check now!</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica automatically checks for updates at every start up.</value>
</data>
<data name="AboutVersion" xml:space="preserve">
<value>Version {0}</value>
</data>
<data name="ApplicationName" xml:space="preserve">
<value>OnTopReplica</value>
<comment>Probably doesn't need localization. :)</comment>
</data>
<data name="AskReset" xml:space="preserve">
<value>Reset window completely?</value>
@ -49,37 +113,26 @@ All settings will be lost.</value>
<data name="AskSettingResetTitle" xml:space="preserve">
<value>Reset settings</value>
</data>
<data name="AskUpdate" xml:space="preserve">
<value>Download OnTopReplica {0}?</value>
<comment>{0} update version</comment>
<data name="UpdateDownloadingContent" xml:space="preserve">
<value>{0}/{1} bytes downloaded.</value>
<comment>{0} downloaded bytes {1} total bytes</comment>
</data>
<data name="AskUpdateButtonCancel" xml:space="preserve">
<value>Cancel update
OnTopReplica will prompt you the next time it is started.</value>
<data name="UpdateAvailableInstruction" xml:space="preserve">
<value>Version {0} available</value>
</data>
<data name="AskUpdateButtonOk" xml:space="preserve">
<value>Download
Install OnTopReplica {0}.</value>
<comment>{0} update version</comment>
<data name="UpdateReadyCommandOk" xml:space="preserve">
<value>Install
OnTopReplica will be closed and the update installed.</value>
</data>
<data name="AskUpdateContent" xml:space="preserve">
<data name="UpdateAvailableContent" xml:space="preserve">
<value>The new version can be downloaded and installed from the official website.</value>
</data>
<data name="AskUpdateExpanded" xml:space="preserve">
<value>Installed version: {0}
Available version: {1}</value>
<comment>{0} installed version number
{1} online available version number</comment>
</data>
<data name="AskUpdateTitle" xml:space="preserve">
<value>Update available</value>
<data name="UpdateReadyContent" xml:space="preserve">
<value>OnTopReplica version {0} is ready to be installed on your computer.</value>
</data>
<data name="ButtonCancel" xml:space="preserve">
<value>&amp;Cancel</value>
</data>
<data name="AboutAuthor" xml:space="preserve">
<value>Created by: %.</value>
<comment>Link % is replaced by string AboutAuthorContent.</comment>
<comment>&amp; marks the ALT+[] shortcut</comment>
</data>
<data name="DrawRegions" xml:space="preserve">
<value>Draw regions using mouse.</value>
@ -375,6 +428,18 @@ You can enable click-through later</value>
<data name="MenuResize" xml:space="preserve">
<value>Resize</value>
</data>
<data name="MenuRestoreLast" xml:space="preserve">
<value>Restore last cloned window</value>
</data>
<data name="MenuRestoreLastTT" xml:space="preserve">
<value>When enabled, OnTopReplica will attempt to restore the last cloned window on start up.</value>
</data>
<data name="MenuSettings" xml:space="preserve">
<value>Settings...</value>
</data>
<data name="MenuSettingsTT" xml:space="preserve">
<value>Displays the settings panel.</value>
</data>
<data name="MenuSwitch" xml:space="preserve">
<value>Switch to window</value>
</data>
@ -423,27 +488,6 @@ You can enable click-through later</value>
<data name="RightClick" xml:space="preserve">
<value>Right-click here to start...</value>
</data>
<data name="AboutSlogan" xml:space="preserve">
<value>A lightweight, real-time, always on top thumbnail of a window of your choice.</value>
</data>
<data name="AboutUpdatesDisclaimer" xml:space="preserve">
<value>OnTopReplica automatically checks for updates at every start up.</value>
</data>
<data name="AboutUpdatesCheckNow" xml:space="preserve">
<value>Check now!</value>
</data>
<data name="MenuSettings" xml:space="preserve">
<value>Settings...</value>
</data>
<data name="MenuSettingsTT" xml:space="preserve">
<value>Displays the settings panel.</value>
</data>
<data name="MenuRestoreLast" xml:space="preserve">
<value>Restore last cloned window</value>
</data>
<data name="MenuRestoreLastTT" xml:space="preserve">
<value>When enabled, OnTopReplica will attempt to restore the last cloned window on start up.</value>
</data>
<data name="SettingsHotKeyClone" xml:space="preserve">
<value>Clone current window</value>
</data>
@ -462,55 +506,41 @@ You can enable click-through later</value>
<data name="SettingsRestartRequired" xml:space="preserve">
<value>Requires a restart.</value>
</data>
<data name="UpdateDownloadingInstruction" xml:space="preserve">
<value>Downloading...</value>
</data>
<data name="UpdateReadyInstruction" xml:space="preserve">
<value>Update ready</value>
</data>
<data name="UpdateAvailableCommandOk" xml:space="preserve">
<value>Download
Install OnTopReplica {0}.</value>
</data>
<data name="UpdateAvailableCommandCancel" xml:space="preserve">
<value>Cancel update
OnTopReplica will prompt you the next time it is started.</value>
</data>
<data name="UpdateInfoInstruction" xml:space="preserve">
<value>OnTopReplica is up to date</value>
</data>
<data name="UpdateInfoFooter" xml:space="preserve">
<value>Latest stable version released on {0}.</value>
<comment>{0} last version release date</comment>
</data>
<data name="UpdateInfoContent" xml:space="preserve">
<value>The latest version of OnTopReplica is already installed. The program automatically checks for updates at every start.
You can keep up to date about OnTopReplica's development, suggest improvements and new features by &lt;a href="website"&gt;visiting the official website&lt;/a&gt;.</value>
<comment>The website link should be enclosed in &lt;a href="website"&gt;&lt;/a&gt; tags.</comment>
</data>
<data name="SettingsTitle" xml:space="preserve">
<value>Settings</value>
</data>
<data name="AboutAuthorContent" xml:space="preserve">
<value>Lorenz Cuno Klopfenstein</value>
<data name="UpdateTitle" xml:space="preserve">
<value>OnTopReplica updates</value>
</data>
<data name="AboutCreditsSources" xml:space="preserve">
<value>OnTopReplica is based upon the WindowsFormsAero library and some other libraries and code sources. %.</value>
<comment>Link % is replaced by string AboutCreditsSourcesContent.</comment>
</data>
<data name="AboutCreditsSourcesContent" xml:space="preserve">
<value>Read the full credits</value>
</data>
<data name="AboutDividerCredits" xml:space="preserve">
<value>Credits</value>
</data>
<data name="AboutDividerUpdates" xml:space="preserve">
<value>Updates</value>
</data>
<data name="AboutTitle" xml:space="preserve">
<value>About OnTopReplica</value>
</data>
<data name="AboutVersion" xml:space="preserve">
<value>Version {0}</value>
</data>
<data name="AboutContribute" xml:space="preserve">
<value>Care to contribute to the project? You are welcome to improve available translations, start a new one for your native language or to check out the % from CodePlex.</value>
</data>
<data name="AboutContributeContent" xml:space="preserve">
<value>source code</value>
</data>
<data name="AboutDividerContribute" xml:space="preserve">
<value>Contribute</value>
</data>
<data name="AboutDividerLicense" xml:space="preserve">
<value>License</value>
</data>
<data name="AboutLicense" xml:space="preserve">
<value>The application is licensed under the % license, which meets the terms of the "open-source" definition specified by OSI.</value>
</data>
<data name="AboutLicenseContent" xml:space="preserve">
<value>Microsoft Reciprocal (MS-RL)</value>
</data>
<data name="AboutTranslators" xml:space="preserve">
<value>Translators: {0}</value>
<comment>{0} translators</comment>
</data>
<data name="AboutTranslatorsContent" xml:space="preserve">
<value>Christian Olaechea M., Daniel Zeus.EX, Federico Lorenzo, Goran Brecelj, Marco Kraxner, Patrik (batupata), Raúl Morillo, René Mihula, Roberto Leiro, Rodrigo Lourenço, Thomas Amundsen.</value>
<comment>Must not be localized. In order to be added, contact author.</comment>
<data name="UpdateAvailableExpanded" xml:space="preserve">
<value>Installed version: {0}
Available version: {1}</value>
</data>
</root>

View file

@ -4,6 +4,7 @@ using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Reflection;
namespace OnTopReplica.Update {
@ -37,6 +38,27 @@ namespace OnTopReplica.Update {
}
}
/// <summary>
/// Returns whether this update information instance represents data about
/// a new available version.
/// </summary>
public bool IsNewVersion {
get {
var currentVersion = CurrentVersion;
return (LatestVersion > currentVersion);
}
}
/// <summary>
/// Gets the currently installed version.
/// </summary>
public Version CurrentVersion {
get {
return Assembly.GetExecutingAssembly().GetName().Version;
}
}
/// <summary>
/// Indicates when the latest version was released.
/// </summary>
@ -49,6 +71,13 @@ namespace OnTopReplica.Update {
[XmlElement("downloadPage")]
public string DownloadPage { get; set; }
/// <summary>
/// Gets the URL of the installer executable.
/// </summary>
/// <remarks>New after version 3.3.1.</remarks>
[XmlElement("downloadInstaller")]
public string DownloadInstaller { get; set; }
/// <summary>
/// Deserializes an UpdateInformation object from a stream.
/// </summary>

View file

@ -1,43 +1,87 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Net.Cache;
using System.IO;
using System.Reflection;
using VistaControls.TaskDialog;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Cache;
using System.Windows.Forms;
using System.Threading;
using VistaControls.TaskDialog;
namespace OnTopReplica.Update {
/// <summary>
/// Handles update checking and information display.
/// </summary>
class UpdateManager {
/// <summary>
/// Constructs a new update manager with an attached form.
/// </summary>
/// <param name="attachedForm">Form through which all GUI calls are made. Closing this form should terminate the application.</param>
public UpdateManager(Form attachedForm) {
if (attachedForm == null)
throw new ArgumentNullException();
AttachedForm = attachedForm;
}
/// <summary>
/// Gets or sets the attached form (through which all GUI calls are made).
/// </summary>
protected Form AttachedForm { get; private set; }
#region Checking
const string UpdateManifestUrl = "http://www.klopfenstein.net/public/Uploads/ontopreplica/update.xml";
/// <summary>
/// Gets the latest update information available.
/// </summary>
public UpdateInformation LastInformation { get; private set; }
HttpWebRequest _checkRequest;
/// <summary>
/// Checks for update asynchronously, updating update information.
/// When check is completed, raises update events.
/// </summary>
public void CheckForUpdate() {
ThreadPool.QueueUserWorkItem(new WaitCallback(o => {
//Build web request
var request = (HttpWebRequest)HttpWebRequest.Create(UpdateManifestUrl);
request.AllowAutoRedirect = true;
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
if (_checkRequest != null) {
_checkRequest.Abort();
}
try {
//Begin request
var response = request.GetResponse();
var info = UpdateInformation.Deserialize(response.GetResponseStream());
//Build web request
_checkRequest = (HttpWebRequest)HttpWebRequest.Create(UpdateManifestUrl);
_checkRequest.AllowAutoRedirect = true;
_checkRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
_checkRequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
OnUpdateCheckSuccess(info);
}
catch (Exception ex) {
OnUpdateCheckError(ex);
return;
}
}));
_checkRequest.BeginGetResponse(CheckForUpdateCallback, null);
}
/// <summary>
/// Asynchronous callback that handles the update check request.
/// </summary>
private void CheckForUpdateCallback(IAsyncResult result) {
if (_checkRequest == null)
return;
try {
var response = _checkRequest.EndGetResponse(result);
LastInformation = UpdateInformation.Deserialize(response.GetResponseStream());
OnUpdateCheckSuccess(LastInformation);
}
catch (Exception ex) {
OnUpdateCheckError(ex);
}
_checkRequest = null;
}
#endregion
#region Eventing
public event EventHandler<UpdateCheckCompletedEventArgs> UpdateCheckCompleted;
protected virtual void OnUpdateCheckError(Exception ex) {
@ -60,47 +104,175 @@ namespace OnTopReplica.Update {
}
}
#endregion
#region Updating
HttpWebRequest _downloadRequest;
TaskDialog _updateDialog;
bool _updateDownloaded = false;
/// <summary>
/// Handles the results of an update check. Must be called from main GUI thread.
/// Asks confirmation for an update and installs the update.
/// </summary>
/// <param name="information">The retrieved update information.</param>
/// <param name="verbose">Determines if the lack of updates should be notified to the user.</param>
public void HandleUpdateCheck(Form parent, UpdateInformation information, bool verbose) {
if (information == null)
public void ConfirmAndInstall() {
if (LastInformation == null || !LastInformation.IsNewVersion)
return;
var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
AttachedForm.SafeInvoke(new Action(ConfirmAndInstallCore));
}
if (information.LatestVersion > currentVersion) {
//New version found
var dlg = new TaskDialog(
string.Format(Strings.AskUpdate, information.LatestVersion),
Strings.AskUpdateTitle,
Strings.AskUpdateContent) {
CustomButtons = new CustomButton[] {
new CustomButton(Result.OK, string.Format(Strings.AskUpdateButtonOk, information.LatestVersion)),
new CustomButton(Result.Cancel, Strings.AskUpdateButtonCancel)
},
UseCommandLinks = true,
CommonIcon = TaskDialogIcon.Information,
ExpandedInformation = string.Format(Strings.AskUpdateExpanded, currentVersion, information.LatestVersion)
};
if (dlg.Show(parent).CommonButton == Result.OK) {
Process.Start(information.DownloadPage);
/// <summary>
/// Core delegate that asks for update confirmation and installs. Must be called from GUI thread.
/// </summary>
private void ConfirmAndInstallCore() {
_updateDialog = new TaskDialog {
Title = Strings.UpdateTitle,
Instruction = string.Format(Strings.UpdateAvailableInstruction, LastInformation.LatestVersion),
Content = Strings.UpdateAvailableContent,
CustomButtons = new CustomButton[] {
new CustomButton(Result.OK, string.Format(Strings.UpdateAvailableCommandOk, LastInformation.LatestVersion)),
new CustomButton(Result.Cancel, Strings.UpdateAvailableCommandCancel)
},
UseCommandLinks = true,
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);
}
}
}
else if(verbose) {
//No updates, but need to inform the user
var dlg = new TaskDialog(Strings.InfoUpToDate, Strings.InfoUpToDateTitle) {
CommonButtons = TaskDialogButton.OK,
CommonIcon = TaskDialogIcon.Information,
//Footer = information.LatestVersion.ToString()
};
dlg.Show();
};
_updateDialog.Show(AttachedForm);
}
/// <summary>
/// Gets the target filename used when downloading the update from the Internet.
/// </summary>
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);
}
}
/// <summary>
/// Handles background downloading.
/// </summary>
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 = VistaControls.ProgressBar.States.Error;
_updateDialog.Content = msg;
}
/// <summary>
/// Displays some information about the current installation and available updates.
/// </summary>
public void DisplayInfo() {
AttachedForm.SafeInvoke(new Action(DisplayInfoCore));
}
/// <summary>
/// Displays info. Called from GUI thread.
/// </summary>
private void DisplayInfoCore() {
//No updates, but need to inform the user
var dlg = new TaskDialog {
Title = Strings.UpdateTitle,
Instruction = Strings.UpdateInfoInstruction,
Content = Strings.UpdateInfoContent,
EnableHyperlinks = true,
CommonButtons = TaskDialogButton.Close,
AllowDialogCancellation = true,
CommonIcon = TaskDialogIcon.Information,
Footer = string.Format(Strings.UpdateInfoFooter, LastInformation.LatestVersionRelease.ToLongDateString())
};
dlg.HyperlinkClick += delegate(object sender, HyperlinkEventArgs args) {
Process.Start("http://ontopreplica.codeplex.com");
};
dlg.Show(AttachedForm);
}
#endregion
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace OnTopReplica {
/// <summary>
/// Extension methods for windows forms.
/// </summary>
static class WindowsFormsExtensions {
/// <summary>
/// Internationalizes the text of a LinkLabel instance.
/// </summary>
/// <param name="text">Main text without link. Contains a '%' character which will be replaced by the link.</param>
/// <param name="linkText">Linked text.</param>
public static void Internationalize(this LinkLabel label, string text, string linkText) {
int linkIndex = text.IndexOf('%');
if (linkIndex == -1) {
//Shouldn't happen, but try to fail with meaningful text
label.Text = text;
return;
}
label.Text = text.Substring(0, linkIndex) + linkText + text.Substring(linkIndex + 1);
label.LinkArea = new LinkArea(linkIndex, linkText.Length);
}
/// <summary>
/// Makes a safe GUI invoke on a form's GUI thread.
/// </summary>
/// <param name="action">The action to be executed on the GUI's thread.</param>
/// <remarks>
/// If the form is invalid or disposed, the action is not performed.
/// </remarks>
public static void SafeInvoke(this Form form, Action action) {
if (form == null || form.IsDisposed)
return;
if (form.InvokeRequired) {
form.Invoke(action);
}
else {
action();
}
}
}
}