using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using NaGet.Packages; using NaGet.Packages.Install; namespace AppliStation { /// /// Description of PackagesInstallConfirmForm. /// public partial class InstallationConfirmForm : Form { private Installation[] selectedInstallations = null; private Installation[] updateInstallations = null; private Installation[] requiredInstallations = null; private PackageListsManager pkgListMan; private ushort instslistviewitemcheckedguardcounter = 0; public IEnumerable Installations { get { return NaGet.Utils.MergeEnumerable(requiredInstallations, selectedInstallations); } set { List selectedInstList = new List(); List updateInstList = new List(); requiredInstallations = null; foreach (Installation inst in value) { Package instPkg = pkgListMan.InstalledPkgList.GetPackageForName(inst.InstalledPackage.Name) ?? pkgListMan.SystemInstalledPkgList.GetPackageForName(inst.InstalledPackage.Name); if (instPkg != null) { updateInstList.Add(inst); } else { selectedInstList.Add(inst); } } selectedInstallations = selectedInstList.ToArray(); updateInstallations = updateInstList.ToArray(); updateInstsListView(); } } public PackageListsManager PkgListsManager { get { return pkgListMan; } set { pkgListMan = value; updateInstsListView(); } } public InstallationConfirmForm() { // // The InitializeComponent() call is required for Windows Forms designer support. // InitializeComponent(); // 管理者権限で動いているならばrunasが必要にはならないので表示しない if (NaGet.Utils.IsAdministrators()) { runasCheckBox.Checked = false; runasCheckBox.Visible = false; } // ListViewの効果 AppliStation.Util.NativeMethods.ListView_EnableVistaExplorerTheme(instsListView); AppliStation.Util.NativeMethods.ListView_SetDoubleBuffer(instsListView, true); } #region インストールリスト表示処理部 #region インストールリストの反映 /// /// インストールリストを更新したなどで、リストの表示を更新する /// private void updateInstsListView() { instsListView.BeginUpdate(); if (instsListView.Items.Count > 0) { instsListView.Items.Clear(); } addInstsListItemPerGroup(requiredInstallations, instsListView.Groups["requires"], true); addInstsListItemPerGroup(selectedInstallations, instsListView.Groups["install"], false); addInstsListItemPerGroup(updateInstallations, instsListView.Groups["update"], false); updateCheckBoxStatuses(); updateSilentInstallAsPossibleCheckBox(); instsListView.EndUpdate(); } /// /// 指定したグループのリストの表示を更新する。 /// /// インストールリスト /// 対象のグループ /// 先頭に追加するか private void addInstsListItemPerGroup(IEnumerable insts, ListViewGroup group, bool firstAppend) { // まず所属グループのアイテムをすべて削除する if (insts == null) return; instsListView.BeginUpdate(); List itemsToAdd = new List(); foreach (Installation inst in insts) { Package pkg = inst.InstalledPackage; string[] itemData = new string[instsListView.Columns.Count]; itemData[nameColumnHeader.Index] = pkg.Name; inst.Silent = true; // silent install as possible! Package curPkg = null; if (pkgListMan != null) { curPkg = pkgListMan.InstalledPkgList.GetPackageForName(pkg.Name) ?? pkgListMan.SystemInstalledPkgList.GetPackageForName(pkg.Name); } itemData[versionColumnHeader.Index] = pkg.Version; itemData[currentVersionColumnHeader.Index] = (curPkg != null)? curPkg.Version : "-"; // itemData[silentInstColumnHeader.Index] の設定は instViewUpdateSilentInstallView で itemData[pkgListNameColumnHeader.Index] = pkg.PackageListName; ListViewItem item = new ListViewItem(itemData); item.Tag = inst; item.ToolTipText = pkg.Summary; item.Checked = true; item.Group = group; instViewUpdateSilentInstallView(item); itemsToAdd.Add(item); } if (firstAppend) { for (int i = 0; i < itemsToAdd.Count; i++) { instsListView.Items.Insert(i, itemsToAdd[i]); } } else { instsListView.Items.AddRange(itemsToAdd.ToArray()); } instsListView.EndUpdate(); } #endregion /// /// アイテムのサイレントインストール部分の表示の更新を行う。 /// /// 対象のインストーラーのリストアイテム private void instViewUpdateSilentInstallView(ListViewItem item) { Installation inst = (Installation) item.Tag; item.SubItems[silentInstColumnHeader.Index].Text = (inst.SupportsSilentOnly)? "サイレントインストールのみサポート" : (inst.Silent)? "サイレントインストール" : (inst.IsSupportsSilent)? "手動でインストール" : "サイレントインストールできませんので、手動でインストールします"; } #region instsListViewのオーナードドロー関連 void InstsListViewDrawSubItem(object sender, DrawListViewSubItemEventArgs e) { if (e.Header == silentInstColumnHeader) { Installation inst = ((Installation) e.Item.Tag); //e.DrawBackground(); e.Graphics.Clip.Intersect(e.Bounds); if (inst.Silent) { AppliStation.Util.GUIUtils.Graphics_DrawCenterImage( e.Graphics, instListViewSilentInstallImageList.Images[0], e.Bounds, null); } else if (inst.IsSupportsSilent) { AppliStation.Util.GUIUtils.Graphics_DrawCenterImage( e.Graphics, instListViewSilentInstallImageList.Images[0], e.Bounds, AppliStation.Util.GUIUtils.GetImageAttributeToGrayOut(0.5f)); } } else { e.DrawDefault = true; } } void InstsListViewDrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) { if (e.Header == silentInstColumnHeader) { e.DrawBackground(); e.Graphics.Clip.Intersect(e.Bounds); AppliStation.Util.GUIUtils.Graphics_DrawCenterImage( e.Graphics, instListViewSilentInstallImageList.Images[0], e.Bounds, null); } else { e.DrawDefault = true; } } #endregion #endregion private void updateCheckBoxStatuses() { System.Windows.Forms.ListView.ListViewItemCollection items = instsListView.Items; System.Windows.Forms.ListView.CheckedListViewItemCollection checkeds = instsListView.CheckedItems; instslistviewitemcheckedguardcounter ++; // すべて選択/非選択 selectAllCheckBox.CheckState = (checkeds == null || checkeds.Count == 0)? CheckState.Unchecked : (checkeds.Count == items.Count)? CheckState.Checked : CheckState.Indeterminate; // runas情報 runasCheckBox.Checked = GetShouldUseRunas(); updateUseRunas(); // インストール可能か okButton.Enabled = (checkeds != null) && (checkeds.Count > 0); checkUnselectedDependencies(); instslistviewitemcheckedguardcounter --; } void InstsListViewItemChecked(object sender, ItemCheckedEventArgs e) { if (instslistviewitemcheckedguardcounter == 0) { updateCheckBoxStatuses(); } } void InstsListViewContextMenuStripOpening(object sender, System.ComponentModel.CancelEventArgs e) { System.Windows.Forms.ListView.CheckedIndexCollection chkIdxes = instsListView.CheckedIndices; System.Windows.Forms.ListView.SelectedIndexCollection selIdxes = instsListView.SelectedIndices; silentInstallStripMenuItem.Visible = selIdxes.Count > 0; if (selIdxes.Count > 0) { Installation inst0th = ((Installation) instsListView.Items[selIdxes[0]].Tag); bool bChecked = inst0th.Silent; bool bEnabled = (inst0th.IsSupportsSilent && (!inst0th.SupportsSilentOnly)); silentInstallStripMenuItem.Checked = bChecked; silentInstallStripMenuItem.Enabled = bEnabled; for (int i = 1; i < selIdxes.Count; i++) { Installation inst = ((Installation) instsListView.Items[selIdxes[i]].Tag); if ( (bChecked != inst.Silent) || (bEnabled != (inst.IsSupportsSilent && (!inst.SupportsSilentOnly))) ) { silentInstallStripMenuItem.CheckState = CheckState.Indeterminate; silentInstallStripMenuItem.Enabled = false; break; } } } else { e.Cancel = true; } } void SilentInstallStripMenuItemClick(object sender, EventArgs e) { instsListView.BeginUpdate(); bool silent = ! silentInstallStripMenuItem.Checked; foreach (ListViewItem item in instsListView.SelectedItems) { ((Installation) item.Tag).Silent = silent; instViewUpdateSilentInstallView(item); } updateSilentInstallAsPossibleCheckBox(); instsListView.EndUpdate(); } void SelectAllCheckBoxCheckedChanged(object sender, EventArgs e) { instsListView.BeginUpdate(); instslistviewitemcheckedguardcounter ++; if (selectAllCheckBox.CheckState == CheckState.Checked) { foreach (ListViewItem item in instsListView.Items) { item.Checked = true; } } if (selectAllCheckBox.CheckState == CheckState.Unchecked) { foreach (ListViewItem item in instsListView.Items) { item.Checked = false; } } instslistviewitemcheckedguardcounter --; updateCheckBoxStatuses(); instsListView.EndUpdate(); } void updateSilentInstallAsPossibleCheckBox() { bool isAllSilentAsPossible = true; bool isAllNotSilentAsPossible = true; bool canChangeSilent = false; foreach (ListViewItem item in instsListView.Items) { Installation inst = item.Tag as Installation; if (inst != null) { if (inst.Silent) { if (! inst.SupportsSilentOnly) { isAllNotSilentAsPossible = false; canChangeSilent = true; } } else { if (inst.IsSupportsSilent) { isAllSilentAsPossible = false; canChangeSilent = true; } } } } silentInstallAsPossibleCheckBox.Enabled = canChangeSilent; silentInstallAsPossibleCheckBox.CheckState = (isAllSilentAsPossible)? CheckState.Checked : (isAllNotSilentAsPossible)? CheckState.Unchecked : CheckState.Indeterminate; } void SilentInstallAsPossibleCheckBoxCheckedChanged(object sender, EventArgs e) { instsListView.BeginUpdate(); if (silentInstallAsPossibleCheckBox.CheckState == CheckState.Checked) { foreach (ListViewItem item in instsListView.Items) { Installation inst = item.Tag as Installation; if (inst != null) { if (inst.IsSupportsSilent && inst.Silent == false) { inst.Silent = true; instViewUpdateSilentInstallView(item); } } } } if (silentInstallAsPossibleCheckBox.CheckState == CheckState.Unchecked) { foreach (ListViewItem item in instsListView.Items) { Installation inst = item.Tag as Installation; if (inst != null) { if ((!inst.SupportsSilentOnly) && inst.Silent == true) { inst.Silent = false; instViewUpdateSilentInstallView(item); } } } } instsListView.EndUpdate(); } void InstallationConfirmFormShown(object sender, EventArgs e) { if (InvokeRequired) { Invoke(new MethodInvoker(resolveDependecies)); } else { resolveDependecies(); } } /// /// 依存関係を解決する /// private void resolveDependecies() { if (requiredInstallations == null) { Installation[] resolved, dependencies; instsListView.BeginUpdate(); DependeciesResolver.ResolveInstallations( selectedInstallations, pkgListMan, out resolved, out dependencies); requiredInstallations = dependencies; addInstsListItemPerGroup(requiredInstallations, instsListView.Groups["requires"], true); updateCheckBoxStatuses(); updateSilentInstallAsPossibleCheckBox(); instsListView.EndUpdate(); } } /// /// 依存関係を確認してGUIに反映させる。 /// 選択されていないが依存関係上必要なソフトを探し出す。 /// /// 選択されていないが依存関係上必要なソフトの個数(何もない場合はゼロ) private uint checkUnselectedDependencies() { uint retVal = 0; List instPkgs = new List(); foreach (Installation inst in Installations) { instPkgs.Add(inst.InstalledPackage); } List pkg = new List(); foreach (Installation inst in DependeciesResolver.CreateRequiresInstallations(CheckedInstallations, pkgListMan, instPkgs)) { pkg.Add(inst.InstalledPackage); } foreach (ListViewItem item in instsListView.Items) { if ((pkg.IndexOf(((Installation) item.Tag).InstalledPackage) >= 0) && !item.Checked) { item.ForeColor = Color.Red; retVal++; } else { item.ForeColor = Color.Empty; } } return retVal; } /// /// インストールするよう選択されたパッケージの配列 /// public Installation[] CheckedInstallations { get { List insts = new List(); foreach (ListViewItem item in instsListView.CheckedItems) { insts.Add((Installation) item.Tag); } return insts.ToArray(); } } #region runas関連 /// /// runasで実行するか否か /// public bool UseRunas { set { runasCheckBox.Checked = (! NaGet.Utils.IsAdministrators()) && value; updateUseRunas(); } get { return runasCheckBox.Checked; } } /// /// 選択されたパッケージを調査して、Runasを使うべきかいなかを返す /// public bool GetShouldUseRunas() { if (NaGet.Utils.IsAdministrators()) { // 管理者権限で動いている場合は不要 return false; } else if (NaGet.Utils.IsUACEnabled()) { // UACが適用されている場合は標準では不要とする return false; } // ひとつでもPCターゲットなインストーラーがあれば必要とする foreach (Installation inst in CheckedInstallations) { if (inst.TargetPC) return true; } // それ以外は不要 return false; } void RunasCheckBoxCheckedChanged(object sender, EventArgs e) { updateUseRunas(); } private void updateUseRunas() { AppliStation.Util.NativeMethods.Button_SetElevationRequiredState(okButton, UseRunas); } #endregion } }