OSDN Git Service

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