Skip to content

Commit 45be12b

Browse files
Add UI for specifying CMake tools and generators locations
Adding UI into CMake Preference page that allow user to specify the location of the CMake tool and the location of CMake generators. Added Unit test Addresses Issue: CDT CMake Improvements eclipse-cdt#1000, IDE-82683-REQ-004 and IDE-82683-REQ-005
1 parent f96dd1a commit 45be12b

File tree

9 files changed

+763
-2
lines changed

9 files changed

+763
-2
lines changed

cmake/org.eclipse.cdt.cmake.ui/src/org/eclipse/cdt/cmake/ui/internal/CMakePreferencePage.java

+282
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
*******************************************************************************/
1111
package org.eclipse.cdt.cmake.ui.internal;
1212

13+
import java.io.BufferedReader;
14+
import java.io.File;
15+
import java.io.IOException;
16+
import java.io.InputStreamReader;
1317
import java.nio.file.Path;
1418
import java.util.ArrayList;
1519
import java.util.Collections;
@@ -20,44 +24,76 @@
2024
import org.eclipse.cdt.cmake.core.ICMakeToolChainFile;
2125
import org.eclipse.cdt.cmake.core.ICMakeToolChainManager;
2226
import org.eclipse.cdt.cmake.core.internal.CMakeToolChainManager;
27+
import org.eclipse.cdt.core.CCorePlugin;
2328
import org.eclipse.cdt.core.build.IToolChain;
29+
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
30+
import org.eclipse.cdt.core.cdtvariables.ICdtVariable;
31+
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
32+
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
33+
import org.eclipse.cdt.internal.core.envvar.CMakeBuildEnvironmentSupplier;
34+
import org.eclipse.cdt.ui.newui.BuildVarListDialog;
35+
import org.eclipse.cdt.utils.ui.controls.FileListControl;
2436
import org.eclipse.core.runtime.CoreException;
37+
import org.eclipse.core.runtime.preferences.InstanceScope;
38+
import org.eclipse.jface.dialogs.Dialog;
2539
import org.eclipse.jface.dialogs.MessageDialog;
2640
import org.eclipse.jface.layout.TableColumnLayout;
2741
import org.eclipse.jface.preference.PreferencePage;
2842
import org.eclipse.jface.viewers.ColumnWeightData;
2943
import org.eclipse.jface.window.Window;
3044
import org.eclipse.jface.wizard.WizardDialog;
3145
import org.eclipse.swt.SWT;
46+
import org.eclipse.swt.events.ModifyEvent;
47+
import org.eclipse.swt.events.ModifyListener;
3248
import org.eclipse.swt.events.SelectionAdapter;
3349
import org.eclipse.swt.events.SelectionEvent;
3450
import org.eclipse.swt.layout.GridData;
3551
import org.eclipse.swt.layout.GridLayout;
3652
import org.eclipse.swt.widgets.Button;
3753
import org.eclipse.swt.widgets.Composite;
3854
import org.eclipse.swt.widgets.Control;
55+
import org.eclipse.swt.widgets.DirectoryDialog;
3956
import org.eclipse.swt.widgets.Group;
57+
import org.eclipse.swt.widgets.Label;
58+
import org.eclipse.swt.widgets.Shell;
4059
import org.eclipse.swt.widgets.Table;
4160
import org.eclipse.swt.widgets.TableColumn;
4261
import org.eclipse.swt.widgets.TableItem;
62+
import org.eclipse.swt.widgets.Text;
4363
import org.eclipse.ui.IWorkbench;
4464
import org.eclipse.ui.IWorkbenchPreferencePage;
65+
import org.osgi.service.prefs.BackingStoreException;
66+
import org.osgi.service.prefs.Preferences;
4567

4668
/**
4769
* GUI page to configure workbench preferences for cmake.
4870
*/
4971
public class CMakePreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
5072

73+
private static final String VALUE_DELIMITER = " || "; //$NON-NLS-1$
74+
5175
private ICMakeToolChainManager manager;
5276
private Table filesTable;
5377
private Button removeButton;
78+
private Button variablesButton;
79+
private Button testButton;
80+
private Button browseButton;
81+
private Button editButton;
82+
83+
private Text cmakeLocationTextBox;
84+
private Text generatorLocationTextBox;
85+
86+
private String[] generatorLocations;
87+
private String cmakeLocation;
88+
private boolean useCmakeToolLocation;
5489

