Browse Source

add onlineConfigForm

tags/4.2.1.0
Student Main 4 years ago
parent
commit
1287b57410
No known key found for this signature in database GPG Key ID: AA78519C208C8742
6 changed files with 713 additions and 236 deletions
  1. +6
    -0
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  2. +295
    -236
      shadowsocks-csharp/View/MenuViewController.cs
  3. +207
    -0
      shadowsocks-csharp/View/OnlineConfigForm.Designer.cs
  4. +76
    -0
      shadowsocks-csharp/View/OnlineConfigForm.cs
  5. +120
    -0
      shadowsocks-csharp/View/OnlineConfigForm.resx
  6. +9
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 6
- 0
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -717,6 +717,12 @@ namespace Shadowsocks.Controller
Configuration.Save(_config);
}
public void SaveOnlineConfigSource(IEnumerable<string> vs)
{
_config.onlineConfigSource = vs.ToList();
SaveConfig(_config);
}
#endregion
}
}

+ 295
- 236
shadowsocks-csharp/View/MenuViewController.cs View File

@@ -57,13 +57,13 @@ namespace Shadowsocks.View
private MenuItem VerboseLoggingToggleItem;
private MenuItem ShowPluginOutputToggleItem;
private MenuItem WriteI18NFileItem;
private MenuItem onlineConfigItem;
private ConfigForm configForm;
private ProxyForm proxyForm;
private LogForm logForm;
private HotkeySettingsForm hotkeySettingsForm;
private OnlineConfigForm onlineConfigForm;
// color definition for icon color transformation
private readonly Color colorMaskBlue = Color.FromArgb(255, 25, 125, 191);
@@ -118,37 +118,6 @@ namespace Shadowsocks.View
}
}
private void controller_TrafficChanged(object sender, EventArgs e)
{
if (icon == null)
return;
Icon newIcon;
bool hasInbound = controller.trafficPerSecondQueue.Last().inboundIncreasement > 0;
bool hasOutbound = controller.trafficPerSecondQueue.Last().outboundIncreasement > 0;
if (hasInbound && hasOutbound)
newIcon = icon_both;
else if (hasInbound)
newIcon = icon_in;
else if (hasOutbound)
newIcon = icon_out;
else
newIcon = icon;
if (newIcon != this.previousIcon)
{
this.previousIcon = newIcon;
_notifyIcon.Icon = newIcon;
}
}
void controller_Errored(object sender, System.IO.ErrorEventArgs e)
{
MessageBox.Show(e.GetException().ToString(), I18N.GetString("Shadowsocks Error: {0}", e.GetException().Message));
}
#region Tray Icon
private void UpdateTrayIconAndNotifyText()
@@ -269,8 +238,6 @@ namespace Shadowsocks.View
icon_both = Icon.FromHandle(ViewUtils.ResizeBitmap(ViewUtils.AddBitmapOverlay(iconBitmap, Resources.ss32In, Resources.ss32Out), size.Width, size.Height).GetHicon());
}
#endregion
#region MenuItems and MenuGroups
@@ -314,6 +281,7 @@ namespace Shadowsocks.View
this.editOnlinePACItem = CreateMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)),
}),
this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)),
this.onlineConfigItem = CreateMenuItem("Online Config...", new EventHandler(this.OnlineConfig_Click)),
new MenuItem("-"),
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
this.ProtocolHandlerItem = CreateMenuItem("Associate ss:// Links", new EventHandler(this.ProtocolHandlerItem_Click)),
@@ -340,99 +308,41 @@ namespace Shadowsocks.View
#endregion
private void controller_ConfigChanged(object sender, EventArgs e)
{
LoadCurrentConfiguration();
UpdateTrayIconAndNotifyText();
}
private void controller_EnableStatusChanged(object sender, EventArgs e)
{
disableItem.Checked = !controller.GetConfigurationCopy().enabled;
}
void controller_ShareOverLANStatusChanged(object sender, EventArgs e)
{
ShareOverLANItem.Checked = controller.GetConfigurationCopy().shareOverLan;
}
void controller_VerboseLoggingStatusChanged(object sender, EventArgs e)
{
VerboseLoggingToggleItem.Checked = controller.GetConfigurationCopy().isVerboseLogging;
}
void controller_ShowPluginOutputChanged(object sender, EventArgs e)
{
ShowPluginOutputToggleItem.Checked = controller.GetConfigurationCopy().showPluginOutput;
}
void controller_EnableGlobalChanged(object sender, EventArgs e)
{
globalModeItem.Checked = controller.GetConfigurationCopy().global;
PACModeItem.Checked = !globalModeItem.Checked;
}
void controller_FileReadyToOpen(object sender, ShadowsocksController.PathEventArgs e)
private void controller_TrafficChanged(object sender, EventArgs e)
{
string argument = @"/select, " + e.Path;
Process.Start("explorer.exe", argument);
}
if (icon == null)
return;
void ShowBalloonTip(string title, string content, ToolTipIcon icon, int timeout)
{
_notifyIcon.BalloonTipTitle = title;
_notifyIcon.BalloonTipText = content;
_notifyIcon.BalloonTipIcon = icon;
_notifyIcon.ShowBalloonTip(timeout);
}
Icon newIcon;
void controller_UpdatePACFromGeositeError(object sender, System.IO.ErrorEventArgs e)
{
ShowBalloonTip(I18N.GetString("Failed to update PAC file"), e.GetException().Message, ToolTipIcon.Error, 5000);
logger.LogUsefulException(e.GetException());
}
bool hasInbound = controller.trafficPerSecondQueue.Last().inboundIncreasement > 0;
bool hasOutbound = controller.trafficPerSecondQueue.Last().outboundIncreasement > 0;
void controller_UpdatePACFromGeositeCompleted(object sender, GeositeResultEventArgs e)
{
string result = e.Success
? I18N.GetString("PAC updated")
: I18N.GetString("No updates found. Please report to Geosite if you have problems with it.");
ShowBalloonTip(I18N.GetString("Shadowsocks"), result, ToolTipIcon.Info, 1000);
}
if (hasInbound && hasOutbound)
newIcon = icon_both;
else if (hasInbound)
newIcon = icon_in;
else if (hasOutbound)
newIcon = icon_out;
else
newIcon = icon;
void updateChecker_CheckUpdateCompleted(object sender, EventArgs e)
{
if (updateChecker.NewVersionFound)
{
ShowBalloonTip(I18N.GetString("Shadowsocks {0} Update Found", updateChecker.LatestVersionNumber + updateChecker.LatestVersionSuffix), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000);
}
else if (!_isStartupChecking)
if (newIcon != this.previousIcon)
{
ShowBalloonTip(I18N.GetString("Shadowsocks"), I18N.GetString("No update is available"), ToolTipIcon.Info, 5000);
this.previousIcon = newIcon;
_notifyIcon.Icon = newIcon;
}
_isStartupChecking = false;
}
void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
void controller_Errored(object sender, System.IO.ErrorEventArgs e)
{
if (updateChecker.NewVersionFound)
{
updateChecker.NewVersionFound = false; /* Reset the flag */
if (File.Exists(updateChecker.LatestVersionLocalName))
{
string argument = "/select, \"" + updateChecker.LatestVersionLocalName + "\"";
Process.Start("explorer.exe", argument);
}
}
MessageBox.Show(e.GetException().ToString(), I18N.GetString("Shadowsocks Error: {0}", e.GetException().Message));
}
private void _notifyIcon_BalloonTipClosed(object sender, EventArgs e)
private void controller_ConfigChanged(object sender, EventArgs e)
{
if (updateChecker.NewVersionFound)
{
updateChecker.NewVersionFound = false; /* Reset the flag */
}
LoadCurrentConfiguration();
UpdateTrayIconAndNotifyText();
}
private void LoadCurrentConfiguration()
@@ -452,48 +362,7 @@ namespace Shadowsocks.View
UpdateUpdateMenu();
}
private void UpdateServersMenu()
{
var items = ServersItem.MenuItems;
while (items[0] != SeperatorItem)
{
items.RemoveAt(0);
}
int strategyCount = 0;
foreach (var strategy in controller.GetStrategies())
{
MenuItem item = new MenuItem(strategy.Name);
item.Tag = strategy.ID;
item.Click += AStrategyItem_Click;
items.Add(strategyCount, item);
strategyCount++;
}
// user wants a seperator item between strategy and servers menugroup
items.Add(strategyCount++, new MenuItem("-"));
int serverCount = 0;
Configuration configuration = controller.GetConfigurationCopy();
foreach (var server in configuration.configs)
{
if (Configuration.ChecksServer(server))
{
MenuItem item = new MenuItem(server.ToString());
item.Tag = configuration.configs.FindIndex(s => s == server);
item.Click += AServerItem_Click;
items.Add(strategyCount + serverCount, item);
serverCount++;
}
}
foreach (MenuItem item in items)
{
if (item.Tag != null && (item.Tag.ToString() == configuration.index.ToString() || item.Tag.ToString() == configuration.strategy))
{
item.Checked = true;
}
}
}
#region Forms
private void ShowConfigForm()
{
@@ -555,6 +424,22 @@ namespace Shadowsocks.View
}
}
private void ShowOnlineConfigForm()
{
if (onlineConfigForm != null)
{
onlineConfigForm.Activate();
}
else
{
onlineConfigForm = new OnlineConfigForm(controller);
onlineConfigForm.Show();
onlineConfigForm.Activate();
onlineConfigForm.FormClosed += onlineConfigForm_FormClosed;
}
}
void logForm_FormClosed(object sender, FormClosedEventArgs e)
{
logForm.Dispose();
@@ -594,29 +479,44 @@ namespace Shadowsocks.View
Utils.ReleaseMemory(true);
}
private void Config_Click(object sender, EventArgs e)
void onlineConfigForm_FormClosed(object sender, FormClosedEventArgs e)
{
ShowConfigForm();
onlineConfigForm.Dispose();
onlineConfigForm = null;
Utils.ReleaseMemory(true);
}
private void Quit_Click(object sender, EventArgs e)
#endregion
#region Misc
void ShowBalloonTip(string title, string content, ToolTipIcon icon, int timeout)
{
controller.Stop();
_notifyIcon.Visible = false;
Application.Exit();
_notifyIcon.BalloonTipTitle = title;
_notifyIcon.BalloonTipText = content;
_notifyIcon.BalloonTipIcon = icon;
_notifyIcon.ShowBalloonTip(timeout);
}
private void CheckUpdateForFirstRun()
void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
{
Configuration config = controller.GetConfigurationCopy();
if (config.isDefault) return;
_isStartupChecking = true;
updateChecker.CheckUpdate(config, 3000);
if (updateChecker.NewVersionFound)
{
updateChecker.NewVersionFound = false; /* Reset the flag */
if (File.Exists(updateChecker.LatestVersionLocalName))
{
string argument = "/select, \"" + updateChecker.LatestVersionLocalName + "\"";
Process.Start("explorer.exe", argument);
}
}
}
private void AboutItem_Click(object sender, EventArgs e)
private void _notifyIcon_BalloonTipClosed(object sender, EventArgs e)
{
Process.Start("https://github.com/shadowsocks/shadowsocks-windows");
if (updateChecker.NewVersionFound)
{
updateChecker.NewVersionFound = false; /* Reset the flag */
}
}
private void notifyIcon1_Click(object sender, MouseEventArgs e)
@@ -636,6 +536,85 @@ namespace Shadowsocks.View
}
}
private void CheckUpdateForFirstRun()
{
Configuration config = controller.GetConfigurationCopy();
if (config.isDefault) return;
_isStartupChecking = true;
updateChecker.CheckUpdate(config, 3000);
}
public void ShowLogForm_HotKey()
{
ShowLogForm();
}
#endregion
#region Main menu
void controller_ShareOverLANStatusChanged(object sender, EventArgs e)
{
ShareOverLANItem.Checked = controller.GetConfigurationCopy().shareOverLan;
}
private void proxyItem_Click(object sender, EventArgs e)
{
ShowProxyForm();
}
private void OnlineConfig_Click(object sender, EventArgs e)
{
ShowOnlineConfigForm();
}
private void hotKeyItem_Click(object sender, EventArgs e)
{
ShowHotKeySettingsForm();
}
private void ShareOverLANItem_Click(object sender, EventArgs e)
{
ShareOverLANItem.Checked = !ShareOverLANItem.Checked;
controller.ToggleShareOverLAN(ShareOverLANItem.Checked);
}
private void AutoStartupItem_Click(object sender, EventArgs e)
{
AutoStartupItem.Checked = !AutoStartupItem.Checked;
if (!AutoStartup.Set(AutoStartupItem.Checked))
{
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
LoadCurrentConfiguration();
}
private void ProtocolHandlerItem_Click(object sender, EventArgs e)
{
ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked;
if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked))
{
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
LoadCurrentConfiguration();
}
private void Quit_Click(object sender, EventArgs e)
{
controller.Stop();
_notifyIcon.Visible = false;
Application.Exit();
}
#endregion
#region System proxy
private void controller_EnableStatusChanged(object sender, EventArgs e)
{
disableItem.Checked = !controller.GetConfigurationCopy().enabled;
}
private void EnableItem_Click(object sender, EventArgs e)
{
controller.ToggleEnable(false);
@@ -643,6 +622,12 @@ namespace Shadowsocks.View
UpdateSystemProxyItemsEnabledStatus(config);
}
void controller_EnableGlobalChanged(object sender, EventArgs e)
{
globalModeItem.Checked = controller.GetConfigurationCopy().global;
PACModeItem.Checked = !globalModeItem.Checked;
}
private void UpdateSystemProxyItemsEnabledStatus(Configuration config)
{
disableItem.Checked = !config.enabled;
@@ -674,25 +659,51 @@ namespace Shadowsocks.View
UpdateSystemProxyItemsEnabledStatus(config);
}
private void ShareOverLANItem_Click(object sender, EventArgs e)
{
ShareOverLANItem.Checked = !ShareOverLANItem.Checked;
controller.ToggleShareOverLAN(ShareOverLANItem.Checked);
}
#endregion
private void EditPACFileItem_Click(object sender, EventArgs e)
{
controller.TouchPACFile();
}
#region Server
private async void UpdatePACFromGeositeItem_Click(object sender, EventArgs e)
private void UpdateServersMenu()
{
await GeositeUpdater.UpdatePACFromGeosite();
}
var items = ServersItem.MenuItems;
while (items[0] != SeperatorItem)
{
items.RemoveAt(0);
}
int strategyCount = 0;
foreach (var strategy in controller.GetStrategies())
{
MenuItem item = new MenuItem(strategy.Name);
item.Tag = strategy.ID;
item.Click += AStrategyItem_Click;
items.Add(strategyCount, item);
strategyCount++;
}
private void EditUserRuleFileForGeositeItem_Click(object sender, EventArgs e)
{
controller.TouchUserRuleFile();
// user wants a seperator item between strategy and servers menugroup
items.Add(strategyCount++, new MenuItem("-"));
int serverCount = 0;
Configuration configuration = controller.GetConfigurationCopy();
foreach (var server in configuration.configs)
{
if (Configuration.ChecksServer(server))
{
MenuItem item = new MenuItem(server.ToString());
item.Tag = configuration.configs.FindIndex(s => s == server);
item.Click += AServerItem_Click;
items.Add(strategyCount + serverCount, item);
serverCount++;
}
}
foreach (MenuItem item in items)
{
if (item.Tag != null && (item.Tag.ToString() == configuration.index.ToString() || item.Tag.ToString() == configuration.strategy))
{
item.Checked = true;
}
}
}
private void AServerItem_Click(object sender, EventArgs e)
@@ -707,21 +718,19 @@ namespace Shadowsocks.View
controller.SelectStrategy((string)item.Tag);
}
private void VerboseLoggingToggleItem_Click(object sender, EventArgs e)
private void Config_Click(object sender, EventArgs e)
{
VerboseLoggingToggleItem.Checked = !VerboseLoggingToggleItem.Checked;
controller.ToggleVerboseLogging(VerboseLoggingToggleItem.Checked);
ShowConfigForm();
}
private void ShowPluginOutputToggleItem_Click(object sender, EventArgs e)
void splash_FormClosed(object sender, FormClosedEventArgs e)
{
ShowPluginOutputToggleItem.Checked = !ShowPluginOutputToggleItem.Checked;
controller.ToggleShowPluginOutput(ShowPluginOutputToggleItem.Checked);
ShowConfigForm();
}
private void WriteI18NFileItem_Click(object sender, EventArgs e)
void openURLFromQRCode(object sender, FormClosedEventArgs e)
{
File.WriteAllText(I18N.I18N_FILE, Resources.i18n_csv, Encoding.UTF8);
Process.Start(_urlToOpen);
}
private void StatisticsConfigItem_Click(object sender, EventArgs e)
@@ -830,34 +839,9 @@ namespace Shadowsocks.View
}
}
void splash_FormClosed(object sender, FormClosedEventArgs e)
{
ShowConfigForm();
}
void openURLFromQRCode(object sender, FormClosedEventArgs e)
{
Process.Start(_urlToOpen);
}
#endregion
private void AutoStartupItem_Click(object sender, EventArgs e)
{
AutoStartupItem.Checked = !AutoStartupItem.Checked;
if (!AutoStartup.Set(AutoStartupItem.Checked))
{
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
LoadCurrentConfiguration();
}
private void ProtocolHandlerItem_Click(object sender, EventArgs e)
{
ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked;
if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked))
{
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
LoadCurrentConfiguration();
}
#region PAC
private void LocalPACItem_Click(object sender, EventArgs e)
{
@@ -930,6 +914,94 @@ namespace Shadowsocks.View
}
}
private void EditPACFileItem_Click(object sender, EventArgs e)
{
controller.TouchPACFile();
}
private async void UpdatePACFromGeositeItem_Click(object sender, EventArgs e)
{
await GeositeUpdater.UpdatePACFromGeosite();
}
private void EditUserRuleFileForGeositeItem_Click(object sender, EventArgs e)
{
controller.TouchUserRuleFile();
}
void controller_FileReadyToOpen(object sender, ShadowsocksController.PathEventArgs e)
{
string argument = @"/select, " + e.Path;
Process.Start("explorer.exe", argument);
}
void controller_UpdatePACFromGeositeError(object sender, System.IO.ErrorEventArgs e)
{
ShowBalloonTip(I18N.GetString("Failed to update PAC file"), e.GetException().Message, ToolTipIcon.Error, 5000);
logger.LogUsefulException(e.GetException());
}
void controller_UpdatePACFromGeositeCompleted(object sender, GeositeResultEventArgs e)
{
string result = e.Success
? I18N.GetString("PAC updated")
: I18N.GetString("No updates found. Please report to Geosite if you have problems with it.");
ShowBalloonTip(I18N.GetString("Shadowsocks"), result, ToolTipIcon.Info, 1000);
}
#endregion
#region Help
void controller_VerboseLoggingStatusChanged(object sender, EventArgs e)
{
VerboseLoggingToggleItem.Checked = controller.GetConfigurationCopy().isVerboseLogging;
}
void controller_ShowPluginOutputChanged(object sender, EventArgs e)
{
ShowPluginOutputToggleItem.Checked = controller.GetConfigurationCopy().showPluginOutput;
}
private void VerboseLoggingToggleItem_Click(object sender, EventArgs e)
{
VerboseLoggingToggleItem.Checked = !VerboseLoggingToggleItem.Checked;
controller.ToggleVerboseLogging(VerboseLoggingToggleItem.Checked);
}
private void ShowLogItem_Click(object sender, EventArgs e)
{
ShowLogForm();
}
private void ShowPluginOutputToggleItem_Click(object sender, EventArgs e)
{
ShowPluginOutputToggleItem.Checked = !ShowPluginOutputToggleItem.Checked;
controller.ToggleShowPluginOutput(ShowPluginOutputToggleItem.Checked);
}
private void WriteI18NFileItem_Click(object sender, EventArgs e)
{
File.WriteAllText(I18N.I18N_FILE, Resources.i18n_csv, Encoding.UTF8);
}
#endregion
#region Update
void updateChecker_CheckUpdateCompleted(object sender, EventArgs e)
{
if (updateChecker.NewVersionFound)
{
ShowBalloonTip(I18N.GetString("Shadowsocks {0} Update Found", updateChecker.LatestVersionNumber + updateChecker.LatestVersionSuffix), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000);
}
else if (!_isStartupChecking)
{
ShowBalloonTip(I18N.GetString("Shadowsocks"), I18N.GetString("No update is available"), ToolTipIcon.Info, 5000);
}
_isStartupChecking = false;
}
private void UpdateUpdateMenu()
{
@@ -957,24 +1029,11 @@ namespace Shadowsocks.View
updateChecker.CheckUpdate(controller.GetConfigurationCopy());
}
private void proxyItem_Click(object sender, EventArgs e)
{
ShowProxyForm();
}
private void hotKeyItem_Click(object sender, EventArgs e)
{
ShowHotKeySettingsForm();
}
private void ShowLogItem_Click(object sender, EventArgs e)
private void AboutItem_Click(object sender, EventArgs e)
{
ShowLogForm();
Process.Start("https://github.com/shadowsocks/shadowsocks-windows");
}
public void ShowLogForm_HotKey()
{
ShowLogForm();
}
#endregion
}
}

