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