5590
private Map<Path, ICMakeToolChainFile> filesToAdd = new HashMap<>();
5691
private Map<Path, ICMakeToolChainFile> filesToRemove = new HashMap<>();
5792

5893
@Override
5994
public void init(IWorkbench workbench) {
6095
manager = Activator.getService(ICMakeToolChainManager.class);
96+
updateCmakeToolGroupData();
6197
}
6298

6399
@Override
@@ -141,11 +177,143 @@ public void widgetSelected(SelectionEvent e) {
141177
}
142178
});
143179

180+
// CMake tools section
181+
Group cmakeToolsGroup = new Group(control, SWT.NONE);
182+
cmakeToolsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
183+
cmakeToolsGroup.setText(Messages.CMakePreferencePage_CMakeTools);
184+
cmakeToolsGroup.setLayout(new GridLayout(1, false));
185+
186+
Composite checkBoxComp = new Composite(cmakeToolsGroup, SWT.NONE);
187+
checkBoxComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
188+
checkBoxComp.setLayout(new GridLayout());
189+
190+
Button useCMakeToolLocCheckBox = new Button(checkBoxComp, SWT.CHECK);
191+
useCMakeToolLocCheckBox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
192+
useCMakeToolLocCheckBox.setText(Messages.CMakePreferencePage_UseCMakeToolLocationsInCMakeBuilds);
193+
useCMakeToolLocCheckBox.setToolTipText(Messages.CMakePreferencePage_UseCMakeToolLocationsInCMakeBuildsTooltip);
194+
useCMakeToolLocCheckBox.setSelection(useCmakeToolLocation);
195+
useCMakeToolLocCheckBox.addListener(SWT.Selection, e -> {
196+
useCmakeToolLocation = useCMakeToolLocCheckBox.getSelection();
197+
updateCMakeGroup(useCmakeToolLocation);
198+
});
199+
200+
// Set width hint to avoid Preference page opens with a horizontal scroll bar when
201+
// location in textBox got too long.
202+
GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
203+
gd.widthHint = control.getSize().x;
204+
205+
Composite locationComp = new Composite(cmakeToolsGroup, SWT.NONE);
206+
locationComp.setLayoutData(gd);
207+
locationComp.setLayout(new GridLayout(3, false));
208+
209+
Label cmakeLocationLabel = new Label(locationComp, SWT.NONE);
210+
cmakeLocationLabel.setText(Messages.CMakePreferencePage_CMakeLocation);
211+
cmakeLocationLabel.setToolTipText(Messages.CMakePreferencePage_CMakeLocationTooltip);
212+
213+
cmakeLocationTextBox = new Text(locationComp, SWT.BORDER);
214+
cmakeLocationTextBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
215+
cmakeLocationTextBox.setText(cmakeLocation);
216+
cmakeLocationTextBox.addModifyListener(new ModifyListener() {
217+
@Override
218+
public void modifyText(ModifyEvent evt) {
219+
cmakeLocation = cmakeLocationTextBox.getText().trim();
220+
testButton.setEnabled(useCmakeToolLocation && !cmakeLocation.isBlank());
221+
}
222+
});
223+
224+
Composite cmakeLocationButtonComp = new Composite(locationComp, SWT.NONE);
225+
cmakeLocationButtonComp.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
226+
cmakeLocationButtonComp.setLayout(new GridLayout(3, true));
227+
228+
variablesButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
229+
variablesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
230+
variablesButton.setText(Messages.CMakePreferencePage_Variables);
231+
variablesButton.addListener(SWT.Selection, e -> {
232+
String variable = getVariableDialog(getShell(), null);
233+
if (variable != null) {
234+
cmakeLocationTextBox.insert(variable);
235+
cmakeLocation = cmakeLocationTextBox.getText().trim();
236+
}
237+
});
238+
239+
testButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
240+
testButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
241+
testButton.setText(Messages.CMakePreferencePage_Test);
242+
testButton.setToolTipText(Messages.CMakePreferencePage_TestTooltip);
243+
testButton.addListener(SWT.Selection, e -> {
244+
try {
245+
Process p = Runtime.getRuntime().exec(new String[] {
246+
resolveVariableValue(cmakeLocation) + File.separatorChar + "cmake", "--version" }); //$NON-NLS-1$ //$NON-NLS-2$
247+
List<String> buf = new ArrayList<>();
248+
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
249+
String line;
250+
while ((line = br.readLine()) != null) {
251+
buf.add(line);
252+
}
253+
MessageDialog.openInformation(getShell(), Messages.CMakePreferencePage_TestCmakeLocation_Title,
254+
Messages.CMakePreferencePage_TestCmakeLocation_Body + String.join(System.lineSeparator(), buf));
255+
} catch (IOException e1) {
256+
MessageDialog.openError(getShell(), Messages.CMakePreferencePage_FailToTestCmakeLocation_Title,
257+
Messages.CMakePreferencePage_FailToTestCmakeLocation_Body + e1.getMessage());
258+
Activator.log(e1);
259+
}
260+
});
261+
262+
browseButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
263+
browseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
264+
browseButton.setText(Messages.CMakePreferencePage_Browse);
265+
browseButton.addListener(SWT.Selection, e -> {
266+
DirectoryDialog dirDialog = new DirectoryDialog(getShell());
267+
if (!cmakeLocation.isBlank()) {
268+
dirDialog.setFilterPath(resolveVariableValue(cmakeLocation));
269+
}
270+
String browsedDirectory = dirDialog.open();
271+
if (browsedDirectory != null) {
272+
cmakeLocationTextBox.setText(browsedDirectory);
273+
cmakeLocation = cmakeLocationTextBox.getText().trim();
274+
}
275+
});
276+
277+
Label generatorLocationsLabel = new Label(locationComp, SWT.NONE);
278+
generatorLocationsLabel.setText(Messages.CMakePreferencePage_GeneratorLocation);
279+
generatorLocationsLabel.setToolTipText(Messages.CMakePreferencePage_GeneratorLocationTooltip);
280+
281+
generatorLocationTextBox = new Text(locationComp, SWT.BORDER);
282+
generatorLocationTextBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
283+
generatorLocationTextBox.setEditable(false);
284+
generatorLocationTextBox.setText(String.join(VALUE_DELIMITER, generatorLocations));
285+
286+
Composite generatorLocationButtonComp = new Composite(locationComp, SWT.NONE);
287+
generatorLocationButtonComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
288+
generatorLocationButtonComp.setLayout(new GridLayout(3, true));
289+
290+
editButton = new Button(generatorLocationButtonComp, SWT.PUSH);
291+
editButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
292+
editButton.setText(Messages.CMakePreferencePage_Edit);
293+
editButton.addListener(SWT.Selection, e -> {
294+
EditGeneratorLocationDialog dialog = new EditGeneratorLocationDialog(getShell(),
295+
Messages.CMakePreferencePage_EditGeneratorLocations_Title, generatorLocations);
296+
if (dialog.open() == Window.OK) {
297+
generatorLocations = dialog.getValues();
298+
generatorLocationTextBox.setText(String.join(VALUE_DELIMITER, generatorLocations));
299+
}
300+
});
301+
144302
updateTable();
303+
updateCMakeGroup(useCmakeToolLocation);
145304

