package io.sloeber.ui.project.properties;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICResourceDescription;
import org.eclipse.cdt.ui.newui.AbstractCPropertyTab;
import org.eclipse.cdt.ui.newui.AbstractPage;
import org.eclipse.cdt.ui.newui.ICPropertyProvider;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import io.sloeber.core.api.BoardDescriptor;
import io.sloeber.core.api.BoardsManager;
import io.sloeber.core.api.Defaults;
import io.sloeber.core.api.PasswordManager;
import io.sloeber.core.api.SerialManager;
import io.sloeber.core.common.Const;
import io.sloeber.ui.Activator;
import io.sloeber.ui.LabelCombo;
import io.sloeber.ui.Messages;
/**
* The ArduinoSelectionPage class is used in the new wizard and the project
* properties. This class controls the gui and the data underneath the gui. This
* class allows to select the arduino board and the port name
*
* @author Jan Baeyens
* @see ArduinoProperties ArduinoSettingsPage
*
*/
public class BoardSelectionPage extends AbstractCPropertyTab {
private static final String TRUE = "TRUE"; //$NON-NLS-1$
private static final String FALSE = "FALSE"; //$NON-NLS-1$
// global stuff to allow to communicate outside this class
public Text mFeedbackControl;
// GUI elements
protected Combo mControlBoardsTxtFile;
protected Combo mcontrolBoardName;
protected Combo mControlUploadProtocol;
protected LabelCombo mControlUploadPort;
protected LabelCombo[] mBoardOptionCombos = null;
private final int ncol = 3;
protected Listener mBoardSelectionChangedListener = null;
protected BoardDescriptor myBoardID = null;
/**
* Get the configuration we are currently working in. The configuration is
* null if we are in the create sketch wizard.
*
* @return the configuration to save info into
*/
public ICConfigurationDescription getConfdesc() {
if (this.page != null) {
return getResDesc().getConfiguration();
}
return null;
}
private Listener boardFileModifyListener = new Listener() {
@Override
public void handleEvent(Event e) {
File boardFile = getSelectedBoardsFile();
BoardSelectionPage.this.myBoardID.setBoardsFile(boardFile);
/*
* Change the list of available boards
*/
String CurrentBoard = getBoardName();
BoardSelectionPage.this.mcontrolBoardName.removeAll();
BoardSelectionPage.this.mcontrolBoardName.setItems(BoardSelectionPage.this.myBoardID.getCompatibleBoards());
BoardSelectionPage.this.mcontrolBoardName.setText(CurrentBoard);
/*
* Change the list of available upload protocols
*/
String CurrentUploadProtocol = getUpLoadProtocol();
BoardSelectionPage.this.mControlUploadProtocol.removeAll();
BoardSelectionPage.this.mControlUploadProtocol
.setItems(BoardSelectionPage.this.myBoardID.getUploadProtocols());
BoardSelectionPage.this.mControlUploadProtocol.setText(CurrentUploadProtocol);
if (BoardSelectionPage.this.mControlUploadProtocol.getText().isEmpty()) {
BoardSelectionPage.this.myBoardID.setUploadProtocol(Defaults.getDefaultUploadProtocol());
BoardSelectionPage.this.mControlUploadProtocol.setText(Defaults.getDefaultUploadProtocol());
}
BoardSelectionPage.this.boardModifyListener.handleEvent(null);
}
};
protected Listener boardModifyListener = new Listener() {
@Override
public void handleEvent(Event e) {
BoardSelectionPage.this.myBoardID.setBoardName(getBoardName());
for (LabelCombo curLabelCombo : BoardSelectionPage.this.mBoardOptionCombos) {
curLabelCombo
.setItems(BoardSelectionPage.this.myBoardID.getMenuItemNamesFromMenuID(curLabelCombo.getID()));
curLabelCombo.setLabel(BoardSelectionPage.this.myBoardID.getMenuNameFromMenuID(curLabelCombo.getID()));
}
isPageComplete();
enableControls();
}
};
protected Listener labelComboListener = new Listener() {
@Override
public void handleEvent(Event e) {
isPageComplete();
}
};
private Composite mComposite;
private TreeMap<String, String> mAllBoardsFiles = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
private org.eclipse.swt.widgets.Button mPwdButton;
@Override
public void createControls(Composite parent, ICPropertyProvider provider) {
super.createControls(parent, provider);
draw(parent);
}
public void setListener(Listener BoardSelectionChangedListener) {
this.mBoardSelectionChangedListener = BoardSelectionChangedListener;
}
private static void createLabel(Composite parent, int ncol, String t) {
Label line = new Label(parent, SWT.HORIZONTAL | SWT.BOLD);
line.setText(t);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = ncol;
line.setLayoutData(gridData);
}
private static void createLine(Composite parent, int ncol) {
Label line = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.BOLD);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = ncol;
line.setLayoutData(gridData);
}
public void draw(Composite composite) {
// create the desired layout for this wizard page
if (this.myBoardID == null) {
this.myBoardID = BoardDescriptor.makeBoardDescriptor(getConfdesc());
}
ICConfigurationDescription confdesc = getConfdesc();
String[] allBoardsFileNames = BoardsManager.getAllBoardsFiles();
for (String curBoardFile : allBoardsFileNames) {
this.mAllBoardsFiles.put(tidyUpLength(curBoardFile), curBoardFile);
}
this.mComposite = composite;
GridLayout theGridLayout = new GridLayout();
theGridLayout.numColumns = this.ncol;
composite.setLayout(theGridLayout);
GridData theGriddata;
if (this.mAllBoardsFiles.isEmpty()) {
Activator.log(new Status(IStatus.ERROR, Activator.getId(), Messages.error_no_platform_files_found, null));
}
// create a combo to select the boards
createLabel(composite, this.ncol, "The platform you want to use"); //$NON-NLS-1$
new Label(composite, SWT.NONE).setText("Platform folder:"); //$NON-NLS-1$
this.mControlBoardsTxtFile = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
theGriddata = new GridData();
theGriddata.horizontalAlignment = SWT.FILL;
theGriddata.horizontalSpan = (this.ncol - 1);
this.mControlBoardsTxtFile.setLayoutData(theGriddata);
this.mControlBoardsTxtFile.setEnabled(false);
this.mControlBoardsTxtFile.setItems(this.mAllBoardsFiles.keySet().toArray(new String[0]));
createLine(composite, this.ncol);
// -------
// ------
createLabel(composite, this.ncol, "Your Arduino board specifications"); //$NON-NLS-1$
new Label(composite, SWT.NONE).setText("Board:"); //$NON-NLS-1$
this.mcontrolBoardName = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
theGriddata = new GridData();
theGriddata.horizontalAlignment = SWT.FILL;
theGriddata.horizontalSpan = (this.ncol - 1);
this.mcontrolBoardName.setLayoutData(theGriddata);
this.mcontrolBoardName.setEnabled(false);
// ------
new Label(composite, SWT.NONE).setText("Upload Protocol:"); //$NON-NLS-1$
this.mControlUploadProtocol = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
theGriddata = new GridData();
theGriddata.horizontalAlignment = SWT.FILL;
theGriddata.horizontalSpan = (this.ncol - 1);
this.mControlUploadProtocol.setLayoutData(theGriddata);
this.mControlUploadProtocol.setEnabled(false);
// ----
this.mControlUploadPort = new LabelCombo(composite, Messages.ui_port, null, this.ncol - 2, false);
this.mControlUploadPort
.setItems(ArrayUtil.addAll(SerialManager.listNetworkPorts(), SerialManager.listComPorts()));
this.mPwdButton = new org.eclipse.swt.widgets.Button(composite, SWT.PUSH | SWT.CENTER);
this.mPwdButton.setText(Messages.Set_or_Remove_password);
this.mPwdButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
switch (e.type) {
case SWT.Selection:
String host = getUpLoadPort().split(Const.SPACE)[0];
if (host.equals(getUpLoadPort())) {
Activator.log(
new Status(IStatus.ERROR, Activator.getId(), Messages.port_is_not_a_computer_name));
} else {
PasswordManager passwordManager = new PasswordManager();
PasswordDialog dialog = new PasswordDialog(composite.getShell());
passwordManager.setHost(host);
dialog.setPasswordManager(passwordManager);
dialog.open();
}
break;
}
}
});
createLine(composite, this.ncol);
TreeMap<String, String> menus = BoardsManager.getAllmenus();
this.mBoardOptionCombos = new LabelCombo[menus.size()];
int index = 0;
for (Map.Entry<String, String> curMenu : menus.entrySet()) {
this.mBoardOptionCombos[index] = new LabelCombo(composite, curMenu.getValue(),
curMenu.getKey().toUpperCase(), this.ncol - 1, true);
this.mBoardOptionCombos[index++].addListener(this.labelComboListener);
}
// Create the control to alert parents of changes
this.mFeedbackControl = new Text(composite, SWT.None);
this.mFeedbackControl.setVisible(false);
this.mFeedbackControl.setEnabled(false);
theGriddata = new GridData();
theGriddata.horizontalSpan = 0;
this.mFeedbackControl.setLayoutData(theGriddata);
// End of special controls
setValues(confdesc);
this.mcontrolBoardName.addListener(SWT.Modify, this.boardModifyListener);
this.mControlBoardsTxtFile.addListener(SWT.Modify, this.boardFileModifyListener);
enableControls();
Dialog.applyDialogFont(composite);
}
private static String tidyUpLength(String longName) {
IPath longPath = new Path(longName).removeLastSegments(1);
IPath tidyPath = longPath;
int segments = longPath.segmentCount();
if (segments > 7) {
tidyPath = longPath.removeLastSegments(segments - 2);
tidyPath = tidyPath.append("..."); //$NON-NLS-1$
tidyPath = tidyPath.append(longPath.removeFirstSegments(segments - 4));
}
return tidyPath.toString();
}
public boolean isPageComplete() {
boolean MenuOpionsValidAndComplete = true;
boolean ret = true;
int selectedBoardFile = this.mControlBoardsTxtFile.getSelectionIndex();
if (selectedBoardFile == -1)
return false;
for (LabelCombo curLabelCombo : this.mBoardOptionCombos) {
MenuOpionsValidAndComplete = MenuOpionsValidAndComplete && curLabelCombo.isValid();
}
ret = !getBoardName().isEmpty() && MenuOpionsValidAndComplete;
if (!this.mFeedbackControl.getText().equals(ret ? TRUE : FALSE)) {
this.mFeedbackControl.setText(ret ? TRUE : FALSE);
}
if (ret) {
if (this.mBoardSelectionChangedListener != null) {
this.mBoardSelectionChangedListener.handleEvent(new Event());
}
}
return ret;
}
protected void enableControls() {
this.mcontrolBoardName.setEnabled(true);
this.mControlUploadPort.setEnabled(true);
this.mControlUploadProtocol.setEnabled(true);
this.mControlBoardsTxtFile.setEnabled(true);
for (LabelCombo curLabelCombo : this.mBoardOptionCombos) {
curLabelCombo.setVisible(true);
}
this.mComposite.layout(true, true);
this.mComposite.requestLayout();
// this.mComposite.getShell().pack();
// this.mComposite.getShell().redraw();
}
@Override
public boolean canBeVisible() {
return true;
}
@Override
protected void performDefaults() {
// nothing to do here
}
@Override
protected void updateData(ICResourceDescription cfg) {
this.myBoardID.saveConfiguration();
this.myBoardID = BoardDescriptor.makeBoardDescriptor(cfg.getConfiguration());
setValues(cfg.getConfiguration());
}
@Override
protected void updateButtons() {
// nothing to do here
}
private void setValues(ICConfigurationDescription confdesc) {
this.mControlBoardsTxtFile.setText(tidyUpLength(this.myBoardID.getBoardsFile()));
this.mcontrolBoardName.setItems(this.myBoardID.getCompatibleBoards());
this.mcontrolBoardName.setText(this.myBoardID.getBoardName());
String CurrentUploadProtocol = getUpLoadProtocol();
BoardSelectionPage.this.mControlUploadProtocol.removeAll();
BoardSelectionPage.this.mControlUploadProtocol.setItems(this.myBoardID.getUploadProtocols());
BoardSelectionPage.this.mControlUploadProtocol.setText(CurrentUploadProtocol);
if (getUpLoadProtocol().isEmpty()) {
this.mControlUploadProtocol.setText(this.myBoardID.getUploadProtocol());
if (this.mControlUploadProtocol.getText().isEmpty()) {
this.mControlUploadProtocol.setText(Defaults.getDefaultUploadProtocol());
}
}
this.mControlUploadPort.setValue(this.myBoardID.getUploadPort());
// set the options in the combo boxes before setting the value
Map<String, String> options = this.myBoardID.getOptions();
for (LabelCombo curLabelCombo : this.mBoardOptionCombos) {
curLabelCombo.setItems(this.myBoardID.getMenuItemNamesFromMenuID(curLabelCombo.getID()));
if (options != null) {
String value = options.get(curLabelCombo.getID());
if (value != null) {
try {
curLabelCombo
.setValue(this.myBoardID.getMenuItemNamedFromMenuItemID(value, curLabelCombo.getID()));
} catch (Exception e) {
// When this fails no default value will be set
// so nothing to do here
}
}
}
}
}
@Override
protected void performOK() {
doOK();
super.performOK();
}
@Override
protected void performApply(ICResourceDescription src, ICResourceDescription dst) {
doOK();
}
private void doOK() {
this.myBoardID.setBoardsFile(getSelectedBoardsFile());
this.myBoardID.setUploadPort(getUpLoadPort());
this.myBoardID.setUploadProtocol(getUpLoadProtocol());
this.myBoardID.setBoardName(getBoardName());
this.myBoardID.setOptions(getOptions());
ICConfigurationDescription confdesc = getConfdesc();
try {
this.myBoardID.save(confdesc);
} catch (Exception e) {
Activator.log(new Status(IStatus.ERROR, Activator.getId(), Messages.error_adding_arduino_code, e));
}
}
private class ArduinoSelectionPageListener implements Listener {
private AbstractPage myPage;
ArduinoSelectionPageListener(AbstractPage page) {
this.myPage = page;
}
@Override
public void handleEvent(Event event) {
this.myPage.setValid(isPageComplete());
}
}
@Override
public void handleTabEvent(int kind, Object data) {
if (kind == 222) {
this.mFeedbackControl.addListener(SWT.Modify, new ArduinoSelectionPageListener((AbstractPage) data));
}
super.handleTabEvent(kind, data);
}
protected File getSelectedBoardsFile() {
if (this.mControlBoardsTxtFile == null) {
return null;
}
String selectedText = this.mControlBoardsTxtFile.getText().trim();
String longText = this.mAllBoardsFiles.get(selectedText);
if (longText == null) {
return null;// this should not happen
}
return new File(longText);
}
public String getUpLoadPort() {
if (this.mControlUploadPort == null) {
return new String();
}
return this.mControlUploadPort.getValue();
}
protected String getBoardName() {
if (this.mcontrolBoardName == null) {
return null;
}
return this.mcontrolBoardName.getText().trim();
}
protected String getUpLoadProtocol() {
if (this.mControlUploadProtocol == null) {
return Defaults.getDefaultUploadProtocol();
}
return this.mControlUploadProtocol.getText().trim();
}
private Map<String, String> getOptions() {
if (this.mBoardOptionCombos == null) {
return null;
}
Map<String, String> options = new HashMap<>();
for (LabelCombo curLabelCombo : BoardSelectionPage.this.mBoardOptionCombos) {
if (curLabelCombo.isVisible()) {
options.put(curLabelCombo.getID(),
this.myBoardID.getMenuItemIDFromMenuItemName(curLabelCombo.getValue(), curLabelCombo.getID()));
}
}
return options;
}
public BoardDescriptor getBoardID() {
if (this.myBoardID == null) {
this.myBoardID = BoardDescriptor.makeBoardDescriptor(getConfdesc());
}
if (this.mBoardOptionCombos != null) {// only update the values if the
// page has been drawn
this.myBoardID.setBoardsFile(getSelectedBoardsFile());
this.myBoardID.setBoardName(getBoardName());
this.myBoardID.setOptions(getOptions());
this.myBoardID.setUploadPort(getUpLoadPort());
this.myBoardID.setUploadProtocol(getUpLoadProtocol());
}
return this.myBoardID;
}
}