Process Hacker
chcol.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * column chooser
4  *
5  * Copyright (C) 2010 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phapp.h>
24 #include <settings.h>
25 #include <windowsx.h>
26 
27 typedef struct _COLUMNS_DIALOG_CONTEXT
28 {
29  HWND ControlHandle;
30  ULONG Type;
31  PPH_LIST Columns;
32 
33  HWND InactiveList;
34  HWND ActiveList;
36 
37 INT_PTR CALLBACK PhpColumnsDlgProc(
38  _In_ HWND hwndDlg,
39  _In_ UINT uMsg,
40  _In_ WPARAM wParam,
41  _In_ LPARAM lParam
42  );
43 
45  _In_ HWND ParentWindowHandle,
46  _In_ HWND ControlHandle,
47  _In_ ULONG Type
48  )
49 {
50  COLUMNS_DIALOG_CONTEXT context;
51 
52  context.ControlHandle = ControlHandle;
53  context.Type = Type;
54 
55  if (Type == PH_CONTROL_TYPE_TREE_NEW)
56  context.Columns = PhCreateList(TreeNew_GetColumnCount(ControlHandle));
57  else
58  return;
59 
60  DialogBoxParam(
62  MAKEINTRESOURCE(IDD_CHOOSECOLUMNS),
63  ParentWindowHandle,
65  (LPARAM)&context
66  );
67 
68  PhDereferenceObject(context.Columns);
69 }
70 
71 static int __cdecl PhpColumnsCompareDisplayIndexTn(
72  _In_ const void *elem1,
73  _In_ const void *elem2
74  )
75 {
76  PPH_TREENEW_COLUMN column1 = *(PPH_TREENEW_COLUMN *)elem1;
77  PPH_TREENEW_COLUMN column2 = *(PPH_TREENEW_COLUMN *)elem2;
78 
79  return uintcmp(column1->DisplayIndex, column2->DisplayIndex);
80 }
81 
82 _Success_(return != -1)
83 static ULONG IndexOfStringInList(
84  _In_ PPH_LIST List,
85  _In_ PWSTR String
86  )
87 {
88  ULONG i;
89 
90  for (i = 0; i < List->Count; i++)
91  {
92  if (PhEqualString2(List->Items[i], String, FALSE))
93  return i;
94  }
95 
96  return -1;
97 }
98 
99 INT_PTR CALLBACK PhpColumnsDlgProc(
100  _In_ HWND hwndDlg,
101  _In_ UINT uMsg,
102  _In_ WPARAM wParam,
103  _In_ LPARAM lParam
104  )
105 {
106  PCOLUMNS_DIALOG_CONTEXT context = NULL;
107 
108  if (uMsg == WM_INITDIALOG)
109  {
110  context = (PCOLUMNS_DIALOG_CONTEXT)lParam;
111  SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context);
112  }
113  else
114  {
115  context = (PCOLUMNS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom());
116  }
117 
118  if (!context)
119  return FALSE;
120 
121  switch (uMsg)
122  {
123  case WM_INITDIALOG:
124  {
125  ULONG count;
126  ULONG total;
127  ULONG i;
128  PPH_LIST displayOrderList = NULL;
129 
130  context->InactiveList = GetDlgItem(hwndDlg, IDC_INACTIVE);
131  context->ActiveList = GetDlgItem(hwndDlg, IDC_ACTIVE);
132 
133  if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
134  {
135  PH_TREENEW_COLUMN column;
136 
137  count = 0;
138  total = TreeNew_GetColumnCount(context->ControlHandle);
139  i = 0;
140 
141  displayOrderList = PhCreateList(total);
142 
143  while (count < total)
144  {
145  if (TreeNew_GetColumn(context->ControlHandle, i, &column))
146  {
147  PPH_TREENEW_COLUMN copy;
148 
149  if (column.Fixed)
150  {
151  i++;
152  total--;
153  continue;
154  }
155 
156  copy = PhAllocateCopy(&column, sizeof(PH_TREENEW_COLUMN));
157  PhAddItemList(context->Columns, copy);
158  count++;
159 
160  if (column.Visible)
161  {
162  PhAddItemList(displayOrderList, copy);
163  }
164  else
165  {
166  ListBox_AddString(context->InactiveList, column.Text);
167  }
168  }
169 
170  i++;
171  }
172 
173  qsort(displayOrderList->Items, displayOrderList->Count, sizeof(PVOID), PhpColumnsCompareDisplayIndexTn);
174  }
175 
176  if (displayOrderList)
177  {
178  for (i = 0; i < displayOrderList->Count; i++)
179  {
180  if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
181  {
182  PPH_TREENEW_COLUMN copy = displayOrderList->Items[i];
183 
184  ListBox_AddString(context->ActiveList, copy->Text);
185  }
186  }
187 
188  PhDereferenceObject(displayOrderList);
189  }
190 
191  SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
192  SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
193  }
194  break;
195  case WM_DESTROY:
196  {
197  ULONG i;
198 
199  for (i = 0; i < context->Columns->Count; i++)
200  PhFree(context->Columns->Items[i]);
201 
202  RemoveProp(hwndDlg, PhMakeContextAtom());
203  }
204  break;
205  case WM_COMMAND:
206  {
207  switch (LOWORD(wParam))
208  {
209  case IDCANCEL:
210  EndDialog(hwndDlg, IDCANCEL);
211  break;
212  case IDOK:
213  {
214 #define ORDER_LIMIT 100
215  PPH_LIST activeList;
216  ULONG activeCount;
217  ULONG i;
218  INT orderArray[ORDER_LIMIT];
219  INT maxOrder;
220 
221  memset(orderArray, 0, sizeof(orderArray));
222  maxOrder = 0;
223 
224  activeCount = ListBox_GetCount(context->ActiveList);
225  activeList = PhCreateList(activeCount);
226 
227  for (i = 0; i < activeCount; i++)
228  PhAddItemList(activeList, PhGetListBoxString(context->ActiveList, i));
229 
230  if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
231  {
232  // Apply visiblity settings and build the order array.
233 
234  TreeNew_SetRedraw(context->ControlHandle, FALSE);
235 
236  for (i = 0; i < context->Columns->Count; i++)
237  {
238  PPH_TREENEW_COLUMN column = context->Columns->Items[i];
239  ULONG index;
240 
241  index = IndexOfStringInList(activeList, column->Text);
242  column->Visible = index != -1;
243 
244  TreeNew_SetColumn(context->ControlHandle, TN_COLUMN_FLAG_VISIBLE, column);
245 
246  if (column->Visible && index < ORDER_LIMIT)
247  {
248  orderArray[index] = column->Id;
249 
250  if ((ULONG)maxOrder < index + 1)
251  maxOrder = index + 1;
252  }
253  }
254 
255  // Apply display order.
256  TreeNew_SetColumnOrderArray(context->ControlHandle, maxOrder, orderArray);
257 
258  TreeNew_SetRedraw(context->ControlHandle, TRUE);
259 
260  PhDereferenceObject(activeList);
261 
262  InvalidateRect(context->ControlHandle, NULL, FALSE);
263  }
264 
265  EndDialog(hwndDlg, IDOK);
266  }
267  break;
268  case IDC_INACTIVE:
269  {
270  switch (HIWORD(wParam))
271  {
272  case LBN_DBLCLK:
273  {
274  SendMessage(hwndDlg, WM_COMMAND, IDC_SHOW, 0);
275  }
276  break;
277  case LBN_SELCHANGE:
278  {
279  INT sel = ListBox_GetCurSel(context->InactiveList);
280 
281  EnableWindow(GetDlgItem(hwndDlg, IDC_SHOW), sel != -1);
282  }
283  break;
284  }
285  }
286  break;
287  case IDC_ACTIVE:
288  {
289  switch (HIWORD(wParam))
290  {
291  case LBN_DBLCLK:
292  {
293  SendMessage(hwndDlg, WM_COMMAND, IDC_HIDE, 0);
294  }
295  break;
296  case LBN_SELCHANGE:
297  {
298  INT sel = ListBox_GetCurSel(context->ActiveList);
299  INT count = ListBox_GetCount(context->ActiveList);
300 
301  EnableWindow(GetDlgItem(hwndDlg, IDC_HIDE), sel != -1 && count != 1);
302  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0 && sel != -1);
303  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1 && sel != -1);
304  }
305  break;
306  }
307  }
308  break;
309  case IDC_SHOW:
310  {
311  INT sel;
312  INT count;
313  PPH_STRING string;
314 
315  sel = ListBox_GetCurSel(context->InactiveList);
316  count = ListBox_GetCount(context->InactiveList);
317 
318  if (string = PhGetListBoxString(context->InactiveList, sel))
319  {
320  ListBox_DeleteString(context->InactiveList, sel);
321  ListBox_AddString(context->ActiveList, string->Buffer);
322  PhDereferenceObject(string);
323 
324  count--;
325 
326  if (sel >= count - 1)
327  sel = count - 1;
328 
329  ListBox_SetCurSel(context->InactiveList, sel);
330 
331  SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
332  SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
333  }
334  }
335  break;
336  case IDC_HIDE:
337  {
338  INT sel;
339  INT count;
340  PPH_STRING string;
341 
342  sel = ListBox_GetCurSel(context->ActiveList);
343  count = ListBox_GetCount(context->ActiveList);
344 
345  if (count != 1)
346  {
347  if (string = PhGetListBoxString(context->ActiveList, sel))
348  {
349  ListBox_DeleteString(context->ActiveList, sel);
350  ListBox_AddString(context->InactiveList, string->Buffer);
351  PhDereferenceObject(string);
352 
353  count--;
354 
355  if (sel >= count - 1)
356  sel = count - 1;
357 
358  ListBox_SetCurSel(context->ActiveList, sel);
359 
360  SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
361  SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
362  }
363  }
364  }
365  break;
366  case IDC_MOVEUP:
367  {
368  INT sel;
369  INT count;
370  PPH_STRING string;
371 
372  sel = ListBox_GetCurSel(context->ActiveList);
373  count = ListBox_GetCount(context->ActiveList);
374 
375  if (sel != 0)
376  {
377  if (string = PhGetListBoxString(context->ActiveList, sel))
378  {
379  ListBox_DeleteString(context->ActiveList, sel);
380  ListBox_InsertString(context->ActiveList, sel - 1, string->Buffer);
381  PhDereferenceObject(string);
382 
383  sel -= 1;
384  ListBox_SetCurSel(context->ActiveList, sel);
385  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0);
386  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1);
387  }
388  }
389  }
390  break;
391  case IDC_MOVEDOWN:
392  {
393  INT sel;
394  INT count;
395  PPH_STRING string;
396 
397  sel = ListBox_GetCurSel(context->ActiveList);
398  count = ListBox_GetCount(context->ActiveList);
399 
400  if (sel != count - 1)
401  {
402  if (string = PhGetListBoxString(context->ActiveList, sel))
403  {
404  ListBox_DeleteString(context->ActiveList, sel);
405  ListBox_InsertString(context->ActiveList, sel + 1, string->Buffer);
406  PhDereferenceObject(string);
407 
408  sel += 1;
409  ListBox_SetCurSel(context->ActiveList, sel);
410  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0);
411  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1);
412  }
413  }
414  }
415  break;
416  }
417  }
418  break;
419  }
420 
421  return FALSE;
422 }