Skip to content

Commit 53cf476

Browse files
authored
Merge pull request #2 from timkoers/board-autoswitch
Board autoswitch
2 parents 67fbd08 + a4278e3 commit 53cf476

File tree

6 files changed

+205
-10
lines changed

6 files changed

+205
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ app/pde.jar
33
build/macosx/work/
44
arduino-core/bin/
55
arduino-core/arduino-core.jar
6+
lib/*
67
hardware/arduino/bootloaders/caterina_LUFA/Descriptors.o
78
hardware/arduino/bootloaders/caterina_LUFA/Descriptors.lst
89
hardware/arduino/bootloaders/caterina_LUFA/Caterina.sym

app/src/processing/app/Base.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,10 @@ public Base(String[] args) throws Exception {
510510
contributionsSelfCheck = new ContributionsSelfCheck(this, new UpdatableBoardsLibsFakeURLsHandler(this), contributionInstaller, libraryInstaller);
511511
new Timer(false).schedule(contributionsSelfCheck, Constants.BOARDS_LIBS_UPDATABLE_CHECK_START_PERIOD);
512512
}
513-
513+
// Load the build settings
514+
for(Editor editor: editors){
515+
editor.findTab(editor.sketch.getPrimaryFile()).loadBuildSettings(this);
516+
}
514517
} else if (parser.isNoOpMode()) {
515518
// Do nothing (intended for only changing preferences)
516519
System.exit(0);
@@ -715,10 +718,8 @@ protected int[] nextEditorLocation() {
715718
}
716719
}
717720

718-
719721
// .................................................................
720722

721-
722723
boolean breakTime = false;
723724
String[] months = {
724725
"jan", "feb", "mar", "apr", "may", "jun",

app/src/processing/app/Editor.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,34 @@
110110
import processing.app.tools.MenuScroller;
111111
import processing.app.tools.Tool;
112112

113+
import javax.swing.*;
114+
import javax.swing.event.*;
115+
import javax.swing.text.BadLocationException;
116+
import java.awt.*;
117+
import java.awt.datatransfer.DataFlavor;
118+
import java.awt.datatransfer.Transferable;
119+
import java.awt.event.*;
120+
import java.awt.print.PageFormat;
121+
import java.awt.print.PrinterException;
122+
import java.awt.print.PrinterJob;
123+
import java.io.File;
124+
import java.io.FileFilter;
125+
import java.io.FilenameFilter;
126+
import java.io.IOException;
127+
import java.net.ConnectException;
128+
import java.net.URL;
129+
import java.net.URLClassLoader;
130+
import java.util.*;
131+
import java.util.List;
132+
import java.util.function.Predicate;
133+
import java.util.stream.Collectors;
134+
import java.util.zip.ZipEntry;
135+
import java.util.zip.ZipFile;
136+
import java.util.ArrayList;
137+
138+
import static processing.app.I18n.tr;
139+
import static processing.app.Theme.scale;
140+
113141
/**
114142
* Main editor panel for the Processing Development Environment.
115143
*/
@@ -748,6 +776,10 @@ private JMenu buildToolsMenu() {
748776
item = new JMenuItem(tr("Get Board Info"));
749777
item.addActionListener(e -> handleBoardInfo());
750778
toolsMenu.add(item);
779+
780+
item = new JMenuItem(tr("Add build settings to .INO file"));
781+
item.addActionListener(e -> handleAddBuildSettings());
782+
toolsMenu.add(item);
751783
toolsMenu.addSeparator();
752784

753785
base.rebuildProgrammerMenu();
@@ -2369,6 +2401,21 @@ public void handlePlotter() {
23692401

23702402
}
23712403

2404+
public void handleAddBuildSettings(){
2405+
final LinkedHashMap<String, String> settingsMap = base.getBoardsCustomMenus().stream().filter(JMenu::isVisible).map((e)->{
2406+
String setting = e.getText().substring(0, e.getText().indexOf(":"));
2407+
String value = e.getText().replace(setting + ":", "").replace("\"", "").trim();
2408+
return new String[]{setting, value};
2409+
}).collect(LinkedHashMap::new, (map, menu) -> map.put(menu[0], menu[1]), LinkedHashMap::putAll);
2410+
handleSave(true);
2411+
Optional<EditorTab> optionalEditorTab = tabs.stream().filter(tab -> tab.getSketch().getSketch().equals(sketch)).findFirst();
2412+
if(optionalEditorTab.isPresent()){
2413+
optionalEditorTab.get().setText(sketch.setBuildSettings(sketch, settingsMap));
2414+
handleSave(true);
2415+
System.out.println("Build settings header should be added");
2416+
}
2417+
}
2418+
23722419
private void handleBurnBootloader() {
23732420
console.clear();
23742421
EditorConsole.setCurrentEditorConsole(this.console);

app/src/processing/app/EditorTab.java

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,12 @@
3333
import java.awt.event.FocusEvent;
3434
import java.awt.event.FocusListener;
3535
import java.io.IOException;
36+
import java.lang.annotation.Target;
37+
import java.util.Arrays;
38+
import java.util.LinkedHashMap;
39+
import java.util.Optional;
3640

37-
import javax.swing.Action;
38-
import javax.swing.BorderFactory;
39-
import javax.swing.JMenuItem;
40-
import javax.swing.JPanel;
41-
import javax.swing.JPopupMenu;
42-
import javax.swing.ToolTipManager;
41+
import javax.swing.*;
4342
import javax.swing.border.MatteBorder;
4443
import javax.swing.event.PopupMenuEvent;
4544
import javax.swing.event.PopupMenuListener;
@@ -57,6 +56,8 @@
5756
import org.fife.ui.rtextarea.RTextScrollPane;
5857

5958
import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
59+
import processing.app.debug.TargetBoard;
60+
import processing.app.debug.TargetPackage;
6061
import processing.app.helpers.DocumentTextChangeListener;
6162
import processing.app.syntax.ArduinoTokenMakerFactory;
6263
import processing.app.syntax.PdeKeywords;
@@ -447,6 +448,42 @@ public void setText(String what) {
447448
textarea.setLineWrap(textarea.getLineWrap());
448449
}
449450

451+
452+
/**
453+
* This method loads the build settings from the main .INO file and sets the Arduino IDE accordingly
454+
*/
455+
public void loadBuildSettings(Base base){
456+
457+
LinkedHashMap<String, String> buildSettings = getSketch().getSketch().getBuildSettingsFromProgram(getText());
458+
459+
Optional<TargetBoard> optionalTargetBoard = BaseNoGui.getTargetPlatform().getBoards().values().stream().filter(board -> board.getPreferences().get("name","").equals("Node32s")).findFirst();
460+
461+
TargetBoard targetBoard;
462+
if(optionalTargetBoard.isPresent()){
463+
targetBoard = optionalTargetBoard.get();
464+
}else{
465+
return;
466+
}
467+
468+
for(String readableName : buildSettings.values()){
469+
base.getBoardsCustomMenus().forEach(menuItem -> {
470+
Optional<JRadioButtonMenuItem> optionalBoardMenuItem = Arrays.stream(menuItem.getMenuComponents()).filter(subItem->{
471+
return subItem instanceof JRadioButtonMenuItem && ((JRadioButtonMenuItem)subItem).getText().equals(readableName) && (((JRadioButtonMenuItem) subItem).getAction().getValue("board") == null || (((JRadioButtonMenuItem) subItem).getAction().getValue("board").equals(targetBoard)));
472+
}
473+
).map(subItem-> {
474+
return subItem instanceof JRadioButtonMenuItem ? (JRadioButtonMenuItem)subItem : new JRadioButtonMenuItem();
475+
}).findFirst();
476+
if(optionalBoardMenuItem.isPresent()){
477+
optionalBoardMenuItem.get().setSelected(true);
478+
optionalBoardMenuItem.get().getAction().actionPerformed(new ActionEvent(this, -1, ""));
479+
}else{
480+
// TODO Ask the user which value should replace the current value
481+
482+
}
483+
});
484+
}
485+
}
486+
450487
/**
451488
* Is the text modified since the last save / load?
452489
*/

arduino-core/src/processing/app/Sketch.java

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,111 @@ public void save() throws IOException {
139139
}
140140
}
141141

142+
private final String buildToolsHeader = "\n/** Arduino IDE Board Tool details\n";
143+
private final String buildToolsHeaderEnd = "*/";
144+
145+
/**
146+
* Checks the code for a valid build tool header
147+
* @param program The code to scan for the build tools
148+
* @return True if the build tool header was found ONE time. Returns false if found MORE than one time, or not found at all.
149+
*/
150+
private boolean containsBuildSettings(String program){
151+
return program.contains(buildToolsHeader) && (program.indexOf(buildToolsHeader) == program.lastIndexOf(buildToolsHeader));
152+
}
153+
154+
/**
155+
* This function returns the index of the Nth occurrence of the substring in the specified string (http://programming.guide/java/nth-occurrence-in-string.html)
156+
* @param str The string to find the Nth occurrence in
157+
* @param substr The string to find
158+
* @param n The occurrence number you'd like to find
159+
* @return
160+
*/
161+
private static int ordinalIndexOf(String str, String substr, int n) {
162+
int pos = str.indexOf(substr);
163+
while (--n > 0 && pos != -1)
164+
pos = str.indexOf(substr, pos + 1);
165+
return pos;
166+
}
167+
168+
private String removeBuildSettingsHeader(Sketch sketch){
169+
if(sketch.getPrimaryFile().getProgram().contains(buildToolsHeader)) {
170+
int headerStartIndex = sketch.getPrimaryFile().getProgram().indexOf(buildToolsHeader);
171+
int headerStopIndex = sketch.getPrimaryFile().getProgram().indexOf(buildToolsHeaderEnd);
172+
if (headerStartIndex > headerStopIndex) {
173+
System.err.println("The build tool header is not the first comment block in your file! Please fix this.");
174+
for (int i = 0; i < sketch.getPrimaryFile().getProgram().length(); i++) {
175+
if (headerStartIndex < ordinalIndexOf(sketch.getPrimaryFile().getProgram(), buildToolsHeaderEnd, i)) {
176+
headerStopIndex = ordinalIndexOf(sketch.getPrimaryFile().getProgram(), buildToolsHeaderEnd, i);
177+
break;
178+
}
179+
}
180+
}
181+
String header = sketch.getPrimaryFile().getProgram().substring(headerStartIndex, headerStopIndex + buildToolsHeaderEnd.length());
182+
return sketch.getPrimaryFile().getProgram().replace(header, "");
183+
}
184+
return sketch.getPrimaryFile().getProgram();
185+
}
186+
187+
/**
188+
* This checks the program code for a valid build tool settings header and returns the LinkedHashMap with the setting name and the value.
189+
* The build tools header should not be changed or manipulated by the pre-processor as the pre-processors output may depend on the build tools.
190+
* @param program The program code
191+
* @return The {@code LinkedHashMap} with the settings and their values of the <b>first</b> header that was found in the program code
192+
*/
193+
public LinkedHashMap<String, String> getBuildSettingsFromProgram(String program){
194+
LinkedHashMap<String, String> buildSettings = new LinkedHashMap<>();
195+
if(containsBuildSettings(program)){
196+
int headerStartIndex = program.indexOf(buildToolsHeader);
197+
int headerStopIndex = program.indexOf(buildToolsHeaderEnd);
198+
if(headerStartIndex > headerStopIndex){
199+
System.err.println("The build tool header is not the first comment block in your file! Please fix this.");
200+
for(int i = 0; i < program.length(); i++){
201+
if(headerStartIndex < ordinalIndexOf(program, buildToolsHeaderEnd, i)){
202+
headerStopIndex = ordinalIndexOf(program, buildToolsHeaderEnd, i);
203+
break;
204+
}
205+
}
206+
}
207+
String header = program.substring(headerStartIndex + buildToolsHeader.length(), headerStopIndex);
208+
209+
String[] headerLines = header.split("\n");
210+
211+
for(int line = 0; line < headerLines.length; line++){
212+
String[] setting = headerLines[line].replace("*","").trim().split(": ");
213+
if(headerLines[line].indexOf(": ") != (headerLines[line].length() -1)){
214+
// The value of the setting is not empty
215+
buildSettings.put(setting[0].trim(), setting[1].trim());
216+
}else{
217+
buildSettings.put(setting[0], "");
218+
}
219+
}
220+
}else{
221+
if(!program.contains(buildToolsHeader)){
222+
// There are multiple headers, remove them
223+
// TODO Create a dialog asking the user to add a build header to the file
224+
}
225+
}
226+
227+
return buildSettings;
228+
}
229+
230+
private boolean isBuildSettingsEqual(LinkedHashMap<String,String> first, LinkedHashMap<String, String> second){
231+
return first.keySet().containsAll(second.keySet()) && first.values().containsAll(second.values());
232+
}
233+
234+
public String setBuildSettings(Sketch sketch, LinkedHashMap<String, String> buildSettings){
235+
if(sketch != this){
236+
return "";
237+
}
238+
239+
String customBoardSettingsHeader = buildSettings.entrySet().stream().map(entry-> String.format(" * %s: %s\n", entry.getKey(), entry.getValue())).collect(Collectors.joining("", buildToolsHeader, "*/"));
240+
if(!isBuildSettingsEqual(getBuildSettingsFromProgram(sketch.getPrimaryFile().getProgram()),buildSettings)){
241+
String headerLessProgram = removeBuildSettingsHeader(sketch);
242+
return customBoardSettingsHeader + ((headerLessProgram.charAt(0) == '\n') ? "" : "\n") + headerLessProgram;
243+
}
244+
return "";
245+
}
246+
142247
public int getCodeCount() {
143248
return files.size();
144249
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/** Arduino IDE Board Tool details
2+
* Board: Arduino/Genuino Uno
3+
*/
4+
15
void setup() {
26
// put your setup code here, to run once:
37

@@ -6,4 +10,4 @@ void setup() {
610
void loop() {
711
// put your main code here, to run repeatedly:
812

9-
}
13+
}

0 commit comments

Comments
 (0)