using System; using System.Drawing; using System.Windows.Forms; using NaGet.Packages; using NaGet.Packages.Install; using System.IO; using System.Collections.Generic; namespace AppliStation { /// /// Description of PackageListViewForm. /// public partial class PackageListViewForm : Form { protected PackageListsManager pkgListsMan = null; public PackageListViewForm() { // // The InitializeComponent() call is required for Windows Forms designer support. // InitializeComponent(); installToolStripMenuItem.Font = new Font(installToolStripMenuItem.Font, FontStyle.Bold); uninstallToolStripMenuItem.Font = new Font(uninstallToolStripMenuItem.Font, FontStyle.Bold); pkgListsMan = new PackageListsManager(); this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); AppliStation.Util.NativeMethods.ListView_EnableVistaExplorerTheme(packageListView); AppliStation.Util.NativeMethods.ListView_SetDoubleBuffer(packageListView, true); } private void ShowInfoToDetailBoxFor(Package pkg) { detailBox.Clear(); detailBox.SelectionFont = new Font(detailBox.Font.FontFamily, 12); detailBox.SelectedText += string.Format("{0} ({1})\r\n", pkg.Name, pkg.Version); if (! string.IsNullOrEmpty(pkg.Tags) ) { detailBox.SelectionFont = new Font(detailBox.Font.FontFamily, 8); detailBox.SelectedText += "タグ:"; foreach (string tag in pkg.Tags.Split(' ')) { detailBox.AppendText(" "); AppliStation.Util.NativeMethods.RichTextBox_AddTextLink(detailBox, tag); } detailBox.AppendText("\r\n"); } if (pkg is InstalledPackage) { InstalledPackage iPkg = (InstalledPackage) pkg; System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (iPkg.UninstallInfo.InstallDate != null) { sb.AppendFormat("インストールした日: {0:d} ", iPkg.UninstallInfo.InstallDate.Value); } if (iPkg.UninstallInfo.EstimatedSize > 0) { sb.AppendFormat("サイズ: {0} ", NaGet.Utils.FormatSize(iPkg.UninstallInfo.EstimatedSize*1024)); } if (sb.Length > 0) { detailBox.SelectionFont = new Font(detailBox.Font.FontFamily, 8); detailBox.SelectedText += sb.ToString(); detailBox.SelectedText += "\r\n"; } } detailBox.SelectionFont = detailBox.Font; if (pkg.Url != null && pkg.Url.Href != null) { detailBox.SelectedText += "公式サイト: "; AppliStation.Util.NativeMethods.RichTextBox_AddTextLink(detailBox, pkg.Url.Href); detailBox.SelectedText += "\r\n"; } detailBox.SelectedText += pkg.Summary; } void PackageListViewSelectedIndexChanged(object sender, EventArgs e) { uint installPkgCount = 0; uint uninstallPkgCount = 0; bool installBtnEnabled, uninstallBtnEnabled; Package[] selectedPkgs = NaGet.Utils.IEnumerable2Array(SelectedPackages()); foreach (Package pkg in selectedPkgs) { if (pkg is InstalledPackage) { uninstallPkgCount ++; } else { installPkgCount ++; } } installBtnEnabled = (installPkgCount > 0) && (uninstallPkgCount == 0); uninstallBtnEnabled = (uninstallPkgCount == 1) && (installPkgCount == 0); upgradeToolStripButton.Visible = (selectedPkgs.Length <= 0); informationToolStripDropDownButton.Visible = (selectedPkgs.Length == 1); uninstallToolStripButton.Visible = uninstallBtnEnabled; installToolStripButton.Visible = installBtnEnabled; // detailBoxのメッセージ設定 detailBox.Clear(); switch (selectedPkgs.Length) { case 0: int count = packageListView.Items.Count; detailBox.Text = (count > 0) ? string.Format("{0}個のソフトがあります。", count) : "該当するソフトがありません。"; break; case 1: ShowInfoToDetailBoxFor(selectedPkgs[0]); break; default: // case 2 and over: detailBox.Text = (installBtnEnabled)? string.Format("{0}個のソフトが選択されています。", installPkgCount) : (uninstallBtnEnabled)? string.Format("{0}個のインストール済みのソフトが選択されています。", uninstallPkgCount) : string.Format("{0}個のソフトが選択されています。\r\n(うち{1}個はインストール済み、{2}個はインストール可能)", installPkgCount+uninstallPkgCount, uninstallPkgCount, installPkgCount); break; } try { detailBox.Select(0, 0); detailBox.ScrollToCaret(); } catch (System.Runtime.InteropServices.COMException) { // ScrollToCaretでこけることがある } } void PackageListViewItemActivate(object sender, EventArgs e) { if (packageListView.SelectedItems.Count <= 0) { return; // exit } foreach (ListViewItem item in packageListView.SelectedItems) { Package pkg = (Package) item.Tag; if (pkg is InstalledPackage) { UninstallToolStripButtonClick(sender, e); } else { InstallToolStripButtonClick(sender, e); } break; } } private void buildInstalledDirectoryMenuItemStripChildren(InstalledPackage pkg) { //installedDirectoryStripMenuItem.BaseFolderPath = pkg.UninstallInfo.InstallLocation; installedDirectoryStripMenuItem.BaseFolderPath = pkg.discoverInstalledLocation(); } #region packageListViewのSort関連 AppliStation.Util.ListViewItemSortComparer packageListViewSortComparer; void PackageListViewColumnClick(object sender, ColumnClickEventArgs e) { SortOrder order = SortOrder.None; if (packageListViewSortComparer == null) { order = SortOrder.Ascending; packageListViewSortComparer = new AppliStation.Util.ListViewItemSortComparer(e.Column, order); packageListView.ListViewItemSorter = packageListViewSortComparer; } else { if (packageListViewSortComparer.Column == e.Column) { order = (packageListViewSortComparer.Order == SortOrder.Ascending)? SortOrder.Descending : SortOrder.Ascending; packageListViewSortComparer.Order = order; } else { order = packageListViewSortComparer.Order; packageListViewSortComparer.Column = e.Column; } packageListView.Sort(); } AppliStation.Util.NativeMethods.ColumnHeader_SetSortState(packageListView, e.Column, order); // ソート対象列の色付け try { // SendMessage(hWnd, LVM_SETSELECTEDCOLUMN, column, NULL); AppliStation.Util.NativeMethods.SendMessage(packageListView.Handle, 0x1000+140, (uint) e.Column, 0); } catch (Exception) { } } #endregion void Form_OnLoad(object sender, EventArgs e) { packageListViewImageList.Images.Add("installed", Icon.ExtractAssociatedIcon(Application.ExecutablePath)); updatePackageFilterToolStripMenuItemCheckState(); installedASPackageFilterToolStripMenuItem.Image = packageListViewImageList.Images["installed"]; installedSysPackageFilterToolStripMenuItem.Image = packageListViewImageList.Images["sys"]; } #region PackageFilter関連 private enum PackageFilterIndex : int { All = 0, NotInstalled = 1, InstalledAS = 2, InstalledSys = 3, } private PackageFilterIndex currentPackageFilter = PackageFilterIndex.All; private PackageFilterIndex CurrentPackageFilter { get { return currentPackageFilter; } set { currentPackageFilter = value; updatePackageFilterToolStripMenuItemCheckState(); } } private void updatePackageFilterToolStripMenuItemCheckState() { ToolStripMenuItem selected = getCheckedPackageFilterToolStripItem(); foreach (ToolStripMenuItem item in packageFilterToolStripDropDownButton.DropDown.Items) { item.Checked = selected == item; } packageFilterToolStripDropDownButton.Text = selected.Text; packageFilterToolStripDropDownButton.Image = selected.Image; packageFilterToolStripDropDownButton.ToolTipText = selected.ToolTipText; } private ToolStripMenuItem getCheckedPackageFilterToolStripItem() { switch (currentPackageFilter) { case PackageFilterIndex.NotInstalled: return notInstalledPackageFilterToolStripMenuItem; case PackageFilterIndex.InstalledAS: return installedASPackageFilterToolStripMenuItem; case PackageFilterIndex.InstalledSys: return installedSysPackageFilterToolStripMenuItem; default: return allPackageFilterToolStripMenuItem; } } void AnyPackageFilterToolStripMenuItemClicked(object sender, EventArgs e) { if (sender == notInstalledPackageFilterToolStripMenuItem) { currentPackageFilter = PackageFilterIndex.NotInstalled; } else if (sender == installedASPackageFilterToolStripMenuItem) { currentPackageFilter = PackageFilterIndex.InstalledAS; } else if (sender == installedSysPackageFilterToolStripMenuItem) { currentPackageFilter = PackageFilterIndex.InstalledSys; } else { currentPackageFilter = PackageFilterIndex.All; } updatePackageFilterToolStripMenuItemCheckState(); searchTextBox.FireTextChangedTrigger(); PackageListViewUpdate(); } #endregion void PackageListViewUpdate() { this.packageListView.Items.Clear(); if (currentPackageFilter == PackageFilterIndex.All || currentPackageFilter == PackageFilterIndex.NotInstalled) { foreach (Package pkg in pkgListsMan.AvailablePkgList.Search(searchTextBox.Text)) { if (Installation.GetPreferInstallerIndex(pkg) >= 0) { // インストール可能 if (currentPackageFilter == PackageFilterIndex.NotInstalled && (pkgListsMan.InstalledPkgList.GetPackageForName(pkg.Name) != null|| pkgListsMan.SystemInstalledPkgList.GetPackageForName(pkg.Name) != null) ) { continue; // インストール済みは次のループへ(未インストールソフト抽出時) } ListViewItem item = new ListViewItem(new string[]{pkg.Name, pkg.Version, pkg.Summary}); item.Tag = pkg; item.ToolTipText = pkg.Summary; this.packageListView.Items.Add(item); } } } if (currentPackageFilter == PackageFilterIndex.All || currentPackageFilter == PackageFilterIndex.InstalledAS) { foreach (Package pkg in pkgListsMan.InstalledPkgList.Search(searchTextBox.Text)) { ListViewItem item = new ListViewItem(new string[]{pkg.Name, pkg.Version, pkg.Summary}); item.Tag = pkg; item.ToolTipText = pkg.Summary; item.ImageKey = "installed"; this.packageListView.Items.Add(item); } } if (currentPackageFilter == PackageFilterIndex.All || currentPackageFilter == PackageFilterIndex.InstalledSys) { foreach (Package pkg in pkgListsMan.SystemInstalledPkgList.Search(searchTextBox.Text)) { ListViewItem item = new ListViewItem(new string[]{pkg.Name, pkg.Version, pkg.Summary}); item.Tag = pkg; item.ToolTipText = pkg.Summary; item.ImageKey = "sys"; this.packageListView.Items.Add(item); } } PackageListViewSelectedIndexChanged(packageListView, null); detailBox.Refresh(); //this.packageListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); } void DetailBoxLinkClicked(object sender, LinkClickedEventArgs e) { if (System.Text.RegularExpressions.Regex.IsMatch(e.LinkText, "^https?://")){ /* URLの場合はブラウザ起動 */ try { System.Diagnostics.Process.Start(e.LinkText); } catch (System.ComponentModel.Win32Exception) { MessageBox.Show(string.Format("{0}を開くのに失敗しました。", e.LinkText), "ブラウザ起動エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { /* それ以外はタグとみなして検索 */ searchTextBox.Text = e.LinkText; } } internal void updateActionInvoke(bool downloadPackageListsFlag) { AppliStation.Util.ExecutionProgressViewer prog = new AppliStation.Util.ExecutionProgressViewer(); prog.Shown += delegate(object sender2, EventArgs e2) { NaGet.SubCommands.NaGetUpdate tasks = new NaGet.SubCommands.NaGetUpdate(pkgListsMan, downloadPackageListsFlag); prog.SetTaskSet(tasks); prog.Refresh(); prog.StartTaskSet(); }; prog.Text = "リストの更新"; prog.ShowDialog(this); } void UpdateToolStripButtonClick(object sender, EventArgs e) { updateActionInvoke(true); UpdatePackageList(); } void LocalupdateToolStripMenuItemClick(object sender, EventArgs e) { updateActionInvoke(false); UpdatePackageList(); } #region searchTextBoxまわり void SearchTextBoxKeyPress(object sender, KeyPressEventArgs e) { switch (e.KeyChar) { case (char)Keys.Enter: searchTextBox.FireTextChangedTrigger(); break; case (char)Keys.Escape: searchTextBox.Text = string.Empty; break; } } void SearchTextBoxTextChangedTriggerFired(object sender, EventArgs e) { PackageListViewUpdate(); } #endregion internal void installActionInvoke(Installation[] insts) { AppliStation.Util.ExecutionProgressViewer prog = new AppliStation.Util.ExecutionProgressViewer(); prog.Shown += delegate(object sender2, EventArgs e2) { NaGet.SubCommands.NaGetInstall tasks = new NaGet.SubCommands.NaGetInstall(pkgListsMan, insts); prog.SetTaskSet(tasks); prog.Refresh(); prog.StartTaskSet(); }; prog.Text = string.Format("ソフトウェアのインストール"); prog.ShowDialog(this); } void InstallToolStripButtonClick(object sender, EventArgs e) { InstallationConfirmForm confirm = new InstallationConfirmForm(); confirm.PkgListsManager = pkgListsMan; confirm.Installations = Installation.ConvertInstallations( NaGet.Utils.IEnumerable2Array(SelectedPackages()) ); confirm.UseRunas = confirm.GetShouldUseRunas(); DialogResult result = confirm.ShowDialog(this); if (result == DialogResult.OK) { Installation[] insts = confirm.CheckedInstallations; if (confirm.UseRunas) { installRunasActionInvoke(insts); } else { installActionInvoke(insts); } UpdatePackageList(); } } public void installRunasActionInvoke(Installation[] insts) { this.setWindowEnabled(false); string tmpfileName = Path.GetTempFileName(); try { NaGet.Utils.PutSerializeObject(tmpfileName, insts); System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo(); procInfo.FileName = Application.ExecutablePath; procInfo.Arguments = string.Format("--noupdate --cmd=install \"--instsref={0}\"", tmpfileName); procInfo.Verb = "runas"; procInfo.WorkingDirectory = Environment.CurrentDirectory; System.Diagnostics.Process hProc = System.Diagnostics.Process.Start(procInfo); hProc.EnableRaisingEvents = true; hProc.SynchronizingObject = this; hProc.Exited += delegate(object sender, EventArgs e) { UpdatePackageList(); this.setWindowEnabled(true); this.BringToFront(); if (File.Exists(tmpfileName)) { File.Delete(tmpfileName); } }; } catch (System.ComponentModel.Win32Exception ex) { MessageBox.Show(ex.Message, "インストール", MessageBoxButtons.OK, MessageBoxIcon.Error); if (File.Exists(tmpfileName)) { File.Delete(tmpfileName); } this.setWindowEnabled(true); } } internal void uninstallActionInvoke(InstalledPackage[] pkgs) { AppliStation.Util.ExecutionProgressViewer prog = new AppliStation.Util.ExecutionProgressViewer(); prog.Shown += delegate(object sender2, EventArgs e2) { NaGet.SubCommands.NaGetUninstall tasks = new NaGet.SubCommands.NaGetUninstall(pkgListsMan, pkgs); prog.SetTaskSet(tasks); prog.Refresh(); prog.StartTaskSet(); }; prog.Text = string.Format("ソフトウェアのアンインストール"); prog.ShowDialog(this); } internal void uninstallRunasActionInvoke(InstalledPackage[] pkgs) { this.setWindowEnabled(false); string tmpfileName = Path.GetTempFileName(); try { NaGet.Utils.PutSerializeObject(tmpfileName, pkgs); System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo(); procInfo.FileName = Application.ExecutablePath; procInfo.Arguments = string.Format("--noupdate --cmd=uninstall \"--pkgsref={0}\"", tmpfileName); procInfo.Verb = "runas"; procInfo.WorkingDirectory = Environment.CurrentDirectory; System.Diagnostics.Process hProc = System.Diagnostics.Process.Start(procInfo); hProc.EnableRaisingEvents = true; hProc.SynchronizingObject = this; hProc.Exited += delegate(object sender, EventArgs e) { UpdatePackageList(); this.setWindowEnabled(true); this.BringToFront(); if (File.Exists(tmpfileName)) { File.Delete(tmpfileName); } }; } catch (System.ComponentModel.Win32Exception ex) { MessageBox.Show(ex.Message, "アンインストール", MessageBoxButtons.OK, MessageBoxIcon.Error); this.setWindowEnabled(true); if (File.Exists(tmpfileName)) { File.Delete(tmpfileName); } } } void UninstallToolStripButtonClick(object sender, EventArgs e) { PackageUninstallConfirmForm confirm = new PackageUninstallConfirmForm(); foreach (InstalledPackage pkg in SelectedPackages()) { confirm.UninstallPackage = pkg; break; } confirm.UseRunas = confirm.GetShouldUseRunas(); DialogResult result = confirm.ShowDialog(this); if (result == DialogResult.OK) { InstalledPackage[] instPkgs = new InstalledPackage[]{confirm.UninstallPackage}; if (confirm.UseRunas) { uninstallRunasActionInvoke(instPkgs); } else { uninstallActionInvoke(instPkgs); } UpdatePackageList(); } } void WebOfficialToolStripMenuItemClick(object sender, EventArgs e) { foreach (Package pkg in SelectedPackages()) { string linkURL = pkg.Url.Href; if (! (pkg == null || string.IsNullOrEmpty(linkURL))) { try { System.Diagnostics.Process.Start(linkURL); } catch (System.ComponentModel.Win32Exception) { MessageBox.Show(string.Format("{0}を開くのに失敗しました。", linkURL), "ブラウザ起動エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } } break; } } void WebGoogleSearchToolStripMenuItemClick(object sender, EventArgs e) { foreach (Package pkg in SelectedPackages()) { string q = System.Web.HttpUtility.UrlEncode(pkg.Name, System.Text.Encoding.UTF8); string googleURL = @"http://www.google.co.jp/search?q="+q; try { System.Diagnostics.Process.Start(googleURL); } catch (System.ComponentModel.Win32Exception) { MessageBox.Show("Googleを開くのに失敗しました。", "ブラウザ起動エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } break; } } void OpenInstalledDirectoryStripMenuItemClick(object sender, EventArgs e) { foreach (InstalledPackage pkg in SelectedPackages()) { if (pkg.Type == InstallerType.ARCHIVE) { System.Diagnostics.Process.Start(Path.Combine(NaGet.Env.ArchiveProgramFiles, pkg.Name)); } else if (Directory.Exists(pkg.discoverInstalledLocation())) { System.Diagnostics.Process.Start(pkg.discoverInstalledLocation()); } break; } } void PropertiesToolStripMenuItemClick(object sender, EventArgs e) { foreach (Package pkg in SelectedPackages()) { PackageInfoForm form = new PackageInfoForm(); form.SelectedObject = pkg; form.Text = string.Format("{0}({1})のプロパティ", pkg.Name, pkg.Version); form.ShowDialog(this); break; } } void PackageListContextMenuStripOpening(object sender, System.ComponentModel.CancelEventArgs e) { // コンテクストメニューから開かれなかった場合はインストール/アンインストールは表示しない bool parentIsPkgListView = (packageListContextMenuStrip.SourceControl == packageListView); // メニューアイテムのインストール/アンインストールの表示はツールストリップに同じ installToolStripMenuItem.Visible = parentIsPkgListView && installToolStripButton.Visible; uninstallToolStripMenuItem.Visible = parentIsPkgListView && uninstallToolStripButton.Visible; // インストールもアンインストールもできない状態ならば、メニューを表示しない if (! (installToolStripButton.Visible || uninstallToolStripButton.Visible)) { e.Cancel = true; return; } // 選択パッケージが1つのとき bool selectionIsOnlyOne = packageListView.SelectedItems.Count == 1; if (selectionIsOnlyOne) { Package pkg = SelectedPackage(); bool isInstalledPackage = pkg is InstalledPackage; webResourcesToolStripMenuItem.Text = string.Format( webResourcesToolStripMenuItem.Tag.ToString(), pkg.Name.Replace("&", "&&")); // pkg.Nameに&が含まれているときはエンコード webOfficialToolStripMenuItem.Enabled = ! (pkg.Url == null || string.IsNullOrEmpty(pkg.Url.Href)); // webGoogleSearchToolStripMenuItem always active. bool installedDirectoryStripMenuItemVisible = isInstalledPackage && ( (pkg.Type == InstallerType.ARCHIVE) || Directory.Exists(((InstalledPackage) pkg).discoverInstalledLocation()) ); installedDirectoryStripMenuItem.Visible = installedDirectoryStripMenuItemVisible; if (installedDirectoryStripMenuItemVisible) { buildInstalledDirectoryMenuItemStripChildren((InstalledPackage) pkg); } } packageListContextMenuStripSeparator.Visible = parentIsPkgListView && selectionIsOnlyOne; webResourcesToolStripMenuItem.Visible = selectionIsOnlyOne; if (! selectionIsOnlyOne) installedDirectoryStripMenuItem.Visible = false; propertiesToolStripMenuItem.Visible = selectionIsOnlyOne; } private IEnumerable getUpdatedPackages(PackageList installedPkgList, PackageList avaiablePkgList, IComparer verComp) { foreach (InstalledPackage pkg in installedPkgList) { Package avaiablePkg = avaiablePkgList.GetPackageForName(pkg.Name); if (avaiablePkgList != null) { if (verComp.Compare(pkg.Version, avaiablePkg.Version) < 0 && installedPkgList.GetPackageForPackage(pkg.Name, avaiablePkg.Version) == null) { yield return avaiablePkg; } } } } void UpgradeToolStripButtonClick(object sender, EventArgs e) { List pkgs; VersionComparetor verComp = new VersionComparetor(); PackageList avaiablePackageList = pkgListsMan.AvailablePkgList; pkgs = NaGet.Utils.MeargeList( getUpdatedPackages(pkgListsMan.InstalledPkgList, avaiablePackageList, verComp), getUpdatedPackages(pkgListsMan.SystemInstalledPkgList, avaiablePackageList, verComp) ); if (pkgs.Count <= 0) { MessageBox.Show(this, "更新されたソフトはありません", "ソフトの更新"); return; } InstallationConfirmForm confirm = new InstallationConfirmForm(); confirm.PkgListsManager = pkgListsMan; confirm.Installations = Installation.ConvertInstallations(pkgs.ToArray()); DialogResult result = confirm.ShowDialog(this); if (result == DialogResult.OK) { Installation[] insts = confirm.CheckedInstallations; if (confirm.UseRunas) { installRunasActionInvoke(insts); } else { installActionInvoke(insts); } UpdatePackageList(); } } public void UpdatePackageList() { pkgListsMan.LoadPackageLists(); this.PackageListViewUpdate(); } /// /// インストールするよう選択されたパッケージの配列 /// public IEnumerable SelectedPackages() where TPackage : Package { List pkgs = new List(); foreach (ListViewItem item in packageListView.SelectedItems) { pkgs.Add((TPackage) item.Tag); } return pkgs; } /// /// インストールするよう選択されたパッケージをひとつ返す。 /// /// 選択されたパッケージ(選択されていないときはnull) public TPackage SelectedPackage() where TPackage : Package { foreach (ListViewItem item in packageListView.SelectedItems) { return (TPackage) item.Tag; } return null; } /// /// 自ウィンドウの有効無効(Enabled)を(必要あればInvokeして)実行する /// /// 有効か否か。Enabledの値に入れられる private void setWindowEnabled(bool enabled) { MethodInvoker process = (MethodInvoker) delegate() { this.Enabled = enabled; }; if (InvokeRequired) { Invoke(process); } else { process.Invoke(); } } } }