OSDN Git Service

na-get-lib,パフォーマンスチューニングなど(動作変更なし)
[applistation/AppliStation.git] / AppliStation / InstallationConfirmForm.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Drawing;\r
4 using System.Windows.Forms;\r
5 using NaGet.Packages;\r
6 using NaGet.Packages.Install;\r
7 \r
8 namespace AppliStation\r
9 {\r
10         /// <summary>\r
11         /// Description of PackagesInstallConfirmForm.\r
12         /// </summary>\r
13         public partial class InstallationConfirmForm : Form\r
14         {\r
15                 private Installation[] selectedInstallations = null;\r
16                 \r
17                 private Installation[] updateInstallations = null;\r
18                 \r
19                 private Installation[] requiredInstallations = null;\r
20                 \r
21                 private PackageListsManager pkgListMan;\r
22 \r
23                 public IEnumerable<Installation> Installations {\r
24                         get {\r
25                                 return NaGet.Utils.MergeEnumerable<Installation>(requiredInstallations, selectedInstallations);\r
26                         }\r
27                         set {\r
28                                 List<Installation> selectedInstList = new List<Installation>();\r
29                                 List<Installation> updateInstList = new List<Installation>();\r
30                                 \r
31                                 requiredInstallations = null;\r
32                                 foreach (Installation inst in value) {\r
33                                         Package instPkg = pkgListMan.InstalledPkgList.GetPackageForName(inst.InstalledPackage.Name) ??\r
34                                                 pkgListMan.SystemInstalledPkgList.GetPackageForName(inst.InstalledPackage.Name);\r
35                                         \r
36                                         if (instPkg != null) {\r
37                                                 updateInstList.Add(inst);\r
38                                         } else {\r
39                                                 selectedInstList.Add(inst);\r
40                                         }\r
41                                 }\r
42                                 selectedInstallations = selectedInstList.ToArray();\r
43                                 updateInstallations = updateInstList.ToArray();\r
44                                 \r
45                                 updateInstsListView();\r
46                         }\r
47                 }\r
48                 \r
49                 public PackageListsManager PkgListsManager {\r
50                         get { return pkgListMan; }\r
51                         set {\r
52                                 pkgListMan = value;\r
53                                 \r
54                                 updateInstsListView();\r
55                         }\r
56                 }\r
57                 \r
58                 public InstallationConfirmForm()\r
59                 {\r
60                         //\r
61                         // The InitializeComponent() call is required for Windows Forms designer support.\r
62                         //\r
63                         InitializeComponent();\r
64                         \r
65                         // 管理者権限で動いているならばrunasが必要にはならないので表示しない\r
66                         if (NaGet.Utils.IsAdministrators()) {\r
67                                 runasCheckBox.Checked = false;\r
68                                 runasCheckBox.Visible = false;\r
69                         }\r
70                         \r
71                         // ListViewの効果\r
72                         AppliStation.Util.NativeMethods.ListView_EnableVistaExplorerTheme(instsListView);\r
73                         AppliStation.Util.NativeMethods.ListView_SetDoubleBuffer(instsListView, true);\r
74                 }\r
75                 \r
76                 #region インストールリスト表示処理部\r
77                 \r
78                 #region インストールリストの反映\r
79                 \r
80                 /// <summary>\r
81                 /// インストールリストを更新したなどで、リストの表示を更新する\r
82                 /// </summary>\r
83                 private void updateInstsListView()\r
84                 {\r
85                         if (instsListView.Items.Count > 0) {\r
86                                 instsListView.Items.Clear();\r
87                         }\r
88                         \r
89                         addInstsListItemPerGroup(requiredInstallations, instsListView.Groups["requires"], true);\r
90                         addInstsListItemPerGroup(selectedInstallations, instsListView.Groups["install"], false);\r
91                         addInstsListItemPerGroup(updateInstallations, instsListView.Groups["update"], false);\r
92                         \r
93                         InstsListViewItemChecked(instsListView, null);\r
94                         instsListView.Refresh();\r
95                 }\r
96 \r
97                 /// <summary>\r
98                 /// 指定したグループのリストの表示を更新する。\r
99                 /// </summary>\r
100                 /// <param name="insts">インストールリスト</param>\r
101                 /// <param name="group">対象のグループ</param>\r
102                 /// <param name="firstAppend">先頭に追加するか</param>\r
103                 private void addInstsListItemPerGroup(IEnumerable<Installation> insts, ListViewGroup group, bool firstAppend)\r
104                 {\r
105                         // まず所属グループのアイテムをすべて削除する\r
106                         if (insts == null) return;\r
107                         \r
108                         List<ListViewItem> itemsToAdd = new List<ListViewItem>();\r
109                         foreach (Installation inst in insts) {\r
110                                 Package pkg = inst.InstalledPackage;\r
111                                 \r
112                                 string[] itemData = new string[instsListView.Columns.Count];\r
113                                 itemData[nameColumnHeader.Index] = pkg.Name;\r
114                                 \r
115                                 inst.Silent = true; // silent install as possible!\r
116                                 \r
117                                 Package curPkg = null;\r
118                                 if (pkgListMan != null) {       \r
119                                         curPkg = pkgListMan.InstalledPkgList.GetPackageForName(pkg.Name) ??\r
120                                                 pkgListMan.SystemInstalledPkgList.GetPackageForName(pkg.Name);\r
121                                 }\r
122                                 itemData[versionColumnHeader.Index]        = pkg.Version;\r
123                                 itemData[currentVersionColumnHeader.Index] = (curPkg != null)? curPkg.Version : "-";\r
124                                 // itemData[silentInstColumnHeader.Index] の設定は instViewUpdateSilentInstallView で\r
125                                 itemData[pkgListNameColumnHeader.Index]    = pkg.PackageListName;\r
126                                 \r
127                                 ListViewItem item = new ListViewItem(itemData);\r
128                                 item.Tag = inst;\r
129                                 item.ToolTipText = pkg.Summary;\r
130                                 item.Checked = true;\r
131                                 item.Group = group;\r
132                                 instViewUpdateSilentInstallView(item);\r
133                                 \r
134                                 itemsToAdd.Add(item);\r
135                         }\r
136                         \r
137                         if (firstAppend) {\r
138                                 for (int i = 0; i < itemsToAdd.Count; i++) {\r
139                                         instsListView.Items.Insert(i, itemsToAdd[i]);\r
140                                 }\r
141                         } else {\r
142                                 instsListView.Items.AddRange(itemsToAdd.ToArray());\r
143                         }\r
144                 }\r
145 \r
146                 #endregion\r
147                 \r
148                 /// <summary>\r
149                 /// アイテムのサイレントインストール部分の表示の更新を行う。\r
150                 /// </summary>\r
151                 /// <param name="item">対象のインストーラのリストアイテム</param>\r
152                 private void instViewUpdateSilentInstallView(ListViewItem item)\r
153                 {\r
154                         Installation inst = (Installation) item.Tag;\r
155                         item.SubItems[silentInstColumnHeader.Index].Text =\r
156                                 (inst.SupportsSilentOnly)? "サイレントインストールのみサポート" :\r
157                                 (inst.Silent)? "サイレントインストール" :\r
158                                 (inst.IsSupportsSilent)? "手動でインストール" :\r
159                                 "サイレントインストールできませんので、手動でインストールします";\r
160                 }\r
161                 \r
162                 #region instsListViewのオーナードドロー関連\r
163                 \r
164                 void InstsListViewDrawSubItem(object sender, DrawListViewSubItemEventArgs e)\r
165                 {\r
166                         if (e.Header == silentInstColumnHeader) {\r
167                                 Installation inst = ((Installation) e.Item.Tag);\r
168                                 \r
169                                 //e.DrawBackground();\r
170                                 e.Graphics.Clip.Intersect(e.Bounds);\r
171                                 \r
172                                 if (inst.Silent) {\r
173                                         AppliStation.Util.GUIUtils.Graphics_DrawCenterImage(\r
174                                                 e.Graphics,\r
175                                                 instListViewSilentInstallImageList.Images[0],\r
176                                                 e.Bounds, null);\r
177                                 } else if (inst.IsSupportsSilent) {\r
178                                         AppliStation.Util.GUIUtils.Graphics_DrawCenterImage(\r
179                                                 e.Graphics,\r
180                                                 instListViewSilentInstallImageList.Images[0],\r
181                                                 e.Bounds,\r
182                                                 AppliStation.Util.GUIUtils.GetImageAttributeToGrayOut(0.5f));\r
183                                 }\r
184                         } else {\r
185                                 e.DrawDefault = true;\r
186                         }\r
187                 }\r
188                 \r
189                 void InstsListViewDrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)\r
190                 {\r
191                         if (e.Header == silentInstColumnHeader) {\r
192                                 e.DrawBackground();\r
193                                 e.Graphics.Clip.Intersect(e.Bounds);\r
194                                 AppliStation.Util.GUIUtils.Graphics_DrawCenterImage(\r
195                                         e.Graphics,\r
196                                         instListViewSilentInstallImageList.Images[0],\r
197                                         e.Bounds, null);\r
198                         } else {\r
199                                 e.DrawDefault = true;\r
200                         }\r
201                 }\r
202                 \r
203                 #endregion\r
204                 \r
205                 #endregion\r
206                 \r
207                 void InstsListViewItemChecked(object sender, ItemCheckedEventArgs e)\r
208                 {\r
209                         System.Windows.Forms.ListView.CheckedListViewItemCollection checkeds = instsListView.CheckedItems;\r
210                         \r
211                         runasCheckBox.Checked = GetShouldUseRunas();\r
212                         updateUseRunas();\r
213                                                 \r
214                         okButton.Enabled = (checkeds != null) && (checkeds.Count > 0);\r
215                         \r
216                         checkUnselectedDependencies();\r
217                 }\r
218                                 \r
219                 void InstsListViewContextMenuStripOpening(object sender, System.ComponentModel.CancelEventArgs e)\r
220                 {\r
221                         System.Windows.Forms.ListView.CheckedIndexCollection  chkIdxes = instsListView.CheckedIndices;\r
222                         System.Windows.Forms.ListView.SelectedIndexCollection selIdxes = instsListView.SelectedIndices;\r
223                         \r
224                         silentInstallStripMenuItem.Visible = selIdxes.Count > 0;\r
225                         if (selIdxes.Count > 0) {\r
226                                 Installation inst0th = ((Installation) instsListView.Items[selIdxes[0]].Tag);\r
227                                 bool bChecked = inst0th.Silent;\r
228                                 bool bEnabled = (inst0th.IsSupportsSilent && (!inst0th.SupportsSilentOnly));\r
229                                 silentInstallStripMenuItem.Checked = bChecked;\r
230                                 silentInstallStripMenuItem.Enabled = bEnabled;\r
231                                 \r
232                                 for (int i = 1; i < selIdxes.Count; i++) {\r
233                                         Installation inst = ((Installation) instsListView.Items[selIdxes[i]].Tag);\r
234                                         \r
235                                         if ( (bChecked != inst.Silent) ||\r
236                                             (bEnabled != (inst.IsSupportsSilent && (!inst.SupportsSilentOnly))) ) {\r
237                                                 silentInstallStripMenuItem.CheckState = CheckState.Indeterminate;\r
238                                                 silentInstallStripMenuItem.Enabled = false;\r
239                                                 break;\r
240                                         }\r
241                                 }\r
242                         }\r
243                         instListToolStripSeparator.Visible = selIdxes.Count > 0;\r
244                 \r
245                         \r
246                         selectAllInstsStripMenuItem.Enabled = chkIdxes.Count < instsListView.Items.Count;\r
247                         unselectAllInstsStripMenuItem.Enabled = chkIdxes.Count > 0;\r
248                 }\r
249                 \r
250                 void SilentInstallStripMenuItemClick(object sender, EventArgs e)\r
251                 {\r
252                         bool silent = ! silentInstallStripMenuItem.Checked;\r
253                         foreach (ListViewItem item in instsListView.SelectedItems) {\r
254                                 ((Installation) item.Tag).Silent = silent;\r
255                                 instViewUpdateSilentInstallView(item);\r
256                         }\r
257                 }\r
258                                 \r
259                 void SelectAllInstsStripMenuItemClick(object sender, EventArgs e)\r
260                 {\r
261                         foreach (ListViewItem item in instsListView.Items) {\r
262                                 item.Checked = true;\r
263                         }\r
264                         instsListView.Refresh();\r
265                 }\r
266                 \r
267                 void UnselectAllInstsStripMenuItemClick(object sender, EventArgs e)\r
268                 {\r
269                         foreach (ListViewItem item in instsListView.CheckedItems) {\r
270                                 item.Checked = false;\r
271                         }\r
272                         instsListView.Refresh();\r
273                 }\r
274 \r
275                 void InstallationConfirmFormShown(object sender, EventArgs e)\r
276                 {\r
277                         if (InvokeRequired) {\r
278                                 Invoke(new MethodInvoker(resolveDependecies));\r
279                         } else {\r
280                                 resolveDependecies();\r
281                         }\r
282                 }\r
283                 \r
284                 /// <summary>\r
285                 /// 依存関係を解決する\r
286                 /// </summary>\r
287                 private void resolveDependecies()\r
288                 {\r
289                         if (requiredInstallations == null) {\r
290                                 Installation[] resolved, dependencies;\r
291                                 \r
292                                 DependeciesResolver.ResolveInstallations(\r
293                                         selectedInstallations,\r
294                                         pkgListMan,\r
295                                         out resolved,\r
296                                         out dependencies);\r
297                                 \r
298                                 requiredInstallations = dependencies;\r
299                                 \r
300                                 addInstsListItemPerGroup(requiredInstallations, instsListView.Groups["requires"], true);\r
301                                 \r
302                                 InstsListViewItemChecked(instsListView, null);\r
303                                 instsListView.Refresh();\r
304                         }\r
305                 }\r
306                 \r
307                 /// <summary>\r
308                 /// 依存関係を確認してGUIに反映させる。\r
309                 /// 選択されていないが依存関係上必要なソフトを探し出す。\r
310                 /// </summary>\r
311                 /// <returns>選択されていないが依存関係上必要なソフトの個数(何もない場合はゼロ)</returns>\r
312                 private uint checkUnselectedDependencies()\r
313                 {\r
314                         uint retVal = 0;\r
315                         \r
316                         List<Package> instPkgs = new List<Package>();\r
317                         foreach (Installation inst in Installations) {\r
318                                 instPkgs.Add(inst.InstalledPackage);\r
319                         }\r
320                         \r
321                         List<Package> pkg = new List<Package>();\r
322                         foreach (Installation inst in DependeciesResolver.CreateRequiresInstallations(CheckedInstallations, pkgListMan, instPkgs)) {\r
323                                 pkg.Add(inst.InstalledPackage);\r
324                         }\r
325                         \r
326                         foreach (ListViewItem item in instsListView.Items) {\r
327                                 if ((pkg.IndexOf(((Installation) item.Tag).InstalledPackage) >= 0) && !item.Checked) {\r
328                                         item.ForeColor = Color.Red;\r
329                                         retVal++;\r
330                                 } else {\r
331                                         item.ForeColor = Color.Empty;\r
332                                 }\r
333                         \r
334                         }\r
335                         return retVal;\r
336                 }\r
337                 \r
338                 /// <summary>\r
339                 /// インストールするよう選択されたパッケージの配列\r
340                 /// </summary>\r
341                 public Installation[] CheckedInstallations {\r
342                         get {\r
343                                 List<Installation> insts = new List<Installation>();\r
344                                 foreach (ListViewItem item in instsListView.CheckedItems) {\r
345                                         insts.Add((Installation) item.Tag);\r
346                                 }\r
347                                 return insts.ToArray();\r
348                         }\r
349                 }\r
350                 \r
351                 #region runas関連\r
352                 \r
353                 /// <summary>\r
354                 /// runasで実行するか否か\r
355                 /// </summary>\r
356                 public bool UseRunas {\r
357                         set {\r
358                                 runasCheckBox.Checked = (! NaGet.Utils.IsAdministrators()) && value;\r
359                                 \r
360                                 updateUseRunas();\r
361                         }\r
362                         get {\r
363                                 return runasCheckBox.Checked;\r
364                         }\r
365                 }\r
366                 \r
367                 /// <summary>\r
368                 /// 選択されたパッケージを調査して、Runasを使うべきかいなかを返す\r
369                 /// </summary>\r
370                 public bool GetShouldUseRunas()\r
371                 {\r
372                         if (NaGet.Utils.IsAdministrators()) {\r
373                                 // 管理者権限で動いている場合は不要\r
374                                 return false;   \r
375                         } else if (NaGet.Utils.IsUACEnabled()) {\r
376                                 // UACが適用されている場合は標準では不要とする\r
377                                 return false;   \r
378                         }\r
379                         \r
380                         // ひとつでもPCターゲットなインストーラがあれば必要とする\r
381                         foreach (Installation inst in CheckedInstallations) {\r
382                                 if (inst.TargetPC) return true;\r
383                         }\r
384                         // それ以外は不要\r
385                         return false;\r
386                 }\r
387                 \r
388                 void RunasCheckBoxCheckedChanged(object sender, EventArgs e)\r
389                 {\r
390                         updateUseRunas();\r
391                 }\r
392                 \r
393                 private void updateUseRunas()\r
394                 {\r
395                         if (UseRunas) {\r
396                                 System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InstallationConfirmForm));\r
397                                 okButton.Image = ((System.Drawing.Bitmap)(resources.GetObject("okButton.Image")));\r
398                         } else {\r
399                                 okButton.Image = null;\r
400                         }\r
401                 }\r
402                 \r
403                 #endregion\r
404         }\r
405 }\r