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
}
}