+ 207
- 0
shadowsocks-csharp/View/OnlineConfigForm.Designer.cs View File

@@ -0,0 +1,207 @@
namespace Shadowsocks.View
{
partial class OnlineConfigForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.UrlListBox = new System.Windows.Forms.ListBox();
this.label1 = new System.Windows.Forms.Label();
this.UrlTextBox = new System.Windows.Forms.TextBox();
this.UpdateButton = new System.Windows.Forms.Button();
this.AddButton = new System.Windows.Forms.Button();
this.DeleteButton = new System.Windows.Forms.Button();
this.UpdateAllButton = new System.Windows.Forms.Button();
this.OkButton = new System.Windows.Forms.Button();
this.CancelButton = new System.Windows.Forms.Button();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.Controls.Add(this.UrlListBox, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.UrlTextBox, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.UpdateButton, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.AddButton, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.DeleteButton, 2, 2);
this.tableLayoutPanel1.Controls.Add(this.OkButton, 1, 3);
this.tableLayoutPanel1.Controls.Add(this.UpdateAllButton, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.CancelButton, 2, 3);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 4;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(488, 465);
this.tableLayoutPanel1.TabIndex = 0;
//
// UrlListBox
//
this.tableLayoutPanel1.SetColumnSpan(this.UrlListBox, 3);
this.UrlListBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.UrlListBox.FormattingEnabled = true;
this.UrlListBox.ItemHeight = 15;
this.UrlListBox.Location = new System.Drawing.Point(3, 3);
this.UrlListBox.Name = "UrlListBox";
this.UrlListBox.Size = new System.Drawing.Size(482, 344);
this.UrlListBox.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(3, 350);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(156, 31);
this.label1.TabIndex = 1;
this.label1.Text = "Online config URL";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// UrlTextBox
//
this.tableLayoutPanel1.SetColumnSpan(this.UrlTextBox, 2);
this.UrlTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.UrlTextBox.Location = new System.Drawing.Point(165, 353);
this.UrlTextBox.Name = "UrlTextBox";
this.UrlTextBox.Size = new System.Drawing.Size(320, 25);
this.UrlTextBox.TabIndex = 2;
//
// UpdateButton
//
this.UpdateButton.Dock = System.Windows.Forms.DockStyle.Fill;
this.UpdateButton.Location = new System.Drawing.Point(20, 386);
this.UpdateButton.Margin = new System.Windows.Forms.Padding(20, 5, 20, 5);
this.UpdateButton.MaximumSize = new System.Drawing.Size(0, 32);
this.UpdateButton.MinimumSize = new System.Drawing.Size(0, 32);
this.UpdateButton.Name = "UpdateButton";
this.UpdateButton.Size = new System.Drawing.Size(122, 32);
this.UpdateButton.TabIndex = 3;
this.UpdateButton.Text = "Update";
this.UpdateButton.UseVisualStyleBackColor = true;
//
// AddButton
//
this.AddButton.Dock = System.Windows.Forms.DockStyle.Fill;
this.AddButton.Location = new System.Drawing.Point(182, 386);
this.AddButton.Margin = new System.Windows.Forms.Padding(20, 5, 20, 5);
this.AddButton.MaximumSize = new System.Drawing.Size(0, 32);
this.AddButton.MinimumSize = new System.Drawing.Size(0, 32);
this.AddButton.Name = "AddButton";
this.AddButton.Size = new System.Drawing.Size(122, 32);
this.AddButton.TabIndex = 4;
this.AddButton.Text = "Add";
this.AddButton.UseVisualStyleBackColor = true;
this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
//
// DeleteButton
//
this.DeleteButton.Dock = System.Windows.Forms.DockStyle.Fill;
this.DeleteButton.Location = new System.Drawing.Point(344, 386);
this.DeleteButton.Margin = new System.Windows.Forms.Padding(20, 5, 20, 5);
this.DeleteButton.MaximumSize = new System.Drawing.Size(0, 32);
this.DeleteButton.MinimumSize = new System.Drawing.Size(0, 32);
this.DeleteButton.Name = "DeleteButton";
this.DeleteButton.Size = new System.Drawing.Size(124, 32);
this.DeleteButton.TabIndex = 5;
this.DeleteButton.Text = "Delete";
this.DeleteButton.UseVisualStyleBackColor = true;
//
// UpdateAllButton
//
this.UpdateAllButton.Dock = System.Windows.Forms.DockStyle.Fill;
this.UpdateAllButton.Location = new System.Drawing.Point(20, 428);
this.UpdateAllButton.Margin = new System.Windows.Forms.Padding(20, 5, 20, 5);
this.UpdateAllButton.MaximumSize = new System.Drawing.Size(0, 32);
this.UpdateAllButton.MinimumSize = new System.Drawing.Size(0, 32);
this.UpdateAllButton.Name = "UpdateAllButton";
this.UpdateAllButton.Size = new System.Drawing.Size(122, 32);
this.UpdateAllButton.TabIndex = 6;
this.UpdateAllButton.Text = "Update all";
this.UpdateAllButton.UseVisualStyleBackColor = true;
//
// OkButton
//
this.OkButton.Dock = System.Windows.Forms.DockStyle.Fill;
this.OkButton.Location = new System.Drawing.Point(182, 428);
this.OkButton.Margin = new System.Windows.Forms.Padding(20, 5, 20, 5);
this.OkButton.MaximumSize = new System.Drawing.Size(0, 32);
this.OkButton.MinimumSize = new System.Drawing.Size(0, 32);
this.OkButton.Name = "OkButton";
this.OkButton.Size = new System.Drawing.Size(122, 32);
this.OkButton.TabIndex = 7;
this.OkButton.Text = "OK";
this.OkButton.UseVisualStyleBackColor = true;
//
// CancelButton
//
this.CancelButton.Dock = System.Windows.Forms.DockStyle.Fill;
this.CancelButton.Location = new System.Drawing.Point(344, 428);
this.CancelButton.Margin = new System.Windows.Forms.Padding(20, 5, 20, 5);
this.CancelButton.MaximumSize = new System.Drawing.Size(0, 32);
this.CancelButton.MinimumSize = new System.Drawing.Size(0, 32);
this.CancelButton.Name = "CancelButton";
this.CancelButton.Size = new System.Drawing.Size(124, 32);
this.CancelButton.TabIndex = 8;
this.CancelButton.Text = "Cancel";
this.CancelButton.UseVisualStyleBackColor = true;
//
// OnlineConfigForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(488, 465);
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "OnlineConfigForm";
this.Text = "OnlineConfigForm";
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.ListBox UrlListBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox UrlTextBox;
private System.Windows.Forms.Button UpdateButton;
private System.Windows.Forms.Button AddButton;
private System.Windows.Forms.Button DeleteButton;
private System.Windows.Forms.Button OkButton;
private System.Windows.Forms.Button UpdateAllButton;
private System.Windows.Forms.Button CancelButton;
}
}