146305
return control;
147306
}
148307

308+
protected void updateCMakeGroup(boolean enable) {
309+
cmakeLocationTextBox.setEnabled(enable);
310+
generatorLocationTextBox.setEnabled(enable);
311+
variablesButton.setEnabled(enable);
312+
testButton.setEnabled(enable && !cmakeLocation.isBlank());
313+
browseButton.setEnabled(enable);
314+
editButton.setEnabled(enable);
315+
}
316+
149317
private void updateTable() {
150318
List<ICMakeToolChainFile> sorted = new ArrayList<>(getFiles().values());
151319
Collections.sort(sorted, (o1, o2) -> o1.getPath().toString().compareToIgnoreCase(o2.getPath().toString()));
@@ -205,7 +373,121 @@ public boolean performOk() {
205373
filesToAdd.clear();
206374
filesToRemove.clear();
207375

376+
// Update Preferences for cmakeSupplier
377+
try {
378+
getPreferences().clear();
379+
getPreferences().node(CMakeBuildEnvironmentSupplier.CMAKE_GENERATOR_LOCATION).clear();
380+
getPreferences().putBoolean(CMakeBuildEnvironmentSupplier.ENABLE_USE_CMAKE_LOCATION, useCmakeToolLocation);
381+
if (!cmakeLocation.isEmpty()) {
382+
getPreferences().put(CMakeBuildEnvironmentSupplier.CMAKE_LOCATION, cmakeLocation);
383+
}
384+
int index;
385+
for (index = 0; index < generatorLocations.length; index++) {
386+
getPreferences().node(CMakeBuildEnvironmentSupplier.CMAKE_GENERATOR_LOCATION).put(
387+
String.format(CMakeBuildEnvironmentSupplier.LOCATION_NODE, index), generatorLocations[index]);
388+
389+
}
390+
getPreferences().flush();
391+
} catch (BackingStoreException e) {
392+
Activator.log(e);
393+
}
208394
return true;
209395
}
210396

397+
private void updateCmakeToolGroupData() {
398+
try {
399+
useCmakeToolLocation = getPreferences().getBoolean(CMakeBuildEnvironmentSupplier.ENABLE_USE_CMAKE_LOCATION,
400+
false);
401+
cmakeLocation = getPreferences().get(CMakeBuildEnvironmentSupplier.CMAKE_LOCATION,
402+
CMakeBuildEnvironmentSupplier.EMPTY_STRING);
403+
List<String> genlocs = new ArrayList<>();
404+
String[] keys = getPreferences().node(CMakeBuildEnvironmentSupplier.CMAKE_GENERATOR_LOCATION).keys();
405+
int index;
406+
for (index = 0; index < keys.length; index++) {
407+
genlocs.add(getPreferences().node(CMakeBuildEnvironmentSupplier.CMAKE_GENERATOR_LOCATION).get(
408+
String.format(CMakeBuildEnvironmentSupplier.LOCATION_NODE, index),
409+
CMakeBuildEnvironmentSupplier.EMPTY_STRING));
410+
}
411+
generatorLocations = genlocs.toArray(new String[0]);
412+
} catch (BackingStoreException e) {
413+
Activator.log(e);
414+
}
415+
}
416+
417+
private String resolveVariableValue(String value) {
418+
try {
419+
ICdtVariableManager vm = CCorePlugin.getDefault().getCdtVariableManager();
420+
return vm.resolveValue(value, null, CMakeBuildEnvironmentSupplier.EMPTY_STRING, null);
421+
} catch (CdtVariableException e) {
422+
Activator.log(e);
423+
}
424+
return null;
425+
}
426+
427+
private String getVariableDialog(Shell shell, ICConfigurationDescription cfgd) {
428+
ICdtVariableManager vm = CCorePlugin.getDefault().getCdtVariableManager();
429+
BuildVarListDialog dialog = new BuildVarListDialog(shell, vm.getVariables(cfgd));
430+
dialog.setTitle(Messages.VariablesDialog_Title);
431+
if (dialog.open() == Window.OK) {
432+
Object[] selected = dialog.getResult();
433+
if (selected.length > 0) {
434+
String s = ((ICdtVariable) selected[0]).getName();
435+
return "${" + s.trim() + "}"; //$NON-NLS-1$//$NON-NLS-2$
436+
}
437+
}
438+
return null;
439+
}
440+
441+
private class EditGeneratorLocationDialog extends Dialog {
442+
443+
private String title;
444+
private FileListControl listEditor;
445+
private String[] genLocs;
446+
447+
public EditGeneratorLocationDialog(Shell parentShell, String title, String[] genLocs) {
448+
super(parentShell);
449+
this.genLocs = genLocs;
450+
this.title = title;
451+
}
452+
453+
@Override
454+
protected void configureShell(Shell shell) {
455+
super.configureShell(shell);
456+
if (title != null) {
457+
shell.setText(title);
458+
}
459+
}
460+
461+
@Override
462+
protected Control createDialogArea(Composite parent) {
463+
Composite comp = new Composite(parent, SWT.NULL);
464+
comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
465+
comp.setLayout(new GridLayout());
466+
listEditor = new FileListControl(comp,
467+
Messages.CMakePreferencePage_EditGeneratorLocations_GeneratorLocation, FileListControl.BROWSE_DIR);
468+
if (genLocs != null) {
469+
listEditor.setList(genLocs);
470+
}
471+
return comp;
472+
}
473+
474+
@Override
475+
protected void okPressed() {
476+
genLocs = listEditor.getItems();
477+
super.okPressed();
478+
}
479+
480+
public String[] getValues() {
481+
List<String> values = new ArrayList<>();
482+
for (String loc : genLocs) {
483+
// Clean up return values
484+
values.add(loc.replace("\"", CMakeBuildEnvironmentSupplier.EMPTY_STRING).trim()); //$NON-NLS-1$
485+
}
486+
return values.toArray(new String[0]);
487+
}
488+
}
489+
490+
private Preferences getPreferences() {
491+
return InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).node(CMakeBuildEnvironmentSupplier.NODENAME);
492+
}
211493
}

