diff --git a/Src/SwqlStudio/ActivityMonitorTab.cs b/Src/SwqlStudio/ActivityMonitorTab.cs index 894ff95a0..3a3e7fa78 100644 --- a/Src/SwqlStudio/ActivityMonitorTab.cs +++ b/Src/SwqlStudio/ActivityMonitorTab.cs @@ -1,5 +1,6 @@ using System; using System.Windows.Forms; +using SwqlStudio.Subscriptions; namespace SwqlStudio { @@ -7,6 +8,15 @@ public partial class ActivityMonitorTab : UserControl, IConnectionTab { private string subscriptionId; + public ConnectionInfo ConnectionInfo { get; set; } + + public SubscriptionManager SubscriptionManager { get; set; } + + public bool AllowsChangeConnection + { + get { return false; } + } + public ActivityMonitorTab() { InitializeComponent(); @@ -15,17 +25,18 @@ public ActivityMonitorTab() void ActivityMonitorTabDisposed(object sender, EventArgs e) { - if (String.IsNullOrEmpty(subscriptionId) && ConnectionInfo.IsConnected) + if (!String.IsNullOrEmpty(subscriptionId) && ConnectionInfo.IsConnected) { - ApplicationService.SubscriptionManager.Unsubscribe(ConnectionInfo, subscriptionId); + this.SubscriptionManager.Unsubscribe(ConnectionInfo, subscriptionId); } } - public IApplicationService ApplicationService { get; set; } - private void SubscriptionIndicationReceived(IndicationEventArgs e) { - BeginInvoke(new Action(AddIndication), e); + if (this.IsDisposed) + return; + + BeginInvoke(new Action(AddIndication), e); } private void AddIndication(IndicationEventArgs obj) @@ -41,8 +52,6 @@ private void AddIndication(IndicationEventArgs obj) item.EnsureVisible(); } - public ConnectionInfo ConnectionInfo { get; set; } - public void Start() { backgroundWorker1.RunWorkerAsync(); @@ -55,7 +64,7 @@ private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWor backgroundWorker1.ReportProgress(0, "Starting subscription..."); try { - subscriptionId = ApplicationService.SubscriptionManager.CreateSubscription(ConnectionInfo, "SUBSCRIBE System.QueryExecuted", SubscriptionIndicationReceived); + subscriptionId = this.SubscriptionManager.CreateSubscription(ConnectionInfo, "SUBSCRIBE System.QueryExecuted", SubscriptionIndicationReceived); backgroundWorker1.ReportProgress(0, "Waiting for notifications"); } catch (ApplicationException ex) diff --git a/Src/SwqlStudio/ConnectionsManager.cs b/Src/SwqlStudio/ConnectionsManager.cs new file mode 100644 index 000000000..039a2f8b3 --- /dev/null +++ b/Src/SwqlStudio/ConnectionsManager.cs @@ -0,0 +1,76 @@ +using System.Windows.Forms; + +namespace SwqlStudio +{ + internal class ConnectionsManager + { + private readonly IApplicationService applicationService; + private readonly ServerList serverList; + private readonly QueriesDockPanel dockPanel; + + public ConnectionsManager(IApplicationService applicationService, ServerList serverList, QueriesDockPanel dockPanel) + { + this.applicationService = applicationService; + this.serverList = serverList; + this.dockPanel = dockPanel; + } + + public void CreateConnection() + { + ConnectionInfo connection = AskForNewConnection(); + if (connection != null) + ResolveExistingConnection(connection); + } + + internal ConnectionInfo ResolveConnection() + { + ConnectionInfo info = EnsureExistingConnection(); + if (info != null) + return ResolveExistingConnection(info); + + return null; + } + + private ConnectionInfo EnsureExistingConnection() + { + var selectedConnection = this.applicationService.SelectedConnection; + if (selectedConnection != null) + return selectedConnection; + + return AskForNewConnection(); + } + + private ConnectionInfo ResolveExistingConnection(ConnectionInfo info) + { + ConnectionInfo found; + bool alreadyExists = serverList.TryGet(info.ServerType, info.Server, info.UserName, out found); + if (alreadyExists) + return found; + + info.Connect(); + var provider = serverList.Add(info); + + info.ConnectionClosed += (sender, args) => + { + this.dockPanel.CloseAllFixedConnectionTabs(info); + serverList.Remove(info); + }; + + this.dockPanel.AddServer(provider, info); + return info; + } + + internal static ConnectionInfo AskForNewConnection() + { + using (var nc = new NewConnection()) + { + if (nc.ShowDialog() == DialogResult.OK) + { + return nc.ConnectionInfo; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/CrudTab.cs b/Src/SwqlStudio/CrudTab.cs index 3099a0333..b87fca071 100644 --- a/Src/SwqlStudio/CrudTab.cs +++ b/Src/SwqlStudio/CrudTab.cs @@ -31,12 +31,11 @@ public Entity Entity } } - /// - public IApplicationService ApplicationService { get; set; } - /// public ConnectionInfo ConnectionInfo { get; set; } + public bool AllowsChangeConnection => true; + public event EventHandler CloseItself; private void CreateSubComponents() diff --git a/Src/SwqlStudio/IApplicationService.cs b/Src/SwqlStudio/IApplicationService.cs index dcae5b43c..baa1954e0 100644 --- a/Src/SwqlStudio/IApplicationService.cs +++ b/Src/SwqlStudio/IApplicationService.cs @@ -8,5 +8,9 @@ public interface IApplicationService PropertyBag QueryParameters { get; set; } SubscriptionManager SubscriptionManager { get; } + + ConnectionInfo SelectedConnection { get; } + + void RefreshSelectedConnections(); } } diff --git a/Src/SwqlStudio/IConnectionTab.cs b/Src/SwqlStudio/IConnectionTab.cs index b0ec78fe5..61f55b0c7 100644 --- a/Src/SwqlStudio/IConnectionTab.cs +++ b/Src/SwqlStudio/IConnectionTab.cs @@ -2,7 +2,8 @@ namespace SwqlStudio { public interface IConnectionTab { - IApplicationService ApplicationService { get; set; } ConnectionInfo ConnectionInfo { get; set; } + + bool AllowsChangeConnection { get; } } } \ No newline at end of file diff --git a/Src/SwqlStudio/ITabsFactory.cs b/Src/SwqlStudio/ITabsFactory.cs index 5756359bf..26bce8c5e 100644 --- a/Src/SwqlStudio/ITabsFactory.cs +++ b/Src/SwqlStudio/ITabsFactory.cs @@ -6,9 +6,9 @@ internal interface ITabsFactory { void AddTextToEditor(string text, ConnectionInfo info); - void OpenActivityMonitor(string title, ConnectionInfo connectionInfo); + void OpenActivityMonitor(ConnectionInfo connectionInfo); - void OpenInvokeTab(string title, ConnectionInfo connectionInfo, Verb verb); + void OpenInvokeTab(ConnectionInfo connectionInfo, Verb verb); void OpenCrudTab(CrudOperation operation, ConnectionInfo connectionInfo, Entity entity); } diff --git a/Src/SwqlStudio/InvokeVerbTab.cs b/Src/SwqlStudio/InvokeVerbTab.cs index b2feb69c8..00e11e846 100644 --- a/Src/SwqlStudio/InvokeVerbTab.cs +++ b/Src/SwqlStudio/InvokeVerbTab.cs @@ -17,8 +17,8 @@ public InvokeVerbTab() InitializeComponent(); } - public IApplicationService ApplicationService { get; set; } public ConnectionInfo ConnectionInfo { get; set; } + public bool AllowsChangeConnection => true; private int locationX = 0; private int locationY = 0; diff --git a/Src/SwqlStudio/MainForm.Designer.cs b/Src/SwqlStudio/MainForm.Designer.cs index e07c54fcd..a128c7053 100644 --- a/Src/SwqlStudio/MainForm.Designer.cs +++ b/Src/SwqlStudio/MainForm.Designer.cs @@ -62,6 +62,7 @@ private void InitializeComponent() this.byHierarchyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.noGroupingToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.enableAutocompleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.discoverQueryParametersMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.aboutSWQLStudioToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); @@ -70,9 +71,23 @@ private void InitializeComponent() this.filesDock = new SwqlStudio.QueriesDockPanel(); this.ObjectExplorerImageList = new System.Windows.Forms.ImageList(this.components); this.startTimer = new System.Windows.Forms.Timer(this.components); - this.discoverQueryParametersMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.mainToolbar = new System.Windows.Forms.ToolStrip(); + this.connectionsCombobox = new System.Windows.Forms.ToolStripComboBox(); + this.executeToolButton = new System.Windows.Forms.ToolStripButton(); + this.newConnectionButton = new System.Windows.Forms.ToolStripButton(); + this.disconnectToolButton = new System.Windows.Forms.ToolStripButton(); + this.undoToolButton = new System.Windows.Forms.ToolStripButton(); + this.redoToolButton = new System.Windows.Forms.ToolStripButton(); + this.newFileToolButton = new System.Windows.Forms.ToolStripButton(); + this.openFileButton = new System.Windows.Forms.ToolStripButton(); + this.saveToolButton = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.refreshToolButton = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.menu.SuspendLayout(); + this.mainToolbar.SuspendLayout(); this.SuspendLayout(); // // toolStripSeparator1 @@ -365,6 +380,16 @@ private void InitializeComponent() this.enableAutocompleteToolStripMenuItem.Text = "Enable Autocomplete"; this.enableAutocompleteToolStripMenuItem.CheckedChanged += new System.EventHandler(this.enableAutocompleteToolStripMenuItem_CheckedChanged); // + // discoverQueryParametersMenuItem + // + this.discoverQueryParametersMenuItem.Checked = true; + this.discoverQueryParametersMenuItem.CheckOnClick = true; + this.discoverQueryParametersMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.discoverQueryParametersMenuItem.Name = "discoverQueryParametersMenuItem"; + this.discoverQueryParametersMenuItem.Size = new System.Drawing.Size(214, 22); + this.discoverQueryParametersMenuItem.Text = "Discover query parameters"; + this.discoverQueryParametersMenuItem.CheckedChanged += new System.EventHandler(this.discoverQueryParametersToolStripMenuItem_CheckedChanged); + // // helpToolStripMenuItem // this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -390,7 +415,7 @@ private void InitializeComponent() this.filesDock.DockBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(238)))), ((int)(((byte)(238)))), ((int)(((byte)(242))))); this.filesDock.Location = new System.Drawing.Point(0, 24); this.filesDock.Name = "filesDock"; - this.filesDock.Padding = new System.Windows.Forms.Padding(6); + this.filesDock.Padding = new System.Windows.Forms.Padding(6, 6, 31, 6); this.filesDock.QueryParameters = ((SolarWinds.InformationService.Contract2.PropertyBag)(resources.GetObject("filesDock.QueryParameters"))); this.filesDock.ShowAutoHideContentOnHover = false; this.filesDock.Size = new System.Drawing.Size(827, 571); @@ -419,15 +444,140 @@ private void InitializeComponent() // this.startTimer.Tick += new System.EventHandler(this.startTimer_Tick); // - // discoverQueryParametersMenuItem - // - this.discoverQueryParametersMenuItem.Checked = true; - this.discoverQueryParametersMenuItem.CheckOnClick = true; - this.discoverQueryParametersMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; - this.discoverQueryParametersMenuItem.Name = "discoverQueryParametersMenuItem"; - this.discoverQueryParametersMenuItem.Size = new System.Drawing.Size(214, 22); - this.discoverQueryParametersMenuItem.Text = "Discover query parameters"; - this.discoverQueryParametersMenuItem.CheckedChanged += new System.EventHandler(this.discoverQueryParametersToolStripMenuItem_CheckedChanged); + // mainToolbar + // + this.mainToolbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.connectionsCombobox, + this.executeToolButton, + this.toolStripSeparator4, + this.newConnectionButton, + this.disconnectToolButton, + this.refreshToolButton, + this.toolStripSeparator2, + this.undoToolButton, + this.redoToolButton, + this.toolStripSeparator3, + this.newFileToolButton, + this.openFileButton, + this.saveToolButton}); + this.mainToolbar.Location = new System.Drawing.Point(0, 24); + this.mainToolbar.Name = "mainToolbar"; + this.mainToolbar.Size = new System.Drawing.Size(827, 25); + this.mainToolbar.TabIndex = 5; + this.mainToolbar.Text = "toolStrip1"; + // + // connectionsCombobox + // + this.connectionsCombobox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.connectionsCombobox.DropDownWidth = 300; + this.connectionsCombobox.Name = "connectionsCombobox"; + this.connectionsCombobox.Size = new System.Drawing.Size(250, 25); + this.connectionsCombobox.SelectedIndexChanged += new System.EventHandler(this.connectionsCombobox_SelectedIndexChanged); + // + // executeToolButton + // + this.executeToolButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.executeToolButton.Image = global::SwqlStudio.Properties.Resources.Run_16x; + this.executeToolButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.executeToolButton.Name = "executeToolButton"; + this.executeToolButton.Size = new System.Drawing.Size(23, 22); + this.executeToolButton.ToolTipText = "Execute query (F5)"; + this.executeToolButton.Click += new System.EventHandler(this.menuQueryExecute_Click); + // + // newConnectionButton + // + this.newConnectionButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.newConnectionButton.Image = global::SwqlStudio.Properties.Resources.ConnectFilled_16x; + this.newConnectionButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.newConnectionButton.Name = "newConnectionButton"; + this.newConnectionButton.Size = new System.Drawing.Size(23, 22); + this.newConnectionButton.ToolTipText = "New connection"; + this.newConnectionButton.Click += new System.EventHandler(this.newConnectionButton_Click); + // + // disconnectToolButton + // + this.disconnectToolButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.disconnectToolButton.Image = global::SwqlStudio.Properties.Resources.Disconnect_16x; + this.disconnectToolButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.disconnectToolButton.Name = "disconnectToolButton"; + this.disconnectToolButton.Size = new System.Drawing.Size(23, 22); + this.disconnectToolButton.Text = "Disconnect"; + this.disconnectToolButton.Click += new System.EventHandler(this.disconnectToolButton_Click); + // + // undoToolButton + // + this.undoToolButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.undoToolButton.Image = global::SwqlStudio.Properties.Resources.Undo_16x; + this.undoToolButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.undoToolButton.Name = "undoToolButton"; + this.undoToolButton.Size = new System.Drawing.Size(23, 22); + this.undoToolButton.ToolTipText = "Undo (Ctrl+Z)"; + this.undoToolButton.Click += new System.EventHandler(this.undoToolStripMenuItem_Click); + // + // redoToolButton + // + this.redoToolButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.redoToolButton.Image = global::SwqlStudio.Properties.Resources.Redo_16x; + this.redoToolButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.redoToolButton.Name = "redoToolButton"; + this.redoToolButton.Size = new System.Drawing.Size(23, 22); + this.redoToolButton.ToolTipText = "Redo (Ctrl+Y)"; + this.redoToolButton.Click += new System.EventHandler(this.redoToolStripMenuItem_Click); + // + // newFileToolButton + // + this.newFileToolButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.newFileToolButton.Image = global::SwqlStudio.Properties.Resources.NewFile_16x; + this.newFileToolButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.newFileToolButton.Name = "newFileToolButton"; + this.newFileToolButton.Size = new System.Drawing.Size(23, 22); + this.newFileToolButton.ToolTipText = "New file (Ctrl+N)"; + this.newFileToolButton.Click += new System.EventHandler(this.menuFileNew_Click); + // + // openFileButton + // + this.openFileButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.openFileButton.Image = global::SwqlStudio.Properties.Resources.OpenFolder_16x; + this.openFileButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.openFileButton.Name = "openFileButton"; + this.openFileButton.Size = new System.Drawing.Size(23, 22); + this.openFileButton.ToolTipText = "Open file (Ctrl+O)"; + this.openFileButton.Click += new System.EventHandler(this.menuFileOpen_Click); + // + // saveToolButton + // + this.saveToolButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.saveToolButton.Image = global::SwqlStudio.Properties.Resources.Save_16x; + this.saveToolButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.saveToolButton.Name = "saveToolButton"; + this.saveToolButton.Size = new System.Drawing.Size(23, 22); + this.saveToolButton.ToolTipText = "Save (Ctrl+S)"; + this.saveToolButton.Click += new System.EventHandler(this.menuFileSave_Click); + // + // toolStripSeparator2 + // + this.toolStripSeparator2.Name = "toolStripSeparator2"; + this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25); + // + // refreshToolButton + // + this.refreshToolButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.refreshToolButton.Image = global::SwqlStudio.Properties.Resources.Refresh_16x; + this.refreshToolButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.refreshToolButton.Name = "refreshToolButton"; + this.refreshToolButton.Size = new System.Drawing.Size(23, 22); + this.refreshToolButton.Text = "Refresh server metadata"; + this.refreshToolButton.Click += new System.EventHandler(this.refreshToolButton_Click); + // + // toolStripSeparator3 + // + this.toolStripSeparator3.Name = "toolStripSeparator3"; + this.toolStripSeparator3.Size = new System.Drawing.Size(6, 25); + // + // toolStripSeparator4 + // + this.toolStripSeparator4.Name = "toolStripSeparator4"; + this.toolStripSeparator4.Size = new System.Drawing.Size(6, 25); // // MainForm // @@ -435,6 +585,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(827, 595); + this.Controls.Add(this.mainToolbar); this.Controls.Add(this.filesDock); this.Controls.Add(this.menu); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); @@ -447,6 +598,8 @@ private void InitializeComponent() this.DragEnter += new System.Windows.Forms.DragEventHandler(this.TextEditorForm_DragEnter); this.menu.ResumeLayout(false); this.menu.PerformLayout(); + this.mainToolbar.ResumeLayout(false); + this.mainToolbar.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -494,6 +647,20 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem undoToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem redoToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem discoverQueryParametersMenuItem; + private System.Windows.Forms.ToolStrip mainToolbar; + private System.Windows.Forms.ToolStripButton undoToolButton; + private System.Windows.Forms.ToolStripButton redoToolButton; + private System.Windows.Forms.ToolStripButton newFileToolButton; + private System.Windows.Forms.ToolStripButton saveToolButton; + private System.Windows.Forms.ToolStripButton executeToolButton; + private System.Windows.Forms.ToolStripButton openFileButton; + private System.Windows.Forms.ToolStripComboBox connectionsCombobox; + private System.Windows.Forms.ToolStripButton newConnectionButton; + private System.Windows.Forms.ToolStripButton disconnectToolButton; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + private System.Windows.Forms.ToolStripButton refreshToolButton; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; } } diff --git a/Src/SwqlStudio/MainForm.cs b/Src/SwqlStudio/MainForm.cs index 6925035ec..20af64923 100644 --- a/Src/SwqlStudio/MainForm.cs +++ b/Src/SwqlStudio/MainForm.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; +using System.ComponentModel; using System.IO; +using System.Linq; using System.ServiceModel; using System.Windows.Forms; using SolarWinds.InformationService.Contract2; @@ -7,6 +10,7 @@ using SwqlStudio.Metadata; using SwqlStudio.Properties; using SwqlStudio.Subscriptions; +using WeifenLuo.WinFormsUI.Docking; namespace SwqlStudio { @@ -16,6 +20,8 @@ namespace SwqlStudio internal partial class MainForm : Form, IApplicationService { private static readonly SolarWinds.Logging.Log log = new SolarWinds.Logging.Log(); + private ServerList serverList; + private ConnectionsManager connectionsManager; public PropertyBag QueryParameters { @@ -25,6 +31,10 @@ public PropertyBag QueryParameters public SubscriptionManager SubscriptionManager { get; } = new SubscriptionManager(); + public ConnectionInfo SelectedConnection + { + get { return this.connectionsCombobox.SelectedItem as ConnectionInfo; } + } public MainForm() { @@ -40,8 +50,45 @@ public MainForm() private void InitializeDockPanel() { + var connectionsDropDown = this.connectionsCombobox.ComboBox; + connectionsDropDown.DisplayMember = "Title"; this.filesDock.SetObjectExplorerImageList(this.ObjectExplorerImageList); - this.filesDock.SetAplicationService(this); + this.serverList = new ServerList(); + this.serverList.ConnectionsChanged += ServerListOnConnectionsChanged; + this.connectionsManager = new ConnectionsManager(this, this.serverList, this.filesDock); + var tabsFactory = new TabsFactory(this.filesDock, this, this.serverList, this.connectionsManager); + this.filesDock.SetAplicationService(tabsFactory); + this.filesDock.ActiveContentChanged += FilesDock_ActiveContentChanged; + } + + private void FilesDock_ActiveContentChanged(object sender, EventArgs e) + { + this.RefreshSelectedConnections(); + + IConnectionTab activeConnectionTab = this.filesDock.ActiveConnectionTab; + if (activeConnectionTab != null) + { + this.connectionsCombobox.SelectedItem = activeConnectionTab.ConnectionInfo; + } + } + + public void RefreshSelectedConnections() + { + IConnectionTab activeConnectionTab = this.filesDock.ActiveConnectionTab; + this.connectionsCombobox.Enabled = activeConnectionTab == null || activeConnectionTab.AllowsChangeConnection; + } + + private void ServerListOnConnectionsChanged(object sender, EventArgs eventArgs) + { + var connectionsDropDown = this.connectionsCombobox.ComboBox; + var lastSelected = this.connectionsCombobox.SelectedItem; + List serverListConnections = this.serverList.Connections; + connectionsDropDown.DataSource = new BindingList(serverListConnections); + + if(lastSelected == null && serverListConnections.Any()) + lastSelected = serverListConnections.First(); + + this.connectionsCombobox.SelectedItem = lastSelected; } private void startTimer_Tick(object sender, EventArgs e) @@ -71,61 +118,54 @@ private void menuFileClose_Click(object sender, EventArgs e) private void menuFileSave_Click(object sender, EventArgs e) { - SciTextEditorControl editor = this.filesDock.ActiveEditor; + var editor = this.filesDock.ActiveQueryTab; if (editor != null) DoSave(editor); } - private bool DoSave(SciTextEditorControl editor) + private bool DoSave(QueryTab editor) { if (string.IsNullOrEmpty(editor.FileName)) return DoSaveAs(editor); - else - { - try - { - editor.SaveFile(editor.FileName); - SetModifiedFlag(editor, false); - return true; - } - catch (Exception ex) - { - MessageBox.Show(this, ex.Message, ex.GetType().Name); - return false; - } - } + + return SaveEditor(editor, editor.FileName); } private void menuFileSaveAs_Click(object sender, EventArgs e) { - var editor = this.filesDock.ActiveEditor; + var editor = this.filesDock.ActiveQueryTab; if (editor != null) DoSaveAs(editor); } - private bool DoSaveAs(SciTextEditorControl editor) + private bool DoSaveAs(QueryTab editor) { saveFileDialog.FileName = editor.FileName; - if (saveFileDialog.ShowDialog() == DialogResult.OK) + if (saveFileDialog.ShowDialog() != DialogResult.OK) + return false; + + return SaveEditor(editor, saveFileDialog.FileName); + } + + private bool SaveEditor(QueryTab editor, string fileName) + { + try { - try - { - editor.SaveFile(saveFileDialog.FileName); - editor.Parent.Text = Path.GetFileName(editor.FileName); - SetModifiedFlag(editor, false); - - // The syntax highlighting strategy doesn't change - // automatically, so do it manually. - //editor.Document.HighlightingStrategy = - // HighlightingStrategyFactory.CreateHighlightingStrategyForFile(editor.FileName); - return true; - } - catch (Exception ex) - { - MessageBox.Show(this, ex.Message, ex.GetType().Name); - } + File.WriteAllText(fileName, editor.QueryText); + editor.FileName = fileName; + editor.MarkSaved(); + + // The syntax highlighting strategy doesn't change + // automatically, so do it manually. + //editor.Document.HighlightingStrategy = + // HighlightingStrategyFactory.CreateHighlightingStrategyForFile(editor.FileName); + return true; + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, ex.GetType().Name); + return false; } - return false; } private void menuNotificationListenerActive_Click(object sender, EventArgs e) @@ -161,32 +201,27 @@ private void menuFileExit_Click(object sender, EventArgs e) private void undoToolStripMenuItem_Click(object sender, EventArgs e) { - if (this.filesDock.ActiveEditor != null) - this.filesDock.ActiveEditor.Undo(); + this.filesDock.ActiveQueryTab?.Undo(); } private void redoToolStripMenuItem_Click(object sender, EventArgs e) { - if (this.filesDock.ActiveEditor != null) - this.filesDock.ActiveEditor.Redo(); + this.filesDock.ActiveQueryTab?.Redo(); } private void menuEditCut_Click(object sender, EventArgs e) { - if (this.filesDock.ActiveEditor != null) - this.filesDock.ActiveEditor.Cut(); + this.filesDock.ActiveQueryTab?.Cut(); } private void menuEditCopy_Click(object sender, EventArgs e) { - if (this.filesDock.ActiveQueryTab != null) - this.filesDock.ActiveQueryTab.CopySelectionToClipboard(); + this.filesDock.ActiveQueryTab?.CopySelectionToClipboard(); } private void menuEditPaste_Click(object sender, EventArgs e) { - if (this.filesDock.ActiveEditor != null) - this.filesDock.ActiveEditor.Paste(); + this.filesDock.ActiveQueryTab?.Paste(); } #endregion @@ -230,29 +265,6 @@ private void TextEditor_FormClosing(object sender, FormClosingEventArgs e) } } - /// Gets whether the file in the specified editor is modified. - /// TextEditorControl doesn't maintain its own internal modified - /// flag, so we use the '*' shown after the file name to represent the - /// modified state. - private static bool IsModified(SciTextEditorControl editor) - { - // TextEditorControl doesn't seem to contain its own 'modified' flag, so - // instead we'll treat the "*" on the filename as the modified flag. - return editor.Parent.Text.EndsWith("*"); - } - - private static void SetModifiedFlag(SciTextEditorControl editor, bool flag) - { - if (IsModified(editor) != flag) - { - var p = editor.Parent; - if (IsModified(editor)) - p.Text = p.Text.Substring(0, p.Text.Length - 1); - else - p.Text += "*"; - } - } - /// We handle DragEnter and DragDrop so users can drop files on the editor. private void TextEditorForm_DragEnter(object sender, DragEventArgs e) { @@ -282,7 +294,7 @@ private void parametersToolStripMenuItem_Click(object sender, EventArgs e) private void enumEntitiesToolStripMenuItem_Click(object sender, EventArgs e) { - ConnectionInfo connection = this.filesDock.ActiveConnectionInfo; + ConnectionInfo connection = this.SelectedConnection; if (connection == null) return; // should we try to connect? @@ -393,5 +405,37 @@ private void discoverQueryParametersToolStripMenuItem_CheckedChanged(object send { this.filesDock.AllowSetParameters(this.discoverQueryParametersMenuItem.Checked); } + + private void connectionsCombobox_SelectedIndexChanged(object sender, EventArgs e) + { + IConnectionTab activeConnectionTab = this.filesDock.ActiveConnectionTab; + if (activeConnectionTab != null && this.SelectedConnection != null) + { + activeConnectionTab.ConnectionInfo = this.SelectedConnection; + } + } + + private void newConnectionButton_Click(object sender, EventArgs e) + { + this.connectionsManager.CreateConnection(); + } + + private void disconnectToolButton_Click(object sender, EventArgs e) + { + var connection = this.connectionsCombobox.SelectedItem as ConnectionInfo; + if (connection != null) + { + this.filesDock.CloseServer(connection); + } + } + + private void refreshToolButton_Click(object sender, EventArgs e) + { + var connection = this.connectionsCombobox.SelectedItem as ConnectionInfo; + if (connection != null) + { + this.filesDock.RefreshServer(connection); + } + } } } diff --git a/Src/SwqlStudio/MainForm.resx b/Src/SwqlStudio/MainForm.resx index 923a3e81f..98a8a0b01 100644 --- a/Src/SwqlStudio/MainForm.resx +++ b/Src/SwqlStudio/MainForm.resx @@ -160,219 +160,221 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABM - MAAAAk1TRnQBSQFMAgEBDgEAAfwBAQH8AQEBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABQAMAAQEBAAEgBgABQBIAgP+AAAT/A1IB/wPAAf8D9AH/A9YB/wM9Tf8DAAH/AwAB/wFLAW4BuRH/ - gAAE/wO0Af8DGwH/AxsB/wMbAf8Dok3/AwAB/wMAAf8BSwFuAbkB/wMADf+AAAT/A/IB/wM0Af8D6AH/ - AzYB/wPoAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAEf8BtwGi - AZMB/wFXAT0BKQH/AVcBPQEpAf8BVwE9ASkB/wFXAT0BKQn/AwAB/wFLAW4BuQH/AUsBbgG5Af8BVwE9 - ASkB/wMACf+AAAT/A/kB/wONAf8DWwH/A2UB/wP3Af8B3wHOAcMB/wHdAcgBuwH/AdsBvwGtAf8B2wG7 - AacB/wHbAbsBpwH/AdsBuwGnAf8BzwG0AaMB/wEYAgAR/wG3AaIBkwH/Af0B+wH5Af8B4QHcAdgB/wHg - AdcB0gH/Ad8BzgHDAf8B3QHIAbsJ/wMAAf8DcwH/AVcBPQEpAf8BVwE9ASkB/wMABf+AAAT/A/0B/wPb - Af8DGwH/A8kB/wP7Af8B+wHsAeMB/wGkAY0BMwH/AZoBgwEnAf8B9gHWAcIB/wGIASYBEwH/AYMBIAEN - Af8BzwG0AaMB/wEYAgAR/wG3AaIBkwH/A/4B/wG6AaYBmAH/AbUBoAGRAf8B+wHsAeMB/wGkAY0BcgH/ - AZoBgwFmCf8DAAH/A3MB/wFXAT0BKQH/AVcBPQEpAf8DAAH/gAAI/wG6AaUBlgH/A/4B/wP+Af8D/gH/ - Af0B+wH5Af8B/QH3AfMB/wH7AewB4wH/AfoB5wHbAf8B+AHhAdIB/wH3AdsByQH/AdABuQGrAf8BGAIA - Ef8BugGlAZYB/wP+Af8D/gH/A/4B/wH9AfsB+QH/Af0B9wHzAf8B+wHsAeMB/wH6AecB2wn/AwAB/wNz - Af8BVwE9ASkB/wFXAT0BKQH/gAAI/wG+AakBmgH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaMBjgEz - Af8BmgGDAScB/wH7AewB4wH/AYkBJgEUAf8BgwEgAQ0B/wHRAcEBtgH/ARgCABH/Ab4BqQGaAf8D/gH/ - AboBpgGYAf8BtAGgAZEB/wP+Af8BowGOAXIB/wGaAYMBZgH/AfsB7AHjAf8BiQFlAVMJ/wMAAf8DcwH/ - AVcBPQEpAf+AAAj/AcMBrgGeAf8D/gH/A/4B/wP+Af8D/gH/A/4B/wH9AfcB8wH/AfwB8gHsAf8B+wHs - AeMB/wH6AecB2wH/AdEBwQG2Af8BGAIAEf8BwwGuAZ4B/wP+Af8D/gH/A/4B/wP+Af8D/gH/Af0B9wHz - Af8B/AHyAewB/wH7AewB4wH/AfoB5wHbCf8DAAH/A3MB/4AACP8ByAGyAaMB/wP+Af8BugGmAZgB/wG0 - AaABkQH/A/4B/wGkAY4BMwH/AZkBhAEnAf8B/QH3AfMB/wGIASYBEwH/AYMBIAENAf8B0QHBAbYB/wEY - AgAR/wHIAbIBowH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaQBjgFyAf8BmQGEAWYB/wH9AfcB8wH/ - AYgBZQFSAf8BgwFfAUwB/wHRAcEBtgn/AVcBPQEpAf+AAAj/AcwBtgGnAf8D/gH/A/4B/wP+Af8D/gH/ - A/4B/wP+Af8B/QH7AfkB/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wEYAgAR/wHMAbYBpwH/A/4B/wP+ - Af8D/gH/A/4B/wP+Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BVwE9ASkJ/4AA - CP8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGlAYQB/wHnAZcBIwH/AeYBjgEXAf8B4wEyAQAB/wHj - ASsBAAH/AeIBJwEAAf8B4gEnAQAB/wHiAScBAAH/AcgBFwEAEf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL - Af8B6QGlAYQB/wHnAZcBYgH/AeYBjgFWAf8B4wFxAT4B/wHjAWoBNAH/AeIBZgEtAf8B4gFmAS0B/wHi - AWYBLQH/AcgBVgEjCf+AAAj/AeoBqgGLAv8BwgGiAf8B/gHAAZ8B/wH9Ab0BmgH/AfsBtQGQAf8B+gGw - AYsB/wH4AacBMgH/AfYBogEsAf8B9QGdASYB/wH1AZkBHwH/AfMBlQEaAf8BzQEaAQAR/wHqAaoBiwL/ - AcIBogH/Af4BwAGfAf8B/QG9AZoB/wH7AbUBkAH/AfoBsAGLAf8B+AGnAXEB/wH2AaIBawH/AfUBnQFl - Af8B9QGZAV4B/wHzAZUBWQH/Ac0BWQElCf+AAAj/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL - Af8B6QGhATQB/wHoAZsBKwH/AeYBjgEXAf8B5QGHAQ0B/wHkAYEBAwH/AeQBMAEAAf8B4wErAQAB/wHi - AScBABH/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGhAXMB/wHoAZsBagH/AeYBjgFW - Af8B5QGHAUwB/wHkAYEBQgH/AeQBbwE6Af8B4wFqATIB/wHiAWYBLQn/gACA/4AAgP//ACkAAdMB3wHr + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA4 + MAAAAk1TRnQBSQFMAgEBDgEAAUwBAgFMAQIBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABQAMAAQEBAAEgBgABQBIAgP+AAAT/A0gB/wPAAf8D9AH/A9YB/wMzTf8DAAH/AwAB/wFBAWQBuRH/ + gAAE/wO0Af8DEQH/AxEB/wMRAf8Dok3/AwAB/wMAAf8BQQFkAbkB/wMADf+AAAT/A/IB/wMqAf8D6AH/ + AywB/wPoAf8BDgIAAf8BDgIAAf8BDgIAAf8BDgIAAf8BDgIAAf8BDgIAAf8BDgIAAf8BDgIAEf8BtwGi + AZMB/wFNATMBHwH/AU0BMwEfAf8BTQEzAR8B/wFNATMBHwn/AwAB/wFBAWQBuQH/AUEBZAG5Af8BTQEz + AR8B/wMACf+AAAT/A/kB/wONAf8DUQH/A1sB/wP3Af8B3wHOAcMB/wHdAcgBuwH/AdsBvwGtAf8B2wG7 + AacB/wHbAbsBpwH/AdsBuwGnAf8BzwG0AaMB/wEOAgAR/wG3AaIBkwH/Af0B+wH5Af8B4QHcAdgB/wHg + AdcB0gH/Ad8BzgHDAf8B3QHIAbsJ/wMAAf8DaQH/AU0BMwEfAf8BTQEzAR8B/wMABf+AAAT/A/0B/wPb + Af8DEQH/A8kB/wP7Af8B+wHsAeMB/wGkAY0BKQH/AZoBgwEdAf8B9gHWAcIB/wGIARwBCQH/AYMBFgED + Af8BzwG0AaMB/wEOAgAR/wG3AaIBkwH/A/4B/wG6AaYBmAH/AbUBoAGRAf8B+wHsAeMB/wGkAY0BaAH/ + AZoBgwFcCf8DAAH/A2kB/wFNATMBHwH/AU0BMwEfAf8DAAH/gAAI/wG6AaUBlgH/A/4B/wP+Af8D/gH/ + Af0B+wH5Af8B/QH3AfMB/wH7AewB4wH/AfoB5wHbAf8B+AHhAdIB/wH3AdsByQH/AdABuQGrAf8BDgIA + Ef8BugGlAZYB/wP+Af8D/gH/A/4B/wH9AfsB+QH/Af0B9wHzAf8B+wHsAeMB/wH6AecB2wn/AwAB/wNp + Af8BTQEzAR8B/wFNATMBHwH/gAAI/wG+AakBmgH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaMBjgEp + Af8BmgGDAR0B/wH7AewB4wH/AYkBHAEKAf8BgwEWAQMB/wHRAcEBtgH/AQ4CABH/Ab4BqQGaAf8D/gH/ + AboBpgGYAf8BtAGgAZEB/wP+Af8BowGOAWgB/wGaAYMBXAH/AfsB7AHjAf8BiQFbAUkJ/wMAAf8DaQH/ + AU0BMwEfAf+AAAj/AcMBrgGeAf8D/gH/A/4B/wP+Af8D/gH/A/4B/wH9AfcB8wH/AfwB8gHsAf8B+wHs + AeMB/wH6AecB2wH/AdEBwQG2Af8BDgIAEf8BwwGuAZ4B/wP+Af8D/gH/A/4B/wP+Af8D/gH/Af0B9wHz + Af8B/AHyAewB/wH7AewB4wH/AfoB5wHbCf8DAAH/A2kB/4AACP8ByAGyAaMB/wP+Af8BugGmAZgB/wG0 + AaABkQH/A/4B/wGkAY4BKQH/AZkBhAEdAf8B/QH3AfMB/wGIARwBCQH/AYMBFgEDAf8B0QHBAbYB/wEO + AgAR/wHIAbIBowH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaQBjgFoAf8BmQGEAVwB/wH9AfcB8wH/ + AYgBWwFIAf8BgwFVAUIB/wHRAcEBtgn/AU0BMwEfAf+AAAj/AcwBtgGnAf8D/gH/A/4B/wP+Af8D/gH/ + A/4B/wP+Af8B/QH7AfkB/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wEOAgAR/wHMAbYBpwH/A/4B/wP+ + Af8D/gH/A/4B/wP+Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BTQEzAR8J/4AA + CP8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGlAYQB/wHnAZcBGQH/AeYBjgENAf8B4wEoAQAB/wHj + ASEBAAH/AeIBHQEAAf8B4gEdAQAB/wHiAR0BAAH/AcgBDQEAEf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL + Af8B6QGlAYQB/wHnAZcBWAH/AeYBjgFMAf8B4wFnATQB/wHjAWABKgH/AeIBXAEjAf8B4gFcASMB/wHi + AVwBIwH/AcgBTAEZCf+AAAj/AeoBqgGLAv8BwgGiAf8B/gHAAZ8B/wH9Ab0BmgH/AfsBtQGQAf8B+gGw + AYsB/wH4AacBKAH/AfYBogEiAf8B9QGdARwB/wH1AZkBFQH/AfMBlQEQAf8BzQEQAQAR/wHqAaoBiwL/ + AcIBogH/Af4BwAGfAf8B/QG9AZoB/wH7AbUBkAH/AfoBsAGLAf8B+AGnAWcB/wH2AaIBYQH/AfUBnQFb + Af8B9QGZAVQB/wHzAZUBTwH/Ac0BTwEbCf+AAAj/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL + Af8B6QGhASoB/wHoAZsBIQH/AeYBjgENAf8B5QGHAQMB/wHkAYEBAAH/AeQBJgEAAf8B4wEhAQAB/wHi + AR0BABH/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGhAWkB/wHoAZsBYAH/AeYBjgFM + Af8B5QGHAUIB/wHkAYEBOAH/AeQBZQEwAf8B4wFgASgB/wHiAVwBIwn/gACA/4AAgP//ACkAAdMB3wHr Af8B6AH0Av8B6AH0Av8B0wHfAesB/wgAA/QB/wP0Af8D9QX/A/YB/wP0Af8D9A3/A/4B/wP2Af8D9QH/ - A/0J/xAAAe8B5gHcAf8BzgG1AZMB/wG4AZMBMwH/AbIBiAEhAf8BuAGSATIB/wHOAbQBkAH/Ae4B5gHb - Af94AAPfAf8B6AH0Av8BmAGkAbAB/wGYAaQBsAH/AegB9AL/A98B/wQAA/YB/wNRAf8DwAH/A/QB/wPW - Af8DPAH/A/UJ/wP+Af8D9gH/AWIBrgHbAf8BYgGuAdsB/wP1Af8D/QX/CAAB/QH7AfoB/wHIAawBhAH/ - AaEBQgEAAf8BnQE8AQAB/wGcAToBAAH/AaQBSAEAAf8BnQE7AQAB/wGdATsBAAH/AZ8BQQEAAf8BxwGq - AYEB/wH8AfsB+QH/HAADhgH/Aw8B/wwAAw8B/wOGAf80AAPfAf8D9AH/AT8BqAHmAf8BDwFdAbYB/wEH - AV0BvgH/ATcBqAHuAf8B6AH0Av8B0wHfAesB/wP6Af8DtAH/AxoB/wMaAf8DGgH/A6IB/wP6Bf8D/gH/ - A/YB/wFiAa4B2wH/AQIBYAHHAf8BAgFgAccB/wFiAa4B2wH/A/UB/wP9Af8EAAH8AfsB+QH/AbwBlgE4 - Af8BoAE/AQAB/wGhAUABAAH/AZ4BOwEAAf8BygGqAUkB/wH2AfEB6AH/Ac0BrwFTAf8BngE7AQAB/wGh - AUABAAH/AaEBPwEAAf8BugGUATQB/wH8AfoB+AH/FAADhgH/AwAB/xcAAf8DhgH/OAABPwGoAeYB/wEP - AV0BtgH/AQcBXQG+Af8BBwFdAb4B/wGYAaQBsAH/AegB9AL/A/4B/wPyAf8DMwH/A+gB/wM1Af8D6AH/ - A/4B/wP0Af8D9AH/A/QB/wGUAb0B4AH/AQIBYAHHAf8BAgFgAccB/wECAWABxwH/AWIBrgHbAf8D9QH/ - BAABzAGvAYgB/wGlAUQBAAH/AaUBRAEAAf8BpQFFAQAB/wGiAT8BAAH/AeYB1gG7Bf8B6wHeAcgB/wGj - AUEBAAH/AaUBRAEAAf8BpQFEAQAB/wGlAUQBAAH/AcoBrQGEAf8UAAMpAf8DAAH/FwAB/wMpAf8wAAEY - AV0BrgH/ARgBXQGuAf8BMAFZAZ0B/wEwAVkBnQH/AQ8BXQG2Af8BDwFdAbYB/wGYAaQBsAH/AegB9Ab/ - A/kB/wONAf8DWgH/A2QB/wP3Bf8D9AH/AQIBYAHHAf8BAgFgAccB/wECAWABxwH/AZQBvQHgAf8BAgFg - AccB/wECAWABxwH/AZQBvQHgAf8D9gH/AfIB6gHhAf8BqQFLAQAB/wGqAUkBAAH/AaoBSQEAAf8BqgFJ - AQAB/wGnAUQBAAH/AeUB0wG2Bf8B6gHcAcMB/wGoAUYBAAH/AaoBSAEAAf8BqgFJAQAB/wGqAUkBAAH/ - AakBSgEAAf8B8AHpAd4B/xAAAykB/wMAAf8XAAH/AykB/xwAA98B/wPfAf8MAAEYAV0BrgH/AbUB+gL/ - Ac0B9gL/Ac0B9gL/AT8BqAHmAf8BPwGoAeYB/wHoAfQC/wHTAd8B6wX/A/0B/wPbAf8DGgH/A8kB/wP7 - Bf8D9AH/AQIBYAHHAf8D9AH/A/QB/wP0Af8BlAG9AeAB/wGUAb0B4AH/A/YB/wP+Af8B1gG+AZ0B/wGw - AVABAAH/Aa4BTQEAAf8BrwFOAQAB/wGvAU4BAAH/AawBSQEAAf8B5gHVAbYF/wHrAdwBxAH/Aa0BSwEA - Af8BrwFNAQAB/wGvAU4BAAH/Aa4BTgEAAf8BrwFNAQAB/wHTAbkBlgH/EwAB/wPAAf8UAAPAAf8DAAH/ - GAAB0wHfAesB/wHoAfQC/wHoAfQC/wHTAd8B6wH/CAABMAFZAZ0B/wHNAfYC/wHJAfYC/wFcAaQB0QH/ - AVwBpAHRAf8ByQH2Av8D5QH/BAAI/wP2Af8D9AH/A/QB/wP9Bf8D9AH/AQIBYAHHAf8D9AH/A/YB/wFi - Aa4B2wH/AWIBrgHbAf8D9AH/A/wF/wHKAakBUAH/AcABjgEMAf8BtQFVAQAB/wGzAVEBAAH/AbQBUwEA - Af8BsgFPAQAB/wHoAdYBuAX/AewB3gHFAf8BsgFQAQAB/wG0AVIBAAH/AbQBUwEAAf8BtAFTAQAB/wG1 - AVMBAAH/AcQBnwE9Af8PAAH/A0IB/xwAA0IB/wMAAf8QAAPfAf8B6AH0Av8BmAGkAbAB/wGYAaQBsAH/ - AegB9AL/A98B/wQAATABWQGdAf8BzQH2Av8BXAGkAdEB/wEsAVkBoQH/ASwBWQGhAf8BXAGkAdEB/wP0 - Af8D3wX/A/4B/wP2Af8BYgGuAdsB/wFiAa4B2wH/A/UB/wP9Af8D9AH/AQIBYAHHAf8D9AH/AWIBrgHb - Af8BAgFgAccB/wECAWABxwH/AWIBrgHbAf8D9QH/A/0B/wHJAaYBRwH/AckBmwEeAf8BxQGUARcB/wG+ - AYkBAgH/AboBgAEAAf8BtwFTAQAB/wHrAdkBuwX/Ae8B4QHIAf8BtwFVAQAB/wG5AVcBAAH/AbkBVwEA - Af8BuQFXAQAB/wG6AVcBAAH/AcMBmgExAf8QAAMPAf8DwAH/FAADwAH/Aw8B/xAAAdMB3wHrAf8B6AH0 - Av8BNwGoAe4B/wEHAV0BvgH/AQcBXQG+Af8BNwGoAe4B/wHNAfYC/wHNAfYC/wEYAV0BrgH/AbUB+gL/ - ATcBqAHuAf8BBwFdAb4B/wEAAV0BxwH/AQABXQHHAf8BjAGkAb0B/wHcAfQC/wP+Af8D9gH/AWIBrgHb - Af8BAgFgAccB/wECAWABxwH/AWIBrgHbAf8D9AH/A/QB/wECAWABxwH/A/QB/wGUAb0B4AH/AQIBYAHH - Af8BAgFgAccB/wECAWABxwH/AWIBrgHbAf8D9QH/AdABrwGBAf8BzgGgASMB/wHLAZwBIgH/AcwBnAEi - Af8BygGZARoB/wHDAY0BBgH/AeUB1AG1Bf8B5wHYAbwB/wG+AYMBAAH/AcABhwEAAf8BwQGIAQAB/wHC - AYoBAAH/AcYBkAEFAf8BzAGoAUoB/xAAAykB/wMPAf8UAAMPAf8DKQH/EAAB6AH0Av8BmAGkAbAB/wEH - AV0BvgH/AQcBXQG+Af8BBwFdAb4B/wEHAV0BvgH/ATABWQGdAf8BMAFZAZ0B/wEYAV0BrgH/ARgBXQGu - Af8BBwFdAb4B/wEHAV0BvgH/AQABXQHHAf8BAAFdAccB/wGMAaQBvQH/AdwB9AL/A/YB/wFiAa4B2wH/ - AQIBYAHHAf8BAgFgAccB/wECAWABxwH/AQIBYAHHAf8BYgGuAdsB/wECAWABxwH/AQIBYAHHAf8BAgFg - AccB/wECAWABxwH/AZQBvQHgAf8BAgFgAccB/wECAWABxwH/AZQBvQHgAf8D9gH/Ad0BxwGrAf8B0wGm - ASwB/wHQAaIBJQH/AdABoQEmAf8B0AGhASYB/wHQAZ8BIQH/AcsBpAE2Af8B1AHDAaUB/wHKAaQBNgH/ - Ac0BmwEZAf8BzgGcARwB/wHOAZwBHAH/Ac4BnAEbAf8BzwGdARsB/wHaAcMBogH/EAADKQH/Aw8B/xQA - Aw8B/wMpAf8QAAHoAfQC/wGYAaQBsAH/AQcBXQG+Af8BBwFdAb4B/wEAAV0BxwH/AQABXQHHAf8BBwFd - Ab4B/wE3AagB7gH/AeoB9gL/AeoB9gL/A/YB/wP2Af8BjAGkAb0B/wGMAaQBvQH/A/QB/wPfAf8D9wH/ - AZQBvQHgAf8BAgFgAccB/wECAWABxwH/AQIBYAHHAf8BAgFgAccB/wECAWABxwH/AWIBrgHbAf8D9AH/ - A/QB/wP0Af8D9AH/AZQBvQHgAf8BlAG9AeAB/wP2Af8D/gH/AfUB7wHnAf8B0QGoAToB/wHYAakBLAH/ - AdUBpgEsAf8B1QGmASoB/wHUAaMBJQH/AeUBxwGRAf8B8wHqAdgB/wHnAcsBmQH/AdMBoQEhAf8B0wGi - ASQB/wHTAaEBIgH/AdUBowEhAf8BzQGdASUB/wH0Ae0B5AH/EAADhgH/Aw8B/xQAAw8B/wOGAf8QAAHT - Ad8B6wH/AegB9AL/ATcBqAHuAf8BBwFdAb4B/wEAAV0BxwH/AQABXQHHAf8BBwFdAb4B/wEHAV0BvgH/ - AZgBpAGwAf8B6AH0Av8D3wH/A98B/wHcAfQC/wHcAfQC/wPfAf8EAAP+Af8D9wH/AZQBvQHgAf8BAgFg - AccB/wECAWABxwH/AQIBYAHHAf8BAgFgAccB/wECAWABxwH/AWIBrgHbAf8D9QH/A/0B/wP+Af8D9wH/ - A/YB/wP+Bf8EAAHdAcgBqgH/Ad0BsgE7Af8B2gGrAS8B/wHZAasBMAH/AdcBpwEpAf8B8QHmAdMF/wH1 - Ae4B4QH/AdcBpgEpAf8B1wGnASkB/wHYAacBJwH/AdkBqgEsAf8B2wHBAZ4B/xgAA4YB/wMPAf8MAAMP - Af8DhgH/GAAD3wH/AegB9AL/AZgBpAGwAf8BBwFdAb4B/wEHAV0BvgH/AQcBXQG+Af8BBwFdAb4B/wGY - AaQBsAH/AegB9AL/A98B/wQAA98B/wPfAf8IAAT/A/4B/wP3Af8BlAG9AeAB/wECAWABxwH/AQIBYAHH - Af8BAgFgAccB/wECAWABxwH/AZQBvQHgAf8D9gH/A/4F/wP+Af8D/gn/BAAB/gL9Af8B2QG/AZoB/wHg - AbYBQQH/Ad8BsQE0Af8B3AGtAS8B/wHXAbUBUgH/AeIB1QG+Af8B1wG3AYAB/wHbAaoBKwH/Ad4BrgEu - Af8B3gGxATYB/wHWAbgBjQH/Af4B/QH8Af9QAAHTAd8B6wH/AegB9AL/ATcBqAHuAf8BBwFdAb4B/wEH - AV0BvgH/ATcBqAHuAf8B6AH0Av8B0wHfAesB/xgACP8D/gH/A/cB/wGUAb0B4AH/AQIBYAHHAf8BAgFg - AccB/wGUAb0B4AH/A/YB/wP+Gf8MAAHfAcsBsQH/AdwBuAFSAf8B4wG4AUMB/wHjAbQBNwH/Ad0BrgEv - Af8B4QGyATMB/wHiAbYBPQH/AdsBswFJAf8B3gHIAaoB/wL+Af0B/1gAA98B/wHoAfQC/wGYAaQBsAH/ + A/0J/xAAAe8B5gHcAf8BzgG1AZMB/wG4AZMBKQH/AbIBiAEXAf8BuAGSASgB/wHOAbQBkAH/Ae4B5gHb + Af94AAPfAf8B6AH0Av8BmAGkAbAB/wGYAaQBsAH/AegB9AL/A98B/wQAA/YB/wNHAf8DwAH/A/QB/wPW + Af8DMgH/A/UJ/wP+Af8D9gH/AVgBrgHbAf8BWAGuAdsB/wP1Af8D/QX/CAAB/QH7AfoB/wHIAawBhAH/ + AaEBOAEAAf8BnQEyAQAB/wGcATABAAH/AaQBPgEAAf8BnQExAQAB/wGdATEBAAH/AZ8BNwEAAf8BxwGq + AYEB/wH8AfsB+QH/HAADhgH/AwUB/wwAAwUB/wOGAf80AAPfAf8D9AH/ATUBqAHmAf8BBQFTAbYB/wEA + AVMBvgH/AS0BqAHuAf8B6AH0Av8B0wHfAesB/wP6Af8DtAH/AxAB/wMQAf8DEAH/A6IB/wP6Bf8D/gH/ + A/YB/wFYAa4B2wH/AQABVgHHAf8BAAFWAccB/wFYAa4B2wH/A/UB/wP9Af8EAAH8AfsB+QH/AbwBlgEu + Af8BoAE1AQAB/wGhATYBAAH/AZ4BMQEAAf8BygGqAT8B/wH2AfEB6AH/Ac0BrwFJAf8BngExAQAB/wGh + ATYBAAH/AaEBNQEAAf8BugGUASoB/wH8AfoB+AH/FAADhgH/AwAB/xcAAf8DhgH/OAABNQGoAeYB/wEF + AVMBtgH/AQABUwG+Af8BAAFTAb4B/wGYAaQBsAH/AegB9AL/A/4B/wPyAf8DKQH/A+gB/wMrAf8D6AH/ + A/4B/wP0Af8D9AH/A/QB/wGUAb0B4AH/AQABVgHHAf8BAAFWAccB/wEAAVYBxwH/AVgBrgHbAf8D9QH/ + BAABzAGvAYgB/wGlAToBAAH/AaUBOgEAAf8BpQE7AQAB/wGiATUBAAH/AeYB1gG7Bf8B6wHeAcgB/wGj + ATcBAAH/AaUBOgEAAf8BpQE6AQAB/wGlAToBAAH/AcoBrQGEAf8UAAMfAf8DAAH/FwAB/wMfAf8wAAEO + AVMBrgH/AQ4BUwGuAf8BJgFPAZ0B/wEmAU8BnQH/AQUBUwG2Af8BBQFTAbYB/wGYAaQBsAH/AegB9Ab/ + A/kB/wONAf8DUAH/A1oB/wP3Bf8D9AH/AQABVgHHAf8BAAFWAccB/wEAAVYBxwH/AZQBvQHgAf8BAAFW + AccB/wEAAVYBxwH/AZQBvQHgAf8D9gH/AfIB6gHhAf8BqQFBAQAB/wGqAT8BAAH/AaoBPwEAAf8BqgE/ + AQAB/wGnAToBAAH/AeUB0wG2Bf8B6gHcAcMB/wGoATwBAAH/AaoBPgEAAf8BqgE/AQAB/wGqAT8BAAH/ + AakBQAEAAf8B8AHpAd4B/xAAAx8B/wMAAf8XAAH/Ax8B/xwAA98B/wPfAf8MAAEOAVMBrgH/AbUB+gL/ + Ac0B9gL/Ac0B9gL/ATUBqAHmAf8BNQGoAeYB/wHoAfQC/wHTAd8B6wX/A/0B/wPbAf8DEAH/A8kB/wP7 + Bf8D9AH/AQABVgHHAf8D9AH/A/QB/wP0Af8BlAG9AeAB/wGUAb0B4AH/A/YB/wP+Af8B1gG+AZ0B/wGw + AUYBAAH/Aa4BQwEAAf8BrwFEAQAB/wGvAUQBAAH/AawBPwEAAf8B5gHVAbYF/wHrAdwBxAH/Aa0BQQEA + Af8BrwFDAQAB/wGvAUQBAAH/Aa4BRAEAAf8BrwFDAQAB/wHTAbkBlgH/EwAB/wPAAf8UAAPAAf8DAAH/ + GAAB0wHfAesB/wHoAfQC/wHoAfQC/wHTAd8B6wH/CAABJgFPAZ0B/wHNAfYC/wHJAfYC/wFSAaQB0QH/ + AVIBpAHRAf8ByQH2Av8D5QH/BAAI/wP2Af8D9AH/A/QB/wP9Bf8D9AH/AQABVgHHAf8D9AH/A/YB/wFY + Aa4B2wH/AVgBrgHbAf8D9AH/A/wF/wHKAakBRgH/AcABjgECAf8BtQFLAQAB/wGzAUcBAAH/AbQBSQEA + Af8BsgFFAQAB/wHoAdYBuAX/AewB3gHFAf8BsgFGAQAB/wG0AUgBAAH/AbQBSQEAAf8BtAFJAQAB/wG1 + AUkBAAH/AcQBnwEzAf8PAAH/AzgB/xwAAzgB/wMAAf8QAAPfAf8B6AH0Av8BmAGkAbAB/wGYAaQBsAH/ + AegB9AL/A98B/wQAASYBTwGdAf8BzQH2Av8BUgGkAdEB/wEiAU8BoQH/ASIBTwGhAf8BUgGkAdEB/wP0 + Af8D3wX/A/4B/wP2Af8BWAGuAdsB/wFYAa4B2wH/A/UB/wP9Af8D9AH/AQABVgHHAf8D9AH/AVgBrgHb + Af8BAAFWAccB/wEAAVYBxwH/AVgBrgHbAf8D9QH/A/0B/wHJAaYBPQH/AckBmwEUAf8BxQGUAQ0B/wG+ + AYkBAAH/AboBgAEAAf8BtwFJAQAB/wHrAdkBuwX/Ae8B4QHIAf8BtwFLAQAB/wG5AU0BAAH/AbkBTQEA + Af8BuQFNAQAB/wG6AU0BAAH/AcMBmgEnAf8QAAMFAf8DwAH/FAADwAH/AwUB/xAAAdMB3wHrAf8B6AH0 + Av8BLQGoAe4B/wEAAVMBvgH/AQABUwG+Af8BLQGoAe4B/wHNAfYC/wHNAfYC/wEOAVMBrgH/AbUB+gL/ + AS0BqAHuAf8BAAFTAb4B/wEAAVMBxwH/AQABUwHHAf8BjAGkAb0B/wHcAfQC/wP+Af8D9gH/AVgBrgHb + Af8BAAFWAccB/wEAAVYBxwH/AVgBrgHbAf8D9AH/A/QB/wEAAVYBxwH/A/QB/wGUAb0B4AH/AQABVgHH + Af8BAAFWAccB/wEAAVYBxwH/AVgBrgHbAf8D9QH/AdABrwGBAf8BzgGgARkB/wHLAZwBGAH/AcwBnAEY + Af8BygGZARAB/wHDAY0BAAH/AeUB1AG1Bf8B5wHYAbwB/wG+AYMBAAH/AcABhwEAAf8BwQGIAQAB/wHC + AYoBAAH/AcYBkAEAAf8BzAGoAUAB/xAAAx8B/wMFAf8UAAMFAf8DHwH/EAAB6AH0Av8BmAGkAbAB/wEA + AVMBvgH/AQABUwG+Af8BAAFTAb4B/wEAAVMBvgH/ASYBTwGdAf8BJgFPAZ0B/wEOAVMBrgH/AQ4BUwGu + Af8BAAFTAb4B/wEAAVMBvgH/AQABUwHHAf8BAAFTAccB/wGMAaQBvQH/AdwB9AL/A/YB/wFYAa4B2wH/ + AQABVgHHAf8BAAFWAccB/wEAAVYBxwH/AQABVgHHAf8BWAGuAdsB/wEAAVYBxwH/AQABVgHHAf8BAAFW + AccB/wEAAVYBxwH/AZQBvQHgAf8BAAFWAccB/wEAAVYBxwH/AZQBvQHgAf8D9gH/Ad0BxwGrAf8B0wGm + ASIB/wHQAaIBGwH/AdABoQEcAf8B0AGhARwB/wHQAZ8BFwH/AcsBpAEsAf8B1AHDAaUB/wHKAaQBLAH/ + Ac0BmwEPAf8BzgGcARIB/wHOAZwBEgH/Ac4BnAERAf8BzwGdAREB/wHaAcMBogH/EAADHwH/AwUB/xQA + AwUB/wMfAf8QAAHoAfQC/wGYAaQBsAH/AQABUwG+Af8BAAFTAb4B/wEAAVMBxwH/AQABUwHHAf8BAAFT + Ab4B/wEtAagB7gH/AeoB9gL/AeoB9gL/A/YB/wP2Af8BjAGkAb0B/wGMAaQBvQH/A/QB/wPfAf8D9wH/ + AZQBvQHgAf8BAAFWAccB/wEAAVYBxwH/AQABVgHHAf8BAAFWAccB/wEAAVYBxwH/AVgBrgHbAf8D9AH/ + A/QB/wP0Af8D9AH/AZQBvQHgAf8BlAG9AeAB/wP2Af8D/gH/AfUB7wHnAf8B0QGoATAB/wHYAakBIgH/ + AdUBpgEiAf8B1QGmASAB/wHUAaMBGwH/AeUBxwGRAf8B8wHqAdgB/wHnAcsBmQH/AdMBoQEXAf8B0wGi + ARoB/wHTAaEBGAH/AdUBowEXAf8BzQGdARsB/wH0Ae0B5AH/EAADhgH/AwUB/xQAAwUB/wOGAf8QAAHT + Ad8B6wH/AegB9AL/AS0BqAHuAf8BAAFTAb4B/wEAAVMBxwH/AQABUwHHAf8BAAFTAb4B/wEAAVMBvgH/ + AZgBpAGwAf8B6AH0Av8D3wH/A98B/wHcAfQC/wHcAfQC/wPfAf8EAAP+Af8D9wH/AZQBvQHgAf8BAAFW + AccB/wEAAVYBxwH/AQABVgHHAf8BAAFWAccB/wEAAVYBxwH/AVgBrgHbAf8D9QH/A/0B/wP+Af8D9wH/ + A/YB/wP+Bf8EAAHdAcgBqgH/Ad0BsgExAf8B2gGrASUB/wHZAasBJgH/AdcBpwEfAf8B8QHmAdMF/wH1 + Ae4B4QH/AdcBpgEfAf8B1wGnAR8B/wHYAacBHQH/AdkBqgEiAf8B2wHBAZ4B/xgAA4YB/wMFAf8MAAMF + Af8DhgH/GAAD3wH/AegB9AL/AZgBpAGwAf8BAAFTAb4B/wEAAVMBvgH/AQABUwG+Af8BAAFTAb4B/wGY + AaQBsAH/AegB9AL/A98B/wQAA98B/wPfAf8IAAT/A/4B/wP3Af8BlAG9AeAB/wEAAVYBxwH/AQABVgHH + Af8BAAFWAccB/wEAAVYBxwH/AZQBvQHgAf8D9gH/A/4F/wP+Af8D/gn/BAAB/gL9Af8B2QG/AZoB/wHg + AbYBNwH/Ad8BsQEqAf8B3AGtASUB/wHXAbUBSAH/AeIB1QG+Af8B1wG3AYAB/wHbAaoBIQH/Ad4BrgEk + Af8B3gGxASwB/wHWAbgBjQH/Af4B/QH8Af9QAAHTAd8B6wH/AegB9AL/AS0BqAHuAf8BAAFTAb4B/wEA + AVMBvgH/AS0BqAHuAf8B6AH0Av8B0wHfAesB/xgACP8D/gH/A/cB/wGUAb0B4AH/AQABVgHHAf8BAAFW + AccB/wGUAb0B4AH/A/YB/wP+Gf8MAAHfAcsBsQH/AdwBuAFIAf8B4wG4ATkB/wHjAbQBLQH/Ad0BrgEl + Af8B4QGyASkB/wHiAbYBMwH/AdsBswE/Af8B3gHIAaoB/wL+Af0B/1gAA98B/wHoAfQC/wGYAaQBsAH/ AZgBpAGwAf8B6AH0Av8D3wH/HAAM/wP+Af8D9wH/AZQBvQHgAf8BlAG9AeAB/wP2Af8D/h3/EAAB9gHx AesB/wHkAdQBvwH/Ad4BxQGjAf8B3gHEAZwB/wHeAcQBoQH/AeQB0wG8Af8B9QHvAekB/2QAAdMB3wHr - Af8B6AH0Av8B6AH0Av8B0wHfAesB/yAAEP8D/gH/A/cB/wP2Af8D/iH/WQABHwG5Af8BAAERAUAB/wED - AQwBIgH/9QABQAHHAf8BCgHNAfwB/wEAASEBhwH/tAADOwFlAQABFgEAAf8DOgFgNQABQAHHAf8BAwGg - AdIB/wEAARcBNwH/HAADAQECAwABARsAAQEMAAEiASEBIgExAwABAVwAAz4BagERAacBAwH/AQABGgEA - Af8BAAEWAQAB/wM2AVgxAAFAAccB/wEMAdEB/AH/AQABIQGHAf8zAAEBAwABARAAAewB0gHsAf8BNwEA - ATYB/wHmAcwB5gH/AwIBAwMSARkQAAE0AT4BQAH/ASoBMgE1Af8BIQEmASkB/wEXARoBHQH/Ag0BEgH/ - AQQBAgEIAf8DAAH/AwAB/wMAAf8cAAM+AWoBEQGnAQMB/wEuAbsBIgH/AQABHgEAAf8BAAEbAQAB/wEA - ARYBAAH/AzUBVy0AAUABxwH/AQUBoQHRAf8BAAEXATcB/z8AAQEEAAHtAdgB7QH/AakBFQGoAf8BgAEA - AUQB/wE6AQABOgH/AesB0QHrAf8UAAE9AYIBgwH/AZcB2wH1Af8BIAGpAcoB/wEgAakBygH/AR8BpwHJ - Af8BFwGfAcIB/wEOAZYBuQH/AQYBjQGwAf8DAAH/HAABEAGkAQIB/wEuAbsBIgH/AS4BuwEiAf8BAAEd - AQAB/wEAAR4BAAH/AQABGwEAAf8BAAEWAQAB/wMwAUwpAAFAAccB/wEWAeIB/QH/AQABHQGAAf8jAAEB - AwABAQMAAQEDAAEBAwABAQMAAQEDAAEBBAAB6AHRAegB/wGqARUBqQH/AcwBLAHLAf8BQwEAAUMB/wGW - AQABlQH/AUABAAE/Af8B8AHVAfAB/xAAAUUCjAH/AaAB4AH3Af8BNgHNAfEB/wEpAccB7gH/AR0BwQHr - Af8BEgG8AegB/wEHAbcB5gH/AQwBkgG2Af8DAAH/HAABEQGnAQMB/wEuAbsBIgH/AS4BuwEiAf8BqgHU - AaIB/wENAaABAAH/AQABHgEAAf8BAAEbAQAB/wEAARUBAAH/KQABQAHHAf8BHQHXAfwB/wEAAR0BgAH/ - JAABqwHwAfcB/wGrAeIB5QH/AawBzgHMAf8BrQG7AbUB/wGuAacBnAH/BAAB5AHKAeQB/wGpARUBqAH/ - AdMBMAHSAf8B1AEzAdMB/wFEAQABQwH/AZ8BAQGfAf8BjgEAAY0B/wFCAQABQQH/EAABhQKUAf8BpwHj - AfgB/wFBAdMB9AH/ATYBzgHxAf8BKgHIAe4B/wEdAcIB6wH/ARIBvAHoAf8BEQGZAbwB/wEBAQABAwH/ - GAADAgEDARMBqwEFAf8BLgG7ASIB/wGqAdQBogH/AbcB2gGwAf8BqgHUAaIB/wEGAZMBAAH/AQABHgEA - Af8BAAEWAQAB/yUAASUBkAH/AQABQAHHAf8BMwHeAfwB/wEAAR0BgAH/AQABEwE/Af84AAGqARcBqQH/ - AdIBLwHRAf8B1QE0AdUB/wG9ATUBvAH/Ad4BmAHdAf8BjwELAY4B/wGdAQEBnAH/AUMBAAFDAf8QAAGM - ApsB/wGuAeYB+gH/AYYB2AH2Af8BQQHUAfQB/wE2Ac0B8QH/ASoBxwHuAf8BHQHCAesB/wEYAaABwQH/ - AggBDQH/GAADBAEFASgBuAEbAf8BtAHZAa0B/wHFAeIBwAH/AbcB2gGwAf8BtwHaAbAB/wGqAdQBogH/ - AQABiAEAAf8BAAEWAQAB/yEAATQBoAH/AQABhwHHAf8BIAHAAfAB/wEVAcsB/gH/ARYBswHdAf8BAQES - ASsB/wEAARMBPwH/GAABqwHwAfcB/wGrAeUB6QH/AawC1QH/AawBxAHBAf8BrQG1AawB/wGuAaQBmAH/ - BAABqAEUAacB/wHSATIB0QH/AbwBNAG7Af8B7wGlAe4B/wH7AZ8B+gH/Ae8BnQHuAf8BlwEXAZYB/wFB - AQABQQH/EAABkQGiAaEB/wGyAegB/AH/AaAB4gH6Af8BhgHYAfYB/wFCAdMB8wH/ATYBzgHxAf8BKQHI - Ae4B/wEcAaUBxwH/AREBEgEXAf8YAAMCAQMDRAF6AY4BxgGEAf8BuQHcAbMB/wHDAeEBvgH/AcMB4QG+ - Af8BtwHaAbAB/wGqAdQBogH/AQABLAEAAf8dAAGAAbEB/wEAAYcByAH/ARcBugH3Af8BGQHCAfkB/wEP - AbcB+QH/AS0B1gH7Af8BCgGmAegB/wEBAREBKQH/AQABFgGDAf8wAAGnARUBpgH/AbwBNAG7Af8B7wGl - Ae4B/wH7AZsB+gH/AfsBmAH6Af8B+wGZAfoB/wHnAZgB5gH/AZEBEwGQAf8QAAGUAaYBpQH/Ab0B7AH8 - Af8BpQHlAfsB/wGfAeIB+gH/AYYB2AH2Af8BQgHUAfQB/wE2Ac0B8QH/ASABqQHKAf8BGQEdASAB/yAA - A0YBfgGQAccBhgH/Ab4B3gG4Af8BwwHhAb4B/wGzAdkBrAH/AZABxwGGAf8DPQFpHQABQAG4Af8BGQHB - AfkB/wEVAbcB+QH/AZMB7gH+Af8BjwHsAf4B/wEXAbQB8wH/AY0B4wH+Af8BFAG6AeIB/wEAARMBMAH/ - HAABqwHwAfcB/wGsAtUB/wGuAbQBrAH/Aa4BmQGKAf8D/QH/Ac8BiAHPAf8B4gGvAeIB/wH7AasB+gH/ - AfsBmAH6Af8B+wGYAfoB/wHqAZAB6QH/Ac8BiAHPAf8B9AHmAfQB/xAAAZQBpgGlAf8BvQHsAfwB/wG9 - AewB/AH/AbIB6AH8Af8BrgHmAfoB/wGnAeQB+QH/AaAB4AH3Af8BlwHbAfUB/wEiAScBKwH/JAADRwGB - AZQByQGKAf8BvQHeAbcB/wGOAcYBhAH/AzABSyEAAYMBuwH/AR4BxgH5Af8BLgGKAawB/wEuAYoBrAH/ - AS4BigGsAf8BLgGKAawB/wEuAYoBrAH/AScB1QH6Af8BAAESAS0B/zAAAfAB1AHwAf8BzwGIAc8B/wHu - Ab4B7gH/AfsBrgH6Af8B7AGRAesB/wHPAYgBzwH/AfMB4AHyAf8UAAGUAaYBpQH/AZQBpgGlAf8BkwKl - Af8BjwGfAZ4B/wGIApcB/wGBAo4B/wE+AoQB/wE0AT4BQAH/ASsBMgE0Af8oAAM8AWYBlAHJAYoB/wMl - ATclAAGDAbwB/wEhAdIB+gH/AQ8BKQGEAf8MAAESAZABwQH/ARgBuwHhAf8BAAEQASoB/zQAAfIB2wHy - Af8BzwGIAc8B/wHjAawB4wH/Ac8BiAHPAf8B8wHjAfMB/2AAAwEBAgQAAwEBAigAAQcBiAHBAf8BCwGd - AdAB/wE/AeMB+gH/AQ8BhQGeAf8BFgEpAYcB/wEWATsBnAH/ARcBvwH0Af8BDQGMAaoB/wEAAR0BPwH/ - OAAB8gHbAfIB/wHPAYgBzwH/AfAB4wHwAf+YAAEOAZQBxgH/AQkBigHBAf8BCwGaAc0B/wEzAdUB9QH/ - ATYB6QH+Af8BMgHUAfMB/wEPAZIBsgH/AQABKQGMAf8BAAE1AaIB/zwAAf4B+wH+Af+gAAEOAZQBxgH/ - AQoBjQHDAf8BBQGLAboB/wEFAYsBugH/AQIBiAG3Af8BAwE4AaAB/wEAAYIBsgH//wCpAAM2AVgBmQIA - Af8DMwFT8AADOAFdAdcBmgEPAf8BmQIAAf8BmQIAAf8DLwFKLAADHgErA1QBrgFZAmQB7AESAYMBlgH/ - AQABKwGNAf8BAAEiAYwB/wFOAl0B8ANWAbMDJQE3mAADOgFhAdcBmgEPAf8B2AGbARAB/wGZAgAB/wGZ - AgAB/wGZAgAB/wMvAUooAAFbAl4B0AEGAbAB0QH/AYQB1QHoAf8BoQHrAfYB/wEoAeQC/wEAAb4B8wH/ - AQABnwHeAf8BAAGLAb4B/wFbAl4B2VQAAbcBogGTAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIA - Af8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8BGAIAAf8UAAHYAZsBEQH/AdgBmwEQAf8B2AGb - ARAB/wGZAgAB/wGZAgAB/wGZAgAB/wGZAgAB/wMvAUokAAEIAY8BqgH/AQIB1wL/AZAB6gH6Af8BoQHr - AfYB/wEmAdkB9AH/AQABvAHyAf8BAAGnAegB/wEAAZwB2gH/AQABGAGEAf8UAAMxAU0CUgFRAaEBXwJY - AeMBXwJYAeMBUgJRAaEBMQIwAU0EAAMxAU0CUgFRAaEBXwJYAeMBXwJYAeMBUgJRAaEBMQIwAU0MAAG3 - AaIBkwH/Af0B+wH5Af8B4QHcAdgB/wHgAdcB0gH/Ad8BzgHDAf8B3QHIAbsB/wHbAb8BrQH/AdsBuwGn - Af8B2wG7AacB/wHbAbsBpwH/Ac8BtAGjAf8BGAIAAf8UAAHYAZsBEAH/AdgBmwEQAf8B6QG0ATEB/wH8 - AdYBrwH/AbUBGAEAAf8BmQIAAf8BmQIAAf8BmQIAAf8DLwFKIAABCQGRAa4B/wEBAdIB+gH/AY0B5AH2 - Af8BoQHrAfYB/wElAdcB8wH/AQABuQHvAf8BAAGnAegB/wEAAZwB2gH/AQABGgGGAf8QAAM1AVUDZAHn - Ac8BuAGpAf8B6wHWAcgB/wHlAcsBuwH/AbMBlQE0Af8BZAJcAecDSwGOA2QB5wHPAbgBqQH/AesB1gHI - Af8B5QHLAbsB/wGzAZUBNAH/AWQCXAHnATUCNAFVCAABtwGiAZMB/wP+Af8BugGmAZgB/wG1AaABkQH/ - AfsB7AHjAf8BpAGNATMB/wGaAYMBJwH/AfYB1gHCAf8BiAEmARMB/wGDASABDQH/Ac8BtAGjAf8BGAIA - Af8UAAHYAZsBEAH/AeoBtwGCAf8B+wHYAbIB/wH+AdEBowH/AfsB2AGyAf8BrwEMAQAB/wGZAgAB/wGZ - AgAB/wGZAgAB/wMqAUEcAAEMAZUBsAH/AQMB0gH6Af8BjQHkAfQB/wGhAesB9gH/ASUB1wHyAf8BAAG5 - Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEdAYgB/xAAA1UBsgHmAdYBywH/A1kBwgJgAVwB1ANgAdQBTAEq - ASEB+wMAAf8DAAH/AwAB/wFhAlgB5gJgAVwB1ANgAdQDWQHCAbkBnAGIAf8DVQGyCAABugGlAZYB/wP+ - Af8D/gH/A/4B/wH9AfsB+QH/Af0B9wHzAf8B+wHsAeMB/wH6AecB2wH/AfgB4QHSAf8B9wHbAckB/wHQ - AbkBqwH/ARgCAAH/FAAB5wGzATEB/wHxAcMBkQH/Af4BzwGdAv8BzQGZAf8B/gHQAZ8B/wH7AdgBsgH/ - AakBAwEAAf8BmQIAAf8BmQIAAf8BmQIAAf8DBAEFGAABDgGZAbUB/wEEAdEB+wH/AY4B5AH1Af8BoQHr - AfYB/wElAdcB8gH/AQABuQHuAf8BAAGnAegB/wEAAZwB2gH/AQABIAGKAf8QAANlAfQE/wNXAd8DHQEq - A1wBzQX/Af4B9wL/AfEB5gH/AfoB4wHUAf8B8wHXAccB/wNKAY0DHQEqA1wB3wHvAdYBxwH/AWQCUgH0 - CAABvgGpAZoB/wP+Af8BugGmAZgB/wG0AaABkQH/A/4B/wGjAY4BMwH/AZoBgwEnAf8B+wHsAeMB/wGJ - ASYBFAH/AYMBIAENAf8B0QHBAbYB/wEYAgAB/xQAA0UBfAHlAbIBMAH/AfQBwAGLAv8BzQGZAv8BzQGZ - Af8B/gHQAaEB/wH7AdgBsgH/AakBAwEAAf8BmQIAAf8BmQIAAf8cAAERAZsBtwH/AQQB0AH5Af8BjQHj - AfUB/wGhAesB9gH/AScB2QHyAf8BAAG5Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEiAY0B/xAAA1UBsgHy - AeYB3gH/A1kBwgNcAdQBYAJcAdQDYQHiAdMBtQGiAf8DTQH6AdoBwAGvAf8DXwHzA1sB1gFgAlwB1ANZ - AcIBywGxAaEB/wNVAbIIAAHDAa4BngH/A/4B/wP+Af8D/gH/A/4B/wP+Af8B/QH3AfMB/wH8AfIB7AH/ - AfsB7AHjAf8B+gHnAdsB/wHRAcEBtgH/ARgCAAH/GAADRgF/AeQBsAEuAf8B9gHEAZAC/wHNAZkC/wHN - AZkB/wH+AdABoQH/AfsB2AGyAf8BqQEDAQAB/wGZAgAB/xwAARMBngG6Af8BAgHQAfkB/wGNAeMB9AH/ - AaEB6wH2Af8BJAHXAfIB/wEAAbcB7gH/AQABpwHoAf8BAAGcAdoB/wEAASQBjwH/EAADNQFVA2QB5wHt - AeEB1wP/Af0C/wH3AfEB/wHYAcQBtwH/A2QB5wNLAY4DZAHnAe0B4QHXA/8B/QL/AfcB8QH/AdgBxAG3 - Af8DZAHnAzUBVQgAAcgBsgGjAf8D/gH/AboBpgGYAf8BtAGgAZEB/wP+Af8BpAGOATMB/wGZAYQBJwH/ - Af0B9wHzAf8BiAEmARMB/wGDASABDQH/AdEBwQG2Af8BGAIAAf8cAANJAYcB4wGvAS0B/wH2AcQBkAL/ - Ac0BmQL/Ac0BmQH/Af4B0AGhAf8B8gHJAZ0B/wGwAQ8BAAH/HAABFAGiAbwB/wEAAc4B9wH/AYsB4wH0 - Af8BoQHrAfYB/wEjAdYB8gH/AQABtwHuAf8BAAGnAegB/wEAAZwB2gH/AQABJQGSAf8UAAMxAU0DUgGh - A18B4wNfAeMDUgGhAzEBTQQAAzEBTQNSAaEDXwHjA18B4wNSAaEDMQFNDAABzAG2AacB/wP+Af8D/gH/ - A/4B/wP+Af8D/gH/A/4B/wH9AfsB+QH/Af0B9wHzAf8B/AHyAewB/wH7AewB4wH/ARgCAAH/IAADSQGH - AeMBrwEtAf8B9gHEAZAC/wHNAZkB/wHzAcIBjgH/AeMBsAEuAf8DQwF4HAABIAGpAcAB/wELAdQB+gH/ - AZwB7AH6Af8BqwHvAfoB/wGmAe0B+AH/AZQB5wH4Af8BJgHZAfYB/wEAAb0B6QH/AQABMQGXAf9UAAHq - AaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHpAaUBhAH/AecBlwEjAf8B5gGOARcB/wHjATIBAAH/AeMBKwEA - Af8B4gEnAQAB/wHiAScBAAH/AeIBJwEAAf8ByAEXAQAB/yQAA0kBhwHjAa8BLQH/Ae4BvQGKAf8B4wGw - AS4B/wM0AVQgAAGAAbMBxQH/AZsB3gHrAf8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wHF - AfkB/QH/AaAB3wHqAf8BGwGRAaIB/1QAAeoBqgGLAv8BwgGiAf8B/gHAAZ8B/wH9Ab0BmgH/AfsBtQGQ - Af8B+gGwAYsB/wH4AacBMgH/AfYBogEsAf8B9QGdASYB/wH1AZkBHwH/AfMBlQEaAf8BzQEaAQAB/ygA - A0ABbgHlAbIBMgH/AyYBOCQAAzsBYwNgAdYBKwGrAboB/wElAaMBswH/ASEBnQGvAf8BIAGbAa4B/wEk - AaIBtAH/A14B2QNAAW9UAAHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AekBoQE0Af8B6AGb - ASsB/wHmAY4BFwH/AeUBhwENAf8B5AGBAQMB/wHkATABAAH/AeMBKwEAAf8B4gEnAQAB//8A/wAKAAFC - AU0BPgcAAT4DAAEoAwABQAMAAUADAAEBAQABAQYAAQIWAAP/gQAF/wHDAgAB8AEfA/8BgQIAAcABBwHz - AZ8B/wMAAYABAwHnAc8B/wHAAgABgAEDAecBzwH/BAABAQHnAc8B5wQAAQEB5wHPAcMBAQMAAQEBzwHn - AYEEAAEBAecBzwUAAQEB5wHPBQABAQHnAc8FAAEBAecBzwEAAQECAAGAAQMB8wGfAYABEwIAAYABAwL/ - AcABPwIAAeABBwL/AeABfwIAAfABHwL/AfAB/wIAAv8B/AF/Bv8B/AF/BP8B/AF/AfwBfwE/AXMC/wH4 - AT8B/AF/AfkB4AHwAQcB8AEfAfwBfwH/AUEB8AEHAfABDwH8AX8CgAHwAQcB8AEPAfwBfwHBAQAB8AEH - AeABDwH4AT8B/wEAAfABBwHgAQ8B8AEfAYEBAAHwAQcB4AEPAeABDwH/AQAB8AEHAfgBDwHgAQ8B4AEA - AfABBwH8AR8B4AEPAf8BAQHwAQcB/gE/AeMBjwH/AYMC/wH9AX8B4AEPAf8BxwT/AeABDwH/Ae8E/wHw - AR8M/wH4B/8B8AF/AfABBwT/AeABPwHwAQcC/wHAAQMB4AEfAfABBwHAAYEBwAEDAeABDwHwAQcBgAEA - AcABAwHgAQcB8AEHAYABAAHAAQMB4AEDAfABBwGAAQABwAEDAeABBwHwAQcBgAEAAcABAwHwAQcB8AEH - AYABAAHAAQMB+AEHAfABBwHAAYEBwAEDAfwBBwHwAQcC/wHAAQMB/gEPAfABBwL/AcABAwH/AR8B8AEH - Av8BwAEDEP8L + Af8B6AH0Av8B6AH0Av8B0wHfAesB/yAAEP8D/gH/A/cB/wP2Af8D/iH/WQABFQG5Af8BAAEHATYB/wEA + AQIBGAH/9QABNgHHAf8BAAHNAfwB/wEAARcBhwH/tAADOwFlAQABDAEAAf8DOgFgNQABNgHHAf8BAAGg + AdIB/wEAAQ0BLQH/HAADAQECAwABARsAAQEMAAEiASEBIgExAwABAVwAAz4BagEHAacBAAH/AQABEAEA + Af8BAAEMAQAB/wM2AVgxAAE2AccB/wECAdEB/AH/AQABFwGHAf8zAAEBAwABARAAAewB0gHsAf8BLQEA + ASwB/wHmAcwB5gH/AwIBAwMSARkQAAEqATQBNgH/ASABKAErAf8BFwEcAR8B/wENARABEwH/AgMBCAH/ + AwAB/wMAAf8DAAH/AwAB/xwAAz4BagEHAacBAAH/ASQBuwEYAf8BAAEUAQAB/wEAAREBAAH/AQABDAEA + Af8DNQFXLQABNgHHAf8BAAGhAdEB/wEAAQ0BLQH/PwABAQQAAe0B2AHtAf8BqQELAagB/wGAAQABOgH/ + ATABAAEwAf8B6wHRAesB/xQAATMBggGDAf8BlwHbAfUB/wEWAakBygH/ARYBqQHKAf8BFQGnAckB/wEN + AZ8BwgH/AQQBlgG5Af8BAAGNAbAB/wMAAf8cAAEGAaQBAAH/ASQBuwEYAf8BJAG7ARgB/wEAARMBAAH/ + AQABFAEAAf8BAAERAQAB/wEAAQwBAAH/AzABTCkAATYBxwH/AQwB4gH9Af8BAAETAYAB/yMAAQEDAAEB + AwABAQMAAQEDAAEBAwABAQMAAQEEAAHoAdEB6AH/AaoBCwGpAf8BzAEiAcsB/wE5AQABOQH/AZYBAAGV + Af8BNgEAATUB/wHwAdUB8AH/EAABOwKMAf8BoAHgAfcB/wEsAc0B8QH/AR8BxwHuAf8BEwHBAesB/wEI + AbwB6AH/AQABtwHmAf8BAgGSAbYB/wMAAf8cAAEHAacBAAH/ASQBuwEYAf8BJAG7ARgB/wGqAdQBogH/ + AQMBoAEAAf8BAAEUAQAB/wEAAREBAAH/AQABCwEAAf8pAAE2AccB/wETAdcB/AH/AQABEwGAAf8kAAGr + AfAB9wH/AasB4gHlAf8BrAHOAcwB/wGtAbsBtQH/Aa4BpwGcAf8EAAHkAcoB5AH/AakBCwGoAf8B0wEm + AdIB/wHUASkB0wH/AToBAAE5Af8BnwEAAZ8B/wGOAQABjQH/ATgBAAE3Af8QAAGFApQB/wGnAeMB+AH/ + ATcB0wH0Af8BLAHOAfEB/wEgAcgB7gH/ARMBwgHrAf8BCAG8AegB/wEHAZkBvAH/AwAB/xgAAwIBAwEJ + AasBAAH/ASQBuwEYAf8BqgHUAaIB/wG3AdoBsAH/AaoB1AGiAf8BAAGTAQAB/wEAARQBAAH/AQABDAEA + Af8lAAEbAZAB/wEAATYBxwH/ASkB3gH8Af8BAAETAYAB/wEAAQkBNQH/OAABqgENAakB/wHSASUB0QH/ + AdUBKgHVAf8BvQErAbwB/wHeAZgB3QH/AY8BAQGOAf8BnQEAAZwB/wE5AQABOQH/EAABjAKbAf8BrgHm + AfoB/wGGAdgB9gH/ATcB1AH0Af8BLAHNAfEB/wEgAccB7gH/ARMBwgHrAf8BDgGgAcEB/wIAAQMB/xgA + AwQBBQEeAbgBEQH/AbQB2QGtAf8BxQHiAcAB/wG3AdoBsAH/AbcB2gGwAf8BqgHUAaIB/wEAAYgBAAH/ + AQABDAEAAf8hAAEqAaAB/wEAAYcBxwH/ARYBwAHwAf8BCwHLAf4B/wEMAbMB3QH/AQABCAEhAf8BAAEJ + ATUB/xgAAasB8AH3Af8BqwHlAekB/wGsAtUB/wGsAcQBwQH/Aa0BtQGsAf8BrgGkAZgB/wQAAagBCgGn + Af8B0gEoAdEB/wG8ASoBuwH/Ae8BpQHuAf8B+wGfAfoB/wHvAZ0B7gH/AZcBDQGWAf8BNwEAATcB/xAA + AZEBogGhAf8BsgHoAfwB/wGgAeIB+gH/AYYB2AH2Af8BOAHTAfMB/wEsAc4B8QH/AR8ByAHuAf8BEgGl + AccB/wEHAQgBDQH/GAADAgEDA0QBegGOAcYBhAH/AbkB3AGzAf8BwwHhAb4B/wHDAeEBvgH/AbcB2gGw + Af8BqgHUAaIB/wEAASIBAAH/HQABgAGxAf8BAAGHAcgB/wENAboB9wH/AQ8BwgH5Af8BBQG3AfkB/wEj + AdYB+wH/AQABpgHoAf8BAAEHAR8B/wEAAQwBgwH/MAABpwELAaYB/wG8ASoBuwH/Ae8BpQHuAf8B+wGb + AfoB/wH7AZgB+gH/AfsBmQH6Af8B5wGYAeYB/wGRAQkBkAH/EAABlAGmAaUB/wG9AewB/AH/AaUB5QH7 + Af8BnwHiAfoB/wGGAdgB9gH/ATgB1AH0Af8BLAHNAfEB/wEWAakBygH/AQ8BEwEWAf8gAANGAX4BkAHH + AYYB/wG+Ad4BuAH/AcMB4QG+Af8BswHZAawB/wGQAccBhgH/Az0BaR0AATYBuAH/AQ8BwQH5Af8BCwG3 + AfkB/wGTAe4B/gH/AY8B7AH+Af8BDQG0AfMB/wGNAeMB/gH/AQoBugHiAf8BAAEJASYB/xwAAasB8AH3 + Af8BrALVAf8BrgG0AawB/wGuAZkBigH/A/0B/wHPAYgBzwH/AeIBrwHiAf8B+wGrAfoB/wH7AZgB+gH/ + AfsBmAH6Af8B6gGQAekB/wHPAYgBzwH/AfQB5gH0Af8QAAGUAaYBpQH/Ab0B7AH8Af8BvQHsAfwB/wGy + AegB/AH/Aa4B5gH6Af8BpwHkAfkB/wGgAeAB9wH/AZcB2wH1Af8BGAEdASEB/yQAA0cBgQGUAckBigH/ + Ab0B3gG3Af8BjgHGAYQB/wMwAUshAAGDAbsB/wEUAcYB+QH/ASQBigGsAf8BJAGKAawB/wEkAYoBrAH/ + ASQBigGsAf8BJAGKAawB/wEdAdUB+gH/AQABCAEjAf8wAAHwAdQB8AH/Ac8BiAHPAf8B7gG+Ae4B/wH7 + Aa4B+gH/AewBkQHrAf8BzwGIAc8B/wHzAeAB8gH/FAABlAGmAaUB/wGUAaYBpQH/AZMCpQH/AY8BnwGe + Af8BiAKXAf8BgQKOAf8BNAKEAf8BKgE0ATYB/wEhASgBKgH/KAADPAFmAZQByQGKAf8DJQE3JQABgwG8 + Af8BFwHSAfoB/wEFAR8BhAH/DAABCAGQAcEB/wEOAbsB4QH/AQABBgEgAf80AAHyAdsB8gH/Ac8BiAHP + Af8B4wGsAeMB/wHPAYgBzwH/AfMB4wHzAf9gAAMBAQIEAAMBAQIpAAGIAcEB/wEBAZ0B0AH/ATUB4wH6 + Af8BBQGFAZ4B/wEMAR8BhwH/AQwBMQGcAf8BDQG/AfQB/wEDAYwBqgH/AQABEwE1Af84AAHyAdsB8gH/ + Ac8BiAHPAf8B8AHjAfAB/5gAAQQBlAHGAf8BAAGKAcEB/wEBAZoBzQH/ASkB1QH1Af8BLAHpAf4B/wEo + AdQB8wH/AQUBkgGyAf8BAAEfAYwB/wEAASsBogH/PAAB/gH7Af4B/6AAAQQBlAHGAf8BAAGNAcMB/wEA + AYsBugH/AQABiwG6Af8BAAGIAbcB/wEAAS4BoAH/AQABggGyAf//AKkAAzYBWAGZAgAB/wMzAVPwAAM4 + AV0B1wGaAQUB/wGZAgAB/wGZAgAB/wMvAUosAAMeASsDVAGuAVkCZAHsAQgBgwGWAf8BAAEhAY0B/wEA + ARgBjAH/AU4CXQHwA1YBswMlATeYAAM6AWEB1wGaAQUB/wHYAZsBBgH/AZkCAAH/AZkCAAH/AZkCAAH/ + Ay8BSigAAVsCXgHQAQABsAHRAf8BhAHVAegB/wGhAesB9gH/AR4B5AL/AQABvgHzAf8BAAGfAd4B/wEA + AYsBvgH/AVsCXgHZVAABtwGiAZMB/wEOAgAB/wEOAgAB/wEOAgAB/wEOAgAB/wEOAgAB/wEOAgAB/wEO + AgAB/wEOAgAB/wEOAgAB/wEOAgAB/wEOAgAB/xQAAdgBmwEHAf8B2AGbAQYB/wHYAZsBBgH/AZkCAAH/ + AZkCAAH/AZkCAAH/AZkCAAH/Ay8BSiUAAY8BqgH/AQAB1wL/AZAB6gH6Af8BoQHrAfYB/wEcAdkB9AH/ + AQABvAHyAf8BAAGnAegB/wEAAZwB2gH/AQABDgGEAf8UAAMxAU0CUgFRAaEBXwJYAeMBXwJYAeMBUgJR + AaEBMQIwAU0EAAMxAU0CUgFRAaEBXwJYAeMBXwJYAeMBUgJRAaEBMQIwAU0MAAG3AaIBkwH/Af0B+wH5 + Af8B4QHcAdgB/wHgAdcB0gH/Ad8BzgHDAf8B3QHIAbsB/wHbAb8BrQH/AdsBuwGnAf8B2wG7AacB/wHb + AbsBpwH/Ac8BtAGjAf8BDgIAAf8UAAHYAZsBBgH/AdgBmwEGAf8B6QG0AScB/wH8AdYBrwH/AbUBDgEA + Af8BmQIAAf8BmQIAAf8BmQIAAf8DLwFKIQABkQGuAf8BAAHSAfoB/wGNAeQB9gH/AaEB6wH2Af8BGwHX + AfMB/wEAAbkB7wH/AQABpwHoAf8BAAGcAdoB/wEAARABhgH/EAADNQFVA2QB5wHPAbgBqQH/AesB1gHI + Af8B5QHLAbsB/wGzAZUBKgH/AWQCXAHnA0sBjgNkAecBzwG4AakB/wHrAdYByAH/AeUBywG7Af8BswGV + ASoB/wFkAlwB5wE1AjQBVQgAAbcBogGTAf8D/gH/AboBpgGYAf8BtQGgAZEB/wH7AewB4wH/AaQBjQEp + Af8BmgGDAR0B/wH2AdYBwgH/AYgBHAEJAf8BgwEWAQMB/wHPAbQBowH/AQ4CAAH/FAAB2AGbAQYB/wHq + AbcBggH/AfsB2AGyAf8B/gHRAaMB/wH7AdgBsgH/Aa8BAgEAAf8BmQIAAf8BmQIAAf8BmQIAAf8DKgFB + HAABAgGVAbAB/wEAAdIB+gH/AY0B5AH0Af8BoQHrAfYB/wEbAdcB8gH/AQABuQHuAf8BAAGnAegB/wEA + AZwB2gH/AQABEwGIAf8QAANVAbIB5gHWAcsB/wNZAcICYAFcAdQDYAHUAUwBKgEhAfsDAAH/AwAB/wMA + Af8BYQJYAeYCYAFcAdQDYAHUA1kBwgG5AZwBiAH/A1UBsggAAboBpQGWAf8D/gH/A/4B/wP+Af8B/QH7 + AfkB/wH9AfcB8wH/AfsB7AHjAf8B+gHnAdsB/wH4AeEB0gH/AfcB2wHJAf8B0AG5AasB/wEOAgAB/xQA + AecBswEnAf8B8QHDAZEB/wH+Ac8BnQL/Ac0BmQH/Af4B0AGfAf8B+wHYAbIB/wGpAgAB/wGZAgAB/wGZ + AgAB/wGZAgAB/wMEAQUYAAEEAZkBtQH/AQAB0QH7Af8BjgHkAfUB/wGhAesB9gH/ARsB1wHyAf8BAAG5 + Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEWAYoB/xAAA2UB9AT/A1cB3wMdASoDXAHNBf8B/gH3Av8B8QHm + Af8B+gHjAdQB/wHzAdcBxwH/A0oBjQMdASoDXAHfAe8B1gHHAf8BZAJSAfQIAAG+AakBmgH/A/4B/wG6 + AaYBmAH/AbQBoAGRAf8D/gH/AaMBjgEpAf8BmgGDAR0B/wH7AewB4wH/AYkBHAEKAf8BgwEWAQMB/wHR + AcEBtgH/AQ4CAAH/FAADRQF8AeUBsgEmAf8B9AHAAYsC/wHNAZkC/wHNAZkB/wH+AdABoQH/AfsB2AGy + Af8BqQIAAf8BmQIAAf8BmQIAAf8cAAEHAZsBtwH/AQAB0AH5Af8BjQHjAfUB/wGhAesB9gH/AR0B2QHy + Af8BAAG5Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEYAY0B/xAAA1UBsgHyAeYB3gH/A1kBwgNcAdQBYAJc + AdQDYQHiAdMBtQGiAf8DTQH6AdoBwAGvAf8DXwHzA1sB1gFgAlwB1ANZAcIBywGxAaEB/wNVAbIIAAHD + Aa4BngH/A/4B/wP+Af8D/gH/A/4B/wP+Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8B+gHnAdsB/wHR + AcEBtgH/AQ4CAAH/GAADRgF/AeQBsAEkAf8B9gHEAZAC/wHNAZkC/wHNAZkB/wH+AdABoQH/AfsB2AGy + Af8BqQIAAf8BmQIAAf8cAAEJAZ4BugH/AQAB0AH5Af8BjQHjAfQB/wGhAesB9gH/ARoB1wHyAf8BAAG3 + Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEaAY8B/xAAAzUBVQNkAecB7QHhAdcD/wH9Av8B9wHxAf8B2AHE + AbcB/wNkAecDSwGOA2QB5wHtAeEB1wP/Af0C/wH3AfEB/wHYAcQBtwH/A2QB5wM1AVUIAAHIAbIBowH/ + A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaQBjgEpAf8BmQGEAR0B/wH9AfcB8wH/AYgBHAEJAf8BgwEW + AQMB/wHRAcEBtgH/AQ4CAAH/HAADSQGHAeMBrwEjAf8B9gHEAZAC/wHNAZkC/wHNAZkB/wH+AdABoQH/ + AfIByQGdAf8BsAEFAQAB/xwAAQoBogG8Af8BAAHOAfcB/wGLAeMB9AH/AaEB6wH2Af8BGQHWAfIB/wEA + AbcB7gH/AQABpwHoAf8BAAGcAdoB/wEAARsBkgH/FAADMQFNA1IBoQNfAeMDXwHjA1IBoQMxAU0EAAMx + AU0DUgGhA18B4wNfAeMDUgGhAzEBTQwAAcwBtgGnAf8D/gH/A/4B/wP+Af8D/gH/A/4B/wP+Af8B/QH7 + AfkB/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wEOAgAB/yAAA0kBhwHjAa8BIwH/AfYBxAGQAv8BzQGZ + Af8B8wHCAY4B/wHjAbABJAH/A0MBeBwAARYBqQHAAf8BAQHUAfoB/wGcAewB+gH/AasB7wH6Af8BpgHt + AfgB/wGUAecB+AH/ARwB2QH2Af8BAAG9AekB/wEAAScBlwH/VAAB6gGqAYsB/wHqAaoBiwH/AeoBqgGL + Af8B6QGlAYQB/wHnAZcBGQH/AeYBjgENAf8B4wEoAQAB/wHjASEBAAH/AeIBHQEAAf8B4gEdAQAB/wHi + AR0BAAH/AcgBDQEAAf8kAANJAYcB4wGvASMB/wHuAb0BigH/AeMBsAEkAf8DNAFUIAABgAGzAcUB/wGb + Ad4B6wH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wGgAd8B6gH/AREBkQGi + Af9UAAHqAaoBiwL/AcIBogH/Af4BwAGfAf8B/QG9AZoB/wH7AbUBkAH/AfoBsAGLAf8B+AGnASgB/wH2 + AaIBIgH/AfUBnQEcAf8B9QGZARUB/wHzAZUBEAH/Ac0BEAEAAf8oAANAAW4B5QGyASgB/wMmATgkAAM7 + AWMDYAHWASEBqwG6Af8BGwGjAbMB/wEXAZ0BrwH/ARYBmwGuAf8BGgGiAbQB/wNeAdkDQAFvVAAB6gGq + AYsB/wHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHpAaEBKgH/AegBmwEhAf8B5gGOAQ0B/wHlAYcBAwH/ + AeQBgQEAAf8B5AEmAQAB/wHjASEBAAH/AeIBHQEAAf//AP8ACgABQgFNAT4HAAE+AwABKAMAAUADAAFA + AwABAQEAAQEGAAECFgAD/4EABf8BwwIAAfABHwP/AYECAAHAAQcB8wGfAf8DAAGAAQMB5wHPAf8BwAIA + AYABAwHnAc8B/wQAAQEB5wHPAecEAAEBAecBzwHDAQEDAAEBAc8B5wGBBAABAQHnAc8FAAEBAecBzwUA + AQEB5wHPBQABAQHnAc8BAAEBAgABgAEDAfMBnwGAARMCAAGAAQMC/wHAAT8CAAHgAQcC/wHgAX8CAAHw + AR8C/wHwAf8CAAL/AfwBfwb/AfwBfwT/AfwBfwH8AX8BPwFzAv8B+AE/AfwBfwH5AeAB8AEHAfABHwH8 + AX8B/wFBAfABBwHwAQ8B/AF/AoAB8AEHAfABDwH8AX8BwQEAAfABBwHgAQ8B+AE/Af8BAAHwAQcB4AEP + AfABHwGBAQAB8AEHAeABDwHgAQ8B/wEAAfABBwH4AQ8B4AEPAeABAAHwAQcB/AEfAeABDwH/AQEB8AEH + Af4BPwHjAY8B/wGDAv8B/QF/AeABDwH/AccE/wHgAQ8B/wHvBP8B8AEfDP8B+Af/AfABfwHwAQcE/wHg + AT8B8AEHAv8BwAEDAeABHwHwAQcBwAGBAcABAwHgAQ8B8AEHAYABAAHAAQMB4AEHAfABBwGAAQABwAED + AeABAwHwAQcBgAEAAcABAwHgAQcB8AEHAYABAAHAAQMB8AEHAfABBwGAAQABwAEDAfgBBwHwAQcBwAGB + AcABAwH8AQcB8AEHAv8BwAEDAf4BDwHwAQcC/wHAAQMB/wEfAfABBwL/AcABAxD/Cw== 651, 17 + + 758, 17 + AAABAAoAMDAQAAEABABoBgAApgAAACAgEAABAAQA6AIAAA4HAAAQEBAAAQAEACgBAAD2CQAAMDAAAAEA diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index 4b492698c..1c52cc17c 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -37,7 +37,7 @@ class ObjectExplorer : Control private TreeNode _contextMenuNode; private readonly Dictionary _tableContextMenuItems; private readonly Dictionary _tableCrudContextMenuItems; - private readonly Dictionary _serverContextMenuItems; + private readonly Dictionary _serverContextMenuItems; private readonly ContextMenu _verbContextMenu; private bool _isDragging; private string _filter; @@ -97,7 +97,7 @@ public ObjectExplorer() _treeSearch.DebounceLimit = TimeSpan.FromMilliseconds(400); _tableContextMenuItems = new Dictionary(); - _serverContextMenuItems = new Dictionary(); + _serverContextMenuItems = new Dictionary(); _tableCrudContextMenuItems = new Dictionary(); _verbContextMenu = new ContextMenu(); @@ -354,6 +354,12 @@ public void RefreshAllServers() UpdateDrawnNodes(); } + internal void RefreshServer(ConnectionInfo connection) + { + TreeNodeWithConnectionInfo serverNode = FindServerNodeByConnection(connection); + RefreshServer(serverNode); + } + private void RefreshServer(TreeNode node) { var provider = node.Tag as IMetadataProvider; @@ -406,7 +412,7 @@ private void OpenActivityMonitor(TreeNode node) { var provider = node.Tag as IMetadataProvider; if (provider != null && provider.ConnectionInfo.CanCreateSubscription) - TabsFactory.OpenActivityMonitor(provider.ConnectionInfo.Title + " Activity", provider.ConnectionInfo); + TabsFactory.OpenActivityMonitor(provider.ConnectionInfo); } private void OpenInvokeTab() @@ -415,21 +421,15 @@ private void OpenInvokeTab() var verb = (Verb)_contextMenuNode.Tag; if (verb.Arguments.Count == 0) verb.Arguments.AddRange(provider.GetVerbArguments(verb)); - TabsFactory.OpenInvokeTab(string.Format("{0} - Invoke {1}.{2}", provider.ConnectionInfo.Title, verb.EntityName, verb.Name), - provider.ConnectionInfo, verb); + TabsFactory.OpenInvokeTab(provider.ConnectionInfo, verb); } public void GenerateSelectStatement(Entity table, bool includeInheritedProperties) { if (table != null) { - string swql = GenerateSwql(table, includeInheritedProperties); - - ConnectionInfo connection = null; - if ((_contextMenuNode as TreeNodeWithConnectionInfo) != null) - connection = (_contextMenuNode as TreeNodeWithConnectionInfo).Connection; - - TabsFactory.AddTextToEditor(swql, connection); + string query = GenerateSwql(table, includeInheritedProperties); + AddTextEditor(query); } } @@ -545,14 +545,15 @@ public void AddServer(IMetadataProvider provider, ConnectionInfo connection) _tableContextMenuItems.Add(connection.Title, tableContextMenuWithoutCrud); _tableCrudContextMenuItems.Add(connection.Title, tableContextMenuWithCrud); - var serverContextMenu = new ContextMenu(); - serverContextMenu.MenuItems.Add("Refresh", (s, e) => RefreshServer(_contextMenuNode)); + var serverContextMenu = new ContextMenuStrip(); + serverContextMenu.Items.Add("Refresh", Properties.Resources.Refresh_16x, (s, e) => RefreshServer(_contextMenuNode)); if (connection.CanCreateSubscription) - serverContextMenu.MenuItems.Add("Activity Monitor", (s, e) => OpenActivityMonitor(_contextMenuNode)); + serverContextMenu.Items.Add("Activity Monitor", null, (s, e) => OpenActivityMonitor(_contextMenuNode)); - serverContextMenu.MenuItems.Add("Generate C# Code...", (s, e) => GenerateCSharpCode(_contextMenuNode)); - serverContextMenu.MenuItems.Add("Close", (s, e) => CloseServer(_contextMenuNode)); + serverContextMenu.Items.Add("Generate C# Code...", null, (s, e) => GenerateCSharpCode(_contextMenuNode)); + var closeMenuItem = new ToolStripMenuItem("Disconnect", Properties.Resources.Disconnect_16x, (s, e) => CloseServer(_contextMenuNode)); + serverContextMenu.Items.Add(closeMenuItem); _serverContextMenuItems.Add(connection.Title, serverContextMenu); @@ -577,25 +578,39 @@ public void AddServer(IMetadataProvider provider, ConnectionInfo connection) connection.ConnectionClosed += (o, e) => { _tableContextMenuItems.Remove(connection.Title); + tableContextMenuWithoutCrud.Dispose(); + tableContextMenuWithoutCrud = null; + + _tableCrudContextMenuItems.Remove(connection.Title); tableContextMenuWithCrud.Dispose(); tableContextMenuWithCrud = null; - tableContextMenuWithoutCrud.Dispose(); - tableContextMenuWithoutCrud = null; - _serverContextMenuItems.Remove(connection.Title); serverContextMenu.Dispose(); serverContextMenu = null; }; } + internal void CloseServer(ConnectionInfo connection) + { + TreeNodeWithConnectionInfo serverNode = FindServerNodeByConnection(connection); + CloseServer(serverNode); + } + + private TreeNodeWithConnectionInfo FindServerNodeByConnection(ConnectionInfo connection) + { + return _tree.Nodes.OfType() + .FirstOrDefault(n => n.Connection == connection); + } + private void CloseServer(TreeNode contextMenuNode) { - TreeNodeWithConnectionInfo node = contextMenuNode as TreeNodeWithConnectionInfo; + var node = contextMenuNode as TreeNodeWithConnectionInfo; if (node != null) { node.Connection.Close(); _treeData.Nodes.Remove(_treeBindings.FindDataNode(node)); + _tree.Nodes.Remove(contextMenuNode); } } @@ -824,12 +839,16 @@ private void StartSubscription(object sender, EventArgs e) if (table != null) { string query = string.Format(table.IsIndication ? "SUBSCRIBE {0}" : "SUBSCRIBE CHANGES TO {0}", table.FullName); + AddTextEditor(query); + } + } - ConnectionInfo connection = null; - if ((_contextMenuNode as TreeNodeWithConnectionInfo) != null) - connection = (_contextMenuNode as TreeNodeWithConnectionInfo).Connection; - - TabsFactory.AddTextToEditor(query, connection); + private void AddTextEditor(string query) + { + var node = _contextMenuNode as TreeNodeWithConnectionInfo; + if (node != null) + { + TabsFactory.AddTextToEditor(query, node.Connection); } } } diff --git a/Src/SwqlStudio/Properties/Resources.Designer.cs b/Src/SwqlStudio/Properties/Resources.Designer.cs index 7461bbbbc..6ceaed678 100644 --- a/Src/SwqlStudio/Properties/Resources.Designer.cs +++ b/Src/SwqlStudio/Properties/Resources.Designer.cs @@ -150,6 +150,16 @@ internal class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Refresh_16x { + get { + object obj = ResourceManager.GetObject("Refresh_16x", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized string similar to div.corner { /// background-color: silver; diff --git a/Src/SwqlStudio/Properties/Resources.resx b/Src/SwqlStudio/Properties/Resources.resx index 948431aad..a059ccd77 100644 --- a/Src/SwqlStudio/Properties/Resources.resx +++ b/Src/SwqlStudio/Properties/Resources.resx @@ -160,4 +160,7 @@ ..\Resources\TextFile_16x.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Refresh_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Src/SwqlStudio/QueriesDockPanel.cs b/Src/SwqlStudio/QueriesDockPanel.cs index b2b7a1322..546da573a 100644 --- a/Src/SwqlStudio/QueriesDockPanel.cs +++ b/Src/SwqlStudio/QueriesDockPanel.cs @@ -20,27 +20,10 @@ public partial class QueriesDockPanel : DockPanel public PropertyBag QueryParameters { get { return this.queryParametersContent.Parameters; } - set { this.queryParametersContent.Parameters = value; } - } - - /// Returns the currently displayed editor, or null if none are open - internal SciTextEditorControl ActiveEditor - { - get - { - var tab = ActiveQueryTab; - if (tab == null) return null; - return tab.Editor; - } - } - - internal ConnectionInfo ActiveConnectionInfo - { - get + set { - var tab = ActiveConnectionTab; - if (tab == null) return null; - return tab.ConnectionInfo; + this.queryParametersContent.Parameters = value; + ShowPropertiesContent(value); } } @@ -61,12 +44,12 @@ internal IConnectionTab ActiveConnectionTab } /// Returns a list of all editor controls - internal IEnumerable AllEditors + internal IEnumerable AllEditors { get { return from t in this.Contents.OfType() - from c in t.Controls.OfType() + from c in t.Controls.OfType() select c; } } @@ -135,7 +118,7 @@ private void InitializeQueryParameters() this.queryParametersContent = new QueryParameters(); this.queryParametersContent.Text = "Query parameters"; ConfigureBuildInToolbox(this.queryParametersContent); - this.queryParametersContent.Show(this, DockState.DockRight); + this.queryParametersContent.Show(this, DockState.DockRightAutoHide); } private void ConfigureBuildInToolbox(DockContent content) @@ -153,7 +136,7 @@ private void FilesDock_ContentRemoved(object sender, DockContentEventArgs e) private void FilesDock_ActiveContentChanged(object sender, EventArgs e) { var content = this.ActiveContent as DockContent; - if (content != null && content != this.objectExplorerContent || content != this.queryParametersContent) + if (content != null && (content != this.objectExplorerContent || content != this.queryParametersContent)) { this.lastActiveContent = content; this.ActiveQueryTab?.DetectQueryParameters(); @@ -219,15 +202,88 @@ internal void AddNewQueryTab() this.tabsFactory.AddNewQueryTab(); } - public void SetAplicationService(IApplicationService applicationService) + internal void SetAplicationService(TabsFactory tabsFactory) { - this.tabsFactory = new TabsFactory(this, applicationService); - this.objectExplorer.TabsFactory = this.tabsFactory; + this.tabsFactory = tabsFactory; + this.objectExplorer.TabsFactory = tabsFactory; } internal void AllowSetParameters(bool allow) { this.queryParametersContent.AllowSetParameters = allow; } + + private void ShowPropertiesContent(PropertyBag value) + { + if (value.Keys.Count > 0 && IsPropertiesTabAutoHiden()) + { + this.queryParametersContent.IsHidden = false; + this.queryParametersContent.DockState = ActivateHidenProperties(); + } + } + + private bool IsPropertiesTabAutoHiden() + { + switch (this.queryParametersContent.DockState) + { + case DockState.DockTopAutoHide: + case DockState.DockLeftAutoHide: + case DockState.DockBottomAutoHide: + case DockState.DockRightAutoHide: + return true; + default: + return false; + } + } + + private DockState ActivateHidenProperties() + { + switch (this.queryParametersContent.DockState) + { + case DockState.DockTopAutoHide: + return DockState.DockTop; + case DockState.DockLeftAutoHide: + return DockState.DockLeft; + case DockState.DockBottomAutoHide: + return DockState.DockBottom; + case DockState.DockRightAutoHide: + return DockState.DockRight; + default: + return DockState.DockRight; + } + } + + internal void CloseServer(ConnectionInfo connection) + { + this.objectExplorer.CloseServer(connection); + } + + internal void RefreshServer(ConnectionInfo connection) + { + this.objectExplorer.RefreshServer(connection); + } + + internal void CloseAllFixedConnectionTabs(ConnectionInfo connection) + { + var toClose =this.Contents.OfType() + .Where(t => IsFixedConnectionTab(t, connection)) + .ToList(); + + foreach (var connectionTab in toClose) + { + connectionTab.Close(); + } + } + + private bool IsFixedConnectionTab(DockContent tab, ConnectionInfo connection) + { + if(tab.Controls.Count < 1) + return false; + + var connectionTab = tab.Controls[0] as IConnectionTab; + return connectionTab != null && + connectionTab.ConnectionInfo == connection && + !connectionTab.AllowsChangeConnection; + } } } diff --git a/Src/SwqlStudio/QueryParameters.cs b/Src/SwqlStudio/QueryParameters.cs index bc4a73b52..e3f2fdbaa 100644 --- a/Src/SwqlStudio/QueryParameters.cs +++ b/Src/SwqlStudio/QueryParameters.cs @@ -24,7 +24,7 @@ public PropertyBag Parameters get { var bag = new PropertyBag(); - foreach (QueryVariable pair in ((BindingList)parametersGrid.DataSource).Where(v => v.Key != null)) + foreach (QueryVariable pair in GetBoundQueryVariables()) bag[pair.Key] = pair.Value; return bag; @@ -36,7 +36,7 @@ public PropertyBag Parameters return; UpdateFromLastKnown(value); - var currentVariables = (BindingList)parametersGrid.DataSource; + var currentVariables = GetBoundQueryVariables(); UpdateWithCurrentValues(value, currentVariables); var pairs = value.Select(pair => new QueryVariable(pair.Key, pair.Value?.ToString())); QuessRenamedParameter(value); @@ -57,9 +57,15 @@ private void QuessRenamedParameter(PropertyBag propertyBag) } } - private void UpdateWithCurrentValues(PropertyBag propertyBag, BindingList currentVariables) + private IEnumerable GetBoundQueryVariables() { - foreach (QueryVariable variable in currentVariables.Where(v => v.Key != null)) + return ((BindingList)parametersGrid.DataSource) + .Where(v => v.Key != null); + } + + private void UpdateWithCurrentValues(PropertyBag propertyBag, IEnumerable currentVariables) + { + foreach (QueryVariable variable in currentVariables) { if (propertyBag.ContainsKey(variable.Key)) { diff --git a/Src/SwqlStudio/QueryTab.cs b/Src/SwqlStudio/QueryTab.cs index 5a8e8c1b9..9345e8f1a 100644 --- a/Src/SwqlStudio/QueryTab.cs +++ b/Src/SwqlStudio/QueryTab.cs @@ -4,6 +4,7 @@ using System.Data; using System.Diagnostics; using System.Drawing; +using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -13,6 +14,7 @@ using SolarWinds.InformationService.Contract2; using SwqlStudio.Playback; using SwqlStudio.Properties; +using SwqlStudio.Subscriptions; namespace SwqlStudio { @@ -22,6 +24,13 @@ public partial class QueryTab : UserControl, IConnectionTab private string subscriptionId; + private bool HasSubscription + { + get { return !String.IsNullOrEmpty(subscriptionId); } + } + + public bool AllowsChangeConnection => !this.HasSubscription; + [Flags] enum Tabs { @@ -35,6 +44,8 @@ enum Tabs } private Font nullFont; + public IApplicationService ApplicationService { get; set; } + public SubscriptionManager SubscriptionManager { get; set; } public QueryTab() { @@ -72,14 +83,13 @@ void QueryTabDisposed(object sender, EventArgs e) private void Unsubscribe() { - if (!String.IsNullOrEmpty(subscriptionId)) + if (HasSubscription) { - ApplicationService.SubscriptionManager.Unsubscribe(ConnectionInfo, subscriptionId); + this.SubscriptionManager.Unsubscribe(ConnectionInfo, subscriptionId); + this.subscriptionId = string.Empty; } } - public IApplicationService ApplicationService { get; set; } - private void ShowTabs(Tabs tabsToShow) { tabControl1.TabPages.Clear(); @@ -105,16 +115,9 @@ public string QueryText set { sciTextEditorControl1.Text = value; } } - public bool IsDirty + internal void MarkSaved() { - get { return sciTextEditorControl1.Modified; } - set - { - if (value == false) - sciTextEditorControl1.SetSavePoint(); - else - throw new ArgumentException("Can't set IsDirty to true, only false"); - } + this.sciTextEditorControl1.SetSavePoint(); } private ConnectionInfo connectionInfo; @@ -185,7 +188,7 @@ private static StringBuilder FormatGridValue(object value) return str; } - public void CopySelectionToClipboard() + internal void CopySelectionToClipboard() { if (sciTextEditorControl1.Focused) { @@ -245,16 +248,13 @@ public void RunPlayback() if (openFileDialog1.ShowDialog() == DialogResult.OK) { var pbi = new PlaybackItem() { FileName = openFileDialog1.FileName, MultiThread = false, QueryTab = this }; - using (var nc = new NewConnection()) - { - if (nc.ShowDialog(this) != DialogResult.OK) - return; - - var info = nc.ConnectionInfo; - info.Connect(); - pbi.ConnectionInfo = info; - PlaybackManager.StartPlayback(pbi); - } + ConnectionInfo info = ConnectionsManager.AskForNewConnection(); + if (info == null) + return; + + info.Connect(); + pbi.ConnectionInfo = info; + PlaybackManager.StartPlayback(pbi); logTextbox.Text = "Started Playback...\r\n"; } } @@ -306,9 +306,12 @@ public void RunQuery() } else { + ShowTabs(Tabs.Results); queryStatusBar1.UpdateStatusLabel("Running query..."); queryWorker.RunWorkerAsync(new QueryArguments(connection, query)); } + + this.ApplicationService.RefreshSelectedConnections(); } void SubscriptionIndicationReceived(IndicationEventArgs e) @@ -643,6 +646,22 @@ private bool LogTabVisible } } + internal string FileName + { + get { return this.sciTextEditorControl1.FileName; } + set + { + this.sciTextEditorControl1.FileName = value; + if (this.Parent != null) + this.Parent.Text = Path.GetFileName(value); + } + } + + public bool Modified + { + get { return this.sciTextEditorControl1.Modified; } + } + private class QueryArguments { public ConnectionInfo Connection { get; set; } @@ -679,9 +698,8 @@ private void subscriptionWorker_DoWork(object sender, System.ComponentModel.DoWo try { - subscriptionId = ApplicationService.SubscriptionManager.CreateSubscription(ConnectionInfo, arg.Query, - SubscriptionIndicationReceived); - + subscriptionId = this.SubscriptionManager.CreateSubscription(ConnectionInfo, arg.Query, SubscriptionIndicationReceived); + this.Invoke(new Action(() => this.ApplicationService.RefreshSelectedConnections())); subscriptionWorker.ReportProgress(0, "Waiting for notifications"); } catch (Exception ex) @@ -751,6 +769,11 @@ private void sciTextEditorControl1_TextChanged(object sender, EventArgs e) private void delayTimer_Tick(object sender, EventArgs e) { this.delayTimer.Stop(); + + if (this.Parent != null && this.Modified && + !string.IsNullOrEmpty(this.FileName) && !this.Parent.Text.EndsWith("*")) + this.Parent.Text = this.Parent.Text + "*"; + DetectQueryParameters(); } @@ -768,5 +791,25 @@ internal void DetectQueryParameters() this.ApplicationService.QueryParameters = propertyBag; } + + internal void Paste() + { + this.sciTextEditorControl1.Paste(); + } + + internal void Cut() + { + this.sciTextEditorControl1.Cut(); + } + + internal void Undo() + { + this.sciTextEditorControl1.Undo(); + } + + internal void Redo() + { + this.sciTextEditorControl1.Redo(); + } } } diff --git a/Src/SwqlStudio/Resources/Refresh_16x.png b/Src/SwqlStudio/Resources/Refresh_16x.png new file mode 100644 index 000000000..23ffe551e Binary files /dev/null and b/Src/SwqlStudio/Resources/Refresh_16x.png differ diff --git a/Src/SwqlStudio/SciTextEditorControl.cs b/Src/SwqlStudio/SciTextEditorControl.cs index 597a962ef..058447bf9 100644 --- a/Src/SwqlStudio/SciTextEditorControl.cs +++ b/Src/SwqlStudio/SciTextEditorControl.cs @@ -1,9 +1,7 @@ using System; using System.Drawing; -using System.IO; using System.Windows.Forms; using ScintillaNET; -using System.Collections.Generic; using System.Linq; using SwqlStudio.Properties; @@ -203,11 +201,6 @@ protected override void OnKeyPress(KeyPressEventArgs e) public LexerService LexerService { get; } - public void SaveFile(string path) - { - File.WriteAllText(path, Text); - } - public event Action Execute; protected override void OnCharAdded(CharAddedEventArgs e) diff --git a/Src/SwqlStudio/ServerList.cs b/Src/SwqlStudio/ServerList.cs index 3e3626a11..3bcdda8b2 100644 --- a/Src/SwqlStudio/ServerList.cs +++ b/Src/SwqlStudio/ServerList.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace SwqlStudio { @@ -7,24 +8,44 @@ internal class ServerList { private readonly Dictionary connections = new Dictionary(); - public void Add(ConnectionInfo connection) + private readonly Dictionary metadataProviders = + new Dictionary(); + + internal List Connections { - connections.Add(GetKey(connection), connection); + get { return this.connections.Values.ToList(); } + } + + public event EventHandler ConnectionsChanged; + + public IMetadataProvider Add(ConnectionInfo connection) + { + string key = GetKey(connection); + connections.Add(key, connection); + var provider = new SwisMetaDataProvider(connection); + metadataProviders[connection] = provider; + ConnectionsChanged(this, EventArgs.Empty); + return provider; } public void Remove(ConnectionInfo connection) { - connections.Remove(GetKey(connection)); + string key = GetKey(connection); + connections.Remove(key); + metadataProviders.Remove(connection); + ConnectionsChanged(this, EventArgs.Empty); } public bool Exists(ConnectionInfo connection) { - return connections.ContainsKey(GetKey(connection)); + string key = GetKey(connection); + return connections.ContainsKey(key); } public bool TryGet(string serverType, string server, string username, out ConnectionInfo connection) { - return connections.TryGetValue(GetKey(serverType, server, username), out connection); + string key = GetKey(serverType, server, username); + return connections.TryGetValue(key, out connection); } private string GetKey(ConnectionInfo connection) @@ -35,7 +56,11 @@ private string GetKey(ConnectionInfo connection) private string GetKey(string serverType, string server, string username) { return String.Format("{0},{1},{2}", serverType, server, username); + } + public bool TryGetProvider(ConnectionInfo connection, out IMetadataProvider provider) + { + return metadataProviders.TryGetValue(connection, out provider); } } } diff --git a/Src/SwqlStudio/SwqlStudio.csproj b/Src/SwqlStudio/SwqlStudio.csproj index 594f43879..f1919daab 100644 --- a/Src/SwqlStudio/SwqlStudio.csproj +++ b/Src/SwqlStudio/SwqlStudio.csproj @@ -125,6 +125,7 @@ + Component @@ -321,6 +322,7 @@ + diff --git a/Src/SwqlStudio/TabsFactory.cs b/Src/SwqlStudio/TabsFactory.cs index b9c87fa9a..3fb4a9aad 100644 --- a/Src/SwqlStudio/TabsFactory.cs +++ b/Src/SwqlStudio/TabsFactory.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.ServiceModel; using System.ServiceModel.Security; @@ -15,66 +14,74 @@ internal class TabsFactory : ITabsFactory { private static readonly SolarWinds.Logging.Log log = new SolarWinds.Logging.Log(); - private readonly Dictionary metadataProviders = - new Dictionary(); - - private readonly ServerList serverList = new ServerList(); - + private readonly ServerList serverList; private readonly QueriesDockPanel dockPanel; private readonly IApplicationService applicationService; + private readonly ConnectionsManager connectionsManager; + private int queryTabsCounter = 0; - internal TabsFactory(QueriesDockPanel dockPanel, IApplicationService applicationService) + internal TabsFactory(QueriesDockPanel dockPanel, IApplicationService applicationService, + ServerList serverList, ConnectionsManager connectionsManager) { this.dockPanel = dockPanel; this.applicationService = applicationService; + this.serverList = serverList; + this.connectionsManager = connectionsManager; } public void AddTextToEditor(string text, ConnectionInfo info) { if (info == null) - info = this.dockPanel.ActiveConnectionInfo; - - IMetadataProvider metadataProvider; - this.metadataProviders.TryGetValue(info, out metadataProvider); + info = this.applicationService.SelectedConnection; + + if (info == null) + return; - CreateQueryTab(info.Title, info, metadataProvider); + string title = CreateQueryTitile(); + CreateQueryTab(title, info); this.dockPanel.ActiveQueryTab.QueryText = text; } - public void OpenActivityMonitor(string title, ConnectionInfo info) + private string CreateQueryTitile() + { + queryTabsCounter++; + return "Query" + queryTabsCounter; + } + + public void OpenActivityMonitor(ConnectionInfo info) { var activityMonitorTab = new ActivityMonitorTab { - ConnectionInfo = info, + ConnectionInfo = info, Dock = DockStyle.Fill, - ApplicationService = this.applicationService + SubscriptionManager = this.applicationService.SubscriptionManager }; + + string title = info.Title + " Activity"; AddNewTab(activityMonitorTab, title); activityMonitorTab.Start(); } - - public void OpenInvokeTab(string title, ConnectionInfo info, Verb verb) + public void OpenInvokeTab(ConnectionInfo info, Verb verb) { var invokeVerbTab = new InvokeVerbTab { - ConnectionInfo = info, + ConnectionInfo = info, Dock = DockStyle.Fill, - ApplicationService = this.applicationService, Verb = verb }; + + string title = string.Format("Invoke {1}.{2}", verb.EntityName, verb.Name); AddNewTab(invokeVerbTab, title); } /// public void OpenCrudTab(CrudOperation operation, ConnectionInfo info, Entity entity) { - string title = entity.FullName + " - " + operation; var crudTab = new CrudTab(operation) { ConnectionInfo = info, Dock = DockStyle.Fill, - ApplicationService = this.applicationService, Entity = entity }; @@ -83,107 +90,84 @@ public void OpenCrudTab(CrudOperation operation, ConnectionInfo info, Entity ent this.dockPanel.RemoveTab(crudTab.Parent as DockContent); }; + string title = entity.FullName + " - " + operation; AddNewTab(crudTab, title); } internal void AddNewQueryTab() { - using (NewConnection nc = new NewConnection()) + string msg = null; + + try { - if (nc.ShowDialog() != DialogResult.OK) + ConnectionInfo info = this.connectionsManager.ResolveConnection(); + if (info== null) return; - string msg = null; - - try - { - ConnectionInfo info; - bool alreadyExists = false; - alreadyExists = serverList.TryGet(nc.ConnectionInfo.ServerType, nc.ConnectionInfo.Server, nc.ConnectionInfo.UserName, out info); - if (!alreadyExists) - { - info = nc.ConnectionInfo; - info.Connect(); - serverList.Add(info); - - info.ConnectionClosed += (sender, args) => serverList.Remove(info); - } - - if (!alreadyExists) - { - var provider = new SwisMetaDataProvider(info); - this.dockPanel.AddServer(provider, info); - metadataProviders[info] = provider; - } - - this.CreateQueryTab(info.Title, info, metadataProviders[info]); - } - catch (FaultException ex) - { - log.Error("Failed to connect", ex); - msg = ex.Detail.Message; - } - catch (SecurityNegotiationException ex) - { - log.Error("Failed to connect", ex); - msg = ex.Message; - } - catch (FaultException ex) - { - log.Error("Failed to connect", ex); - msg = (ex.InnerException != null) ? ex.InnerException.Message : ex.Message; - } - catch (MessageSecurityException ex) + string title = CreateQueryTitile(); + this.CreateQueryTab(title, info); + } + catch (FaultException ex) + { + log.Error("Failed to connect", ex); + msg = ex.Detail.Message; + } + catch (SecurityNegotiationException ex) + { + log.Error("Failed to connect", ex); + msg = ex.Message; + } + catch (FaultException ex) + { + log.Error("Failed to connect", ex); + msg = (ex.InnerException != null) ? ex.InnerException.Message : ex.Message; + } + catch (MessageSecurityException ex) + { + log.Error("Failed to connect", ex); + if (ex.InnerException != null && ex.InnerException is FaultException) { - log.Error("Failed to connect", ex); - if (ex.InnerException != null && ex.InnerException is FaultException) - { - msg = (ex.InnerException as FaultException).Message; - } - else - { - msg = ex.Message; - } + msg = (ex.InnerException as FaultException).Message; } - catch (Exception ex) + else { - log.Error("Failed to connect", ex); msg = ex.Message; } + } + catch (Exception ex) + { + log.Error("Failed to connect", ex); + msg = ex.Message; + } - if (msg != null) - { - msg = string.Format("Unable to connect to Information Service. {0}", msg); - MessageBox.Show(msg, "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + if (msg != null) + { + msg = string.Format("Unable to connect to Information Service. {0}", msg); + MessageBox.Show(msg, "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } internal void OpenFiles(string[] files) { - var originalConnection = this.dockPanel.ActiveConnectionInfo; - if (originalConnection == null) + var connectionInfo = this.connectionsManager.ResolveConnection(); + if (connectionInfo == null) return; this.dockPanel.ColoseInitialDocument(); - + connectionInfo.Connect(); + // Open file(s) foreach (string fn in files) { QueryTab queryTab = null; try { - var connectionInfo = originalConnection.Copy(); - connectionInfo.Connect(); - - IMetadataProvider metadataProvider; - metadataProviders.TryGetValue(connectionInfo, out metadataProvider); - - queryTab = this.CreateQueryTab(Path.GetFileName(fn), connectionInfo, metadataProvider); + queryTab = this.CreateQueryTab(string.Empty, connectionInfo); queryTab.QueryText = File.ReadAllText(fn); + queryTab.FileName = fn; // Modified flag is set during loading because the document // "changes" (from nothing to something). So, clear it again. - queryTab.IsDirty = false; + queryTab.MarkSaved(); } catch (Exception ex) { @@ -207,7 +191,10 @@ internal void CreateTabFromPrevious() var tab = this.dockPanel.ActiveConnectionTab; if (tab != null) { - var connection = tab.ConnectionInfo; + var connection = this.connectionsManager.ResolveConnection(); + if (connection == null) + return; + var swql = this.dockPanel.ActiveQueryTab.QueryText; this.AddTextToEditor(swql, connection); } @@ -217,24 +204,20 @@ internal void CreateTabFromPrevious() } } - private QueryTab CreateQueryTab(string title, ConnectionInfo info, IMetadataProvider provider) + private QueryTab CreateQueryTab(string title, ConnectionInfo info) { var queryTab = new QueryTab { ConnectionInfo = info, Dock = DockStyle.Fill, - ApplicationService = this.applicationService + ApplicationService = this.applicationService, + SubscriptionManager = this.applicationService.SubscriptionManager }; - + + IMetadataProvider provider; + this.serverList.TryGetProvider(info, out provider); queryTab.SetMetadataProvider(provider); - AddNewTab(queryTab, title); - - info.ConnectionClosed += (sender, args) => - { - this.dockPanel.RemoveTab(queryTab.Parent as DockContent); - }; - return queryTab; }