+ 76
- 0
shadowsocks-csharp/View/OnlineConfigForm.cs View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Shadowsocks.Controller;
using Shadowsocks.Model;

namespace Shadowsocks.View
{
public partial class OnlineConfigForm : Form
{
private ShadowsocksController controller;
private Configuration config;

private const string DefaultPrefix = "http://www.baidu.com/";

public OnlineConfigForm(ShadowsocksController controller)
{
this.controller = controller;
InitializeComponent();
LoadConfig();
}

private void LoadConfig()
{
config = controller.GetConfigurationCopy();
var idx = UrlListBox.SelectedIndex;
UrlListBox.Items.Clear();

foreach (var item in config.onlineConfigSource)
{
UrlListBox.Items.Add(item);
}

if (idx >= UrlListBox.Items.Count) idx = 0;
UrlListBox.SelectedIndex = idx;
}

private bool ValidateUrl()
{
try
{
var scheme = new Uri(UrlTextBox.Text).Scheme;
if (scheme != "http" && scheme != "https") return false;
}
catch
{
return false;
}
return true;
}

private bool Commit()
{
if (!ValidateUrl()) return false;
UrlListBox.Items[UrlListBox.SelectedIndex] = UrlTextBox.Text;
controller.SaveOnlineConfigSource(UrlListBox.Items.OfType<string>().Where(s=>!string.IsNullOrWhiteSpace(s)));
LoadConfig();
return true;
}

private void AddButton_Click(object sender, EventArgs e)
{
Commit();
UrlListBox.Items.Add("");
UrlTextBox.Text = DefaultPrefix;
UrlListBox.SelectedIndex = UrlListBox.Items.Count - 1;
}
}
}

+ 120
- 0
shadowsocks-csharp/View/OnlineConfigForm.resx View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

+ 9
- 0
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -273,6 +273,12 @@
<DependentUpon>LogForm.cs</DependentUpon>
</Compile>
<Compile Include="View\MenuViewController.cs" />
<Compile Include="View\OnlineConfigForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="View\OnlineConfigForm.Designer.cs">
<DependentUpon>OnlineConfigForm.cs</DependentUpon>
</Compile>
<Compile Include="View\ProxyForm.cs">
<SubType>Form</SubType>
</Compile>
@@ -312,6 +318,9 @@
<EmbeddedResource Include="View\LogForm.resx">
<DependentUpon>LogForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="View\OnlineConfigForm.resx">
<DependentUpon>OnlineConfigForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="View\ProxyForm.resx">
<DependentUpon>ProxyForm.cs</DependentUpon>
</EmbeddedResource>


Loading…
Cancel
Save