OSDN Git Service

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