cmake/org.eclipse.cdt.cmake.ui/src/org/eclipse/cdt/cmake/ui/internal/Messages.java

+21
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,31 @@ public class Messages extends NLS {
3030
public static String CMakeBuildTab_useDefaultCmakeSettingsTip;
3131
public static String CMakeBuildTab_UsedForLaunchMode;
3232
public static String CMakePreferencePage_Add;
33+
public static String CMakePreferencePage_Browse;
34+
public static String CMakePreferencePage_CMakeLocation;
35+
public static String CMakePreferencePage_CMakeLocationTooltip;
36+
public static String CMakePreferencePage_CMakeTools;
3337
public static String CMakePreferencePage_ConfirmRemoveDesc;
3438
public static String CMakePreferencePage_ConfirmRemoveTitle;
39+
public static String CMakePreferencePage_Delete;
40+
public static String CMakePreferencePage_Edit;
41+
public static String CMakePreferencePage_EditGeneratorLocations_Title;
42+
public static String CMakePreferencePage_EditGeneratorLocations_GeneratorLocation;
43+
public static String CMakePreferencePage_FailToTestCmakeLocation_Body;
44+
public static String CMakePreferencePage_FailToTestCmakeLocation_Title;
3545
public static String CMakePreferencePage_Files;
46+
public static String CMakePreferencePage_GeneratorLocation;
47+
public static String CMakePreferencePage_GeneratorLocationTooltip;
3648
public static String CMakePreferencePage_Path;
3749
public static String CMakePreferencePage_Remove;
50+
public static String CMakePreferencePage_Test;
51+
public static String CMakePreferencePage_TestCmakeLocation_Body;
52+
public static String CMakePreferencePage_TestCmakeLocation_Title;
53+
public static String CMakePreferencePage_TestTooltip;
3854
public static String CMakePreferencePage_Toolchain;
55+
public static String CMakePreferencePage_UseCMakeToolLocationsInCMakeBuilds;
56+
public static String CMakePreferencePage_UseCMakeToolLocationsInCMakeBuildsTooltip;
57+
public static String CMakePreferencePage_Variables;
3958
public static String CMakePropertyPage_FailedToStartCMakeGui_Body;
4059
public static String CMakePropertyPage_FailedToStartCMakeGui_Title;
4160
public static String CMakePropertyPage_FailedToGetOS_Body;
@@ -57,6 +76,8 @@ public class Messages extends NLS {
5776
public static String NewCMakeToolChainFilePage_Title;
5877
public static String NewCMakeToolChainFilePage_Toolchain;
5978

79+
public static String VariablesDialog_Title;
80+
6081
static {
6182
// initialize resource bundle
6283
NLS.initializeMessages("org.eclipse.cdt.cmake.ui.internal.messages", Messages.class); //$NON-NLS-1$

0 commit comments

Comments
 (0)