Skip to content

Commit 71e6170

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 71e6170

File tree

9 files changed

+764
-2
lines changed

9 files changed

+764
-2
lines changed

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

+283
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,78 @@
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.Platform;
38+
import org.eclipse.core.runtime.Status;
39+
import org.eclipse.core.runtime.preferences.InstanceScope;
40+
import org.eclipse.jface.dialogs.Dialog;
2541
import org.eclipse.jface.dialogs.MessageDialog;
2642
import org.eclipse.jface.layout.TableColumnLayout;
2743
import org.eclipse.jface.preference.PreferencePage;
2844
import org.eclipse.jface.viewers.ColumnWeightData;
2945
import org.eclipse.jface.window.Window;
3046
import org.eclipse.jface.wizard.WizardDialog;
3147
import org.eclipse.swt.SWT;
48+
import org.eclipse.swt.events.ModifyEvent;
49+
import org.eclipse.swt.events.ModifyListener;
3250
import org.eclipse.swt.events.SelectionAdapter;
3351
import org.eclipse.swt.events.SelectionEvent;
3452
import org.eclipse.swt.layout.GridData;
3553
import org.eclipse.swt.layout.GridLayout;
3654
import org.eclipse.swt.widgets.Button;
3755
import org.eclipse.swt.widgets.Composite;
3856
import org.eclipse.swt.widgets.Control;
57+
import org.eclipse.swt.widgets.DirectoryDialog;
3958
import org.eclipse.swt.widgets.Group;
59+
import org.eclipse.swt.widgets.Label;
60+
import org.eclipse.swt.widgets.Shell;
4061
import org.eclipse.swt.widgets.Table;
4162
import org.eclipse.swt.widgets.TableColumn;
4263
import org.eclipse.swt.widgets.TableItem;
64+
import org.eclipse.swt.widgets.Text;
4365
import org.eclipse.ui.IWorkbench;
4466
import org.eclipse.ui.IWorkbenchPreferencePage;
67+
import org.osgi.service.prefs.BackingStoreException;
68+
import org.osgi.service.prefs.Preferences;
4569

4670
/**
4771
* GUI page to configure workbench preferences for cmake.
4872
*/
4973
public class CMakePreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
5074

75+
private static final String VALUE_DELIMITER = " || "; //$NON-NLS-1$
76+
5177
private ICMakeToolChainManager manager;
5278
private Table filesTable;
5379
private Button removeButton;
80+
private Button variablesButton;
81+
private Button testButton;
82+
private Button browseButton;
83+
private Button editButton;
84+
85+
private Text cmakeLocationTextBox;
86+
private Text generatorLocationTextBox;
87+
88+
private String[] generatorLocations;
89+
private String cmakeLocation;
90+
private boolean useCmakeToolLocation;
5491

5592
private Map<Path, ICMakeToolChainFile> filesToAdd = new HashMap<>();
5693
private Map<Path, ICMakeToolChainFile> filesToRemove = new HashMap<>();
5794

5895
@Override
5996
public void init(IWorkbench workbench) {
6097
manager = Activator.getService(ICMakeToolChainManager.class);
98+
updateCmakeToolGroupData();
6199
}
62100

63101
@Override
@@ -141,11 +179,142 @@ public void widgetSelected(SelectionEvent e) {
141179
}
142180
});
143181

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

146306
return control;
147307
}
148308

309+
protected void updateCMakeGroup(boolean enable) {
310+
cmakeLocationTextBox.setEnabled(enable);
311+
generatorLocationTextBox.setEnabled(enable);
312+
variablesButton.setEnabled(enable);
313+
testButton.setEnabled(enable && !cmakeLocation.isBlank());
314+
browseButton.setEnabled(enable);
315+
editButton.setEnabled(enable);
316+
}
317+
149318
private void updateTable() {
150319
List<ICMakeToolChainFile> sorted = new ArrayList<>(getFiles().values());
151320
Collections.sort(sorted, (o1, o2) -> o1.getPath().toString().compareToIgnoreCase(o2.getPath().toString()));
@@ -205,7 +374,121 @@ public boolean performOk() {
205374
filesToAdd.clear();
206375
filesToRemove.clear();
207376

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

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

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)