1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 
18 #include "stdafx.h"
19 #include "utils.h"
20 #include "FindJava2Dlg.h"
21 #include "afxdialogex.h"
22 #include <atlpath.h>                            // ATL CPath
23 
24 #ifdef _DEBUG
25 #define new DEBUG_NEW
26 #endif
27 
28 #define COL_PATH 1
29 
30 
CFindJava2Dlg(CWnd * pParent)31 CFindJava2Dlg::CFindJava2Dlg(CWnd* pParent /*=NULL*/)
32     : CDialog(CFindJava2Dlg::IDD, pParent), mSelectedIndex(-1) {
33     m_hIcon = AfxGetApp()->LoadIcon(IDI_ANDROID_ICON);
34 }
35 
DoDataExchange(CDataExchange * pDX)36 void CFindJava2Dlg::DoDataExchange(CDataExchange* pDX) {
37     CDialog::DoDataExchange(pDX);
38     DDX_Control(pDX, IDC_PATH_LIST, mPathsListCtrl);
39     DDX_Control(pDX, IDOK, mOkButton);
40 }
41 
BEGIN_MESSAGE_MAP(CFindJava2Dlg,CDialog)42 BEGIN_MESSAGE_MAP(CFindJava2Dlg, CDialog)
43     ON_WM_PAINT()
44     ON_WM_QUERYDRAGICON()
45     ON_BN_CLICKED(IDC_BUTTON_ADD, &CFindJava2Dlg::OnBnClickedButtonAdd)
46     ON_NOTIFY(NM_CLICK, IDC_PATH_LIST, &CFindJava2Dlg::OnNMClickPathList)
47     ON_NOTIFY(LVN_ITEMCHANGED, IDC_PATH_LIST, &CFindJava2Dlg::OnLvnItemchangedPathList)
48 END_MESSAGE_MAP()
49 
50 
51 // -----
52 // CFindJava2Dlg message handlers
53 
54 BOOL CFindJava2Dlg::OnInitDialog() {
55     CDialog::OnInitDialog();
56 
57     SetWindowText(getAppName());
58 
59     // Set the icon for this dialog.  The framework does this automatically
60     //  when the application's main window is not a dialog
61     SetIcon(m_hIcon, TRUE);			// Set big icon
62     SetIcon(m_hIcon, FALSE);		// Set small icon
63 
64     // Initialize list controls
65     mPathsListCtrl.SetExtendedStyle(
66         mPathsListCtrl.GetExtendedStyle() |
67         LVS_EX_CHECKBOXES |
68         LVS_EX_FULLROWSELECT |
69         LVS_EX_GRIDLINES);
70 
71     // We want 2 columns: Java version and path
72     mPathsListCtrl.InsertColumn(0, _T("Version"), LVCFMT_RIGHT, 60,  0);
73     mPathsListCtrl.InsertColumn(1, _T("Path"),     LVCFMT_LEFT, 386, 0);
74 
75     mJavaFinder->findJavaPaths(&mPaths);
76     fillPathsList();
77     adjustButtons();
78 
79     return TRUE;  // return TRUE  unless you set the focus to a control
80 }
81 
82 // If you add a minimize button to your dialog, you will need the code below
83 // to draw the icon.  For MFC applications using the document/view model,
84 // this is automatically done for you by the framework.
85 // [Note: MFC boilerplate, keep as-is]
OnPaint()86 void CFindJava2Dlg::OnPaint() {
87     if (IsIconic()) {
88         CPaintDC dc(this); // device context for painting
89 
90         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
91 
92         // Center icon in client rectangle
93         int cxIcon = GetSystemMetrics(SM_CXICON);
94         int cyIcon = GetSystemMetrics(SM_CYICON);
95         CRect rect;
96         GetClientRect(&rect);
97         int x = (rect.Width() - cxIcon + 1) / 2;
98         int y = (rect.Height() - cyIcon + 1) / 2;
99 
100         // Draw the icon
101         dc.DrawIcon(x, y, m_hIcon);
102     } else {
103         CDialog::OnPaint();
104     }
105 }
106 
107 // The system calls this function to obtain the cursor to display while the user drags
108 // the minimized window. [Note: MFC boilerplate, keep as-is]
OnQueryDragIcon()109 HCURSOR CFindJava2Dlg::OnQueryDragIcon() {
110     return static_cast<HCURSOR>(m_hIcon);
111 }
112 
113 // Button add has been pressed; use file dialog and add path if it's a valid java.exe
OnBnClickedButtonAdd()114 void CFindJava2Dlg::OnBnClickedButtonAdd() {
115     CFileDialog fileDlg(
116         TRUE,           // true=open dialog,  false=save-as dialog
117         _T("exe"),      // lpszDefExt
118         _T("java.exe"), // lpszFileName
119         OFN_FILEMUSTEXIST || OFN_PATHMUSTEXIST,
120         NULL,           // lpszFilter
121         this);          // pParentWnd
122 
123     if (fileDlg.DoModal() == IDOK) {
124         CString path = fileDlg.GetPathName();
125 
126         CJavaPath javaPath;
127         if (!mJavaFinder->checkJavaPath(path, &javaPath)) {
128             CString msg;
129             if (javaPath.mVersion > 0) {
130                 msg.Format(_T("Insufficient Java Version found: expected %s, got %s"),
131                            CJavaPath(mJavaFinder->getMinVersion(), CPath()).getVersion(),
132                            javaPath.getVersion());
133             } else {
134                 msg.Format(_T("No valid Java Version found for %s"), path);
135             }
136             AfxMessageBox(msg, MB_OK);
137 
138         } else {
139             if (mPaths.find(javaPath) == mPaths.end()) {
140                 // Path isn't known yet so add it and refresh the list.
141                 mPaths.insert(javaPath);
142                 fillPathsList();
143             }
144 
145             // Select item in list and set mSelectedIndex
146             selectPath(-1 /*index*/, &javaPath);
147         }
148     }
149 }
150 
151 // An item in the list has been selected, select checkmark and set mSelectedIndex.
OnNMClickPathList(NMHDR * pNMHDR,LRESULT * pResult)152 void CFindJava2Dlg::OnNMClickPathList(NMHDR *pNMHDR, LRESULT *pResult) {
153     LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
154     int index = pNMItemActivate->iItem;
155     selectPath(index, nullptr);
156     *pResult = TRUE;
157 }
158 
159 // An item in the list has changed, toggle checkmark as needed.
OnLvnItemchangedPathList(NMHDR * pNMHDR,LRESULT * pResult)160 void CFindJava2Dlg::OnLvnItemchangedPathList(NMHDR *pNMHDR, LRESULT *pResult) {
161     *pResult = FALSE;
162     LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
163 
164     if ((pNMLV->uChanged & LVIF_STATE) != 0) {
165         // Item's state has changed. Check the selection to see if it needs to be adjusted.
166         int index = pNMLV->iItem;
167 
168         UINT oldState = pNMLV->uOldState;
169         UINT newState = pNMLV->uNewState;
170 
171         if ((oldState & LVIS_STATEIMAGEMASK) != 0 || (newState & LVIS_STATEIMAGEMASK) != 0) {
172             // Checkbox uses the STATEIMAGE: 1 for unchecked, 2 for checked.
173             // Checkbox is checked when (old/new-state & state-image-mask) == INDEXTOSTATEIMAGEMASK(2).
174 
175             bool oldChecked = (oldState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2);
176             bool newChecked = (newState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2);
177 
178             if (oldChecked && !newChecked && index == mSelectedIndex) {
179                 mSelectedIndex = -1;
180                 adjustButtons();
181             } else if (!oldChecked && newChecked && index != mSelectedIndex) {
182                 // Uncheck any checked rows if any
183                 for (int n = mPathsListCtrl.GetItemCount() - 1; n >= 0; --n) {
184                     if (n != index && mPathsListCtrl.GetCheck(n)) {
185                         mPathsListCtrl.SetCheck(n, FALSE);
186                     }
187                 }
188 
189                 mSelectedIndex = index;
190                 adjustButtons();
191             }
192             // We handled this case, don't dispatch it further
193             *pResult = TRUE;
194         }
195     }
196 }
197 
198 // -----
199 
getSelectedPath()200 const CJavaPath& CFindJava2Dlg::getSelectedPath() {
201     int i = 0;
202     for (const CJavaPath &p : mPaths) {
203         if (i == mSelectedIndex) {
204             return p;
205         }
206         ++i;
207     }
208 
209     return CJavaPath::sEmpty;
210 }
211 
212 
fillPathsList()213 void CFindJava2Dlg::fillPathsList() {
214     mPathsListCtrl.DeleteAllItems();
215     int index = 0;
216 
217     for (const CJavaPath& pv : mPaths) {
218         mPathsListCtrl.InsertItem(index, pv.getVersion());        // column 0 = version
219         mPathsListCtrl.SetItemText(index, COL_PATH, pv.mPath);    // column 1 = path
220         mPathsListCtrl.SetCheck(index, mSelectedIndex == index);
221         ++index;
222     }
223 }
224 
225 // Checks the given index if valid. Unchecks all other items.
226 //
227 // If index >= 0, it is used to select that item from the ListControl.
228 // Otherwise if path != nullptr, it is used to find the item and select it.
229 //
230 // Side effect: in both cases, mSelectedIndex is set to the matching index or -1.
231 //
232 // If index is invalid and path isn't in the mPaths list, all items are unselected
233 // so calling this with (0, nullptr) will clear the current selection.
selectPath(int index,const CJavaPath * path)234 void CFindJava2Dlg::selectPath(int index, const CJavaPath *path) {
235 
236     const CJavaPath *foundPath;
237     // If index is not defined, find the given path in the internal list.
238     // If path is not defined, find its index in the internal list.
239     int i = 0;
240     int n = mPathsListCtrl.GetItemCount();
241     for (const CJavaPath &p : mPaths) {
242         if (index < 0 && path != nullptr && p == *path) {
243             index = i;
244             foundPath = path;
245         } else if (index == i) {
246             foundPath = &p;
247         }
248 
249         // uncheck any marked path
250         if (i != index && i < n && mPathsListCtrl.GetCheck(i)) {
251             mPathsListCtrl.SetCheck(i, FALSE);
252         }
253 
254         ++i;
255     }
256 
257     mSelectedIndex = index;
258     if (index >= 0 && index <= n) {
259         mPathsListCtrl.SetCheck(index, TRUE);
260     }
261 
262     adjustButtons();
263 }
264 
adjustButtons()265 void CFindJava2Dlg::adjustButtons() {
266     int n = mPathsListCtrl.GetItemCount();
267     mOkButton.EnableWindow(mSelectedIndex >= 0 && mSelectedIndex < n);
268 }
269