1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-10-16 22:27:59 +03:00

Merge branch 'master' into esp8266

* master: (414 commits)
  Don't export sketch if the underlying core does not support it. Fixes #3171
  RSyntaxTextArea: using a modified version, tracked at https://github.com/arduino/RSyntaxTextArea. Fixes #3099
  Updated keywords.txt
  New editor on MacOSX: since CMD+J is known as "jump to selection" and the editor has no such feature, CMD+J is disabled on mac. See #3098
  Old Preferences class remains for backwards compatibility as a delegate for PreferencesData
  New Preferences window: renders fine on every OS and it's easier to adapt using NetBeans as visual editor. Fixes #3140
  Remove spawn from exec command
  Removed redundant call to File.deleteIfExists()
  Removed buggy redundant check in FileUtils.deleteIfExists()
  Restored current line/current selected lines display on lower left of the IDE. Fixes #3134
  Updated cursor.ino
  New editor on MacOSX: restored CMD+E for finding selected text
  New editor on MacOSX: CMD+UP/DOWN moves cursor to start or end of sketch. See #3098
  New editor on MacOSX: CMD+BACKSPACE deletes current line until cursor position, ALT+BACKSPACE deletes previous word. See #3098
  ArduinoIDE is in the default package. Removed
  Fixes  #2969:
  Fix Uncategorized warning message
  New editor: ALT+ BACKSPACE deletes next word (OSX only). See #3098
  New editor: ALT+ UP/DOWN move current line only if "editor.advanced" (hidden pref) is true. Fixes #3101
  New editor: mark occurrences enable when "editor.advanced" (hidden pref) is true. Fixes #3102
  ...

Conflicts:
	.gitignore
	build/build.xml
	hardware/esp8266com/esp8266/libraries/ESP8266WiFi/keywords.txt
	hardware/esp8266com/esp8266/libraries/ESP8266WiFi/library.properties
	hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h
	libraries/WiFi/README.adoc
	libraries/WiFi/src/WiFi.cpp
	libraries/WiFi/src/WiFiClient.cpp
	libraries/WiFi/src/WiFiClient.h
	libraries/WiFi/src/WiFiServer.cpp
	libraries/WiFi/src/WiFiUdp.cpp
This commit is contained in:
Ivan Grokhotkov
2015-05-18 14:54:06 +03:00
644 changed files with 37518 additions and 12166 deletions

View File

@@ -0,0 +1,115 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions;
import cc.arduino.contributions.filters.BuiltInPredicate;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.packages.ContributedPackage;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.view.Event;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import processing.app.Base;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.PreferencesData;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.util.LinkedList;
import java.util.List;
import static processing.app.I18n._;
public class BuiltInCoreIsNewerCheck implements Runnable {
private final Base base;
public BuiltInCoreIsNewerCheck(Base base) {
this.base = base;
}
@Override
public void run() {
try {
builtInPackageIsNewerCheck();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void builtInPackageIsNewerCheck() throws InterruptedException {
if (PreferencesData.getInteger("builtin_platform_is_newer", -1) >= BaseNoGui.REVISION) {
return;
}
LinkedList<ContributedPlatform> contributedPlatforms = Lists.newLinkedList(Iterables.concat(Collections2.transform(BaseNoGui.indexer.getPackages(), new Function<ContributedPackage, List<ContributedPlatform>>() {
@Override
public List<ContributedPlatform> apply(ContributedPackage input) {
return input.getPlatforms();
}
})));
List<ContributedPlatform> installedBuiltInPlatforms = new LinkedList<ContributedPlatform>(Collections2.filter(contributedPlatforms, Predicates.and(new InstalledPredicate(), new BuiltInPredicate())));
if (installedBuiltInPlatforms.size() != 1) {
return;
}
final ContributedPlatform installedBuiltIn = installedBuiltInPlatforms.get(0);
ContributedPlatform installedNotBuiltIn = BaseNoGui.indexer.getInstalled(installedBuiltIn.getParentPackage().getName(), installedBuiltIn.getArchitecture());
if (installedNotBuiltIn == null) {
return;
}
while (!base.hasActiveEditor()) {
Thread.sleep(100);
}
if (VersionHelper.valueOf(installedBuiltIn.getParsedVersion()).greaterThan(VersionHelper.valueOf(installedNotBuiltIn.getParsedVersion()))) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
PreferencesData.setInteger("builtin_platform_is_newer", BaseNoGui.REVISION);
assert base.hasActiveEditor();
int chosenOption = JOptionPane.showConfirmDialog(base.getActiveEditor(), I18n.format(_("The IDE includes an updated {0} package, but you're using an older one.\nDo you want to upgrade {0}?"), installedBuiltIn.getName()), I18n.format(_("A newer {0} package is available"), installedBuiltIn.getName()), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (chosenOption == JOptionPane.YES_OPTION) {
Action openBoardsManager = base.getOpenBoardsManager();
Event event = new Event(base.getActiveEditor(), ActionEvent.ACTION_PERFORMED, installedBuiltIn.getName());
event.getPayload().put("filterText", installedBuiltIn.getName());
openBoardsManager.actionPerformed(event);
}
}
});
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.filters;
import com.google.common.base.Predicate;
public class NoopPredicate<T> implements Predicate<T> {
@Override
public boolean apply(T input) {
return true;
}
@Override
public boolean equals(Object obj) {
return obj instanceof NoopPredicate;
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.filters;
import cc.arduino.contributions.libraries.ContributedLibrary;
import com.google.common.base.Predicate;
public class CategoryPredicate implements Predicate<ContributedLibrary> {
private final String category;
public CategoryPredicate(String category) {
this.category = category;
}
@Override
public boolean apply(ContributedLibrary input) {
return input.getCategory() != null && category.equals(input.getCategory());
}
@Override
public boolean equals(Object obj) {
return obj instanceof CategoryPredicate && ((CategoryPredicate) obj).category.equals(category);
}
}

View File

@@ -0,0 +1,64 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.filters;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.LibrariesIndex;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import java.util.Collection;
public class InstalledLibraryPredicate implements Predicate<ContributedLibrary> {
private final LibrariesIndex index;
public InstalledLibraryPredicate(LibrariesIndex index) {
this.index = index;
}
@Override
public boolean apply(ContributedLibrary input) {
if (input.isInstalled()) {
return true;
}
Collection<ContributedLibrary> installed = Collections2.filter(index.find(input.getName()), new InstalledPredicate());
return !installed.isEmpty();
}
@Override
public boolean equals(Object obj) {
return obj instanceof InstalledLibraryPredicate;
}
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.filters;
import cc.arduino.contributions.libraries.ContributedLibrary;
import com.google.common.base.Predicate;
import processing.app.packages.UserLibrary;
public class OnlyUpstreamReleasePredicate implements Predicate<ContributedLibrary> {
@Override
public boolean apply(ContributedLibrary input) {
return !(input instanceof UserLibrary);
}
@Override
public boolean equals(Object obj) {
return obj instanceof OnlyUpstreamReleasePredicate;
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.filters;
import cc.arduino.contributions.libraries.ContributedLibrary;
import com.google.common.base.Predicate;
public class TypePredicate implements Predicate<ContributedLibrary> {
private final String type;
public TypePredicate(String type) {
this.type = type;
}
@Override
public boolean apply(ContributedLibrary input) {
return input.getTypes() != null && input.getTypes().contains(type);
}
@Override
public boolean equals(Object obj) {
return obj instanceof TypePredicate && ((TypePredicate) obj).type.equals(type);
}
}

View File

@@ -0,0 +1,441 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.ui;
import cc.arduino.contributions.VersionComparator;
import cc.arduino.contributions.filters.BuiltInPredicate;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.filters.OnlyUpstreamReleasePredicate;
import cc.arduino.contributions.packages.DownloadableContribution;
import cc.arduino.contributions.DownloadableContributionVersionComparator;
import cc.arduino.contributions.ui.InstallerTableCell;
import cc.arduino.contributions.ui.listeners.DelegatingKeyListener;
import cc.arduino.utils.ReverseComparator;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import processing.app.Base;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.StyleSheet;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import static processing.app.I18n._;
import static processing.app.I18n.format;
@SuppressWarnings("serial")
public class ContributedLibraryTableCell extends InstallerTableCell {
private JPanel panel;
private JButton installButton;
private Component installButtonPlaceholder;
private JComboBox downgradeChooser;
private JComboBox versionToInstallChooser;
private JButton downgradeButton;
private JPanel buttonsPanel;
private JPanel inactiveButtonsPanel;
private JLabel statusLabel;
public ContributedLibraryTableCell() {
{
installButton = new JButton(_("Install"));
installButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onInstall(editorValue.getSelected(), editorValue.getInstalled());
}
});
int width = installButton.getPreferredSize().width;
installButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1));
}
downgradeButton = new JButton(_("Install"));
downgradeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ContributedLibrary selected = (ContributedLibrary) downgradeChooser.getSelectedItem();
onInstall(selected, editorValue.getInstalled());
}
});
downgradeChooser = new JComboBox();
downgradeChooser.addItem("-");
downgradeChooser.setMaximumSize(downgradeChooser.getPreferredSize());
downgradeChooser.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
Object selectVersionItem = downgradeChooser.getItemAt(0);
boolean disableDowngrade = (e.getItem() == selectVersionItem);
downgradeButton.setEnabled(!disableDowngrade);
}
});
versionToInstallChooser = new JComboBox();
versionToInstallChooser.addItem("-");
versionToInstallChooser.setMaximumSize(versionToInstallChooser.getPreferredSize());
versionToInstallChooser.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
editorValue.select((ContributedLibrary) versionToInstallChooser.getSelectedItem());
}
});
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
makeNewDescription(panel);
{
buttonsPanel = new JPanel();
buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS));
buttonsPanel.setOpaque(false);
buttonsPanel.add(Box.createHorizontalStrut(7));
buttonsPanel.add(downgradeChooser);
buttonsPanel.add(Box.createHorizontalStrut(5));
buttonsPanel.add(downgradeButton);
buttonsPanel.add(Box.createHorizontalGlue());
buttonsPanel.add(versionToInstallChooser);
buttonsPanel.add(Box.createHorizontalStrut(5));
buttonsPanel.add(installButton);
buttonsPanel.add(Box.createHorizontalStrut(5));
buttonsPanel.add(Box.createHorizontalStrut(15));
panel.add(buttonsPanel);
}
{
inactiveButtonsPanel = new JPanel();
inactiveButtonsPanel.setLayout(new BoxLayout(inactiveButtonsPanel, BoxLayout.X_AXIS));
inactiveButtonsPanel.setOpaque(false);
int height = installButton.getMinimumSize().height;
inactiveButtonsPanel.add(Box.createVerticalStrut(height));
inactiveButtonsPanel.add(Box.createGlue());
statusLabel = new JLabel(" ");
inactiveButtonsPanel.add(statusLabel);
inactiveButtonsPanel.add(Box.createHorizontalStrut(15));
panel.add(inactiveButtonsPanel);
}
panel.add(Box.createVerticalStrut(15));
}
private JTextPane makeNewDescription(JPanel panel) {
if (panel.getComponentCount() > 0) {
panel.remove(0);
}
JTextPane description = new JTextPane();
description.setInheritsPopupMenu(true);
Insets margin = description.getMargin();
margin.bottom = 0;
description.setMargin(margin);
description.setContentType("text/html");
Document doc = description.getDocument();
if (doc instanceof HTMLDocument) {
HTMLDocument html = (HTMLDocument) doc;
StyleSheet stylesheet = html.getStyleSheet();
stylesheet.addRule("body { margin: 0; padding: 0;"
+ "font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;"
+ "font-size: 100%;" + "font-size: 0.95em; }");
}
description.setOpaque(false);
description.setBorder(new EmptyBorder(4, 7, 7, 7));
description.setHighlighter(null);
description.setEditable(false);
description.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
Base.openURL(e.getDescription());
}
}
});
description.addKeyListener(new DelegatingKeyListener(parentTable));
panel.add(description, 0);
return description;
}
protected void onRemove(ContributedLibrary selected) {
// Empty
}
protected void onInstall(ContributedLibrary selected, ContributedLibrary installed) {
// Empty
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected,
boolean hasFocus, int row,
int column) {
parentTable = table;
setEnabled(false);
Component component = getUpdatedCellComponent(value, isSelected, row, false);
if (row % 2 == 0) {
component.setBackground(new Color(236, 241, 241)); //#ecf1f1
} else {
component.setBackground(new Color(255, 255, 255));
}
int height = new Double(component.getPreferredSize().getHeight()).intValue();
if (table.getRowHeight(row) < height) {
table.setRowHeight(row, height);
}
return component;
}
private LibrariesIndexTableModel.ContributedLibraryReleases editorValue;
private JTable parentTable;
@Override
public Object getCellEditorValue() {
return editorValue;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row,
int column) {
parentTable = table;
editorValue = (LibrariesIndexTableModel.ContributedLibraryReleases) value;
setEnabled(true);
final ContributedLibrary installed = editorValue.getInstalled();
List<ContributedLibrary> releases = new LinkedList<ContributedLibrary>(Collections2.filter(editorValue.releases, new OnlyUpstreamReleasePredicate()));
List<ContributedLibrary> uninstalledReleases = new LinkedList<ContributedLibrary>(Collections2.filter(releases, Predicates.not(new InstalledPredicate())));
List<ContributedLibrary> installedBuiltIn = new LinkedList<ContributedLibrary>(Collections2.filter(releases, Predicates.and(new InstalledPredicate(), new BuiltInPredicate())));
if (installed != null && !installedBuiltIn.contains(installed)) {
uninstalledReleases.addAll(installedBuiltIn);
}
Collections.sort(uninstalledReleases, new ReverseComparator<DownloadableContribution>(new DownloadableContributionVersionComparator()));
downgradeChooser.removeAllItems();
downgradeChooser.addItem(_("Select version"));
final List<ContributedLibrary> uninstalledPreviousReleases = Lists.newLinkedList();
final List<ContributedLibrary> uninstalledNewerReleases = Lists.newLinkedList();
final VersionComparator versionComparator = new VersionComparator();
Lists.newLinkedList(Lists.transform(uninstalledReleases, new Function<ContributedLibrary, ContributedLibrary>() {
@Override
public ContributedLibrary apply(ContributedLibrary input) {
if (installed == null || versionComparator.greaterThan(installed.getParsedVersion(), input.getParsedVersion())) {
uninstalledPreviousReleases.add(input);
} else {
uninstalledNewerReleases.add(input);
}
return input;
}
}));
for (ContributedLibrary release : uninstalledNewerReleases) {
downgradeChooser.addItem(release);
}
for (ContributedLibrary release : uninstalledPreviousReleases) {
downgradeChooser.addItem(release);
}
downgradeChooser.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1));
downgradeButton.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1));
versionToInstallChooser.removeAllItems();
for (ContributedLibrary release : uninstalledReleases) {
versionToInstallChooser.addItem(release);
}
versionToInstallChooser.setVisible(installed == null && uninstalledReleases.size() > 1);
Component component = getUpdatedCellComponent(value, true, row, !installedBuiltIn.isEmpty());
component.setBackground(new Color(218, 227, 227)); //#dae3e3
return component;
}
private Component getUpdatedCellComponent(Object value, boolean isSelected, int row, boolean hasBuiltInRelease) {
LibrariesIndexTableModel.ContributedLibraryReleases releases = (LibrariesIndexTableModel.ContributedLibraryReleases) value;
JTextPane description = makeNewDescription(panel);
//FIXME: happens on macosx, don't know why
if (releases == null) {
return panel;
}
ContributedLibrary selected = releases.getSelected();
ContributedLibrary installed = releases.getInstalled();
boolean removable, installable, upgradable;
if (installed == null) {
installable = true;
removable = false;
upgradable = false;
} else {
installable = false;
removable = !installed.isReadOnly() && !hasBuiltInRelease;
upgradable = new DownloadableContributionVersionComparator().compare(selected, installed) > 0;
}
if (installable) {
installButton.setText(_("Install"));
}
if (upgradable) {
installButton.setText(_("Update"));
}
installButton.setVisible(installable || upgradable);
installButtonPlaceholder.setVisible(!(installable || upgradable));
String name = selected.getName();
String author = selected.getAuthor();
// String maintainer = selectedLib.getMaintainer();
String website = selected.getWebsite();
String sentence = selected.getSentence();
String paragraph = selected.getParagraph();
// String availableVer = selectedLib.getVersion();
// String url = selected.getUrl();
String midcolor = isSelected ? "#000000" : "#888888";
String desc = "<html><body>";
// Library name...
desc += format("<b>{0}</b>", name);
if (installed != null && installed.isReadOnly()) {
desc += " Built-In ";
}
// ...author...
desc += format("<font color=\"{0}\">", midcolor);
if (author != null && !author.isEmpty()) {
desc += format(" by <b>{0}</b>", author);
}
// ...version.
if (installed != null) {
String installedVer = installed.getParsedVersion();
if (installedVer == null) {
desc += " " + _("Version unknown");
} else {
desc += " " + format(_("Version <b>{0}</b>"), installedVer);
}
}
desc += "</font>";
if (installed != null) {
desc += " <strong><font color=\"#00979D\">INSTALLED</font></strong>";
}
desc += "<br/>";
// Description
if (sentence != null) {
desc += format("<b>{0}</b> ", sentence);
if (paragraph != null && !paragraph.isEmpty())
desc += format("{0}", paragraph);
desc += "<br />";
}
if (author != null && !author.isEmpty()) {
desc += format("<a href=\"{0}\">More info</a>", website);
}
desc += "</body></html>";
description.setText(desc);
description.setBackground(Color.WHITE);
// for modelToView to work, the text area has to be sized. It doesn't
// matter if it's visible or not.
// See:
// http://stackoverflow.com/questions/3081210/how-to-set-jtextarea-to-have-height-that-matches-the-size-of-a-text-it-contains
int width = parentTable.getBounds().width;
setJTextPaneDimensionToFitContainedText(description, width);
if (isSelected) {
panel.setBackground(parentTable.getSelectionBackground());
panel.setForeground(parentTable.getSelectionForeground());
} else {
panel.setBackground(parentTable.getBackground());
panel.setForeground(parentTable.getForeground());
}
return panel;
}
private Timer enabler = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
enable(true);
enabler.stop();
}
});
@Override
public void setEnabled(boolean enabled) {
enable(false);
if (enabled) {
enabler.start();
} else {
enabler.stop();
}
buttonsPanel.setVisible(enabled);
inactiveButtonsPanel.setVisible(!enabled);
}
public void enable(boolean enabled) {
installButton.setEnabled(enabled);
}
public void setStatus(String status) {
statusLabel.setText(status);
}
public void invalidate() {
panel.invalidate();
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.ui;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.LibrariesIndex;
import cc.arduino.contributions.libraries.filters.InstalledLibraryPredicate;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
import static processing.app.I18n._;
public class DropdownInstalledLibraryItem implements DropdownItem<ContributedLibrary> {
private final LibrariesIndex index;
public DropdownInstalledLibraryItem(LibrariesIndex index) {
this.index = index;
}
public String toString() {
return _("Installed");
}
@Override
public Predicate<ContributedLibrary> getFilterPredicate() {
return new InstalledLibraryPredicate(index);
}
@Override
public boolean equals(Object obj) {
return obj instanceof DropdownInstalledLibraryItem;
}
}

View File

@@ -0,0 +1,59 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.ui;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.filters.CategoryPredicate;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
public class DropdownLibraryOfCategoryItem implements DropdownItem<ContributedLibrary> {
private final String category;
public DropdownLibraryOfCategoryItem(String category) {
this.category = category;
}
public String toString() {
return category;
}
@Override
public Predicate<ContributedLibrary> getFilterPredicate() {
return new CategoryPredicate(category);
}
@Override
public boolean equals(Object obj) {
return obj instanceof DropdownLibraryOfCategoryItem && ((DropdownLibraryOfCategoryItem) obj).category.equals(category);
}
}

View File

@@ -0,0 +1,60 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.ui;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.filters.CategoryPredicate;
import cc.arduino.contributions.libraries.filters.TypePredicate;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
public class DropdownLibraryOfTypeItem implements DropdownItem<ContributedLibrary> {
private final String type;
public DropdownLibraryOfTypeItem(String type) {
this.type = type;
}
public String toString() {
return type;
}
@Override
public Predicate<ContributedLibrary> getFilterPredicate() {
return new TypePredicate(type);
}
@Override
public boolean equals(Object obj) {
return obj instanceof DropdownLibraryOfTypeItem && ((DropdownLibraryOfTypeItem) obj).type.equals(type);
}
}

View File

@@ -0,0 +1,280 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.ui;
import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator;
import cc.arduino.contributions.VersionHelper;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.LibrariesIndexer;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.contributions.ui.FilteredAbstractTableModel;
import com.github.zafarkhaja.semver.Version;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@SuppressWarnings("serial")
public class LibrariesIndexTableModel extends FilteredAbstractTableModel<ContributedLibrary> {
public final static int DESCRIPTION_COL = 0;
public static class ContributedLibraryReleases implements Comparable<ContributedLibraryReleases> {
public final String name;
public final List<ContributedLibrary> releases;
public final List<String> versions;
public ContributedLibrary selected;
public ContributedLibraryReleases(ContributedLibrary library) {
this.name = library.getName();
this.versions = new LinkedList<String>();
this.releases = new LinkedList<ContributedLibrary>();
this.selected = null;
add(library);
}
public boolean shouldContain(ContributedLibrary lib) {
return lib.getName().equals(name);
}
public void add(ContributedLibrary library) {
releases.add(library);
String version = library.getParsedVersion();
if (version != null) {
versions.add(version);
}
selected = getLatest();
}
public ContributedLibrary getInstalled() {
List<ContributedLibrary> installedReleases = new LinkedList<ContributedLibrary>(Collections2.filter(releases, new InstalledPredicate()));
Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator());
if (installedReleases.isEmpty()) {
return null;
}
return installedReleases.get(0);
}
public ContributedLibrary getLatest() {
return getLatestOf(releases);
}
public ContributedLibrary getSelected() {
return selected;
}
public void select(ContributedLibrary value) {
for (ContributedLibrary plat : releases) {
if (plat == value) {
selected = plat;
return;
}
}
}
@Override
public int compareTo(ContributedLibraryReleases o) {
return name.compareToIgnoreCase(o.name);
}
}
private final List<ContributedLibraryReleases> contributions = new ArrayList<ContributedLibraryReleases>();
private final String[] columnNames = {"Description"};
private final Class<?>[] columnTypes = {ContributedPlatform.class};
private LibrariesIndexer indexer;
public void setIndexer(LibrariesIndexer _index) {
indexer = _index;
}
Predicate<ContributedLibrary> selectedCategoryFilter = null;
String selectedFilters[] = null;
public void updateIndexFilter(String filters[], Predicate<ContributedLibrary>... additionalFilters) {
selectedCategoryFilter = Predicates.and(additionalFilters);
selectedFilters = filters;
update();
}
/**
* Check if <b>string</b> contains all the substrings in <b>set</b>. The
* compare is case insensitive.
*
* @param string
* @param filters
* @return <b>true<b> if all the strings in <b>set</b> are contained in
* <b>string</b>.
*/
private boolean stringContainsAll(String string, String filters[]) {
if (string == null) {
return false;
}
if (filters == null) {
return true;
}
for (String filter : filters) {
if (!string.toLowerCase().contains(filter.toLowerCase())) {
return false;
}
}
return true;
}
private void addContribution(ContributedLibrary lib) {
for (ContributedLibraryReleases contribution : contributions) {
if (!contribution.shouldContain(lib))
continue;
contribution.add(lib);
return;
}
contributions.add(new ContributedLibraryReleases(lib));
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return contributions.size();
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public Class<?> getColumnClass(int colum) {
return columnTypes[colum];
}
@Override
public void setValueAt(Object value, int row, int col) {
if (col == DESCRIPTION_COL) {
fireTableCellUpdated(row, col);
}
}
@Override
public Object getValueAt(int row, int col) {
if (row >= contributions.size()) {
return null;
}
ContributedLibraryReleases contribution = contributions.get(row);
if (col == DESCRIPTION_COL) {
return contribution;// .getSelected();
}
return null;
}
@Override
public boolean isCellEditable(int row, int col) {
return col == DESCRIPTION_COL;
}
public ContributedLibraryReleases getReleases(int row) {
return contributions.get(row);
}
public ContributedLibrary getSelectedRelease(int row) {
return contributions.get(row).getSelected();
}
public void update() {
updateContributions();
fireTableDataChanged();
}
private void applyFilterToLibrary(ContributedLibrary lib) {
if (selectedCategoryFilter != null && !selectedCategoryFilter.apply(lib)) {
return;
}
if (!stringContainsAll(lib.getName(), selectedFilters) && !stringContainsAll(lib.getParagraph(), selectedFilters) && !stringContainsAll(lib.getSentence(), selectedFilters)) {
return;
}
addContribution(lib);
}
public void updateLibrary(ContributedLibrary lib) {
// Find the row interested in the change
int row = -1;
for (ContributedLibraryReleases releases : contributions) {
if (releases.shouldContain(lib))
row = contributions.indexOf(releases);
}
updateContributions();
// If the library is found in the list send update event
// or insert event on the specific row...
for (ContributedLibraryReleases releases : contributions) {
if (releases.shouldContain(lib)) {
if (row == -1) {
row = contributions.indexOf(releases);
fireTableRowsInserted(row, row);
} else {
fireTableRowsUpdated(row, row);
}
return;
}
}
// ...otherwise send a row deleted event
fireTableRowsDeleted(row, row);
}
private void updateContributions() {
contributions.clear();
for (ContributedLibrary l : indexer.getIndex().getLibraries()) {
applyFilterToLibrary(l);
}
for (ContributedLibrary l : indexer.getInstalledLibraries()) {
applyFilterToLibrary(l);
}
Collections.sort(contributions);
}
}

View File

@@ -0,0 +1,285 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.ui;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.LibrariesIndexer;
import cc.arduino.contributions.libraries.LibraryInstaller;
import cc.arduino.contributions.packages.DownloadableContribution;
import cc.arduino.contributions.ui.InstallerJDialogUncaughtExceptionHandler;
import cc.arduino.contributions.ui.*;
import cc.arduino.utils.Progress;
import com.google.common.base.Predicate;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import static processing.app.I18n._;
@SuppressWarnings("serial")
public class LibraryManagerUI extends InstallerJDialog<ContributedLibrary> {
private LibrariesIndexer indexer;
private final JComboBox typeChooser;
private Predicate<ContributedLibrary> typeFilter;
@Override
protected FilteredAbstractTableModel createContribModel() {
return new LibrariesIndexTableModel();
}
private LibrariesIndexTableModel getContribModel() {
return (LibrariesIndexTableModel) contribModel;
}
@Override
protected InstallerTableCell createCellRenderer() {
return new ContributedLibraryTableCell();
}
@Override
protected InstallerTableCell createCellEditor() {
return new ContributedLibraryTableCell() {
@Override
protected void onInstall(ContributedLibrary selectedLibrary, ContributedLibrary installedLibrary) {
if (selectedLibrary.isReadOnly()) {
onRemovePressed(installedLibrary);
} else {
onInstallPressed(selectedLibrary, installedLibrary);
}
}
@Override
protected void onRemove(ContributedLibrary library) {
onRemovePressed(library);
}
};
}
public LibraryManagerUI(Frame parent) {
super(parent, "Library Manager", Dialog.ModalityType.APPLICATION_MODAL, _("Unable to reach Arduino.cc due to possible network issues."));
filtersContainer.add(new JLabel(_("Topic")), 1);
filtersContainer.remove(2);
typeChooser = new JComboBox();
typeChooser.setMaximumRowCount(20);
typeChooser.setEnabled(false);
filtersContainer.add(Box.createHorizontalStrut(5), 0);
filtersContainer.add(new JLabel(_("Type")), 1);
filtersContainer.add(Box.createHorizontalStrut(5), 2);
filtersContainer.add(typeChooser, 3);
}
protected final ActionListener typeChooserActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
DropdownItem<ContributedLibrary> selected = (DropdownItem<ContributedLibrary>) typeChooser.getSelectedItem();
if (typeFilter == null || !typeFilter.equals(selected)) {
typeFilter = selected.getFilterPredicate();
if (contribTable.getCellEditor() != null) {
contribTable.getCellEditor().stopCellEditing();
}
updateIndexFilter(filters, categoryFilter, typeFilter);
}
}
};
@Override
public void updateIndexFilter(String[] filters, Predicate<ContributedLibrary>... additionalFilters) {
if (additionalFilters.length == 1) {
additionalFilters = new Predicate[] { additionalFilters[0], typeFilter };
}
super.updateIndexFilter(filters, additionalFilters);
}
public void setIndexer(LibrariesIndexer indexer) {
this.indexer = indexer;
DropdownItem<DownloadableContribution> previouslySelectedCategory = (DropdownItem<DownloadableContribution>) categoryChooser.getSelectedItem();
DropdownItem<DownloadableContribution> previouslySelectedType = (DropdownItem<DownloadableContribution>) typeChooser.getSelectedItem();
categoryChooser.removeActionListener(categoryChooserActionListener);
typeChooser.removeActionListener(typeChooserActionListener);
// TODO: Remove setIndexer and make getContribModel
// return a FilteredAbstractTableModel
getContribModel().setIndexer(indexer);
categoryFilter = null;
categoryChooser.removeAllItems();
// Load categories
categoryChooser.addItem(new DropdownAllItem());
Collection<String> categories = indexer.getIndex().getCategories();
for (String category : categories) {
categoryChooser.addItem(new DropdownLibraryOfCategoryItem(category));
}
categoryChooser.setEnabled(categoryChooser.getItemCount() > 1);
categoryChooser.addActionListener(categoryChooserActionListener);
if (previouslySelectedCategory != null) {
categoryChooser.setSelectedItem(previouslySelectedCategory);
} else {
categoryChooser.setSelectedIndex(0);
}
typeFilter = null;
typeChooser.removeAllItems();
typeChooser.addItem(new DropdownAllItem());
typeChooser.addItem(new DropdownInstalledLibraryItem(indexer.getIndex()));
Collection<String> types = indexer.getIndex().getTypes();
for (String type : types) {
typeChooser.addItem(new DropdownLibraryOfTypeItem(type));
}
typeChooser.setEnabled(typeChooser.getItemCount() > 1);
typeChooser.addActionListener(typeChooserActionListener);
if (previouslySelectedType != null) {
typeChooser.setSelectedItem(previouslySelectedType);
} else {
typeChooser.setSelectedIndex(0);
}
filterField.setEnabled(contribModel.getRowCount() > 0);
// Create LibrariesInstaller tied with the provided index
installer = new LibraryInstaller(indexer) {
@Override
public void onProgress(Progress progress) {
setProgress(progress);
}
};
}
public LibrariesIndexer getIndexer() {
return indexer;
}
public void setProgress(Progress progress) {
progressBar.setValue(progress);
}
/*
* Installer methods follows
*/
private LibraryInstaller installer;
private Thread installerThread = null;
@Override
protected void onCancelPressed() {
super.onUpdatePressed();
if (installerThread != null) {
installerThread.interrupt();
}
}
@Override
protected void onUpdatePressed() {
super.onUpdatePressed();
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true, "");
installer.updateIndex();
onIndexesUpdated();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
setProgressVisible(false, "");
}
}
});
installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage));
installerThread.start();
}
public void onInstallPressed(final ContributedLibrary lib, final ContributedLibrary replaced) {
clearErrorMessage();
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true, _("Installing..."));
installer.install(lib, replaced);
onIndexesUpdated(); // TODO: Do a better job in refreshing only the needed element
//getContribModel().updateLibrary(lib);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
setProgressVisible(false, "");
}
}
});
installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage));
installerThread.start();
}
public void onRemovePressed(final ContributedLibrary lib) {
boolean managedByIndex = indexer.getIndex().getLibraries().contains(lib);
if (!managedByIndex) {
int chosenOption = JOptionPane.showConfirmDialog(this, _("This library is not listed on Library Manager. You won't be able to resinstall it from here.\nAre you sure you want to delete it?"), _("Please confirm library deletion"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (chosenOption != JOptionPane.YES_OPTION) {
return;
}
}
clearErrorMessage();
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true, _("Removing..."));
installer.remove(lib);
onIndexesUpdated(); // TODO: Do a better job in refreshing only the needed element
//getContribModel().updateLibrary(lib);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
setProgressVisible(false, "");
}
}
});
installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage));
installerThread.start();
}
protected void onIndexesUpdated() throws Exception {
// Empty
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages.filters;
import cc.arduino.contributions.packages.ContributedPlatform;
import com.google.common.base.Predicate;
public class CategoryPredicate implements Predicate<ContributedPlatform> {
private final String category;
public CategoryPredicate(String category) {
this.category = category;
}
@Override
public boolean apply(ContributedPlatform input) {
return input.getCategory() != null && category.equals(input.getCategory());
}
@Override
public boolean equals(Object obj) {
return obj instanceof CategoryPredicate && ((CategoryPredicate) obj).category.equals(category);
}
}

View File

@@ -0,0 +1,446 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages.ui;
import cc.arduino.contributions.DownloadableContributionVersionComparator;
import cc.arduino.contributions.VersionComparator;
import cc.arduino.contributions.filters.BuiltInPredicate;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.packages.ContributedBoard;
import cc.arduino.contributions.packages.ContributedHelp;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.contributions.packages.DownloadableContribution;
import cc.arduino.contributions.ui.InstallerTableCell;
import cc.arduino.contributions.ui.listeners.DelegatingKeyListener;
import cc.arduino.utils.ReverseComparator;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import processing.app.Base;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.StyleSheet;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Collections;
import java.util.LinkedList;
import static processing.app.I18n._;
import static processing.app.I18n.format;
@SuppressWarnings("serial")
public class ContributedPlatformTableCell extends InstallerTableCell {
private JPanel panel;
private JButton installButton;
private JButton removeButton;
private Component removeButtonPlaceholder;
private Component installButtonPlaceholder;
private JComboBox downgradeChooser;
private JComboBox versionToInstallChooser;
private JButton downgradeButton;
private JPanel buttonsPanel;
private JPanel inactiveButtonsPanel;
private JLabel statusLabel;
public ContributedPlatformTableCell() {
{
installButton = new JButton(_("Install"));
installButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onInstall(editorValue.getSelected(), editorValue.getInstalled());
}
});
int width = installButton.getPreferredSize().width;
installButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1));
}
{
removeButton = new JButton(_("Remove"));
removeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onRemove(editorValue.getInstalled());
}
});
int width = removeButton.getPreferredSize().width;
removeButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1));
}
downgradeButton = new JButton(_("Install"));
downgradeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ContributedPlatform selected = (ContributedPlatform) downgradeChooser.getSelectedItem();
onInstall(selected, editorValue.getInstalled());
}
});
downgradeChooser = new JComboBox();
downgradeChooser.addItem("-");
downgradeChooser.setMaximumSize(downgradeChooser.getPreferredSize());
downgradeChooser.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
Object selectVersionItem = downgradeChooser.getItemAt(0);
boolean disableDowngrade = (e.getItem() == selectVersionItem);
downgradeButton.setEnabled(!disableDowngrade);
}
});
versionToInstallChooser = new JComboBox();
versionToInstallChooser.addItem("-");
versionToInstallChooser.setMaximumSize(versionToInstallChooser.getPreferredSize());
versionToInstallChooser.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
editorValue.select((ContributedPlatform) versionToInstallChooser.getSelectedItem());
}
});
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
makeNewDescription(panel);
{
buttonsPanel = new JPanel();
buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS));
buttonsPanel.setOpaque(false);
buttonsPanel.add(Box.createHorizontalStrut(7));
buttonsPanel.add(downgradeChooser);
buttonsPanel.add(Box.createHorizontalStrut(5));
buttonsPanel.add(downgradeButton);
buttonsPanel.add(Box.createHorizontalGlue());
buttonsPanel.add(versionToInstallChooser);
buttonsPanel.add(Box.createHorizontalStrut(5));
buttonsPanel.add(installButton);
buttonsPanel.add(Box.createHorizontalStrut(5));
buttonsPanel.add(removeButton);
buttonsPanel.add(Box.createHorizontalStrut(5));
buttonsPanel.add(Box.createHorizontalStrut(15));
panel.add(buttonsPanel);
}
{
inactiveButtonsPanel = new JPanel();
inactiveButtonsPanel.setLayout(new BoxLayout(inactiveButtonsPanel, BoxLayout.X_AXIS));
inactiveButtonsPanel.setOpaque(false);
int height = installButton.getMinimumSize().height;
inactiveButtonsPanel.add(Box.createVerticalStrut(height));
inactiveButtonsPanel.add(Box.createGlue());
statusLabel = new JLabel(" ");
inactiveButtonsPanel.add(statusLabel);
inactiveButtonsPanel.add(Box.createHorizontalStrut(15));
panel.add(inactiveButtonsPanel);
}
panel.add(Box.createVerticalStrut(15));
}
private JTextPane makeNewDescription(JPanel panel) {
if (panel.getComponentCount() > 0) {
panel.remove(0);
}
JTextPane description = new JTextPane();
description.setInheritsPopupMenu(true);
Insets margin = description.getMargin();
margin.bottom = 0;
description.setMargin(margin);
description.setContentType("text/html");
Document doc = description.getDocument();
if (doc instanceof HTMLDocument) {
HTMLDocument html = (HTMLDocument) doc;
StyleSheet stylesheet = html.getStyleSheet();
stylesheet.addRule("body { margin: 0; padding: 0;"
+ "font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;"
+ "font-size: 100%;" + "font-size: 0.95em; }");
}
description.setOpaque(false);
description.setBorder(new EmptyBorder(4, 7, 7, 7));
description.setHighlighter(null);
description.setEditable(false);
description.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
Base.openURL(e.getDescription());
}
}
});
description.addKeyListener(new DelegatingKeyListener(parentTable));
panel.add(description, 0);
return description;
}
protected void onRemove(ContributedPlatform contributedPlatform) {
// Empty
}
protected void onInstall(ContributedPlatform contributedPlatform, ContributedPlatform installed) {
// Empty
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected,
boolean hasFocus, int row,
int column) {
parentTable = table;
setEnabled(false);
Component component = getUpdatedCellComponent(value, isSelected, row, false);
if (row % 2 == 0) {
component.setBackground(new Color(236, 241, 241)); //#ecf1f1
} else {
component.setBackground(new Color(255, 255, 255));
}
int height = new Double(component.getPreferredSize().getHeight()).intValue();
if (table.getRowHeight(row) < height) {
table.setRowHeight(row, height);
}
return component;
}
private ContributionIndexTableModel.ContributedPlatformReleases editorValue;
private JTable parentTable;
@Override
public Object getCellEditorValue() {
return editorValue;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row,
int column) {
parentTable = table;
editorValue = (ContributionIndexTableModel.ContributedPlatformReleases) value;
setEnabled(true);
final ContributedPlatform installed = editorValue.getInstalled();
java.util.List<ContributedPlatform> releases = new LinkedList<ContributedPlatform>(editorValue.releases);
java.util.List<ContributedPlatform> uninstalledReleases = new LinkedList<ContributedPlatform>(Collections2.filter(releases, Predicates.not(new InstalledPredicate())));
java.util.List<ContributedPlatform> installedBuiltIn = new LinkedList<ContributedPlatform>(Collections2.filter(releases, Predicates.and(new InstalledPredicate(), new BuiltInPredicate())));
if (installed != null && !installedBuiltIn.contains(installed)) {
uninstalledReleases.addAll(installedBuiltIn);
}
Collections.sort(uninstalledReleases, new ReverseComparator<DownloadableContribution>(new DownloadableContributionVersionComparator()));
downgradeChooser.removeAllItems();
downgradeChooser.addItem(_("Select version"));
final java.util.List<ContributedPlatform> uninstalledPreviousReleases = Lists.newLinkedList();
final java.util.List<ContributedPlatform> uninstalledNewerReleases = Lists.newLinkedList();
final VersionComparator versionComparator = new VersionComparator();
Lists.newLinkedList(Lists.transform(uninstalledReleases, new Function<ContributedPlatform, ContributedPlatform>() {
@Override
public ContributedPlatform apply(ContributedPlatform input) {
if (installed == null || versionComparator.greaterThan(installed.getParsedVersion(), input.getParsedVersion())) {
uninstalledPreviousReleases.add(input);
} else {
uninstalledNewerReleases.add(input);
}
return input;
}
}));
for (ContributedPlatform release : uninstalledNewerReleases) {
downgradeChooser.addItem(release);
}
for (ContributedPlatform release : uninstalledPreviousReleases) {
downgradeChooser.addItem(release);
}
downgradeChooser.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1));
downgradeButton.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1));
versionToInstallChooser.removeAllItems();
for (ContributedPlatform release : uninstalledReleases) {
versionToInstallChooser.addItem(release);
}
versionToInstallChooser.setVisible(installed == null && uninstalledReleases.size() > 1);
Component component = getUpdatedCellComponent(value, true, row, !installedBuiltIn.isEmpty());
component.setBackground(new Color(218, 227, 227)); //#dae3e3
return component;
}
private Component getUpdatedCellComponent(Object value, boolean isSelected, int row, boolean hasBuiltInRelease) {
ContributionIndexTableModel.ContributedPlatformReleases releases = (ContributionIndexTableModel.ContributedPlatformReleases) value;
JTextPane description = makeNewDescription(panel);
//FIXME: happens on macosx, don't know why
if (releases == null) {
return panel;
}
ContributedPlatform selected = releases.getSelected();
ContributedPlatform installed = releases.getInstalled();
boolean removable, installable, upgradable;
if (installed == null) {
installable = true;
removable = false;
upgradable = false;
} else {
installable = false;
removable = !installed.isReadOnly() && !hasBuiltInRelease;
upgradable = new DownloadableContributionVersionComparator().compare(selected, installed) > 0;
}
if (installable) {
installButton.setText(_("Install"));
}
if (upgradable) {
installButton.setText(_("Update"));
}
installButton.setVisible(installable || upgradable);
installButtonPlaceholder.setVisible(!(installable || upgradable));
removeButton.setVisible(removable);
removeButtonPlaceholder.setVisible(!removable);
String desc = "<html><body>";
desc += "<b>" + selected.getName() + "</b>";
if (installed != null && installed.isReadOnly()) {
desc += " Built-In ";
}
String author = selected.getParentPackage().getMaintainer();
if (author != null && !author.isEmpty()) {
desc += " " + format("by <b>{0}</b>", author);
}
if (installed != null) {
desc += " " + format(_("version <b>{0}</b>"), installed.getParsedVersion()) + " <strong><font color=\"#00979D\">INSTALLED</font></strong>";
}
desc += "<br />";
desc += _("Boards included in this package:") + "<br />";
for (ContributedBoard board : selected.getBoards()) {
desc += board.getName() + ", ";
}
desc = desc.substring(0, desc.lastIndexOf(',')) + ".<br />";
ContributedHelp help = null;
if (selected.getHelp() != null) {
help = selected.getHelp();
} else if (selected.getParentPackage().getHelp() != null) {
help = selected.getParentPackage().getHelp();
}
if (help != null) {
String url = help.getOnline();
if (url != null && !url.isEmpty()) {
desc += " " + format("<a href=\"{0}\">Online help</a><br/>", url);
}
}
String url = selected.getParentPackage().getWebsiteURL();
if (url != null && !url.isEmpty()) {
desc += " " + format("<a href=\"{0}\">More info</a>", url);
}
desc += "</body></html>";
description.setText(desc);
description.setBackground(Color.WHITE);
// for modelToView to work, the text area has to be sized. It doesn't
// matter if it's visible or not.
// See:
// http://stackoverflow.com/questions/3081210/how-to-set-jtextarea-to-have-height-that-matches-the-size-of-a-text-it-contains
int width = parentTable.getBounds().width;
setJTextPaneDimensionToFitContainedText(description, width);
if (isSelected) {
panel.setBackground(parentTable.getSelectionBackground());
panel.setForeground(parentTable.getSelectionForeground());
} else {
panel.setBackground(parentTable.getBackground());
panel.setForeground(parentTable.getForeground());
}
return panel;
}
private Timer enabler = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
enable(true);
enabler.stop();
}
});
@Override
public void setEnabled(boolean enabled) {
enable(false);
if (enabled) {
enabler.start();
} else {
enabler.stop();
}
buttonsPanel.setVisible(enabled);
inactiveButtonsPanel.setVisible(!enabled);
}
public void enable(boolean enabled) {
installButton.setEnabled(enabled);
removeButton.setEnabled(enabled);
}
public void setStatus(String status) {
statusLabel.setText(status);
}
public void invalidate() {
panel.invalidate();
}
}

View File

@@ -0,0 +1,224 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages.ui;
import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.packages.ContributedPackage;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.contributions.packages.ContributionsIndexer;
import cc.arduino.contributions.ui.FilteredAbstractTableModel;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@SuppressWarnings("serial")
public class ContributionIndexTableModel extends FilteredAbstractTableModel<ContributedPlatform> {
public final static int DESCRIPTION_COL = 0;
public static class ContributedPlatformReleases {
public final ContributedPackage packager;
public final String arch;
public final List<ContributedPlatform> releases;
public final List<String> versions;
public ContributedPlatform selected = null;
public ContributedPlatformReleases(ContributedPlatform platform) {
this.packager = platform.getParentPackage();
this.arch = platform.getArchitecture();
this.releases = new LinkedList<ContributedPlatform>();
this.versions = new LinkedList<String>();
add(platform);
}
public boolean shouldContain(ContributedPlatform platform) {
if (platform.getParentPackage() != packager)
return false;
return platform.getArchitecture().equals(arch);
}
public void add(ContributedPlatform platform) {
releases.add(platform);
String version = platform.getParsedVersion();
if (version != null) {
versions.add(version);
}
selected = getLatest();
}
public ContributedPlatform getInstalled() {
List<ContributedPlatform> installedReleases = new LinkedList<ContributedPlatform>(Collections2.filter(releases, new InstalledPredicate()));
Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator());
if (installedReleases.isEmpty()) {
return null;
}
return installedReleases.get(0);
}
public ContributedPlatform getLatest() {
return getLatestOf(releases);
}
public ContributedPlatform getSelected() {
return selected;
}
public void select(ContributedPlatform value) {
for (ContributedPlatform plat : releases) {
if (plat == value) {
selected = plat;
return;
}
}
}
}
private List<ContributedPlatformReleases> contributions = new ArrayList<ContributedPlatformReleases>();
private String[] columnNames = {"Description"};
private Class<?>[] columnTypes = {ContributedPlatform.class};
private ContributionsIndexer indexer;
public void setIndexer(ContributionsIndexer indexer) {
this.indexer = indexer;
}
public void updateIndexFilter(String filters[], Predicate<ContributedPlatform>... additionalFilters) {
contributions.clear();
Predicate<ContributedPlatform> filter = Predicates.and(additionalFilters);
for (ContributedPackage pack : indexer.getPackages()) {
for (ContributedPlatform platform : pack.getPlatforms()) {
if (!filter.apply(platform)) {
continue;
}
if (!stringContainsAll(platform.getName(), filters))
continue;
addContribution(platform);
}
}
fireTableDataChanged();
}
/**
* Check if <b>string</b> contains all the substrings in <b>set</b>. The
* compare is case insensitive.
*
* @param string
* @param set
* @return <b>true<b> if all the strings in <b>set</b> are contained in
* <b>string</b>.
*/
private boolean stringContainsAll(String string, String set[]) {
if (set == null)
return true;
for (String s : set) {
if (!string.toLowerCase().contains(s.toLowerCase()))
return false;
}
return true;
}
private void addContribution(ContributedPlatform platform) {
for (ContributedPlatformReleases contribution : contributions) {
if (!contribution.shouldContain(platform))
continue;
contribution.add(platform);
return;
}
contributions.add(new ContributedPlatformReleases(platform));
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return contributions.size();
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public Class<?> getColumnClass(int colum) {
return columnTypes[colum];
}
@Override
public void setValueAt(Object value, int row, int col) {
if (col == DESCRIPTION_COL) {
fireTableCellUpdated(row, col);
}
}
@Override
public Object getValueAt(int row, int col) {
if (row >= contributions.size()) {
return null;
}
ContributedPlatformReleases contribution = contributions.get(row);
if (col == DESCRIPTION_COL) {
return contribution;// .getSelected();
}
return null;
}
@Override
public boolean isCellEditable(int row, int col) {
return col == DESCRIPTION_COL;
}
public ContributedPlatformReleases getReleases(int row) {
return contributions.get(row);
}
public ContributedPlatform getSelectedRelease(int row) {
return contributions.get(row).getSelected();
}
public void update() {
fireTableDataChanged();
}
}

View File

@@ -0,0 +1,229 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages.ui;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.contributions.packages.ContributionInstaller;
import cc.arduino.contributions.packages.ContributionsIndexer;
import cc.arduino.contributions.packages.DownloadableContribution;
import cc.arduino.contributions.ui.*;
import cc.arduino.utils.Progress;
import processing.app.I18n;
import javax.swing.*;
import java.awt.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import static processing.app.I18n._;
@SuppressWarnings("serial")
public class ContributionManagerUI extends InstallerJDialog {
// private ContributedPlatformTableCell cellEditor;
@Override
protected FilteredAbstractTableModel createContribModel() {
return new ContributionIndexTableModel();
}
private ContributionIndexTableModel getContribModel() {
return (ContributionIndexTableModel) contribModel;
}
@Override
protected InstallerTableCell createCellRenderer() {
return new ContributedPlatformTableCell();
}
@Override
protected InstallerTableCell createCellEditor() {
return new ContributedPlatformTableCell() {
@Override
protected void onInstall(ContributedPlatform selected, ContributedPlatform installed) {
if (selected.isReadOnly()) {
onRemovePressed(installed, false);
} else {
onInstallPressed(selected, installed);
}
}
@Override
protected void onRemove(ContributedPlatform installedPlatform) {
onRemovePressed(installedPlatform, true);
}
};
}
public ContributionManagerUI(Frame parent) {
super(parent, _("Boards Manager"), Dialog.ModalityType.APPLICATION_MODAL, _("Unable to reach Arduino.cc due to possible network issues."));
}
public void setIndexer(ContributionsIndexer indexer) {
DropdownItem<DownloadableContribution> previouslySelectedCategory = (DropdownItem<DownloadableContribution>) categoryChooser.getSelectedItem();
categoryChooser.removeActionListener(categoryChooserActionListener);
getContribModel().setIndexer(indexer);
categoryFilter = null;
categoryChooser.removeAllItems();
filterField.setEnabled(getContribModel().getRowCount() > 0);
categoryChooser.addActionListener(categoryChooserActionListener);
// Enable categories combo only if there are two or more choices
categoryChooser.addItem(new DropdownAllCoresItem());
Collection<String> categories = indexer.getCategories();
for (String s : categories) {
categoryChooser.addItem(new DropdownCoreOfCategoryItem(s));
}
if (previouslySelectedCategory != null) {
categoryChooser.setSelectedItem(previouslySelectedCategory);
} else {
categoryChooser.setSelectedIndex(0);
}
// Create ConstributionInstaller tied with the provided index
installer = new ContributionInstaller(indexer) {
@Override
public void onProgress(Progress progress) {
setProgress(progress);
}
};
}
public void setProgress(Progress progress) {
progressBar.setValue(progress);
}
/*
* Installer methods follows
*/
private ContributionInstaller installer;
private Thread installerThread = null;
@Override
public void onCancelPressed() {
super.onCancelPressed();
if (installerThread != null) {
installerThread.interrupt();
}
}
@Override
public void onUpdatePressed() {
super.onUpdatePressed();
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true, "");
List<String> downloadedPackageIndexFiles = installer.updateIndex();
installer.deleteUnknownFiles(downloadedPackageIndexFiles);
onIndexesUpdated();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
setProgressVisible(false, "");
}
}
});
installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage));
installerThread.start();
}
public void onInstallPressed(final ContributedPlatform platformToInstall, final ContributedPlatform platformToRemove) {
clearErrorMessage();
installerThread = new Thread(new Runnable() {
@Override
public void run() {
List<String> errors = new LinkedList<String>();
try {
setProgressVisible(true, _("Installing..."));
errors.addAll(installer.install(platformToInstall));
if (platformToRemove != null && !platformToRemove.isReadOnly()) {
errors.addAll(installer.remove(platformToRemove));
}
onIndexesUpdated();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
setProgressVisible(false, "");
if (!errors.isEmpty()) {
setErrorMessage(errors.get(0));
}
}
}
});
installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage));
installerThread.start();
}
public void onRemovePressed(final ContributedPlatform platform, boolean showWarning) {
clearErrorMessage();
if (showWarning) {
int chosenOption = JOptionPane.showConfirmDialog(this, I18n.format(_("Do you want to remove {0}?\nIf you do so you won't be able to use {0} any more."), platform.getName()), _("Please confirm boards deletion"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (chosenOption != JOptionPane.YES_OPTION) {
return;
}
}
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true, _("Removing..."));
installer.remove(platform);
onIndexesUpdated();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
setProgressVisible(false, "");
}
}
});
installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage));
installerThread.start();
}
/**
* Callback invoked when indexes are updated
*
* @throws Exception
*/
protected void onIndexesUpdated() throws Exception {
// Empty
}
}

View File

@@ -0,0 +1,54 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages.ui;
import cc.arduino.contributions.filters.NoopPredicate;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
import static processing.app.I18n._;
public class DropdownAllCoresItem implements DropdownItem<ContributedPlatform> {
public String toString() {
return _("All");
}
@Override
public Predicate<ContributedPlatform> getFilterPredicate() {
return new NoopPredicate<ContributedPlatform>();
}
@Override
public boolean equals(Object obj) {
return obj instanceof DropdownAllCoresItem;
}
}

View File

@@ -0,0 +1,59 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages.ui;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.contributions.packages.filters.CategoryPredicate;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
public class DropdownCoreOfCategoryItem implements DropdownItem<ContributedPlatform> {
private final String category;
public DropdownCoreOfCategoryItem(String category) {
this.category = category;
}
public String toString() {
return category;
}
@Override
public Predicate<ContributedPlatform> getFilterPredicate() {
return new CategoryPredicate(category);
}
@Override
public boolean equals(Object obj) {
return obj instanceof DropdownCoreOfCategoryItem && ((DropdownCoreOfCategoryItem) obj).category.equals(category);
}
}

View File

@@ -0,0 +1,55 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import cc.arduino.contributions.filters.NoopPredicate;
import cc.arduino.contributions.packages.DownloadableContribution;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
import static processing.app.I18n._;
public class DropdownAllItem implements DropdownItem<DownloadableContribution> {
public String toString() {
return _("All");
}
@Override
public Predicate<DownloadableContribution> getFilterPredicate() {
return new NoopPredicate<DownloadableContribution>();
}
@Override
public boolean equals(Object obj) {
return obj instanceof DropdownAllItem;
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import com.google.common.base.Predicate;
public interface DropdownItem<T> {
Predicate<T> getFilterPredicate();
}

View File

@@ -0,0 +1,117 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
@SuppressWarnings("serial")
public class FilterJTextField extends JTextField {
private final String filterHint;
private boolean showingHint;
public FilterJTextField(String hint) {
super(hint);
filterHint = hint;
showingHint = true;
updateStyle();
addFocusListener(new FocusListener() {
public void focusLost(FocusEvent focusEvent) {
if (getText().isEmpty()) {
showingHint = true;
}
updateStyle();
}
public void focusGained(FocusEvent focusEvent) {
if (showingHint) {
showingHint = false;
setText("");
}
updateStyle();
}
});
getDocument().addDocumentListener(new DocumentListener() {
public void removeUpdate(DocumentEvent e) {
applyFilter();
}
public void insertUpdate(DocumentEvent e) {
applyFilter();
}
public void changedUpdate(DocumentEvent e) {
applyFilter();
}
});
}
private String lastFilter = "";
private void applyFilter() {
String filter = showingHint ? "" : getText();
filter = filter.toLowerCase();
// Replace anything but 0-9, a-z, or : with a space
filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a^\\x3a]", " ");
// Fire event only if the filter is changed
if (filter.equals(lastFilter))
return;
lastFilter = filter;
onFilter(filter.split(" "));
}
protected void onFilter(String[] strings) {
// Empty
}
public void updateStyle() {
if (showingHint) {
setText(filterHint);
setForeground(Color.gray);
setFont(getFont().deriveFont(Font.ITALIC));
} else {
setForeground(UIManager.getColor("TextField.foreground"));
setFont(getFont().deriveFont(Font.PLAIN));
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import cc.arduino.contributions.VersionComparator;
import cc.arduino.contributions.packages.DownloadableContribution;
import com.google.common.base.Predicate;
import javax.swing.table.AbstractTableModel;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public abstract class FilteredAbstractTableModel<T> extends AbstractTableModel {
abstract public void updateIndexFilter(String[] filters, Predicate<T>... additionalFilters);
protected static <T extends DownloadableContribution> T getLatestOf(List<T> contribs) {
contribs = new LinkedList<T>(contribs);
final VersionComparator versionComparator = new VersionComparator();
Collections.sort(contribs, new Comparator<T>() {
@Override
public int compare(T contrib1, T contrib2) {
return versionComparator.compare(contrib1.getParsedVersion(), contrib2.getParsedVersion());
}
});
if (contribs.isEmpty()) {
return null;
}
return contribs.get(contribs.size() - 1);
}
}

View File

@@ -0,0 +1,301 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import cc.arduino.contributions.packages.ui.ContributionIndexTableModel;
import cc.arduino.contributions.ui.listeners.AbstractKeyListener;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import processing.app.Base;
import processing.app.Theme;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import static cc.arduino.contributions.packages.ui.ContributionIndexTableModel.DESCRIPTION_COL;
import static processing.app.I18n._;
public abstract class InstallerJDialog<T> extends JDialog {
// Toolbar on top of the window:
// - Categories drop-down menu
protected final JComboBox categoryChooser;
// - Search text-field
protected final FilterJTextField filterField;
protected final JPanel filtersContainer;
// Currently selected category and filters
protected Predicate<T> categoryFilter;
protected String[] filters;
protected final String noConnectionErrorMessage;
// Real contribution table
protected JTable contribTable;
// Model behind the table
protected FilteredAbstractTableModel<T> contribModel;
abstract protected FilteredAbstractTableModel createContribModel();
abstract protected InstallerTableCell createCellRenderer();
abstract protected InstallerTableCell createCellEditor();
// Bottom:
// - Progress bar
protected final ProgressJProgressBar progressBar;
protected final Box progressBox;
protected final Box errorMessageBox;
private final JLabel errorMessage;
public InstallerJDialog(Frame parent, String title, ModalityType applicationModal, String noConnectionErrorMessage) {
super(parent, title, applicationModal);
this.noConnectionErrorMessage = noConnectionErrorMessage;
setResizable(true);
Container pane = getContentPane();
pane.setLayout(new BorderLayout());
{
categoryChooser = new JComboBox();
categoryChooser.setMaximumRowCount(20);
categoryChooser.setEnabled(false);
filterField = new FilterJTextField(_("Filter your search...")) {
@Override
protected void onFilter(String[] _filters) {
filters = _filters;
if (contribTable.getCellEditor() != null) {
contribTable.getCellEditor().stopCellEditing();
}
updateIndexFilter(filters, categoryFilter);
}
};
filtersContainer = new JPanel();
filtersContainer.setLayout(new BoxLayout(filtersContainer, BoxLayout.X_AXIS));
filtersContainer.add(Box.createHorizontalStrut(5));
filtersContainer.add(new JLabel(_("Type")));
filtersContainer.add(Box.createHorizontalStrut(5));
filtersContainer.add(categoryChooser);
filtersContainer.add(Box.createHorizontalStrut(5));
filtersContainer.add(filterField);
filtersContainer.setBorder(new EmptyBorder(7, 7, 7, 7));
pane.add(filtersContainer, BorderLayout.NORTH);
}
contribModel = createContribModel();
contribTable = new JTable(contribModel);
contribTable.setTableHeader(null);
contribTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
contribTable.setColumnSelectionAllowed(false);
contribTable.setDragEnabled(false);
contribTable.setIntercellSpacing(new Dimension(0, 1));
contribTable.setShowVerticalLines(false);
contribTable.setSelectionBackground(Theme.getColor("status.notice.bgcolor"));
contribTable.addKeyListener(new AbstractKeyListener() {
@Override
public void keyReleased(KeyEvent keyEvent) {
if (keyEvent.getKeyCode() != KeyEvent.VK_DOWN && keyEvent.getKeyCode() != KeyEvent.VK_UP) {
return;
}
if (!contribTable.isEnabled()) {
return;
}
contribTable.editCellAt(contribTable.getSelectedRow(), contribTable.getSelectedColumn());
}
});
{
TableColumnModel tcm = contribTable.getColumnModel();
TableColumn col = tcm.getColumn(DESCRIPTION_COL);
col.setCellRenderer(createCellRenderer());
col.setCellEditor(createCellEditor());
col.setResizable(true);
}
{
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(contribTable);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.getVerticalScrollBar().setUnitIncrement(7);
pane.add(scrollPane, BorderLayout.CENTER);
}
pane.add(Box.createHorizontalStrut(10), BorderLayout.WEST);
pane.add(Box.createHorizontalStrut(10), BorderLayout.EAST);
progressBar = new ProgressJProgressBar();
progressBar.setStringPainted(true);
progressBar.setString(" ");
progressBar.setVisible(true);
errorMessage = new JLabel("");
errorMessage.setForeground(Color.RED);
{
JButton cancelButton = new JButton(_("Cancel"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
onCancelPressed();
}
});
progressBox = Box.createHorizontalBox();
progressBox.add(progressBar);
progressBox.add(Box.createHorizontalStrut(5));
progressBox.add(cancelButton);
JButton dismissErrorMessageButton = new JButton(_("OK"));
dismissErrorMessageButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
clearErrorMessage();
}
});
errorMessageBox = Box.createHorizontalBox();
errorMessageBox.add(Box.createHorizontalGlue());
errorMessageBox.add(errorMessage);
errorMessageBox.add(Box.createHorizontalGlue());
errorMessageBox.add(dismissErrorMessageButton);
errorMessageBox.setVisible(false);
}
{
JPanel progressPanel = new JPanel();
progressPanel.setBorder(new EmptyBorder(7, 7, 7, 7));
progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS));
progressPanel.add(progressBox);
progressPanel.add(errorMessageBox);
pane.add(progressPanel, BorderLayout.SOUTH);
}
setProgressVisible(false, "");
setMinimumSize(new Dimension(800, 450));
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Base.registerWindowCloseKeys(getRootPane(), new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
InstallerJDialog.this.dispatchEvent(new WindowEvent(InstallerJDialog.this, WindowEvent.WINDOW_CLOSING));
}
});
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
onUpdatePressed();
}
});
}
public void updateIndexFilter(String[] filters, Predicate<T>... additionalFilters) {
Collection<Predicate<T>> notNullAdditionalFilters = Collections2.filter(Arrays.asList(additionalFilters), Predicates.notNull());
contribModel.updateIndexFilter(filters, notNullAdditionalFilters.toArray(new Predicate[notNullAdditionalFilters.size()]));
}
public void setErrorMessage(String message) {
errorMessage.setText("<html><body>" + message + "</body></html>");
errorMessageBox.setVisible(true);
}
public void clearErrorMessage() {
errorMessage.setText("");
errorMessageBox.setVisible(false);
}
public void setProgressVisible(boolean visible, String status) {
if (visible) {
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
} else {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
progressBox.setVisible(visible);
filterField.setEnabled(!visible);
categoryChooser.setEnabled(!visible);
contribTable.setEnabled(!visible);
errorMessageBox.setVisible(false);
if (contribTable.getCellEditor() != null) {
((InstallerTableCell) contribTable.getCellEditor()).setEnabled(!visible);
((InstallerTableCell) contribTable.getCellEditor()).setStatus(status);
}
}
protected final ActionListener categoryChooserActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
DropdownItem<T> selected = (DropdownItem<T>) categoryChooser.getSelectedItem();
if (categoryFilter == null || !categoryFilter.equals(selected)) {
categoryFilter = selected.getFilterPredicate();
if (contribTable.getCellEditor() != null) {
contribTable.getCellEditor().stopCellEditing();
}
updateIndexFilter(filters, categoryFilter);
}
}
};
public void setFilterText(String filterText) {
for (FocusListener listener : filterField.getFocusListeners()) {
listener.focusGained(new FocusEvent(filterField, FocusEvent.FOCUS_GAINED));
}
filterField.setText(filterText);
}
/**
* Action performed when the Cancel button is pressed.
*/
protected void onCancelPressed() {
clearErrorMessage();
}
/**
* Action performed when the "Update List" button is pressed.
*/
protected void onUpdatePressed() {
clearErrorMessage();
}
}

View File

@@ -0,0 +1,65 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import cc.arduino.contributions.ui.InstallerJDialog;
import javax.swing.*;
import static processing.app.I18n._;
public class InstallerJDialogUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private final InstallerJDialog parent;
private final String connectionErrorMessage;
public InstallerJDialogUncaughtExceptionHandler(InstallerJDialog parent, String connectionErrorMessage) {
this.parent = parent;
this.connectionErrorMessage = connectionErrorMessage;
}
@Override
public void uncaughtException(Thread t, final Throwable e) {
String errorMessage = _(e.getMessage().substring(e.getMessage().indexOf(":") + 1));
if (errorMessage.startsWith("Error downloading")) {
errorMessage = connectionErrorMessage;
}
final String finalErrorMessage = errorMessage;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.err.println(finalErrorMessage);
e.printStackTrace();
}
});
parent.setErrorMessage(finalErrorMessage);
}
}

View File

@@ -0,0 +1,61 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
public abstract class InstallerTableCell extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
public void setEnabled(boolean b) {
}
public void setStatus(String s) {
}
protected void setJTextPaneDimensionToFitContainedText(JTextPane jTextPane, int width) {
Dimension minimumDimension = new Dimension(width, 10);
jTextPane.setPreferredSize(minimumDimension);
jTextPane.setSize(minimumDimension);
try {
Rectangle r = jTextPane.modelToView(jTextPane.getDocument().getLength());
//r.height += jTextPane.modelToView(0).y; // add margins
Dimension d = new Dimension(minimumDimension.width, r.y + r.height);
jTextPane.setPreferredSize(d);
} catch (BadLocationException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui;
import javax.swing.JProgressBar;
import cc.arduino.utils.Progress;
@SuppressWarnings("serial")
public class ProgressJProgressBar extends JProgressBar {
public void setValue(Progress p) {
setValue((int) p.getProgress());
if (p.getStatus() != null)
setString(p.getStatus());
}
}

View File

@@ -0,0 +1,52 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui.listeners;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public abstract class AbstractKeyListener implements KeyListener {
@Override
public void keyTyped(KeyEvent keyEvent) {
}
@Override
public void keyPressed(KeyEvent keyEvent) {
}
@Override
public void keyReleased(KeyEvent keyEvent) {
}
}

View File

@@ -0,0 +1,76 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.ui.listeners;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class DelegatingKeyListener implements KeyListener {
private final Component delegate;
public DelegatingKeyListener(Component delegate) {
this.delegate = delegate;
}
@Override
public void keyTyped(final KeyEvent keyEvent) {
if (delegate.getKeyListeners() == null) {
return;
}
for (KeyListener listener : delegate.getKeyListeners()) {
listener.keyTyped(keyEvent);
}
}
@Override
public void keyPressed(KeyEvent keyEvent) {
if (delegate.getKeyListeners() == null) {
return;
}
for (KeyListener listener : delegate.getKeyListeners()) {
listener.keyPressed(keyEvent);
}
}
@Override
public void keyReleased(KeyEvent keyEvent) {
if (delegate.getKeyListeners() == null) {
return;
}
for (KeyListener listener : delegate.getKeyListeners()) {
listener.keyReleased(keyEvent);
}
}
}

View File

@@ -1,3 +1,32 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages;
import processing.app.AbstractMonitor;

View File

@@ -1,11 +1,43 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.formatter;
import processing.app.Base;
import processing.app.Editor;
import processing.app.helpers.FileUtils;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.SketchTextArea;
import processing.app.tools.Tool;
import javax.swing.text.BadLocationException;
import java.io.File;
import java.io.IOException;
@@ -13,7 +45,7 @@ import static processing.app.I18n._;
public class AStyle implements Tool {
private static String FORMATTER_CONF = "formatter.conf";
private static final String FORMATTER_CONF = "formatter.conf";
private final AStyleInterface aStyleInterface;
private final String formatterConfiguration;
@@ -35,7 +67,7 @@ public class AStyle implements Tool {
try {
formatterConfiguration = FileUtils.readFileToString(formatterConf);
} catch (IOException e) {
// noop
// ignored
}
this.formatterConfiguration = formatterConfiguration;
}
@@ -55,17 +87,50 @@ public class AStyle implements Tool {
return;
}
JEditTextArea textArea = editor.getTextArea();
int line = textArea.getLineOfOffset(textArea.getCaretPosition());
int lineOffset = textArea.getCaretPosition() - textArea.getLineStartOffset(line);
SketchTextArea textArea = editor.getTextArea();
int line = getLineOfOffset(textArea);
int lineOffset = getLineOffset(textArea, line);
editor.getTextArea().getUndoManager().beginInternalAtomicEdit();
editor.setText(formattedText);
editor.getSketch().setModified(true);
textArea.setCaretPosition(Math.min(textArea.getLineStartOffset(line) + lineOffset, textArea.getSafeLineStopOffset(line) - 1));
editor.getTextArea().getUndoManager().endInternalAtomicEdit();
if (line != -1 && lineOffset != -1) {
setCaretPosition(textArea, line, lineOffset);
}
// mark as finished
editor.statusNotice(_("Auto Format finished."));
}
private void setCaretPosition(SketchTextArea textArea, int line, int lineOffset) {
try {
textArea.setCaretPosition(Math.min(textArea.getLineStartOffset(line) + lineOffset, textArea.getLineEndOffset(line) - 1));
} catch (BadLocationException e) {
e.printStackTrace();
}
}
private int getLineOffset(SketchTextArea textArea, int line) {
try {
return textArea.getCaretPosition() - textArea.getLineStartOffset(line);
} catch (BadLocationException e) {
e.printStackTrace();
}
return -1;
}
private int getLineOfOffset(SketchTextArea textArea) {
try {
return textArea.getLineOfOffset(textArea.getCaretPosition());
} catch (BadLocationException e) {
e.printStackTrace();
}
return -1;
}
@Override
public String getMenuTitle() {
return _("Auto Format");

View File

@@ -1,3 +1,32 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.formatter;
import processing.app.Base;

View File

@@ -48,10 +48,7 @@ public class Event extends ActionEvent {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append("\n").append(payload.toString());
return sb.toString();
return super.toString() + "\n" + payload.toString();
}
}

View File

@@ -0,0 +1,96 @@
/*
* This file is part of Arduino.
*
* Code inspired by this tutorial http://wiki.netbeans.org/Splash_Screen_Beginner_Tutorial. License says "You may modify and use it as you wish."
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.view;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.Map;
public class SplashScreenHelper {
private final Map desktopHints;
private final SplashScreen splash;
private Rectangle2D.Double splashTextArea;
private Graphics2D splashGraphics;
public SplashScreenHelper(SplashScreen splash) {
this.splash = splash;
Toolkit tk = Toolkit.getDefaultToolkit();
desktopHints = (Map) tk.getDesktopProperty("awt.font.desktophints");
}
public void splashText(String str) {
if (splash == null) {
printText(str);
return;
}
if (!splash.isVisible()) {
return;
}
if (splashTextArea == null) {
// stake out some area for our status information
splashTextArea = new Rectangle2D.Double(0, 300, 520, 30);
// create the Graphics environment for drawing status info
splashGraphics = splash.createGraphics();
if (desktopHints != null) {
splashGraphics.addRenderingHints(desktopHints);
}
}
// erase the last status text
splashGraphics.setPaint(new Color(245, 245, 245));
splashGraphics.fill(splashTextArea);
// draw the text
splashGraphics.setPaint(Color.BLACK);
FontMetrics metrics = splashGraphics.getFontMetrics();
splashGraphics.drawString(str, (int) splashTextArea.getX() + 10, (int) splashTextArea.getY() + (30 - metrics.getHeight()) + 4);
// make sure it's displayed
splash.update();
}
public void close() {
if (splash == null) {
return;
}
splash.close();
}
private void printText(String str) {
System.out.println(str);
}
}

View File

@@ -1,6 +1,8 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -23,37 +25,25 @@
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.view;
import processing.app.Preferences;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import java.awt.*;
public class StubMenuListener implements MenuListener {
public class ShowUncertifiedBoardWarning implements Runnable {
private final Frame parent;
public ShowUncertifiedBoardWarning(Frame parent) {
this.parent = parent;
@Override
public void menuSelected(MenuEvent e) {
}
@Override
public void run() {
UncertifiedBoardWarning uncertifiedBoardWarning = new UncertifiedBoardWarning(parent, new EventListener() {
@Override
public void eventHappened(cc.arduino.view.Event event) {
if (!"uncertified_board_warning_ok_pressed".equals(event.getActionCommand())) {
return;
}
Preferences.set("uncertifiedBoardWarning_dontShowMeAgain", event.getPayload().get("dontShowMeAgain").toString());
}
});
uncertifiedBoardWarning.setLocationRelativeTo(parent);
uncertifiedBoardWarning.setVisible(true);
public void menuDeselected(MenuEvent e) {
}
@Override
public void menuCanceled(MenuEvent e) {
}
}

View File

@@ -1,146 +0,0 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.view;
import javax.swing.*;
import java.awt.*;
import static processing.app.I18n._;
public class UncertifiedBoardWarning extends javax.swing.JDialog {
private final EventListener listener;
public UncertifiedBoardWarning(Frame parent, EventListener listener) {
super(parent);
initComponents();
this.listener = listener;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
dontShowMeAgain = new javax.swing.JCheckBox();
ok = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(_("Uncertified board"));
setModal(true);
setName("uncertifiedBoardWarning"); // NOI18N
setResizable(false);
jLabel1.setText("<html><body>" + _("This board comes from an uncertified manufacturer.") + "<br>" + _("We won't be able to provide any support if it doesn't work as expected.") + "</body></html>");
jLabel1.setVerticalAlignment(javax.swing.SwingConstants.TOP);
dontShowMeAgain.setText(_("Don't show me again"));
dontShowMeAgain.setName("dontShowMeAgain"); // NOI18N
ok.setText(_("OK"));
ok.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(dontShowMeAgain)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 206, Short.MAX_VALUE)
.addComponent(ok, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(dontShowMeAgain)
.addComponent(ok))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void okActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okActionPerformed
Event event = new Event(evt.getSource(), evt.getID(), "uncertified_board_warning_ok_pressed");
event.getPayload().put("dontShowMeAgain", dontShowMeAgain.isSelected());
listener.eventHappened(event);
this.dispose();
}//GEN-LAST:event_okActionPerformed
/**
* @param args the command line arguments
*/
public static void main(String args[]) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
/* Create and display the dialog */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
UncertifiedBoardWarning dialog = new UncertifiedBoardWarning(new javax.swing.JFrame(), new EventListener() {
@Override
public void eventHappened(Event event) {
System.out.println(event);
}
});
dialog.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
System.exit(0);
}
});
dialog.setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox dontShowMeAgain;
private javax.swing.JLabel jLabel1;
private javax.swing.JButton ok;
// End of variables declaration//GEN-END:variables
}

View File

@@ -3,10 +3,11 @@
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" value="_(&quot;Not supported board&quot;)"/>
<Property name="title" type="java.lang.String" value="_(&quot;Additional Boards Manager URLs: &quot;)"/>
<Property name="modal" type="boolean" value="true"/>
<Property name="name" type="java.lang.String" value="uncertifiedBoardWarning" noResource="true"/>
<Property name="resizable" type="boolean" value="false"/>
<Property name="modalExclusionType" type="java.awt.Dialog$ModalExclusionType" editor="org.netbeans.modules.form.editors.EnumEditor">
<Value id="APPLICATION_EXCLUDE"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
@@ -27,15 +28,16 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" pref="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="dontShowMeAgain" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="206" max="32767" attributes="0"/>
<Component id="ok" min="-2" pref="82" max="-2" attributes="0"/>
<EmptySpace min="0" pref="439" max="32767" attributes="0"/>
<Component id="ok" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@@ -45,29 +47,50 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" pref="87" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="141" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="dontShowMeAgain" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ok" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel1">
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="additionalBoardsManagerURLs">
<Properties>
<Property name="columns" type="int" value="20"/>
<Property name="rows" type="int" value="5"/>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="18"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="cancel">
<Properties>
<Property name="text" type="java.lang.String" value="&lt;html&gt;&lt;body&gt;This board comes from an non certified manufacturer.&lt;br&gt;We won&apos;t be able to provide any support if it doesn&apos;t work as expected.&lt;/body&gt;&lt;/html&gt;"/>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="dontShowMeAgain">
<Properties>
<Property name="text" type="java.lang.String" value="Don&apos;t show me again"/>
<Property name="name" type="java.lang.String" value="dontShowMeAgain" noResource="true"/>
<Property name="text" type="java.lang.String" value="Cancel"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="ok">
<Properties>
@@ -76,6 +99,10 @@
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@@ -0,0 +1,216 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.view.preferences;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import processing.app.Base;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.util.Arrays;
import java.util.Collection;
import static processing.app.I18n._;
public class AdditionalBoardsManagerURLTextArea extends javax.swing.JDialog {
private ActionListener onOkListener;
public AdditionalBoardsManagerURLTextArea(Window parent) {
super(parent);
initComponents();
setLocationRelativeTo(parent);
Base.registerWindowCloseKeys(getRootPane(), new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cancelActionPerformed(e);
}
});
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
javax.swing.JButton cancel = new javax.swing.JButton();
javax.swing.JButton ok = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(_("Additional Boards Manager URLs"));
setModal(true);
setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
additionalBoardsManagerURLs.setColumns(20);
additionalBoardsManagerURLs.setRows(5);
additionalBoardsManagerURLs.setName(""); // NOI18N
jScrollPane1.setViewportView(additionalBoardsManagerURLs);
cancel.setText(_("Cancel"));
cancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelActionPerformed(evt);
}
});
ok.setText(_("OK"));
ok.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 439, Short.MAX_VALUE)
.addComponent(ok)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancel))
.addComponent(jScrollPane1))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 141, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cancel)
.addComponent(ok))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void cancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelActionPerformed
dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}//GEN-LAST:event_cancelActionPerformed
private void okActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okActionPerformed
ActionEvent actionEvent = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "");
onOkListener.actionPerformed(actionEvent);
cancelActionPerformed(evt);
}//GEN-LAST:event_okActionPerformed
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the dialog */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
AdditionalBoardsManagerURLTextArea dialog = new AdditionalBoardsManagerURLTextArea(new javax.swing.JFrame());
dialog.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
System.exit(0);
}
});
dialog.setVisible(true);
}
});
}
public void setText(String text) {
Collection<String> urls = splitAndTrim(text, ",");
additionalBoardsManagerURLs.setText(Joiner.on("\n").skipNulls().join(urls));
}
private Collection<String> splitAndTrim(String text, String separator) {
Collection<String> urls = Arrays.asList(text.split(separator));
return FluentIterable.from(urls).transform(new Function<String, String>() {
@Override
public String apply(String input) {
return input.trim();
}
}).filter(new Predicate<String>() {
@Override
public boolean apply(String input) {
return !input.isEmpty();
}
}).toList();
}
public String getText() {
Collection<String> urls = splitAndTrim(additionalBoardsManagerURLs.getText(), "\n");
return Joiner.on(",").skipNulls().join(urls);
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private final javax.swing.JTextArea additionalBoardsManagerURLs = new javax.swing.JTextArea();
// End of variables declaration//GEN-END:variables
public void onOk(ActionListener listener) {
this.onOkListener = listener;
}
}

View File

@@ -0,0 +1,634 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Preferences&quot;)" type="code"/>
</Property>
<Property name="modal" type="boolean" value="true"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="proxySettingsPanel" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="sketchbookLocationField" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="checkboxesContainer" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="arduinoNotRunningLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="sketchbookLocationLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="comboWarningsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="comboWarnings" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="morePreferencesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="showVerboseLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="verboseCompilationBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="verboseUploadBox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="comboLanguageLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="fontSizeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="fontSizeField" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="comboLanguage" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="requiresRestartLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Component id="preferencesFileLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="additionalBoardsManagerLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="additionalBoardsManagerField" min="-2" pref="494" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="extendedAdditionalUrlFieldWindow" min="-2" pref="36" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="okButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="sketchbookLocationLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="sketchbookLocationField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="comboLanguageLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="comboLanguage" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="requiresRestartLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fontSizeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="fontSizeField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="showVerboseLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="verboseCompilationBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="verboseUploadBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="comboWarningsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="comboWarnings" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="checkboxesContainer" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="proxySettingsPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
<Component id="additionalBoardsManagerLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="additionalBoardsManagerField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="extendedAdditionalUrlFieldWindow" min="-2" pref="27" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="morePreferencesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="preferencesFileLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="arduinoNotRunningLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="sketchbookLocationLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Sketchbook location:&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="sketchbookLocationField">
<Properties>
<Property name="columns" type="int" value="40"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="I18n.PROMPT_BROWSE" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="comboLanguageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Editor language: &quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JComboBox" name="comboLanguage">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JComboBox(languages)"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="requiresRestartLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot; (requires restart of Arduino)&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="fontSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Editor font size: &quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="fontSizeField">
<Properties>
<Property name="columns" type="int" value="4"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value=""/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="showVerboseLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Show verbose output during: &quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="verboseCompilationBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;compilation &quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="verboseUploadBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;upload&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="comboWarningsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Compiler warnings: &quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JComboBox" name="comboWarnings">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JComboBox(warningItems)"/>
</AuxValues>
</Component>
<Container class="javax.swing.JPanel" name="proxySettingsPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="&lt;User Code&gt;">
<Connection PropertyName="titleX" code="_(&quot;Proxy Settings&quot;)" type="code"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="proxyHTTPSServerLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="proxyHTTPServerLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="proxyUserLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="proxyHTTPServer" max="32767" attributes="0"/>
<Component id="proxyHTTPSServer" max="32767" attributes="0"/>
<Component id="proxyUser" alignment="1" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="proxyHTTPSPortLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="proxyPasswordLabel" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="proxyHTTPPortLabel" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="proxyHTTPSPort" alignment="0" max="32767" attributes="0"/>
<Component id="proxyHTTPPort" alignment="0" max="32767" attributes="0"/>
<Component id="proxyPassword" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="proxyHTTPServerLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="proxyHTTPServer" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="proxyHTTPSServerLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="proxyHTTPSServer" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="proxyUser" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="proxyUserLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="proxyHTTPPortLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="proxyHTTPPort" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="proxyHTTPSPort" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="proxyHTTPSPortLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="proxyPasswordLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="proxyPassword" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="proxyHTTPServerLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Server (HTTP):&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="proxyHTTPServer">
<Properties>
<Property name="columns" type="int" value="10"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="proxyHTTPPortLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Port (HTTP):&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="proxyHTTPPort">
<Properties>
<Property name="columns" type="int" value="10"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="proxyHTTPSServerLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Server (HTTPS):&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="proxyHTTPSServer">
<Properties>
<Property name="columns" type="int" value="10"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="proxyHTTPSPortLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Port (HTTPS):&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="proxyHTTPSPort">
<Properties>
<Property name="columns" type="int" value="10"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="proxyUserLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Username:&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="proxyUser">
<Properties>
<Property name="columns" type="int" value="10"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="proxyPasswordLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Password:&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JPasswordField" name="proxyPassword">
<Properties>
<Property name="columns" type="int" value="10"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="additionalBoardsManagerLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Additional Boards Manager URLs: &quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="additionalBoardsManagerField">
</Component>
<Component class="javax.swing.JButton" name="extendedAdditionalUrlFieldWindow">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new ImageIcon(Base.getThemeImage(&quot;newwindow.gif&quot;, this))" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="extendedAdditionalUrlFieldWindowActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="morePreferencesLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="Color.GRAY" type="code"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;More preferences can be edited directly in the file&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="preferencesFileLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="PreferencesData.getPreferencesFile().getAbsolutePath()" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="preferencesFileLabelMousePressed"/>
<EventHandler event="mouseExited" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="preferencesFileLabelMouseExited"/>
<EventHandler event="mouseEntered" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="preferencesFileLabelMouseEntered"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="arduinoNotRunningLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="Color.GRAY" type="code"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;(edit only when Arduino is not running)&quot;)" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="I18n.PROMPT_OK" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="I18n.PROMPT_CANCEL" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Container class="javax.swing.JPanel" name="checkboxesContainer">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="1"/>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="displayLineNumbersBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Display line numbers&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="enableCodeFoldingBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Enable Code Folding&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="verifyUploadBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Verify code after upload&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="externalEditorBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Use external editor&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="checkUpdatesBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Check for updates on startup&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="updateExtensionBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Update sketch files to new extension on save (.pde -&gt; .ino)&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="autoAssociateBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Automatically associate .ino files with Arduino&quot;)" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="saveVerifyUploadBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="_(&quot;Save when verifying or uploading&quot;)" type="code"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,770 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.view.preferences;
import processing.app.Base;
import processing.app.Editor;
import processing.app.I18n;
import processing.app.PreferencesData;
import processing.app.helpers.FileUtils;
import processing.app.helpers.OSUtils;
import processing.app.legacy.PApplet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.File;
import static processing.app.I18n._;
public class Preferences extends javax.swing.JDialog {
private final Language[] languages;
private final Language[] missingLanguages;
private final WarningItem[] warningItems;
private final Base base;
public static class Language {
private final String name;
private final String originalName;
private final String isoCode;
public Language(String name, String originalName, String isoCode) {
this.name = name;
this.originalName = originalName;
this.isoCode = isoCode;
}
public String toString() {
if (originalName.length() == 0) {
return name;
}
return originalName + " (" + name + ")";
}
public String getIsoCode() {
return isoCode;
}
}
private static class WarningItem {
private final String value;
private final String translation;
public WarningItem(String value, String translation) {
this.value = value;
this.translation = translation;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return translation;
}
}
public Preferences(Window parent, Base base) {
super(parent);
this.base = base;
this.languages = new Language[]{
new Language(_("System Default"), "", ""),
new Language(_("Albanian"), "shqip", "sq"),
new Language(_("Arabic"), "العربية", "ar"),
new Language(_("Aragonese"), "Aragonés", "an"),
new Language(_("Belarusian"), "Беларуская мова", "be"),
new Language(_("Bulgarian"), "български", "bg"),
new Language(_("Catalan"), "Català", "ca"),
new Language(_("Chinese Simplified"), "简体中文", "zh_CN"),
new Language(_("Chinese Traditional"), "繁體中文", "zh_TW"),
new Language(_("Croatian"), "Hrvatski", "hr_HR"),
new Language(_("Czech (Czech Republic)"), "český (Czech Republic)", "cs_CZ"),
new Language(_("Danish (Denmark)"), "Dansk (Denmark)", "da_DK"),
new Language(_("Dutch"), "Nederlands", "nl"),
new Language(_("English"), "English", "en"),
new Language(_("English (United Kingdom)"), "English (United Kingdom)", "en_GB"),
new Language(_("Estonian"), "Eesti", "et"),
new Language(_("Estonian (Estonia)"), "Eesti keel", "et_EE"),
new Language(_("Filipino"), "Pilipino", "fil"),
new Language(_("Finnish"), "Suomi", "fi"),
new Language(_("French"), "Français", "fr"),
new Language(_("Canadian French"), "Canadienne-français", "fr_CA"),
new Language(_("Galician"), "Galego", "gl"),
new Language(_("Georgian"), "საქართველოს", "ka_GE"),
new Language(_("German"), "Deutsch", "de_DE"),
new Language(_("Greek"), "ελληνικά", "el_GR"),
new Language(_("Hebrew"), "עברית", "he"),
new Language(_("Hindi"), "हिंदी", "hi"),
new Language(_("Hungarian"), "Magyar", "hu"),
new Language(_("Indonesian"), "Bahasa Indonesia", "id"),
new Language(_("Italian"), "Italiano", "it_IT"),
new Language(_("Japanese"), "日本語", "ja_JP"),
new Language(_("Korean"), "한국어", "ko_KR"),
new Language(_("Latvian"), "Latviešu", "lv_LV"),
new Language(_("Lithuaninan"), "Lietuvių Kalba", "lt_LT"),
new Language(_("Norwegian Bokmål"), "Norsk bokmål", "nb_NO"),
new Language(_("Persian"), "فارسی", "fa"),
new Language(_("Polish"), "Język Polski", "pl"),
new Language(_("Portuguese (Brazil)"), "Português (Brazil)", "pt_BR"),
new Language(_("Portuguese (Portugal)"), "Português (Portugal)", "pt_PT"),
new Language(_("Romanian"), "Română", "ro"),
new Language(_("Russian"), "Русский", "ru"),
new Language(_("Slovenian"), "Slovenščina", "sl_SI"),
new Language(_("Spanish"), "Español", "es"),
new Language(_("Swedish"), "Svenska", "sv"),
new Language(_("Tamil"), "தமிழ்", "ta"),
new Language(_("Turkish"), "Türk", "tr"),
new Language(_("Ukrainian"), "Український", "uk"),
new Language(_("Vietnamese"), "Tiếng Việt", "vi"),
};
this.missingLanguages = new Language[]{
new Language(_("Afrikaans"), "Afrikaans", "af"),
new Language(_("Armenian"), "Հայերեն", "hy"),
new Language(_("Asturian"), "Asturianu", "ast"),
new Language(_("Basque"), "Euskara", "eu"),
new Language(_("Bengali (India)"), "বাংলা (India)", "bn_IN"),
new Language(_("Bosnian"), "Bosanski", "bs"),
new Language(_("Burmese (Myanmar)"), "ဗမာစကား", "my_MM"),
new Language(_("Chinese (China)"), "", "zh_CN"),
new Language(_("Chinese (Hong Kong)"), "", "zh_HK"),
new Language(_("Chinese (Taiwan)"), "", "zh_TW"),
new Language(_("Chinese (Taiwan) (Big5)"), "", "zh_TW.Big5"),
new Language(_("Czech"), "český", "cs"),
new Language(_("Danish"), "Dansk", "da"),
new Language(_("Dutch (Netherlands)"), "Nederlands", "nl_NL"),
new Language(_("Galician (Spain)"), "Galego (Spain)", "gl_ES"),
new Language(_("Nepali"), "नेपाली", "ne"),
new Language(_("N'Ko"), "ߒߞߏ", "nqo"),
new Language(_("Marathi"), "मराठी", "mr"),
new Language(_("Malay (Malaysia)"), "بهاس ملايو (Malaysia)", "ms_MY"),
new Language(_("Norwegian"), "Norsk", "no"),
new Language(_("Norwegian Nynorsk"), "Norsk Nynorsk", "nn"),
new Language(_("Portugese"), "Português", "pt"),
new Language(_("Persian (Iran)"), "فارسی (Iran)", "fa_IR"),
new Language(_("Slovak"), "Slovenčina", "sk"),
new Language(_("Swahili"), "كِسوَهِل", "sw"),
new Language(_("Talossan"), "Talossan", "tzl"),
new Language(_("Urdu (Pakistan)"), "اردو (Pakistan)", "ur_PK"),
new Language(_("Western Frisian"), "Western Frisian", "fy"),
};
this.warningItems = new WarningItem[]{
new WarningItem("none", _("None")),
new WarningItem("default", _("Default")),
new WarningItem("more", _("More")),
new WarningItem("all", _("All"))
};
initComponents();
Base.registerWindowCloseKeys(getRootPane(), new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cancelButtonActionPerformed(e);
}
});
if (!OSUtils.isWindows() || base.getPortableFolder() != null) {
autoAssociateBox.setEnabled(false);
autoAssociateBox.getParent().remove(autoAssociateBox);
}
showPrerefencesData();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
javax.swing.JLabel sketchbookLocationLabel = new javax.swing.JLabel();
sketchbookLocationField = new javax.swing.JTextField();
javax.swing.JButton browseButton = new javax.swing.JButton();
javax.swing.JLabel comboLanguageLabel = new javax.swing.JLabel();
comboLanguage = new JComboBox(languages);
javax.swing.JLabel requiresRestartLabel = new javax.swing.JLabel();
javax.swing.JLabel fontSizeLabel = new javax.swing.JLabel();
fontSizeField = new javax.swing.JTextField();
javax.swing.JLabel showVerboseLabel = new javax.swing.JLabel();
verboseCompilationBox = new javax.swing.JCheckBox();
verboseUploadBox = new javax.swing.JCheckBox();
javax.swing.JLabel comboWarningsLabel = new javax.swing.JLabel();
comboWarnings = new JComboBox(warningItems);
javax.swing.JPanel proxySettingsPanel = new javax.swing.JPanel();
javax.swing.JLabel proxyHTTPServerLabel = new javax.swing.JLabel();
proxyHTTPServer = new javax.swing.JTextField();
javax.swing.JLabel proxyHTTPPortLabel = new javax.swing.JLabel();
proxyHTTPPort = new javax.swing.JTextField();
javax.swing.JLabel proxyHTTPSServerLabel = new javax.swing.JLabel();
proxyHTTPSServer = new javax.swing.JTextField();
javax.swing.JLabel proxyHTTPSPortLabel = new javax.swing.JLabel();
proxyHTTPSPort = new javax.swing.JTextField();
javax.swing.JLabel proxyUserLabel = new javax.swing.JLabel();
proxyUser = new javax.swing.JTextField();
javax.swing.JLabel proxyPasswordLabel = new javax.swing.JLabel();
proxyPassword = new javax.swing.JPasswordField();
javax.swing.JLabel additionalBoardsManagerLabel = new javax.swing.JLabel();
additionalBoardsManagerField = new javax.swing.JTextField();
javax.swing.JButton extendedAdditionalUrlFieldWindow = new javax.swing.JButton();
javax.swing.JLabel morePreferencesLabel = new javax.swing.JLabel();
preferencesFileLabel = new javax.swing.JLabel();
javax.swing.JLabel arduinoNotRunningLabel = new javax.swing.JLabel();
javax.swing.JButton okButton = new javax.swing.JButton();
javax.swing.JButton cancelButton = new javax.swing.JButton();
javax.swing.JPanel checkboxesContainer = new javax.swing.JPanel();
displayLineNumbersBox = new javax.swing.JCheckBox();
enableCodeFoldingBox = new javax.swing.JCheckBox();
verifyUploadBox = new javax.swing.JCheckBox();
externalEditorBox = new javax.swing.JCheckBox();
checkUpdatesBox = new javax.swing.JCheckBox();
updateExtensionBox = new javax.swing.JCheckBox();
autoAssociateBox = new javax.swing.JCheckBox();
saveVerifyUploadBox = new javax.swing.JCheckBox();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(_("Preferences"));
setModal(true);
setResizable(false);
sketchbookLocationLabel.setText(_("Sketchbook location:"));
sketchbookLocationField.setColumns(40);
browseButton.setText(I18n.PROMPT_BROWSE);
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
comboLanguageLabel.setText(_("Editor language: "));
requiresRestartLabel.setText(_(" (requires restart of Arduino)"));
fontSizeLabel.setText(_("Editor font size: "));
fontSizeField.setColumns(4);
showVerboseLabel.setText(_("Show verbose output during: "));
verboseCompilationBox.setText(_("compilation "));
verboseUploadBox.setText(_("upload"));
comboWarningsLabel.setText(_("Compiler warnings: "));
proxySettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(_("Proxy Settings")));
proxyHTTPServerLabel.setText(_("Server (HTTP):"));
proxyHTTPServer.setColumns(10);
proxyHTTPPortLabel.setText(_("Port (HTTP):"));
proxyHTTPPort.setColumns(10);
proxyHTTPSServerLabel.setText(_("Server (HTTPS):"));
proxyHTTPSServer.setColumns(10);
proxyHTTPSPortLabel.setText(_("Port (HTTPS):"));
proxyHTTPSPort.setColumns(10);
proxyUserLabel.setText(_("Username:"));
proxyUser.setColumns(10);
proxyPasswordLabel.setText(_("Password:"));
proxyPassword.setColumns(10);
javax.swing.GroupLayout proxySettingsPanelLayout = new javax.swing.GroupLayout(proxySettingsPanel);
proxySettingsPanel.setLayout(proxySettingsPanelLayout);
proxySettingsPanelLayout.setHorizontalGroup(
proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(proxySettingsPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(proxyHTTPSServerLabel)
.addGroup(proxySettingsPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(proxyHTTPServerLabel)))
.addComponent(proxyUserLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(proxyHTTPServer)
.addComponent(proxyHTTPSServer)
.addComponent(proxyUser, javax.swing.GroupLayout.Alignment.TRAILING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(proxyHTTPSPortLabel)
.addComponent(proxyPasswordLabel, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(proxyHTTPPortLabel, javax.swing.GroupLayout.Alignment.TRAILING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(proxyHTTPSPort, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(proxyHTTPPort, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(proxyPassword, javax.swing.GroupLayout.Alignment.LEADING))
.addContainerGap())
);
proxySettingsPanelLayout.setVerticalGroup(
proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(proxySettingsPanelLayout.createSequentialGroup()
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(proxySettingsPanelLayout.createSequentialGroup()
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(proxyHTTPServerLabel)
.addComponent(proxyHTTPServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(proxyHTTPSServerLabel)
.addComponent(proxyHTTPSServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(proxyUser, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(proxyUserLabel)))
.addGroup(proxySettingsPanelLayout.createSequentialGroup()
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(proxyHTTPPortLabel)
.addComponent(proxyHTTPPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(proxyHTTPSPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(proxyHTTPSPortLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(proxyPasswordLabel)
.addComponent(proxyPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
additionalBoardsManagerLabel.setText(_("Additional Boards Manager URLs: "));
extendedAdditionalUrlFieldWindow.setIcon(new ImageIcon(Base.getThemeImage("newwindow.gif", this)));
extendedAdditionalUrlFieldWindow.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
extendedAdditionalUrlFieldWindowActionPerformed(evt);
}
});
morePreferencesLabel.setForeground(Color.GRAY);
morePreferencesLabel.setText(_("More preferences can be edited directly in the file"));
preferencesFileLabel.setText(PreferencesData.getPreferencesFile().getAbsolutePath());
preferencesFileLabel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mousePressed(java.awt.event.MouseEvent evt) {
preferencesFileLabelMousePressed(evt);
}
public void mouseExited(java.awt.event.MouseEvent evt) {
preferencesFileLabelMouseExited(evt);
}
public void mouseEntered(java.awt.event.MouseEvent evt) {
preferencesFileLabelMouseEntered(evt);
}
});
arduinoNotRunningLabel.setForeground(Color.GRAY);
arduinoNotRunningLabel.setText(_("(edit only when Arduino is not running)"));
okButton.setText(I18n.PROMPT_OK);
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
cancelButton.setText(I18n.PROMPT_CANCEL);
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
checkboxesContainer.setLayout(new javax.swing.BoxLayout(checkboxesContainer, javax.swing.BoxLayout.Y_AXIS));
displayLineNumbersBox.setText(_("Display line numbers"));
checkboxesContainer.add(displayLineNumbersBox);
enableCodeFoldingBox.setText(_("Enable Code Folding"));
checkboxesContainer.add(enableCodeFoldingBox);
verifyUploadBox.setText(_("Verify code after upload"));
checkboxesContainer.add(verifyUploadBox);
externalEditorBox.setText(_("Use external editor"));
checkboxesContainer.add(externalEditorBox);
checkUpdatesBox.setText(_("Check for updates on startup"));
checkboxesContainer.add(checkUpdatesBox);
updateExtensionBox.setText(_("Update sketch files to new extension on save (.pde -> .ino)"));
checkboxesContainer.add(updateExtensionBox);
autoAssociateBox.setText(_("Automatically associate .ino files with Arduino"));
checkboxesContainer.add(autoAssociateBox);
saveVerifyUploadBox.setText(_("Save when verifying or uploading"));
checkboxesContainer.add(saveVerifyUploadBox);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(proxySettingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(sketchbookLocationField)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(browseButton))
.addComponent(checkboxesContainer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(arduinoNotRunningLabel)
.addComponent(sketchbookLocationLabel)
.addGroup(layout.createSequentialGroup()
.addComponent(comboWarningsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(comboWarnings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(morePreferencesLabel)
.addGroup(layout.createSequentialGroup()
.addComponent(showVerboseLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(verboseCompilationBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(verboseUploadBox))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(comboLanguageLabel)
.addComponent(fontSizeLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(fontSizeField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(comboLanguage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(requiresRestartLabel))))
.addComponent(preferencesFileLabel))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(additionalBoardsManagerLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(additionalBoardsManagerField, javax.swing.GroupLayout.PREFERRED_SIZE, 494, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(extendedAdditionalUrlFieldWindow, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(okButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(sketchbookLocationLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(sketchbookLocationField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(comboLanguageLabel)
.addComponent(comboLanguage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(requiresRestartLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fontSizeLabel)
.addComponent(fontSizeField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(showVerboseLabel)
.addComponent(verboseCompilationBox)
.addComponent(verboseUploadBox))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(comboWarningsLabel)
.addComponent(comboWarnings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(checkboxesContainer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(proxySettingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(additionalBoardsManagerLabel)
.addComponent(additionalBoardsManagerField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(extendedAdditionalUrlFieldWindow, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(morePreferencesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(preferencesFileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(arduinoNotRunningLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cancelButton)
.addComponent(okButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
File dflt = new File(sketchbookLocationField.getText());
File file = Base.selectFolder(_("Select new sketchbook location"), dflt, this);
if (file != null) {
String path = file.getAbsolutePath();
if (Base.getPortableFolder() != null) {
path = FileUtils.relativePath(Base.getPortableFolder().toString(), path);
if (path == null) {
path = Base.getPortableSketchbookFolder();
}
}
sketchbookLocationField.setText(path);
}
}//GEN-LAST:event_browseButtonActionPerformed
private void extendedAdditionalUrlFieldWindowActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_extendedAdditionalUrlFieldWindowActionPerformed
final AdditionalBoardsManagerURLTextArea additionalBoardsManagerURLTextArea = new AdditionalBoardsManagerURLTextArea(this);
additionalBoardsManagerURLTextArea.setText(additionalBoardsManagerField.getText());
additionalBoardsManagerURLTextArea.onOk(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
additionalBoardsManagerField.setText(additionalBoardsManagerURLTextArea.getText());
}
});
additionalBoardsManagerURLTextArea.setVisible(true);
}//GEN-LAST:event_extendedAdditionalUrlFieldWindowActionPerformed
private void preferencesFileLabelMouseEntered(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_preferencesFileLabelMouseEntered
preferencesFileLabel.setForeground(new Color(0, 0, 140));
}//GEN-LAST:event_preferencesFileLabelMouseEntered
private void preferencesFileLabelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_preferencesFileLabelMousePressed
Base.openFolder(PreferencesData.getPreferencesFile().getParentFile());
}//GEN-LAST:event_preferencesFileLabelMousePressed
private void preferencesFileLabelMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_preferencesFileLabelMouseExited
preferencesFileLabel.setForeground(Color.BLACK);
}//GEN-LAST:event_preferencesFileLabelMouseExited
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
savePreferencesData();
for (Editor editor : base.getEditors()) {
editor.applyPreferences();
}
cancelButtonActionPerformed(evt);
}//GEN-LAST:event_okButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField additionalBoardsManagerField;
private javax.swing.JCheckBox autoAssociateBox;
private javax.swing.JCheckBox checkUpdatesBox;
private javax.swing.JComboBox comboLanguage;
private javax.swing.JComboBox comboWarnings;
private javax.swing.JCheckBox displayLineNumbersBox;
private javax.swing.JCheckBox enableCodeFoldingBox;
private javax.swing.JCheckBox externalEditorBox;
private javax.swing.JTextField fontSizeField;
private javax.swing.JLabel preferencesFileLabel;
private javax.swing.JTextField proxyHTTPPort;
private javax.swing.JTextField proxyHTTPSPort;
private javax.swing.JTextField proxyHTTPSServer;
private javax.swing.JTextField proxyHTTPServer;
private javax.swing.JPasswordField proxyPassword;
private javax.swing.JTextField proxyUser;
private javax.swing.JCheckBox saveVerifyUploadBox;
private javax.swing.JTextField sketchbookLocationField;
private javax.swing.JCheckBox updateExtensionBox;
private javax.swing.JCheckBox verboseCompilationBox;
private javax.swing.JCheckBox verboseUploadBox;
private javax.swing.JCheckBox verifyUploadBox;
// End of variables declaration//GEN-END:variables
private void savePreferencesData() {
String oldPath = PreferencesData.get("sketchbook.path");
String newPath = sketchbookLocationField.getText();
if (newPath.isEmpty()) {
if (base.getPortableFolder() == null) {
newPath = base.getDefaultSketchbookFolderOrPromptForIt().toString();
} else {
newPath = base.getPortableSketchbookFolder();
}
}
if (!newPath.equals(oldPath)) {
base.rebuildSketchbookMenus();
PreferencesData.set("sketchbook.path", newPath);
}
Language newLanguage = (Language) comboLanguage.getSelectedItem();
PreferencesData.set("editor.languages.current", newLanguage.getIsoCode());
String newSizeText = fontSizeField.getText();
try {
int newSize = Integer.parseInt(newSizeText.trim());
String pieces[] = PApplet.split(PreferencesData.get("editor.font"), ',');
pieces[2] = String.valueOf(newSize);
PreferencesData.set("editor.font", PApplet.join(pieces, ','));
} catch (Exception e) {
System.err.println(I18n.format(_("ignoring invalid font size {0}"), newSizeText));
}
// put each of the settings into the table
PreferencesData.setBoolean("build.verbose", verboseCompilationBox.isSelected());
PreferencesData.setBoolean("upload.verbose", verboseUploadBox.isSelected());
WarningItem warningItem = (WarningItem) comboWarnings.getSelectedItem();
PreferencesData.set("compiler.warning_level", warningItem.getValue());
PreferencesData.setBoolean("editor.linenumbers", displayLineNumbersBox.isSelected());
PreferencesData.setBoolean("editor.code_folding", enableCodeFoldingBox.isSelected());
PreferencesData.setBoolean("upload.verify", verifyUploadBox.isSelected());
PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
PreferencesData.setBoolean("editor.external", externalEditorBox.isSelected());
PreferencesData.setBoolean("update.check", checkUpdatesBox.isSelected());
PreferencesData.setBoolean("editor.update_extension", updateExtensionBox.isSelected());
if (autoAssociateBox != null) {
PreferencesData.setBoolean("platform.auto_file_type_associations", autoAssociateBox.isSelected());
}
PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
PreferencesData.set("proxy.http.server", proxyHTTPServer.getText());
try {
PreferencesData.set("proxy.http.port", Integer.valueOf(proxyHTTPPort.getText()).toString());
} catch (NumberFormatException e) {
PreferencesData.remove("proxy.http.port");
}
PreferencesData.set("proxy.https.server", proxyHTTPSServer.getText());
try {
PreferencesData.set("proxy.https.port", Integer.valueOf(proxyHTTPSPort.getText()).toString());
} catch (NumberFormatException e) {
PreferencesData.remove("proxy.https.port");
}
PreferencesData.set("proxy.user", proxyUser.getText());
PreferencesData.set("proxy.password", new String(proxyPassword.getPassword()));
PreferencesData.set("boardsmanager.additional.urls", additionalBoardsManagerField.getText().replace("\r\n", "\n").replace("\r", "\n").replace("\n", ","));
//editor.applyPreferences();
}
private void showPrerefencesData() {
sketchbookLocationField.setText(PreferencesData.get("sketchbook.path"));
String currentLanguageISOCode = PreferencesData.get("editor.languages.current");
for (Language language : languages) {
if (language.getIsoCode().equals(currentLanguageISOCode)) {
comboLanguage.setSelectedItem(language);
}
}
Font editorFont = PreferencesData.getFont("editor.font");
fontSizeField.setText(String.valueOf(editorFont.getSize()));
verboseCompilationBox.setSelected(PreferencesData.getBoolean("build.verbose"));
verboseUploadBox.setSelected(PreferencesData.getBoolean("upload.verbose"));
String currentWarningLevel = PreferencesData.get("compiler.warning_level", "none");
for (WarningItem item : warningItems) {
if (currentWarningLevel.equals(item.getValue())) {
comboWarnings.setSelectedItem(item);
}
}
displayLineNumbersBox.setSelected(PreferencesData.getBoolean("editor.linenumbers"));
enableCodeFoldingBox.setSelected(PreferencesData.getBoolean("editor.code_folding"));
verifyUploadBox.setSelected(PreferencesData.getBoolean("upload.verify"));
externalEditorBox.setSelected(PreferencesData.getBoolean("editor.external"));
checkUpdatesBox.setSelected(PreferencesData.getBoolean("update.check"));
updateExtensionBox.setSelected(PreferencesData.get("editor.update_extension") == null || PreferencesData.getBoolean("editor.update_extension"));
if (autoAssociateBox != null) {
autoAssociateBox.setSelected(PreferencesData.getBoolean("platform.auto_file_type_associations"));
}
saveVerifyUploadBox.setSelected(PreferencesData.getBoolean("editor.save_on_verify"));
proxyHTTPServer.setText(PreferencesData.get("proxy.http.server"));
try {
proxyHTTPPort.setText(Integer.toString(PreferencesData.getInteger("proxy.http.port", 8080)));
} catch (NumberFormatException e) {
proxyHTTPPort.setText("");
}
proxyHTTPSServer.setText(PreferencesData.get("proxy.https.server"));
try {
proxyHTTPSPort.setText(Integer.toString(PreferencesData.getInteger("proxy.https.port", 8443)));
} catch (NumberFormatException e) {
proxyHTTPSPort.setText("");
}
proxyUser.setText(PreferencesData.get("proxy.user"));
proxyPassword.setText(PreferencesData.get("proxy.password"));
additionalBoardsManagerField.setText(PreferencesData.get("boardsmanager.additional.urls"));
}
}

View File

@@ -78,7 +78,7 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
getContentPane().setLayout(new BorderLayout());
Font consoleFont = Theme.getFont("console.font");
Font editorFont = Preferences.getFont("editor.font");
Font editorFont = PreferencesData.getFont("editor.font");
Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize());
textArea = new TextAreaFIFO(8000000);
@@ -124,12 +124,12 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
lineEndings = new JComboBox(new String[]{_("No line ending"), _("Newline"), _("Carriage return"), _("Both NL & CR")});
lineEndings.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
Preferences.setInteger("serial.line_ending", lineEndings.getSelectedIndex());
PreferencesData.setInteger("serial.line_ending", lineEndings.getSelectedIndex());
noLineEndingAlert.setForeground(pane.getBackground());
}
});
if (Preferences.get("serial.line_ending") != null) {
lineEndings.setSelectedIndex(Preferences.getInteger("serial.line_ending"));
if (PreferencesData.get("serial.line_ending") != null) {
lineEndings.setSelectedIndex(PreferencesData.getInteger("serial.line_ending"));
}
lineEndings.setMaximumSize(lineEndings.getMinimumSize());
@@ -160,13 +160,13 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
pack();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
if (Preferences.get("last.screen.height") != null) {
if (PreferencesData.get("last.screen.height") != null) {
// if screen size has changed, the window coordinates no longer
// make sense, so don't use them unless they're identical
int screenW = Preferences.getInteger("last.screen.width");
int screenH = Preferences.getInteger("last.screen.height");
int screenW = PreferencesData.getInteger("last.screen.width");
int screenH = PreferencesData.getInteger("last.screen.height");
if ((screen.width == screenW) && (screen.height == screenH)) {
String locationStr = Preferences.get("last.serial.location");
String locationStr = PreferencesData.get("last.serial.location");
if (locationStr != null) {
int[] location = PApplet.parseInt(PApplet.split(locationStr, ','));
setPlacement(location);

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
package processing.app;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.SketchTextArea;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
@@ -11,7 +11,7 @@ public class CaretAwareUndoableEdit implements UndoableEdit {
private final UndoableEdit undoableEdit;
private final int caretPosition;
public CaretAwareUndoableEdit(UndoableEdit undoableEdit, JEditTextArea textArea) {
public CaretAwareUndoableEdit(UndoableEdit undoableEdit, SketchTextArea textArea) {
this.undoableEdit = undoableEdit;
this.caretPosition = textArea.getCaretPosition();
}

File diff suppressed because it is too large Load Diff

View File

@@ -68,7 +68,7 @@ public class EditorConsole extends JScrollPane {
public EditorConsole(Editor _editor) {
editor = _editor;
int maxLineCount = Preferences.getInteger("console.length");
int maxLineCount = PreferencesData.getInteger("console.length");
consoleDoc = new BufferedStyledDocument(4000, maxLineCount);
consoleTextPane = new JTextPane(consoleDoc);
@@ -84,7 +84,7 @@ public class EditorConsole extends JScrollPane {
Color fgColorOut = Theme.getColor("console.output.color");
Color fgColorErr = Theme.getColor("console.error.color");
Font consoleFont = Theme.getFont("console.font");
Font editorFont = Preferences.getFont("editor.font");
Font editorFont = PreferencesData.getFont("editor.font");
Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize());
stdStyle = new SimpleAttributeSet();
@@ -112,7 +112,7 @@ public class EditorConsole extends JScrollPane {
// and size window accordingly
FontMetrics metrics = getFontMetrics(font);
int height = metrics.getAscent() + metrics.getDescent();
int lines = Preferences.getInteger("console.lines");
int lines = PreferencesData.getInteger("console.lines");
int sizeFudge = 6; //10; // unclear why this is necessary, but it is
setPreferredSize(new Dimension(1024, (height * lines) + sizeFudge));
setMinimumSize(new Dimension(1024, (height * 4) + sizeFudge));

View File

@@ -1,5 +1,7 @@
package processing.app;
import cc.arduino.files.DeleteFilesOnShutdown;
import static processing.app.I18n._;
import java.io.File;
@@ -33,19 +35,19 @@ class EditorConsoleStream extends OutputStream {
// The files and folders are not deleted on exit because they may be
// needed for debugging or bug reporting.
tempFolder = Base.createTempFolder("console");
tempFolder.deleteOnExit();
DeleteFilesOnShutdown.add(tempFolder);
try {
String outFileName = Preferences.get("console.output.file");
String outFileName = PreferencesData.get("console.output.file");
if (outFileName != null) {
outFile = new File(tempFolder, outFileName);
outFile.deleteOnExit();
DeleteFilesOnShutdown.add(outFile);
stdoutFile = new FileOutputStream(outFile);
}
String errFileName = Preferences.get("console.error.file");
String errFileName = PreferencesData.get("console.error.file");
if (errFileName != null) {
errFile = new File(tempFolder, errFileName);
errFile.deleteOnExit();
DeleteFilesOnShutdown.add(errFile);
stderrFile = new FileOutputStream(errFile);
}
} catch (IOException e) {
@@ -56,7 +58,7 @@ class EditorConsoleStream extends OutputStream {
consoleOut = new PrintStream(new EditorConsoleStream(false));
consoleErr = new PrintStream(new EditorConsoleStream(true));
if (Preferences.getBoolean("console")) {
if (PreferencesData.getBoolean("console")) {
try {
System.setOut(consoleOut);
System.setErr(consoleErr);

View File

@@ -1,3 +1,5 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
@@ -20,26 +22,21 @@
package processing.app;
import processing.app.helpers.OSUtils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import javax.swing.JComponent;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesMap;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.SketchTextArea;
/**
* Li'l status bar fella that shows the line number.
*/
@SuppressWarnings("serial")
public class EditorLineStatus extends JComponent {
JEditTextArea textarea;
int start = -1, stop;
Image resize;
@@ -55,10 +52,8 @@ public class EditorLineStatus extends JComponent {
String name = "";
String serialport = "";
public EditorLineStatus(JEditTextArea textarea) {
this.textarea = textarea;
textarea.editorLineStatus = this;
public EditorLineStatus() {
background = Theme.getColor("linestatus.bgcolor");
font = Theme.getFont("linestatus.font");
foreground = Theme.getColor("linestatus.color");
@@ -101,7 +96,7 @@ public class EditorLineStatus extends JComponent {
setBoardName(boardPreferences.get("name"));
else
setBoardName("-");
setSerialPort(Preferences.get("serial.port"));
setSerialPort(PreferencesData.get("serial.port"));
}
g.setColor(background);
Dimension size = getSize();

View File

@@ -1,636 +1,83 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app;
import processing.app.syntax.*;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.*;
import java.awt.event.*;
import processing.app.syntax.SketchTextArea;
/**
* Filters key events for tab expansion/indent/etc.
* <p/>
* For version 0099, some changes have been made to make the indents
* smarter. There are still issues though:
* + indent happens when it picks up a curly brace on the previous line,
* but not if there's a blank line between them.
* + It also doesn't handle single indent situations where a brace
* isn't used (i.e. an if statement or for loop that's a single line).
* It shouldn't actually be using braces.
* Solving these issues, however, would probably best be done by a
* smarter parser/formatter, rather than continuing to hack this class.
*/
public class EditorListener {
public class EditorListener implements KeyListener {
private Editor editor;
private JEditTextArea textarea;
private boolean externalEditor;
private boolean tabsExpand;
private boolean tabsIndent;
private int tabSize;
private String tabString;
private boolean autoIndent;
// private int selectionStart, selectionEnd;
// private int position;
/** ctrl-alt on windows and linux, cmd-alt on mac os x */
static final int CTRL_ALT = ActionEvent.ALT_MASK |
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
public EditorListener(Editor editor, JEditTextArea textarea) {
public EditorListener(Editor editor) {
super();
this.editor = editor;
this.textarea = textarea;
// let him know that i'm leechin'
textarea.editorListener = this;
applyPreferences();
}
/** ctrl-alt on windows and linux, cmd-alt on mac os x */
static final int CTRL_ALT = ActionEvent.ALT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
static final int CTRL_SHIFT = ActionEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
static final int CTRL = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
public void applyPreferences() {
tabsExpand = Preferences.getBoolean("editor.tabs.expand");
//tabsIndent = Preferences.getBoolean("editor.tabs.indent");
tabSize = Preferences.getInteger("editor.tabs.size");
tabString = Editor.EMPTY.substring(0, tabSize);
autoIndent = Preferences.getBoolean("editor.indent");
externalEditor = Preferences.getBoolean("editor.external");
}
//public void setExternalEditor(boolean externalEditor) {
//this.externalEditor = externalEditor;
//}
/**
* Intercepts key pressed events for JEditTextArea.
* <p/>
* Called by JEditTextArea inside processKeyEvent(). Note that this
* won't intercept actual characters, because those are fired on
* keyTyped().
* @return true if the event has been handled (to remove it from the queue)
*/
public boolean keyPressed(KeyEvent event) {
// don't do things if the textarea isn't editable
if (externalEditor) return false;
//deselect(); // this is for paren balancing
public void keyTyped(KeyEvent event) {
char c = event.getKeyChar();
int code = event.getKeyCode();
// if (code == KeyEvent.VK_SHIFT) {
// editor.toolbar.setShiftPressed(true);
// }
//System.out.println((int)c + " " + code + " " + event);
//System.out.println();
if ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
// The char is not control code when CTRL key pressed? It should be a shortcut.
if (!Character.isISOControl(c)) {
event.consume();
}
}
}
@Override
public void keyPressed(KeyEvent event) {
SketchTextArea textarea = editor.getTextArea();
if (!textarea.isEditable()) return;
Sketch sketch = editor.getSketch();
int code = event.getKeyCode();
// Navigation..
if ((event.getModifiers() & CTRL) == CTRL && code == KeyEvent.VK_TAB) {
sketch.handleNextCode();
}
// Navigation..
// FIXME: not working on LINUX !!!
if (((event.getModifiers() & CTRL_SHIFT) == CTRL_SHIFT)) {
if(code == KeyEvent.VK_TAB)
sketch.handlePrevCode();
}
// Navigation..
if ((event.getModifiers() & CTRL_ALT) == CTRL_ALT) {
if (code == KeyEvent.VK_LEFT) {
sketch.handlePrevCode();
return true;
} else if (code == KeyEvent.VK_RIGHT) {
sketch.handleNextCode();
return true;
}
}
if ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
// Consume ctrl-m(carriage return) keypresses
if (code == KeyEvent.VK_M) {
event.consume(); // does nothing
return false;
}
// The char is not control code when CTRL key pressed? It should be a shortcut.
if (!Character.isISOControl(c)) {
return false;
}
}
if ((event.getModifiers() & KeyEvent.META_MASK) != 0) {
//event.consume(); // does nothing
return false;
}
// TODO i don't like these accessors. clean em up later.
if (!editor.getSketch().isModified()) {
if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_TAB) ||
(code == KeyEvent.VK_ENTER) || ((c >= 32) && (c < 128))) {
sketch.setModified(true);
}
}
if ((code == KeyEvent.VK_UP) &&
((event.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
// back up to the last empty line
char contents[] = textarea.getText().toCharArray();
//int origIndex = textarea.getCaretPosition() - 1;
int caretIndex = textarea.getCaretPosition();
int index = calcLineStart(caretIndex - 1, contents);
//System.out.println("line start " + (int) contents[index]);
index -= 2; // step over the newline
//System.out.println((int) contents[index]);
boolean onlySpaces = true;
while (index > 0) {
if (contents[index] == 10) {
if (onlySpaces) {
index++;
break;
} else {
onlySpaces = true; // reset
}
} else if (contents[index] != ' ') {
onlySpaces = false;
}
index--;
}
// if the first char, index will be -2
if (index < 0) index = 0;
if ((event.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
textarea.setCaretPosition(index);
}
event.consume();
return true;
} else if ((code == KeyEvent.VK_DOWN) &&
((event.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
char contents[] = textarea.getText().toCharArray();
int caretIndex = textarea.getCaretPosition();
int index = caretIndex;
int lineStart = 0;
boolean onlySpaces = false; // don't count this line
while (index < contents.length) {
if (contents[index] == 10) {
if (onlySpaces) {
index = lineStart; // this is it
break;
} else {
lineStart = index + 1;
onlySpaces = true; // reset
}
} else if (contents[index] != ' ') {
onlySpaces = false;
}
index++;
}
// if the first char, index will be -2
//if (index < 0) index = 0;
//textarea.setSelectionStart(index);
//textarea.setSelectionEnd(index);
if ((event.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
textarea.setCaretPosition(index);
}
event.consume();
return true;
}
switch ((int) c) {
case 9: // TAB
if (textarea.isSelectionActive()) {
boolean outdent = (event.getModifiers() & KeyEvent.SHIFT_MASK) != 0;
editor.handleIndentOutdent(!outdent);
} else if (tabsExpand) { // expand tabs
textarea.setSelectedText(tabString);
event.consume();
return true;
} else if (tabsIndent) {
// this code is incomplete
// if this brace is the only thing on the line, outdent
//char contents[] = getCleanedContents();
char contents[] = textarea.getText().toCharArray();
// index to the character to the left of the caret
int prevCharIndex = textarea.getCaretPosition() - 1;
// now find the start of this line
int lineStart = calcLineStart(prevCharIndex, contents);
int lineEnd = lineStart;
while ((lineEnd < contents.length - 1) &&
(contents[lineEnd] != 10)) {
lineEnd++;
}
// get the number of braces, to determine whether this is an indent
int braceBalance = 0;
int index = lineStart;
while ((index < contents.length) &&
(contents[index] != 10)) {
if (contents[index] == '{') {
braceBalance++;
} else if (contents[index] == '}') {
braceBalance--;
}
index++;
}
// if it's a starting indent, need to ignore it, so lineStart
// will be the counting point. but if there's a closing indent,
// then the lineEnd should be used.
int where = (braceBalance > 0) ? lineStart : lineEnd;
int indent = calcBraceIndent(where, contents);
if (indent == -1) {
// no braces to speak of, do nothing
indent = 0;
} else {
indent += tabSize;
}
// and the number of spaces it has
int spaceCount = calcSpaceCount(prevCharIndex, contents);
textarea.setSelectionStart(lineStart);
textarea.setSelectionEnd(lineStart + spaceCount);
textarea.setSelectedText(Editor.EMPTY.substring(0, indent));
event.consume();
return true;
}
break;
case 10: // auto-indent
case 13:
if (autoIndent) {
char contents[] = textarea.getText().toCharArray();
// this is the previous character
// (i.e. when you hit return, it'll be the last character
// just before where the newline will be inserted)
int origIndex = textarea.getCaretPosition() - 1;
// NOTE all this cursing about CRLF stuff is probably moot
// NOTE since the switch to JEditTextArea, which seems to use
// NOTE only LFs internally (thank god). disabling for 0099.
// walk through the array to the current caret position,
// and count how many weirdo windows line endings there are,
// which would be throwing off the caret position number
/*
int offset = 0;
int realIndex = origIndex;
for (int i = 0; i < realIndex-1; i++) {
if ((contents[i] == 13) && (contents[i+1] == 10)) {
offset++;
realIndex++;
}
}
// back up until \r \r\n or \n.. @#($* cross platform
//System.out.println(origIndex + " offset = " + offset);
origIndex += offset; // ARGH!#(* WINDOWS#@($*
*/
// if the previous thing is a brace (whether prev line or
// up farther) then the correct indent is the number of spaces
// on that line + 'indent'.
// if the previous line is not a brace, then just use the
// identical indentation to the previous line
// calculate the amount of indent on the previous line
// this will be used *only if the prev line is not an indent*
int spaceCount = calcSpaceCount(origIndex, contents);
// If the last character was a left curly brace, then indent.
// For 0122, walk backwards a bit to make sure that the there
// isn't a curly brace several spaces (or lines) back. Also
// moved this before calculating extraCount, since it'll affect
// that as well.
int index2 = origIndex;
while ((index2 >= 0) &&
Character.isWhitespace(contents[index2])) {
index2--;
}
if (index2 != -1) {
// still won't catch a case where prev stuff is a comment
if (contents[index2] == '{') {
// intermediate lines be damned,
// use the indent for this line instead
spaceCount = calcSpaceCount(index2, contents);
spaceCount += tabSize;
}
}
//System.out.println("spaceCount should be " + spaceCount);
// now before inserting this many spaces, walk forward from
// the caret position and count the number of spaces,
// so that the number of spaces aren't duplicated again
int index = origIndex + 1;
int extraCount = 0;
while ((index < contents.length) &&
(contents[index] == ' ')) {
//spaceCount--;
extraCount++;
index++;
}
int braceCount = 0;
while ((index < contents.length) && (contents[index] != '\n')) {
if (contents[index] == '}') {
braceCount++;
}
index++;
}
// hitting return on a line with spaces *after* the caret
// can cause trouble. for 0099, was ignoring the case, but this is
// annoying, so in 0122 we're trying to fix that.
/*
if (spaceCount - extraCount > 0) {
spaceCount -= extraCount;
}
*/
spaceCount -= extraCount;
//if (spaceCount < 0) spaceCount = 0;
//System.out.println("extraCount is " + extraCount);
// now, check to see if the current line contains a } and if so,
// outdent again by indent
//if (braceCount > 0) {
//spaceCount -= 2;
//}
if (spaceCount < 0) {
// for rev 0122, actually delete extra space
//textarea.setSelectionStart(origIndex + 1);
textarea.setSelectionEnd(textarea.getSelectionStop() - spaceCount);
textarea.setSelectedText("\n");
} else {
String insertion = "\n" + Editor.EMPTY.substring(0, spaceCount);
textarea.setSelectedText(insertion);
}
// not gonna bother handling more than one brace
if (braceCount > 0) {
int sel = textarea.getSelectionStart();
// sel - tabSize will be -1 if start/end parens on the same line
// http://dev.processing.org/bugs/show_bug.cgi?id=484
if (sel - tabSize >= 0) {
textarea.select(sel - tabSize, sel);
String s = Editor.EMPTY.substring(0, tabSize);
// if these are spaces that we can delete
if (textarea.getSelectedText().equals(s)) {
textarea.setSelectedText("");
} else {
textarea.select(sel, sel);
}
}
}
} else {
// Enter/Return was being consumed by somehow even if false
// was returned, so this is a band-aid to simply fire the event again.
// http://dev.processing.org/bugs/show_bug.cgi?id=1073
textarea.setSelectedText(String.valueOf(c));
}
// mark this event as already handled (all but ignored)
event.consume();
return true;
case '}':
if (autoIndent) {
// first remove anything that was there (in case this multiple
// characters are selected, so that it's not in the way of the
// spaces for the auto-indent
if (textarea.getSelectionStart() != textarea.getSelectionStop()) {
textarea.setSelectedText("");
}
// if this brace is the only thing on the line, outdent
char contents[] = textarea.getText().toCharArray();
// index to the character to the left of the caret
int prevCharIndex = textarea.getCaretPosition() - 1;
// backup from the current caret position to the last newline,
// checking for anything besides whitespace along the way.
// if there's something besides whitespace, exit without
// messing any sort of indenting.
int index = prevCharIndex;
boolean finished = false;
while ((index != -1) && (!finished)) {
if (contents[index] == 10) {
finished = true;
index++;
} else if (contents[index] != ' ') {
// don't do anything, this line has other stuff on it
return false;
} else {
index--;
}
}
if (!finished) return false; // brace with no start
int lineStartIndex = index;
int pairedSpaceCount = calcBraceIndent(prevCharIndex, contents); //, 1);
if (pairedSpaceCount == -1) return false;
textarea.setSelectionStart(lineStartIndex);
textarea.setSelectedText(Editor.EMPTY.substring(0, pairedSpaceCount));
// mark this event as already handled
event.consume();
return true;
}
break;
}
return false;
}
// public boolean keyReleased(KeyEvent event) {
// if (code == KeyEvent.VK_SHIFT) {
// editor.toolbar.setShiftPressed(false);
// if (event.isAltDown() && code == KeyEvent.VK_T) {
// int line = textarea.getCaretLineNumber();
// textarea.setActiveLineRange(line, line + 3);
// }
// }
public boolean keyTyped(KeyEvent event) {
char c = event.getKeyChar();
if ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
// The char is not control code when CTRL key pressed? It should be a shortcut.
if (!Character.isISOControl(c)) {
event.consume();
return true;
}
}
return false;
}
/**
* Return the index for the first character on this line.
*/
protected int calcLineStart(int index, char contents[]) {
// backup from the current caret position to the last newline,
// so that we can figure out how far this line was indented
/*int spaceCount = 0;*/
boolean finished = false;
while ((index != -1) && (!finished)) {
if ((contents[index] == 10) ||
(contents[index] == 13)) {
finished = true;
//index++; // maybe ?
} else {
index--; // new
}
}
// add one because index is either -1 (the start of the document)
// or it's the newline character for the previous line
return index + 1;
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
/**
* Calculate the number of spaces on this line.
*/
protected int calcSpaceCount(int index, char contents[]) {
index = calcLineStart(index, contents);
int spaceCount = 0;
// now walk forward and figure out how many spaces there are
while ((index < contents.length) && (index >= 0) &&
(contents[index++] == ' ')) {
spaceCount++;
}
return spaceCount;
}
/**
* Walk back from 'index' until the brace that seems to be
* the beginning of the current block, and return the number of
* spaces found on that line.
*/
protected int calcBraceIndent(int index, char contents[]) {
// now that we know things are ok to be indented, walk
// backwards to the last { to see how far its line is indented.
// this isn't perfect cuz it'll pick up commented areas,
// but that's not really a big deal and can be fixed when
// this is all given a more complete (proper) solution.
int braceDepth = 1;
boolean finished = false;
while ((index != -1) && (!finished)) {
if (contents[index] == '}') {
// aww crap, this means we're one deeper
// and will have to find one more extra {
braceDepth++;
//if (braceDepth == 0) {
//finished = true;
//}
index--;
} else if (contents[index] == '{') {
braceDepth--;
if (braceDepth == 0) {
finished = true;
}
index--;
} else {
index--;
}
}
// never found a proper brace, be safe and don't do anything
if (!finished) return -1;
// check how many spaces on the line with the matching open brace
//int pairedSpaceCount = calcSpaceCount(index, contents);
//System.out.println(pairedSpaceCount);
return calcSpaceCount(index, contents);
}
/**
* Get the character array and blank out the commented areas.
* This hasn't yet been tested, the plan was to make auto-indent
* less gullible (it gets fooled by braces that are commented out).
*/
protected char[] getCleanedContents() {
char c[] = textarea.getText().toCharArray();
int index = 0;
while (index < c.length - 1) {
if ((c[index] == '/') && (c[index+1] == '*')) {
c[index++] = 0;
c[index++] = 0;
while ((index < c.length - 1) &&
!((c[index] == '*') && (c[index+1] == '/'))) {
c[index++] = 0;
}
} else if ((c[index] == '/') && (c[index+1] == '/')) {
// clear out until the end of the line
while ((index < c.length) && (c[index] != 10)) {
c[index++] = 0;
}
if (index != c.length) {
index++; // skip over the newline
}
}
}
return c;
}
/*
protected char[] getCleanedContents() {
char c[] = textarea.getText().toCharArray();
boolean insideMulti; // multi-line comment
boolean insideSingle; // single line double slash
//for (int i = 0; i < c.length - 1; i++) {
int index = 0;
while (index < c.length - 1) {
if (insideMulti && (c[index] == '*') && (c[index+1] == '/')) {
insideMulti = false;
index += 2;
} else if ((c[index] == '/') && (c[index+1] == '*')) {
insideMulti = true;
index += 2;
} else if ((c[index] == '/') && (c[index+1] == '/')) {
// clear out until the end of the line
while (c[index] != 10) {
c[index++] = 0;
}
index++;
}
}
}
*/
}
}

View File

@@ -219,7 +219,7 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ {
public void unprogress()
{
if (Preferences.getBoolean("editor.beep.compile")) {
if (PreferencesData.getBoolean("editor.beep.compile")) {
Toolkit.getDefaultToolkit().beep();
}
if (progressBar == null) return;
@@ -464,10 +464,10 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ {
copyErrorButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String message = "";
message += _("Arduino: ") + BaseNoGui.VERSION_NAME + " (" + System.getProperty("os.name") + "), ";
message += _("Arduino: ") + BaseNoGui.VERSION_NAME_LONG + " (" + System.getProperty("os.name") + "), ";
message += _("Board: ") + "\"" + Base.getBoardPreferences().get("name") + "\"\n\n";
message += editor.console.consoleTextPane.getText().trim();
if ((Preferences.getBoolean("build.verbose")) == false) {
if ((PreferencesData.getBoolean("build.verbose")) == false) {
message += "\n\n";
message += " " + _("This report would have more information with") + "\n";
message += " \"" + _("Show verbose output during compilation") + "\"\n";

View File

@@ -321,7 +321,7 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key
switch (sel) {
case RUN:
editor.handleRun(false);
editor.handleRun(false, editor.presentHandler, editor.runHandler);
break;
// case STOP:

View File

@@ -2,31 +2,36 @@ package processing.app;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
@SuppressWarnings("serial")
public class LastUndoableEditAwareUndoManager extends UndoManager {
import org.fife.ui.rtextarea.RUndoManager;
private UndoableEdit lastUndoableEdit;
import processing.app.syntax.SketchTextArea;
public LastUndoableEditAwareUndoManager() {
this.lastUndoableEdit = null;
public class LastUndoableEditAwareUndoManager extends RUndoManager {
private Editor editor;
public LastUndoableEditAwareUndoManager(SketchTextArea textarea, Editor editor) {
super(textarea);
this.editor = editor;
}
@Override
public synchronized void undo() throws CannotUndoException {
lastUndoableEdit = super.editToBeUndone();
super.undo();
}
@Override
public synchronized void redo() throws CannotRedoException {
lastUndoableEdit = super.editToBeRedone();
super.redo();
}
public UndoableEdit getLastUndoableEdit() {
return lastUndoableEdit;
@Override
public void updateActions() {
super.updateActions();
editor.undoAction.updateUndoState();
editor.redoAction.updateRedoState();
}
}

View File

@@ -21,58 +21,30 @@
package processing.app;
import static processing.app.I18n._;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.SystemColor;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import processing.app.helpers.FileUtils;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesHelper;
import processing.app.helpers.PreferencesMap;
import processing.app.legacy.PApplet;
import java.awt.*;
import java.io.File;
/**
* Storage class for user preferences and environment settings.
* <P>
* <p/>
* This class no longer uses the Properties class, since
* properties files are iso8859-1, which is highly likely to
* be a problem when trying to save sketch folders and locations.
* <p>
* <p/>
* The GUI portion in here is really ugly, as it uses exact layout. This was
* done in frustration one evening (and pre-Swing), but that's long since past,
* and it should all be moved to a proper swing layout like BoxLayout.
* <p>
* <p/>
* This is very poorly put together, that the preferences panel and the actual
* preferences i/o is part of the same code. But there hasn't yet been a
* compelling reason to bother with the separation aside from concern about
* being lectured by strangers who feel that it doesn't look like what they
* learned in CS class.
* <p>
* <p/>
* Would also be possible to change this to use the Java Preferences API.
* Some useful articles
* <a href="http://www.onjava.com/pub/a/onjava/synd/2001/10/17/j2se.html">here</a> and
@@ -85,114 +57,12 @@ import processing.app.legacy.PApplet;
*/
public class Preferences {
static final String PREFS_FILE = PreferencesData.PREFS_FILE;
class Language {
Language(String _name, String _originalName, String _isoCode) {
name = _name;
originalName = _originalName;
isoCode = _isoCode;
}
public String toString() {
if (originalName.length() == 0)
return name;
return originalName + " (" + name + ")";
};
String name;
String originalName;
String isoCode;
}
Language languages[] = {
new Language(_("System Default"), "", ""),
new Language(_("Albanian"), "shqip", "sq"),
new Language(_("Arabic"), "العربية", "ar"),
new Language(_("Aragonese"), "Aragonés", "an"),
new Language(_("Belarusian"), "Беларуская мова", "be"),
new Language(_("Bulgarian"), "български", "bg"),
new Language(_("Catalan"), "Català", "ca"),
new Language(_("Chinese Simplified"), "简体中文", "zh_CN"),
new Language(_("Chinese Traditional"), "繁體中文", "zh_TW"),
new Language(_("Croatian"), "Hrvatski", "hr_HR"),
new Language(_("Czech (Czech Republic)"), "český (Czech Republic)", "cs_CZ"),
new Language(_("Danish (Denmark)"), "Dansk (Denmark)", "da_DK"),
new Language(_("Dutch"), "Nederlands", "nl"),
new Language(_("English"), "English", "en"),
new Language(_("English (United Kingdom)"), "English (United Kingdom)", "en_GB"),
new Language(_("Estonian"), "Eesti", "et"),
new Language(_("Estonian (Estonia)"), "Eesti keel", "et_EE"),
new Language(_("Filipino"), "Pilipino", "fil"),
new Language(_("Finnish"), "Suomi", "fi"),
new Language(_("French"), "Français", "fr"),
new Language(_("Canadian French"), "Canadienne-français", "fr_CA"),
new Language(_("Galician"), "Galego", "gl"),
new Language(_("Georgian"), "საქართველოს", "ka_GE"),
new Language(_("German"), "Deutsch", "de_DE"),
new Language(_("Greek"), "ελληνικά", "el_GR"),
new Language(_("Hebrew"), "עברית", "he"),
new Language(_("Hindi"), "हिंदी", "hi"),
new Language(_("Hungarian"), "Magyar", "hu"),
new Language(_("Indonesian"), "Bahasa Indonesia", "id"),
new Language(_("Italian"), "Italiano", "it_IT"),
new Language(_("Japanese"), "日本語", "ja_JP"),
new Language(_("Korean"), "한국어", "ko_KR"),
new Language(_("Latvian"), "Latviešu", "lv_LV"),
new Language(_("Lithuaninan"), "Lietuvių Kalba", "lt_LT"),
new Language(_("Norwegian Bokmål"), "Norsk bokmål", "nb_NO"),
new Language(_("Persian"), "فارسی", "fa"),
new Language(_("Polish"), "Język Polski", "pl"),
new Language(_("Portuguese (Brazil)"), "Português (Brazil)", "pt_BR"),
new Language(_("Portuguese (Portugal)"), "Português (Portugal)", "pt_PT"),
new Language(_("Romanian"), "Română", "ro"),
new Language(_("Russian"), "Русский", "ru"),
new Language(_("Slovenian"), "Slovenščina", "sl_SI"),
new Language(_("Spanish"), "Español", "es"),
new Language(_("Swedish"), "Svenska", "sv"),
new Language(_("Tamil"), "தமிழ்", "ta"),
new Language(_("Turkish"), "Türk", "tr"),
new Language(_("Ukrainian"), "Український", "uk"),
new Language(_("Vietnamese"), "Tiếng Việt", "vi"),
};
// Incomplete languages
Language missingLanguages[] = {
new Language(_("Afrikaans"), "Afrikaans", "af"),
new Language(_("Armenian"), "Հայերեն", "hy"),
new Language(_("Asturian"), "Asturianu", "ast"),
new Language(_("Basque"), "Euskara", "eu"),
new Language(_("Bengali (India)"), "বাংলা (India)", "bn_IN"),
new Language(_("Bosnian"), "Bosanski", "bs"),
new Language(_("Burmese (Myanmar)"), "ဗမာစကား", "my_MM"),
new Language(_("Chinese (China)"), "", "zh_CN"),
new Language(_("Chinese (Hong Kong)"), "", "zh_HK"),
new Language(_("Chinese (Taiwan)"), "", "zh_TW"),
new Language(_("Chinese (Taiwan) (Big5)"), "", "zh_TW.Big5"),
new Language(_("Czech"), "český", "cs"),
new Language(_("Danish"), "Dansk", "da"),
new Language(_("Dutch (Netherlands)"), "Nederlands", "nl_NL"),
new Language(_("Galician (Spain)"), "Galego (Spain)", "gl_ES"),
new Language(_("Nepali"), "नेपाली", "ne"),
new Language(_("N'Ko"), "ߒߞߏ", "nqo"),
new Language(_("Marathi"), "मराठी", "mr"),
new Language(_("Malay (Malaysia)"), "بهاس ملايو (Malaysia)", "ms_MY"),
new Language(_("Norwegian"), "Norsk", "no"),
new Language(_("Norwegian Nynorsk"), "Norsk Nynorsk", "nn"),
new Language(_("Portugese"), "Português", "pt"),
new Language(_("Persian (Iran)"), "فارسی (Iran)", "fa_IR"),
new Language(_("Slovak"), "Slovenčina", "sk"),
new Language(_("Swahili"), "كِسوَهِل", "sw"),
new Language(_("Talossan"), "Talossan", "tzl"),
new Language(_("Urdu (Pakistan)"), "اردو (Pakistan)", "ur_PK"),
new Language(_("Western Frisian"), "Western Frisian", "fy"),
};
/**
* Standardized width for buttons. Mac OS X 10.3 wants 70 as its default,
* Windows XP needs 66, and my Ubuntu machine needs 80+, so 80 seems proper.
*/
static public int BUTTON_WIDTH = 80;
static public int BUTTON_WIDTH = 80;
/**
* Standardized button height. Mac OS X 10.3 (Java 1.4) wants 29,
@@ -205,549 +75,85 @@ public class Preferences {
// value for the size bars, buttons, etc
static final int GRID_SIZE = 33;
static final int GRID_SIZE = 33;
// indents and spacing standards. these probably need to be modified
// per platform as well, since macosx is so huge, windows is smaller,
// and linux is all over the map
static final int GUI_BIG = 13;
static final int GUI_BETWEEN = 10;
static final int GUI_SMALL = 6;
// gui elements
JFrame dialog;
int wide, high;
JTextField sketchbookLocationField;
JCheckBox exportSeparateBox;
JCheckBox verboseCompilationBox;
JCheckBox verboseUploadBox;
JCheckBox displayLineNumbersBox;
JCheckBox verifyUploadBox;
JCheckBox externalEditorBox;
JCheckBox memoryOverrideBox;
JTextField memoryField;
JCheckBox checkUpdatesBox;
JTextField fontSizeField;
JCheckBox updateExtensionBox;
JCheckBox autoAssociateBox;
JComboBox comboLanguage;
JCheckBox saveVerifyUploadBox;
// the calling editor, so updates can be applied
Editor editor;
static final int GUI_SMALL = 6;
static protected void init(File file) {
PreferencesData.init(file);
PreferencesData.init(file);
// other things that have to be set explicitly for the defaults
PreferencesHelper.putColor(PreferencesData.prefs, "run.window.bgcolor", SystemColor.control);
}
public Preferences() {
// setup dialog for the prefs
//dialog = new JDialog(editor, "Preferences", true);
dialog = new JFrame(_("Preferences"));
dialog.setResizable(false);
Container pain = dialog.getContentPane();
pain.setLayout(null);
int top = GUI_BIG;
int left = GUI_BIG;
int right = 0;
JLabel label;
JButton button; //, button2;
//JComboBox combo;
Dimension d, d2; //, d3;
int h, vmax;
// Sketchbook location:
// [...............................] [ Browse ]
label = new JLabel(_("Sketchbook location:"));
pain.add(label);
d = label.getPreferredSize();
label.setBounds(left, top, d.width, d.height);
top += d.height; // + GUI_SMALL;
sketchbookLocationField = new JTextField(40);
pain.add(sketchbookLocationField);
d = sketchbookLocationField.getPreferredSize();
button = new JButton(I18n.PROMPT_BROWSE);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
File dflt = new File(sketchbookLocationField.getText());
File file =
Base.selectFolder(_("Select new sketchbook location"), dflt, dialog);
if (file != null) {
String path = file.getAbsolutePath();
if (Base.getPortableFolder() != null) {
path = FileUtils.relativePath(Base.getPortableFolder().toString(), path);
if (path == null) {
path = Base.getPortableSketchbookFolder();
}
}
sketchbookLocationField.setText(path);
}
}
});
pain.add(button);
d2 = button.getPreferredSize();
// take max height of all components to vertically align em
vmax = Math.max(d.height, d2.height);
sketchbookLocationField.setBounds(left, top + (vmax-d.height)/2,
d.width, d.height);
h = left + d.width + GUI_SMALL;
button.setBounds(h, top + (vmax-d2.height)/2,
d2.width, d2.height);
right = Math.max(right, h + d2.width + GUI_BIG);
top += vmax + GUI_BETWEEN;
// Preferred language: [ ] (requires restart of Arduino)
Container box = Box.createHorizontalBox();
label = new JLabel(_("Editor language: "));
box.add(label);
comboLanguage = new JComboBox(languages);
String currentLanguage = PreferencesData.get("editor.languages.current");
for (Language language : languages) {
if (language.isoCode.equals(currentLanguage))
comboLanguage.setSelectedItem(language);
}
box.add(comboLanguage);
label = new JLabel(_(" (requires restart of Arduino)"));
box.add(label);
pain.add(box);
d = box.getPreferredSize();
box.setForeground(Color.gray);
box.setBounds(left, top, d.width, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// Editor font size [ ]
box = Box.createHorizontalBox();
label = new JLabel(_("Editor font size: "));
box.add(label);
fontSizeField = new JTextField(4);
box.add(fontSizeField);
label = new JLabel(_(" (requires restart of Arduino)"));
box.add(label);
pain.add(box);
d = box.getPreferredSize();
box.setBounds(left, top, d.width, d.height);
Font editorFont = Preferences.getFont("editor.font");
fontSizeField.setText(String.valueOf(editorFont.getSize()));
top += d.height + GUI_BETWEEN;
// Show verbose output during: [ ] compilation [ ] upload
box = Box.createHorizontalBox();
label = new JLabel(_("Show verbose output during: "));
box.add(label);
verboseCompilationBox = new JCheckBox(_("compilation "));
box.add(verboseCompilationBox);
verboseUploadBox = new JCheckBox(_("upload"));
box.add(verboseUploadBox);
pain.add(box);
d = box.getPreferredSize();
box.setBounds(left, top, d.width, d.height);
top += d.height + GUI_BETWEEN;
// [ ] Display line numbers
displayLineNumbersBox = new JCheckBox(_("Display line numbers"));
pain.add(displayLineNumbersBox);
d = displayLineNumbersBox.getPreferredSize();
displayLineNumbersBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// [ ] Verify code after upload
verifyUploadBox = new JCheckBox(_("Verify code after upload"));
pain.add(verifyUploadBox);
d = verifyUploadBox.getPreferredSize();
verifyUploadBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// [ ] Use external editor
externalEditorBox = new JCheckBox(_("Use external editor"));
pain.add(externalEditorBox);
d = externalEditorBox.getPreferredSize();
externalEditorBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// [ ] Check for updates on startup
checkUpdatesBox = new JCheckBox(_("Check for updates on startup"));
pain.add(checkUpdatesBox);
d = checkUpdatesBox.getPreferredSize();
checkUpdatesBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// [ ] Update sketch files to new extension on save (.pde -> .ino)
updateExtensionBox = new JCheckBox(_("Update sketch files to new extension on save (.pde -> .ino)"));
pain.add(updateExtensionBox);
d = updateExtensionBox.getPreferredSize();
updateExtensionBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// [ ] Automatically associate .pde files with Processing
if (OSUtils.isWindows()) {
autoAssociateBox =
new JCheckBox(_("Automatically associate .ino files with Arduino"));
pain.add(autoAssociateBox);
d = autoAssociateBox.getPreferredSize();
autoAssociateBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// If using portable mode, it's bad manner to change PC setting.
if (Base.getPortableFolder() != null)
autoAssociateBox.setEnabled(false);
}
// [ ] save when verifying or uploading
saveVerifyUploadBox = new JCheckBox(_("Save when verifying or uploading"));
pain.add(saveVerifyUploadBox);
d = saveVerifyUploadBox.getPreferredSize();
saveVerifyUploadBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
// More preferences are in the ...
label = new JLabel(_("More preferences can be edited directly in the file"));
pain.add(label);
d = label.getPreferredSize();
label.setForeground(Color.gray);
label.setBounds(left, top, d.width, d.height);
right = Math.max(right, left + d.width);
top += d.height; // + GUI_SMALL;
label = new JLabel(PreferencesData.preferencesFile.getAbsolutePath());
final JLabel clickable = label;
label.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
Base.openFolder(PreferencesData.preferencesFile.getParentFile());
}
public void mouseEntered(MouseEvent e) {
clickable.setForeground(new Color(0, 0, 140));
}
public void mouseExited(MouseEvent e) {
clickable.setForeground(Color.BLACK);
}
});
pain.add(label);
d = label.getPreferredSize();
label.setBounds(left, top, d.width, d.height);
right = Math.max(right, left + d.width);
top += d.height;
label = new JLabel(_("(edit only when Arduino is not running)"));
pain.add(label);
d = label.getPreferredSize();
label.setForeground(Color.gray);
label.setBounds(left, top, d.width, d.height);
right = Math.max(right, left + d.width);
top += d.height; // + GUI_SMALL;
// [ OK ] [ Cancel ] maybe these should be next to the message?
button = new JButton(I18n.PROMPT_OK);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
applyFrame();
disposeFrame();
}
});
pain.add(button);
d2 = button.getPreferredSize();
BUTTON_HEIGHT = d2.height;
h = right - (BUTTON_WIDTH + GUI_SMALL + BUTTON_WIDTH);
button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
h += BUTTON_WIDTH + GUI_SMALL;
button = new JButton(I18n.PROMPT_CANCEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
disposeFrame();
}
});
pain.add(button);
button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
top += BUTTON_HEIGHT + GUI_BETWEEN;
// finish up
wide = right + GUI_BIG;
high = top + GUI_SMALL;
// closing the window is same as hitting cancel button
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
disposeFrame();
}
});
ActionListener disposer = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
disposeFrame();
}
};
Base.registerWindowCloseKeys(dialog.getRootPane(), disposer);
Base.setIcon(dialog);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
dialog.setLocation((screen.width - wide) / 2,
(screen.height - high) / 2);
dialog.pack(); // get insets
Insets insets = dialog.getInsets();
dialog.setSize(wide + insets.left + insets.right,
high + insets.top + insets.bottom);
// handle window closing commands for ctrl/cmd-W or hitting ESC.
pain.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
//System.out.println(e);
KeyStroke wc = Editor.WINDOW_CLOSE_KEYSTROKE;
if ((e.getKeyCode() == KeyEvent.VK_ESCAPE) ||
(KeyStroke.getKeyStrokeForEvent(e).equals(wc))) {
disposeFrame();
}
}
});
}
// .................................................................
/**
* Close the window after an OK or Cancel.
*/
protected void disposeFrame() {
dialog.dispose();
}
/**
* Change internal settings based on what was chosen in the prefs,
* then send a message to the editor saying that it's time to do the same.
*/
protected void applyFrame() {
// put each of the settings into the table
PreferencesData.setBoolean("build.verbose", verboseCompilationBox.isSelected());
PreferencesData.setBoolean("upload.verbose", verboseUploadBox.isSelected());
PreferencesData.setBoolean("editor.linenumbers", displayLineNumbersBox.isSelected());
PreferencesData.setBoolean("upload.verify", verifyUploadBox.isSelected());
PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
// setBoolean("sketchbook.closing_last_window_quits",
// closingLastQuitsBox.isSelected());
//setBoolean("sketchbook.prompt", sketchPromptBox.isSelected());
//setBoolean("sketchbook.auto_clean", sketchCleanBox.isSelected());
// if the sketchbook path has changed, rebuild the menus
String oldPath = PreferencesData.get("sketchbook.path");
String newPath = sketchbookLocationField.getText();
if (newPath.isEmpty()) {
if (Base.getPortableFolder() == null)
newPath = editor.base.getDefaultSketchbookFolderOrPromptForIt().toString();
else
newPath = Base.getPortableSketchbookFolder();
}
if (!newPath.equals(oldPath)) {
editor.base.rebuildSketchbookMenus();
PreferencesData.set("sketchbook.path", newPath);
}
PreferencesData.setBoolean("editor.external", externalEditorBox.isSelected());
PreferencesData.setBoolean("update.check", checkUpdatesBox.isSelected());
PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
/*
// was gonna use this to check memory settings,
// but it quickly gets much too messy
if (getBoolean("run.options.memory")) {
Process process = Runtime.getRuntime().exec(new String[] {
"java", "-Xms" + memoryMin + "m", "-Xmx" + memoryMax + "m"
});
processInput = new SystemOutSiphon(process.getInputStream());
processError = new MessageSiphon(process.getErrorStream(), this);
}
*/
String newSizeText = fontSizeField.getText();
try {
int newSize = Integer.parseInt(newSizeText.trim());
String pieces[] = PApplet.split(PreferencesData.get("editor.font"), ',');
pieces[2] = String.valueOf(newSize);
PreferencesData.set("editor.font", PApplet.join(pieces, ','));
} catch (Exception e) {
System.err.println(I18n.format(_("ignoring invalid font size {0}"), newSizeText));
}
if (autoAssociateBox != null) {
PreferencesData.setBoolean("platform.auto_file_type_associations",
autoAssociateBox.isSelected());
}
PreferencesData.setBoolean("editor.update_extension", updateExtensionBox.isSelected());
// adds the selected language to the preferences file
Language newLanguage = (Language) comboLanguage.getSelectedItem();
PreferencesData.set("editor.languages.current", newLanguage.isoCode);
editor.applyPreferences();
}
protected void showFrame(Editor editor) {
this.editor = editor;
// set all settings entry boxes to their actual status
verboseCompilationBox.setSelected(PreferencesData.getBoolean("build.verbose"));
verboseUploadBox.setSelected(PreferencesData.getBoolean("upload.verbose"));
displayLineNumbersBox.setSelected(PreferencesData.getBoolean("editor.linenumbers"));
verifyUploadBox.setSelected(PreferencesData.getBoolean("upload.verify"));
//closingLastQuitsBox.
// setSelected(getBoolean("sketchbook.closing_last_window_quits"));
//sketchPromptBox.
// setSelected(getBoolean("sketchbook.prompt"));
//sketchCleanBox.
// setSelected(getBoolean("sketchbook.auto_clean"));
sketchbookLocationField.
setText(PreferencesData.get("sketchbook.path"));
externalEditorBox.
setSelected(PreferencesData.getBoolean("editor.external"));
checkUpdatesBox.
setSelected(PreferencesData.getBoolean("update.check"));
saveVerifyUploadBox.
setSelected(PreferencesData.getBoolean("editor.save_on_verify"));
if (autoAssociateBox != null) {
autoAssociateBox.
setSelected(PreferencesData.getBoolean("platform.auto_file_type_associations"));
}
updateExtensionBox.setSelected(PreferencesData.get("editor.update_extension") == null ||
PreferencesData.getBoolean("editor.update_extension"));
dialog.setVisible(true);
}
static protected void save() {
@Deprecated
protected static void save() {
PreferencesData.save();
}
// .................................................................
static public String get(String attribute) {
@Deprecated
public static String get(String attribute) {
return PreferencesData.get(attribute);
}
static public String get(String attribute, String defaultValue) {
@Deprecated
public static String get(String attribute, String defaultValue) {
return PreferencesData.get(attribute, defaultValue);
}
@Deprecated
public static boolean has(String key) {
return PreferencesData.has(key);
}
@Deprecated
public static void remove(String key) {
PreferencesData.remove(key);
}
static public void set(String attribute, String value) {
@Deprecated
public static void set(String attribute, String value) {
PreferencesData.set(attribute, value);
}
static public boolean getBoolean(String attribute) {
@Deprecated
public static boolean getBoolean(String attribute) {
return PreferencesData.getBoolean(attribute);
}
static public void setBoolean(String attribute, boolean value) {
@Deprecated
public static void setBoolean(String attribute, boolean value) {
PreferencesData.setBoolean(attribute, value);
}
static public int getInteger(String attribute) {
@Deprecated
public static int getInteger(String attribute) {
return PreferencesData.getInteger(attribute);
}
@Deprecated
public static int getInteger(String attribute, int defaultValue) {
return PreferencesData.getInteger(attribute, defaultValue);
}
static public void setInteger(String key, int value) {
@Deprecated
public static void setInteger(String key, int value) {
PreferencesData.setInteger(key, value);
}
static public Font getFont(String attr) {
Font font = PreferencesHelper.getFont(PreferencesData.prefs, attr);
if (font == null) {
String value = PreferencesData.defaults.get(attr);
PreferencesData.prefs.put(attr, value);
font = PreferencesHelper.getFont(PreferencesData.prefs, attr);
}
return font;
}
// get a copy of the Preferences
static public PreferencesMap getMap()
{
@Deprecated
public static PreferencesMap getMap() {
return PreferencesData.getMap();
}
// Decide wether changed preferences will be saved. When value is
// false, Preferences.save becomes a no-op.
static public void setDoSave(boolean value)
{
@Deprecated
public static void setDoSave(boolean value) {
PreferencesData.setDoSave(value);
}
}

View File

@@ -74,14 +74,14 @@ public class PresentMode {
public void actionPerformed(ActionEvent e) {
int index = selector.getSelectedIndex();
//device = devices[index];
Preferences.setInteger("run.present.display", index + 1);
PreferencesData.setInteger("run.present.display", index + 1);
}
});
}
static public JComboBox getSelector() {
int deviceIndex = Preferences.getInteger("run.present.display") - 1;
int deviceIndex = PreferencesData.getInteger("run.present.display") - 1;
selector.setSelectedIndex(deviceIndex);
return selector;
}

View File

@@ -39,14 +39,14 @@ public class SerialMonitor extends AbstractMonitor {
this.port = port.getAddress();
serialRate = Preferences.getInteger("serial.debug_rate");
serialRate = PreferencesData.getInteger("serial.debug_rate");
serialRates.setSelectedItem(serialRate + " " + _("baud"));
onSerialRateChange(new ActionListener() {
public void actionPerformed(ActionEvent event) {
String wholeString = (String) serialRates.getSelectedItem();
String rateString = wholeString.substring(0, wholeString.indexOf(' '));
serialRate = Integer.parseInt(rateString);
Preferences.set("serial.debug_rate", rateString);
PreferencesData.set("serial.debug_rate", rateString);
try {
close();
Thread.sleep(100); // Wait for serial port to properly close
@@ -80,9 +80,9 @@ public class SerialMonitor extends AbstractMonitor {
s += "\r\n";
break;
}
if ("".equals(s) && lineEndings.getSelectedIndex() == 0 && !Preferences.has("runtime.line.ending.alert.notified")) {
if ("".equals(s) && lineEndings.getSelectedIndex() == 0 && !PreferencesData.has("runtime.line.ending.alert.notified")) {
noLineEndingAlert.setForeground(Color.RED);
Preferences.set("runtime.line.ending.alert.notified", "true");
PreferencesData.set("runtime.line.ending.alert.notified", "true");
}
serial.write(s);
}
@@ -103,7 +103,7 @@ public class SerialMonitor extends AbstractMonitor {
if (serial != null) {
int[] location = getPlacement();
String locationStr = PApplet.join(PApplet.str(location), ",");
Preferences.set("last.serial.location", locationStr);
PreferencesData.set("last.serial.location", locationStr);
textArea.setText("");
serial.dispose();
serial = null;

View File

@@ -23,18 +23,15 @@
package processing.app;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader;
import cc.arduino.view.*;
import processing.app.debug.Compiler;
import processing.app.debug.Compiler.ProgressListener;
import processing.app.debug.RunnerException;
import processing.app.debug.TargetBoard;
import processing.app.forms.PasswordAuthorizationDialog;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.PreferencesMapException;
import processing.app.packages.Library;
import processing.app.packages.UserLibrary;
import static processing.app.I18n._;
import javax.swing.*;
import java.awt.*;
@@ -45,8 +42,6 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import static processing.app.I18n._;
/**
* Stores information about files in the current sketch
@@ -117,7 +112,7 @@ public class Sketch {
for (SketchCode code : data.getCodes()) {
if (code.getMetadata() == null)
code.setMetadata(new SketchCodeDocument(code));
code.setMetadata(new SketchCodeDocument(this, code));
}
// set the main file to be the current tab
@@ -414,7 +409,7 @@ public class Sketch {
return;
}
ensureExistence();
data.addCode((new SketchCodeDocument(newFile)).getCode());
data.addCode((new SketchCodeDocument(this, newFile)).getCode());
}
// sort the entries
@@ -580,7 +575,7 @@ public class Sketch {
});
if (pdeFiles != null && pdeFiles.length > 0) {
if (Preferences.get("editor.update_extension") == null) {
if (PreferencesData.get("editor.update_extension") == null) {
Object[] options = { _("OK"), _("Cancel") };
int result = JOptionPane.showOptionDialog(editor,
_("In Arduino 1.0, the default file extension has changed\n" +
@@ -599,10 +594,10 @@ public class Sketch {
if (result != JOptionPane.OK_OPTION) return false; // save cancelled
Preferences.setBoolean("editor.update_extension", true);
PreferencesData.setBoolean("editor.update_extension", true);
}
if (Preferences.getBoolean("editor.update_extension")) {
if (PreferencesData.getBoolean("editor.update_extension")) {
// Do rename of all .pde files to new .ino extension
for (File pdeFile : pdeFiles)
renameCodeToInoExtension(pdeFile);
@@ -806,7 +801,7 @@ public class Sketch {
if (result) {
editor.statusNotice(_("One file added to the sketch."));
Preferences.set("last.folder", sourceFile.getAbsolutePath());
PreferencesData.set("last.folder", sourceFile.getAbsolutePath());
}
}
@@ -910,7 +905,7 @@ public class Sketch {
}
if (codeExtension != null) {
SketchCode newCode = (new SketchCodeDocument(destFile)).getCode();
SketchCode newCode = (new SketchCodeDocument(this, destFile)).getCode();
if (replacement) {
data.replaceCode(newCode);
@@ -938,7 +933,7 @@ public class Sketch {
}
public void importLibrary(Library lib) throws IOException {
public void importLibrary(UserLibrary lib) throws IOException {
importLibrary(lib.getSrcFolder());
}
@@ -1064,7 +1059,7 @@ public class Sketch {
// if an external editor is being used, need to grab the
// latest version of the code from the file.
if (Preferences.getBoolean("editor.external")) {
if (PreferencesData.getBoolean("editor.external")) {
// history gets screwed by the open..
//String historySaved = history.lastRecorded;
//handleOpen(sketch);
@@ -1138,8 +1133,8 @@ public class Sketch {
* @return null if compilation failed, main class name if not
* @throws RunnerException
*/
public String build(boolean verbose) throws RunnerException, PreferencesMapException {
return build(tempBuildFolder.getAbsolutePath(), verbose);
public String build(boolean verbose, boolean save) throws RunnerException, PreferencesMapException {
return build(tempBuildFolder.getAbsolutePath(), verbose, save);
}
/**
@@ -1151,9 +1146,7 @@ public class Sketch {
*
* @return null if compilation failed, main class name if not
*/
public String build(String buildPath, boolean verbose) throws RunnerException, PreferencesMapException {
useOriginalVidPidIfUncertified();
public String build(String buildPath, boolean verbose, boolean save) throws RunnerException, PreferencesMapException {
// run the preprocessor
editor.status.progressUpdate(20);
@@ -1166,7 +1159,7 @@ public class Sketch {
}
};
return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose);
return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose, save);
}
protected boolean exportApplet(boolean usingProgrammer) throws Exception {
@@ -1184,7 +1177,7 @@ public class Sketch {
// build the sketch
editor.status.progressNotice(_("Compiling sketch..."));
String foundName = build(appletPath, false);
String foundName = build(appletPath, false, false);
// (already reported) error during export, exit this function
if (foundName == null) return false;
@@ -1203,45 +1196,13 @@ public class Sketch {
return success;
}
private void useOriginalVidPidIfUncertified() {
BoardPort boardPort = BaseNoGui.getDiscoveryManager().find(PreferencesData.get("serial.port"));
if (boardPort == null) {
return;
}
TargetBoard targetBoard = BaseNoGui.getTargetBoard();
if (targetBoard == null) {
return;
}
PreferencesMap boardPreferences = targetBoard.getPreferences();
if (boardPreferences.containsKey("build.vid") && boardPreferences.containsKey("build.pid")) {
if (!boardPreferences.containsKey("backup.build.vid")) {
boardPreferences.put("backup.build.vid", boardPreferences.get("build.vid"));
boardPreferences.put("backup.build.pid", boardPreferences.get("build.pid"));
}
if (boardPort.getPrefs().get("warning") != null) {
boardPreferences.put("build.vid", boardPort.getPrefs().get("vid"));
boardPreferences.put("build.pid", boardPort.getPrefs().get("pid"));
} else {
boardPreferences.put("build.vid", boardPreferences.get("backup.build.vid"));
boardPreferences.put("build.pid", boardPreferences.get("backup.build.pid"));
}
}
if (boardPort.getPrefs().get("warning") != null && !Preferences.getBoolean("uncertifiedBoardWarning_dontShowMeAgain")) {
SwingUtilities.invokeLater(new ShowUncertifiedBoardWarning(editor));
}
}
protected boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws Exception {
Uploader uploader = Compiler.getUploaderByPreferences(false);
boolean success = false;
do {
if (uploader.requiresAuthorization() && !Preferences.has(uploader.getAuthorizationKey())) {
if (uploader.requiresAuthorization() && !PreferencesData.has(uploader.getAuthorizationKey())) {
PasswordAuthorizationDialog dialog = new PasswordAuthorizationDialog(editor, _("Type board password to upload a new sketch"));
dialog.setLocationRelativeTo(editor);
dialog.setVisible(true);
@@ -1251,7 +1212,7 @@ public class Sketch {
return false;
}
Preferences.set(uploader.getAuthorizationKey(), dialog.getPassword());
PreferencesData.set(uploader.getAuthorizationKey(), dialog.getPassword());
}
List<String> warningsAccumulator = new LinkedList<String>();
@@ -1259,7 +1220,7 @@ public class Sketch {
success = Compiler.upload(data, uploader, buildPath, suggestedClassName, usingProgrammer, false, warningsAccumulator);
} finally {
if (uploader.requiresAuthorization() && !success) {
Preferences.remove(uploader.getAuthorizationKey());
PreferencesData.remove(uploader.getAuthorizationKey());
}
}

View File

@@ -2,37 +2,43 @@ package processing.app;
import java.io.File;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.undo.UndoManager;
public class SketchCodeDocument{
public class SketchCodeDocument implements DocumentListener{
private SketchCode code;
private Sketch sketch;
private Document document;
// Undo Manager for this tab, each tab keeps track of their own Editor.undo
// will be set to this object when this code is the tab that's currently the
// front.
private LastUndoableEditAwareUndoManager undo = new LastUndoableEditAwareUndoManager();
private UndoManager undo;
// saved positions from last time this tab was used
private int selectionStart;
private int selectionStop;
private int scrollPosition;
public SketchCodeDocument(SketchCode code) {
public SketchCodeDocument(Sketch sketch, SketchCode code) {
this.code = code;
this.sketch = sketch;
this.code.setMetadata(this);
}
public SketchCodeDocument(File file) {
public SketchCodeDocument(Sketch sketch, File file) {
this.code = new SketchCode(file, this);
this.sketch = sketch;
}
public LastUndoableEditAwareUndoManager getUndo() {
public UndoManager getUndo() {
return undo;
}
public void setUndo(LastUndoableEditAwareUndoManager undo) {
public void setUndo(UndoManager undo) {
this.undo = undo;
}
@@ -74,6 +80,24 @@ public class SketchCodeDocument{
public void setDocument(Document document) {
this.document = document;
document.addDocumentListener(this);
}
@Override
public void insertUpdate(DocumentEvent e) {
if(!code.isModified()) sketch.setModified(true);
}
@Override
public void removeUpdate(DocumentEvent e) {
if(!code.isModified()) sketch.setModified(true);
}
@Override
public void changedUpdate(DocumentEvent e) {
// Callback for when styles in the current document change.
// This method is never called.
}
}

View File

@@ -21,15 +21,19 @@
package processing.app;
import static processing.app.I18n._;
import java.awt.Color;
import java.awt.Font;
import java.awt.SystemColor;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesHelper;
import processing.app.helpers.PreferencesMap;
import processing.app.syntax.SyntaxStyle;
import javax.swing.text.StyleContext;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.io.File;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import static processing.app.I18n._;
/**
* Storage class for theme settings. This was separated from the Preferences
@@ -38,17 +42,21 @@ import processing.app.syntax.SyntaxStyle;
*/
public class Theme {
/** Copy of the defaults in case the user mangles a preference. */
/**
* Copy of the defaults in case the user mangles a preference.
*/
static PreferencesMap defaults;
/** Table of attributes/values for the theme. */
/**
* Table of attributes/values for the theme.
*/
static PreferencesMap table = new PreferencesMap();
static protected void init() {
try {
table.load(Base.getLibStream("theme/theme.txt"));
table.load(new File(BaseNoGui.getContentFile("lib"), "theme/theme.txt"));
} catch (Exception te) {
Base.showError(null, _("Could not read color theme settings.\n" +
"You'll need to reinstall Arduino."), te);
"You'll need to reinstall Arduino."), te);
}
// other things that have to be set explicitly for the defaults
@@ -104,7 +112,41 @@ public class Theme {
return font;
}
static public SyntaxStyle getStyle(String what) {
/**
* Returns the default font for text areas.
*
* @return The default font.
*/
public static final Font getDefaultFont() {
// Use StyleContext to get a composite font for better Asian language
// support; see Sun bug S282887.
StyleContext sc = StyleContext.getDefaultStyleContext();
Font font = null;
if (OSUtils.isMacOS()) {
// Snow Leopard (1.6) uses Menlo as default monospaced font,
// pre-Snow Leopard used Monaco.
font = sc.getFont("Menlo", Font.PLAIN, 12);
if (!"Menlo".equals(font.getFamily())) {
font = sc.getFont("Monaco", Font.PLAIN, 12);
if (!"Monaco".equals(font.getFamily())) { // Shouldn't happen
font = sc.getFont("Monospaced", Font.PLAIN, 13);
}
}
} else {
// Consolas added in Vista, used by VS2010+.
font = sc.getFont("Consolas", Font.PLAIN, 13);
if (!"Consolas".equals(font.getFamily())) {
font = sc.getFont("Monospaced", Font.PLAIN, 13);
}
}
//System.out.println(font.getFamily() + ", " + font.getName());
return font;
}
public static Map<String, Object> getStyledFont(String what, Font font) {
String split[] = get("editor." + what + ".style").split(",");
Color color = PreferencesHelper.parseColor(split[0]);
@@ -114,6 +156,18 @@ public class Theme {
boolean italic = style.contains("italic");
boolean underlined = style.contains("underlined");
return new SyntaxStyle(color, italic, bold, underlined);
Font styledFont = new Font(font.getFamily(), (bold ? Font.BOLD : 0) | (italic ? Font.ITALIC : 0), font.getSize());
if (underlined) {
Map<TextAttribute, Object> attr = new Hashtable<TextAttribute, Object>();
attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
styledFont = styledFont.deriveFont(attr);
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("color", color);
result.put("font", styledFont);
return result;
}
}

View File

@@ -22,16 +22,16 @@
package processing.app;
import processing.app.legacy.PApplet;
import javax.swing.*;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Random;
import javax.swing.JOptionPane;
import processing.app.legacy.PApplet;
import static processing.app.I18n._;
@@ -69,11 +69,11 @@ public class UpdateCheck implements Runnable {
Random r = new Random();
long id = r.nextLong();
String idString = Preferences.get("update.id");
String idString = PreferencesData.get("update.id");
if (idString != null) {
id = Long.parseLong(idString);
} else {
Preferences.set("update.id", String.valueOf(id));
PreferencesData.set("update.id", String.valueOf(id));
}
try {
@@ -88,7 +88,7 @@ public class UpdateCheck implements Runnable {
int latest = readInt(downloadURL + "?" + info);
String lastString = Preferences.get("update.last");
String lastString = PreferencesData.get("update.last");
long now = System.currentTimeMillis();
if (lastString != null) {
long when = Long.parseLong(lastString);
@@ -97,7 +97,7 @@ public class UpdateCheck implements Runnable {
return;
}
}
Preferences.set("update.last", String.valueOf(now));
PreferencesData.set("update.last", String.valueOf(now));
String prompt =
_("A new version of Arduino is available,\n" +
@@ -126,11 +126,16 @@ public class UpdateCheck implements Runnable {
}
protected int readInt(String filename) throws Exception {
protected int readInt(String filename) throws IOException {
URL url = new URL(filename);
InputStream stream = url.openStream();
InputStreamReader isr = new InputStreamReader(stream);
BufferedReader reader = new BufferedReader(isr);
return Integer.parseInt(reader.readLine());
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(url.openStream()));
return Integer.parseInt(reader.readLine());
} finally {
if (reader != null) {
reader.close();
}
}
}
}

View File

@@ -0,0 +1,38 @@
package processing.app.debug;
import java.util.Collection;
import java.util.Map;
public class TargetPackageStub implements TargetPackage {
private final String id;
public TargetPackageStub(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public Map<String, TargetPlatform> getPlatforms() {
return null;
}
@Override
public Collection<TargetPlatform> platforms() {
return null;
}
@Override
public TargetPlatform get(String platform) {
return null;
}
@Override
public boolean hasPlatform(TargetPlatform platform) {
return false;
}
}

View File

@@ -0,0 +1,60 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br)
* Copyright 2015 Arduino LLC
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.helpers;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;
public class ConsoleLogger extends StreamHandler {
public ConsoleLogger() {
setOutputStream(new PrintStream(new FileOutputStream(FileDescriptor.out)));
}
public void publish(LogRecord record) {
super.publish(record);
flush();
}
/**
* Override <tt>StreamHandler.close</tt> to do a flush but not
* to close the output stream. That is, we do <b>not</b>
* close <tt>FileDescriptor.out</tt>.
*/
public void close() {
flush();
}
}

View File

@@ -0,0 +1,79 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br)
* Copyright 2015 Arduino LLC
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.helpers;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
public class LogFormatter extends Formatter {
public String format;
private final Date dat = new Date();
public LogFormatter(String logformat) {
format = logformat;
}
@Override
public String format(LogRecord record) {
dat.setTime(record.getMillis());
String source;
if (record.getSourceClassName() != null) {
source = record.getSourceClassName().substring(record.getSourceClassName().lastIndexOf('.') + 1);
if (record.getSourceMethodName() != null) {
source += "." + record.getSourceMethodName();
}
} else {
source = record.getLoggerName();
}
String message = formatMessage(record);
String throwable = "";
if (record.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println();
record.getThrown().printStackTrace(pw);
pw.close();
throwable = sw.toString();
}
return String.format(format,
dat,
source,
record.getLoggerName(),
record.getLevel(),
message,
throwable);
}
}

View File

@@ -22,113 +22,95 @@
package processing.app.macosx;
import processing.app.Base;
import com.apple.eawt.*;
import processing.app.Base;
import processing.app.Editor;
import java.io.File;
import java.util.List;
/**
* Deal with issues related to thinking different. This handles the basic
* Mac OS X menu commands (and apple events) for open, about, prefs, etc.
*
* <p/>
* Based on OSXAdapter.java from Apple DTS.
*
* As of 0140, this code need not be built on platforms other than OS X,
* <p/>
* As of 0140, this code need not be built on platforms other than OS X,
* because of the new platform structure which isolates through reflection.
*/
public class ThinkDifferent implements ApplicationListener {
public class ThinkDifferent {
// pseudo-singleton model; no point in making multiple instances
// of the EAWT application or our adapter
private static ThinkDifferent adapter;
// http://developer.apple.com/documentation/Java/Reference/1.4.2/appledoc/api/com/apple/eawt/Application.html
private static Application application;
private static final int MAX_WAIT_FOR_BASE = 10000;
// reference to the app where the existing quit, about, prefs code is
private Base base;
static public void init() {
Application application = Application.getApplication();
application.setAboutHandler(new AboutHandler() {
@Override
public void handleAbout(AppEvent.AboutEvent aboutEvent) {
if (waitForBase()) {
Base.INSTANCE.handleAbout();
}
}
});
application.setPreferencesHandler(new PreferencesHandler() {
@Override
public void handlePreferences(AppEvent.PreferencesEvent preferencesEvent) {
if (waitForBase()) {
Base.INSTANCE.handlePrefs();
}
}
});
application.setOpenFileHandler(new OpenFilesHandler() {
@Override
public void openFiles(final AppEvent.OpenFilesEvent openFilesEvent) {
if (waitForBase()) {
for (File file : openFilesEvent.getFiles()) {
try {
Base.INSTANCE.handleOpen(file);
List<Editor> editors = Base.INSTANCE.getEditors();
if (editors.size() == 2 && editors.get(0).getSketch().isUntitled()) {
Base.INSTANCE.handleClose(editors.get(0));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
});
application.setQuitHandler(new QuitHandler() {
@Override
public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent, QuitResponse quitResponse) {
if (waitForBase()) {
if (Base.INSTANCE.handleClose(Base.INSTANCE.getActiveEditor())) {
quitResponse.performQuit();
} else {
quitResponse.cancelQuit();
}
}
}
});
}
static public void init(Base base) {
if (application == null) {
//application = new com.apple.eawt.Application();
application = com.apple.eawt.Application.getApplication();
}
if (adapter == null) {
adapter = new ThinkDifferent(base);
}
application.addApplicationListener(adapter);
application.setEnabledAboutMenu(true);
application.setEnabledPreferencesMenu(true);
}
public ThinkDifferent(Base base) {
this.base = base;
}
// implemented handler methods. These are basically hooks into existing
// functionality from the main app, as if it came over from another platform.
public void handleAbout(ApplicationEvent ae) {
if (base != null) {
ae.setHandled(true);
base.handleAbout();
} else {
throw new IllegalStateException("handleAbout: Base instance detached from listener");
}
}
public void handlePreferences(ApplicationEvent ae) {
if (base != null) {
base.handlePrefs();
ae.setHandled(true);
} else {
throw new IllegalStateException("handlePreferences: Base instance detached from listener");
private static boolean waitForBase() {
int slept = 0;
while (Base.INSTANCE == null) {
if (slept >= MAX_WAIT_FOR_BASE) {
return false;
}
sleep(100);
slept += 100;
}
return true;
}
public void handleOpenApplication(ApplicationEvent ae) {
}
public void handleOpenFile(ApplicationEvent ae) {
// System.out.println("got open file event " + ae.getFilename());
String filename = ae.getFilename();
private static void sleep(int millis) {
try {
base.handleOpen(new File(filename));
} catch (Exception e) {
e.printStackTrace();
}
ae.setHandled(true);
}
public void handlePrintFile(ApplicationEvent ae) {
// TODO implement os x print handler here (open app, call handlePrint, quit)
}
public void handleQuit(ApplicationEvent ae) {
if (base != null) {
/*
/ You MUST setHandled(false) if you want to delay or cancel the quit.
/ This is important for cross-platform development -- have a universal quit
/ routine that chooses whether or not to quit, so the functionality is identical
/ on all platforms. This example simply cancels the AppleEvent-based quit and
/ defers to that universal method.
*/
boolean result = base.handleQuit();
ae.setHandled(result);
} else {
throw new IllegalStateException("handleQuit: Base instance detached from listener");
Thread.sleep(100);
} catch (InterruptedException e) {
//ignore
}
}
public void handleReOpenApplication(ApplicationEvent arg0) {
}
}

View File

@@ -0,0 +1,54 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
import org.fife.ui.rsyntaxtextarea.TokenMaker;
public class ArduinoTokenMakerFactory extends AbstractTokenMakerFactory {
private final PdeKeywords pdeKeywords;
public ArduinoTokenMakerFactory(PdeKeywords pdeKeywords) {
this.pdeKeywords = pdeKeywords;
}
@Override
protected TokenMaker getTokenMakerImpl(String key) {
return new SketchTokenMaker(pdeKeywords);
}
@Override
protected void initTokenMakerMap() {
putMapping(RSyntaxDocument.SYNTAX_STYLE_CPLUSPLUS, SketchTokenMaker.class.getName());
}
}

View File

@@ -1,273 +0,0 @@
/*
* CTokenMarker.java - C token marker
* Copyright (C) 1998, 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import javax.swing.text.Segment;
/**
* C token marker.
*
* @author Slava Pestov
*/
public class CTokenMarker extends TokenMarker
{
public CTokenMarker()
{
this(true,getKeywords());
}
public CTokenMarker(boolean cpp, KeywordMap keywords)
{
this.cpp = cpp;
this.keywords = keywords;
}
public byte markTokensImpl(byte token, Segment line, int lineIndex)
{
char[] array = line.array;
int offset = line.offset;
lastOffset = offset;
lastKeyword = offset;
int mlength = line.count + offset;
boolean backslash = false;
loop: for(int i = offset; i < mlength; i++)
{
int i1 = (i+1);
char c = array[i];
if(c == '\\')
{
backslash = !backslash;
continue;
}
switch(token)
{
case Token.NULL:
switch(c)
{
case '#':
if(backslash)
backslash = false;
else if(cpp)
{
if(doKeyword(line,i,c))
break;
addToken(i - lastOffset,token);
addToken(mlength - i,Token.KEYWORD2);
lastOffset = lastKeyword = mlength;
break loop;
}
break;
case '"':
doKeyword(line,i,c);
if(backslash)
backslash = false;
else
{
addToken(i - lastOffset,token);
token = Token.LITERAL1;
lastOffset = lastKeyword = i;
}
break;
case '\'':
doKeyword(line,i,c);
if(backslash)
backslash = false;
else
{
addToken(i - lastOffset,token);
token = Token.LITERAL2;
lastOffset = lastKeyword = i;
}
break;
case ':':
if(lastKeyword == offset)
{
if(doKeyword(line,i,c))
break;
backslash = false;
addToken(i1 - lastOffset,Token.LABEL);
lastOffset = lastKeyword = i1;
}
else if(doKeyword(line,i,c))
break;
break;
case '/':
backslash = false;
doKeyword(line,i,c);
if(mlength - i > 1)
{
switch(array[i1])
{
case '*':
addToken(i - lastOffset,token);
lastOffset = lastKeyword = i;
if(mlength - i > 2 && array[i+2] == '*')
token = Token.COMMENT2;
else
token = Token.COMMENT1;
break;
case '/':
addToken(i - lastOffset,token);
addToken(mlength - i,Token.COMMENT1);
lastOffset = lastKeyword = mlength;
break loop;
}
}
break;
default:
backslash = false;
if(!Character.isLetterOrDigit(c)
&& c != '_')
doKeyword(line,i,c);
break;
}
break;
case Token.COMMENT1:
case Token.COMMENT2:
backslash = false;
if(c == '*' && mlength - i > 1)
{
if(array[i1] == '/')
{
i++;
addToken((i+1) - lastOffset,token);
token = Token.NULL;
lastOffset = lastKeyword = i+1;
}
}
break;
case Token.LITERAL1:
if(backslash)
backslash = false;
else if(c == '"')
{
addToken(i1 - lastOffset,token);
token = Token.NULL;
lastOffset = lastKeyword = i1;
}
break;
case Token.LITERAL2:
if(backslash)
backslash = false;
else if(c == '\'')
{
addToken(i1 - lastOffset,Token.LITERAL1);
token = Token.NULL;
lastOffset = lastKeyword = i1;
}
break;
default:
throw new InternalError("Invalid state: "
+ token);
}
}
if(token == Token.NULL)
doKeyword(line,mlength,'\0');
switch(token)
{
case Token.LITERAL1:
case Token.LITERAL2:
addToken(mlength - lastOffset,Token.INVALID);
token = Token.NULL;
break;
case Token.KEYWORD2:
addToken(mlength - lastOffset,token);
if (!backslash) token = Token.NULL;
addToken(mlength - lastOffset,token);
break;
default:
addToken(mlength - lastOffset,token);
break;
}
return token;
}
public static KeywordMap getKeywords()
{
if(cKeywords == null)
{
cKeywords = new KeywordMap(false);
cKeywords.add("char",Token.KEYWORD3);
cKeywords.add("double",Token.KEYWORD3);
cKeywords.add("enum",Token.KEYWORD3);
cKeywords.add("float",Token.KEYWORD3);
cKeywords.add("int",Token.KEYWORD3);
cKeywords.add("long",Token.KEYWORD3);
cKeywords.add("short",Token.KEYWORD3);
cKeywords.add("signed",Token.KEYWORD3);
cKeywords.add("struct",Token.KEYWORD3);
cKeywords.add("typedef",Token.KEYWORD3);
cKeywords.add("union",Token.KEYWORD3);
cKeywords.add("unsigned",Token.KEYWORD3);
cKeywords.add("void",Token.KEYWORD3);
cKeywords.add("auto",Token.KEYWORD1);
cKeywords.add("const",Token.KEYWORD1);
cKeywords.add("extern",Token.KEYWORD1);
cKeywords.add("register",Token.KEYWORD1);
cKeywords.add("static",Token.KEYWORD1);
cKeywords.add("volatile",Token.KEYWORD1);
cKeywords.add("break",Token.KEYWORD1);
cKeywords.add("case",Token.KEYWORD1);
cKeywords.add("continue",Token.KEYWORD1);
cKeywords.add("default",Token.KEYWORD1);
cKeywords.add("do",Token.KEYWORD1);
cKeywords.add("else",Token.KEYWORD1);
cKeywords.add("for",Token.KEYWORD1);
cKeywords.add("goto",Token.KEYWORD1);
cKeywords.add("if",Token.KEYWORD1);
cKeywords.add("return",Token.KEYWORD1);
cKeywords.add("sizeof",Token.KEYWORD1);
cKeywords.add("switch",Token.KEYWORD1);
cKeywords.add("while",Token.KEYWORD1);
cKeywords.add("asm",Token.KEYWORD2);
cKeywords.add("asmlinkage",Token.KEYWORD2);
cKeywords.add("far",Token.KEYWORD2);
cKeywords.add("huge",Token.KEYWORD2);
cKeywords.add("inline",Token.KEYWORD2);
cKeywords.add("near",Token.KEYWORD2);
cKeywords.add("pascal",Token.KEYWORD2);
cKeywords.add("true",Token.LITERAL2);
cKeywords.add("false",Token.LITERAL2);
cKeywords.add("NULL",Token.LITERAL2);
}
return cKeywords;
}
// private members
private static KeywordMap cKeywords;
private boolean cpp;
private KeywordMap keywords;
private int lastOffset;
private int lastKeyword;
private boolean doKeyword(Segment line, int i, char c)
{
int i1 = i+1;
int len = i - lastKeyword;
byte id = keywords.lookup(line,lastKeyword,len);
if(id != Token.NULL)
{
if(lastKeyword != lastOffset)
addToken(lastKeyword - lastOffset,Token.NULL);
addToken(len,id);
lastOffset = i;
}
lastKeyword = i1;
return false;
}
}

View File

@@ -1,373 +0,0 @@
/*
* DefaultInputHandler.java - Default implementation of an input handler
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import javax.swing.KeyStroke;
import java.awt.event.*;
import java.awt.Toolkit;
import java.util.Hashtable;
import java.util.StringTokenizer;
/**
* The default input handler. It maps sequences of keystrokes into actions
* and inserts key typed events into the text area.
* @author Slava Pestov
*/
public class DefaultInputHandler extends InputHandler
{
/**
* Creates a new input handler with no key bindings defined.
*/
public DefaultInputHandler()
{
bindings = currentBindings = new Hashtable();
}
/**
* Sets up the default key bindings.
*/
public void addDefaultKeyBindings()
{
addKeyBinding("BACK_SPACE",BACKSPACE);
addKeyBinding("C+BACK_SPACE",BACKSPACE_WORD);
addKeyBinding("DELETE",DELETE);
addKeyBinding("C+DELETE",DELETE_WORD);
addKeyBinding("ENTER",INSERT_BREAK);
addKeyBinding("TAB",INSERT_TAB);
addKeyBinding("INSERT",OVERWRITE);
addKeyBinding("C+\\",TOGGLE_RECT);
addKeyBinding("HOME",HOME);
addKeyBinding("END",END);
addKeyBinding("S+HOME",SELECT_HOME);
addKeyBinding("S+END",SELECT_END);
addKeyBinding("C+HOME",DOCUMENT_HOME);
addKeyBinding("C+END",DOCUMENT_END);
addKeyBinding("CS+HOME",SELECT_DOC_HOME);
addKeyBinding("CS+END",SELECT_DOC_END);
addKeyBinding("PAGE_UP",PREV_PAGE);
addKeyBinding("PAGE_DOWN",NEXT_PAGE);
addKeyBinding("S+PAGE_UP",SELECT_PREV_PAGE);
addKeyBinding("S+PAGE_DOWN",SELECT_NEXT_PAGE);
addKeyBinding("LEFT",PREV_CHAR);
addKeyBinding("S+LEFT",SELECT_PREV_CHAR);
addKeyBinding("C+LEFT",PREV_WORD);
addKeyBinding("CS+LEFT",SELECT_PREV_WORD);
addKeyBinding("RIGHT",NEXT_CHAR);
addKeyBinding("S+RIGHT",SELECT_NEXT_CHAR);
addKeyBinding("C+RIGHT",NEXT_WORD);
addKeyBinding("CS+RIGHT",SELECT_NEXT_WORD);
addKeyBinding("UP",PREV_LINE);
addKeyBinding("S+UP",SELECT_PREV_LINE);
addKeyBinding("DOWN",NEXT_LINE);
addKeyBinding("S+DOWN",SELECT_NEXT_LINE);
addKeyBinding("C+ENTER",REPEAT);
}
/**
* Adds a key binding to this input handler. The key binding is
* a list of white space separated key strokes of the form
* <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
* or S for Shift, and key is either a character (a-z) or a field
* name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
* @param keyBinding The key binding
* @param action The action
*/
public void addKeyBinding(String keyBinding, ActionListener action)
{
Hashtable current = bindings;
StringTokenizer st = new StringTokenizer(keyBinding);
while(st.hasMoreTokens())
{
KeyStroke keyStroke = parseKeyStroke(st.nextToken());
if(keyStroke == null)
return;
if(st.hasMoreTokens())
{
Object o = current.get(keyStroke);
if(o instanceof Hashtable)
current = (Hashtable)o;
else
{
o = new Hashtable();
current.put(keyStroke,o);
current = (Hashtable)o;
}
}
else
current.put(keyStroke,action);
}
}
/**
* Removes a key binding from this input handler. This is not yet
* implemented.
* @param keyBinding The key binding
*/
public void removeKeyBinding(String keyBinding)
{
throw new InternalError("Not yet implemented");
}
/**
* Removes all key bindings from this input handler.
*/
public void removeAllKeyBindings()
{
bindings.clear();
}
/**
* Returns a copy of this input handler that shares the same
* key bindings. Setting key bindings in the copy will also
* set them in the original.
*/
public InputHandler copy()
{
return new DefaultInputHandler(this);
}
/**
* Handle a key pressed event. This will look up the binding for
* the key stroke and execute it.
*/
public void keyPressed(KeyEvent evt)
{
int keyCode = evt.getKeyCode();
int modifiers = evt.getModifiers();
// moved this earlier so it doesn't get random meta clicks
if (keyCode == KeyEvent.VK_CONTROL ||
keyCode == KeyEvent.VK_SHIFT ||
keyCode == KeyEvent.VK_ALT ||
keyCode == KeyEvent.VK_META) {
return;
}
// don't get command-s or other menu key equivs on mac
// unless it's something that's specifically bound (cmd-left or right)
//if ((modifiers & KeyEvent.META_MASK) != 0) return;
if ((modifiers & KeyEvent.META_MASK) != 0) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers);
if (currentBindings.get(keyStroke) == null) {
return;
}
}
/*
char keyChar = evt.getKeyChar();
System.out.println("code=" + keyCode + " char=" + keyChar +
" charint=" + ((int)keyChar));
System.out.println("other codes " + KeyEvent.VK_ALT + " " +
KeyEvent.VK_META);
*/
if((modifiers & ~KeyEvent.SHIFT_MASK) != 0
|| evt.isActionKey()
|| keyCode == KeyEvent.VK_BACK_SPACE
|| keyCode == KeyEvent.VK_DELETE
|| keyCode == KeyEvent.VK_ENTER
|| keyCode == KeyEvent.VK_TAB
|| keyCode == KeyEvent.VK_ESCAPE)
{
if(grabAction != null)
{
handleGrabAction(evt);
return;
}
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
modifiers);
Object o = currentBindings.get(keyStroke);
if(o == null)
{
// Don't beep if the user presses some
// key we don't know about unless a
// prefix is active. Otherwise it will
// beep when caps lock is pressed, etc.
if(currentBindings != bindings)
{
Toolkit.getDefaultToolkit().beep();
// F10 should be passed on, but C+e F10
// shouldn't
repeatCount = 0;
repeat = false;
evt.consume();
}
currentBindings = bindings;
return;
}
else if(o instanceof ActionListener)
{
currentBindings = bindings;
executeAction(((ActionListener)o),
evt.getSource(),null);
evt.consume();
return;
}
else if(o instanceof Hashtable)
{
currentBindings = (Hashtable)o;
evt.consume();
return;
}
}
}
/**
* Handle a key typed event. This inserts the key into the text area.
*/
public void keyTyped(KeyEvent evt)
{
int modifiers = evt.getModifiers();
char c = evt.getKeyChar();
// this is the apple/cmd key on macosx.. so menu commands
// were being passed through as legit keys.. added this line
// in an attempt to prevent.
if ((modifiers & KeyEvent.META_MASK) != 0) return;
if (c != KeyEvent.CHAR_UNDEFINED) // &&
// (modifiers & KeyEvent.ALT_MASK) == 0)
{
if(c >= 0x20 && c != 0x7f)
{
KeyStroke keyStroke = KeyStroke.getKeyStroke(
Character.toUpperCase(c));
Object o = currentBindings.get(keyStroke);
if(o instanceof Hashtable)
{
currentBindings = (Hashtable)o;
return;
}
else if(o instanceof ActionListener)
{
currentBindings = bindings;
executeAction((ActionListener)o,
evt.getSource(),
String.valueOf(c));
return;
}
currentBindings = bindings;
if(grabAction != null)
{
handleGrabAction(evt);
return;
}
// 0-9 adds another 'digit' to the repeat number
if(repeat && Character.isDigit(c))
{
repeatCount *= 10;
repeatCount += (c - '0');
return;
}
executeAction(INSERT_CHAR,evt.getSource(),
String.valueOf(evt.getKeyChar()));
repeatCount = 0;
repeat = false;
}
}
}
/**
* Converts a string to a keystroke. The string should be of the
* form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
* is any combination of A for Alt, C for Control, S for Shift
* or M for Meta, and <i>shortcut</i> is either a single character,
* or a keycode name from the <code>KeyEvent</code> class, without
* the <code>VK_</code> prefix.
* @param keyStroke A string description of the key stroke
*/
public static KeyStroke parseKeyStroke(String keyStroke)
{
if(keyStroke == null)
return null;
int modifiers = 0;
int index = keyStroke.indexOf('+');
if(index != -1)
{
for(int i = 0; i < index; i++)
{
switch(Character.toUpperCase(keyStroke
.charAt(i)))
{
case 'A':
modifiers |= InputEvent.ALT_MASK;
break;
case 'C':
modifiers |= InputEvent.CTRL_MASK;
break;
case 'M':
modifiers |= InputEvent.META_MASK;
break;
case 'S':
modifiers |= InputEvent.SHIFT_MASK;
break;
}
}
}
String key = keyStroke.substring(index + 1);
if(key.length() == 1)
{
char ch = Character.toUpperCase(key.charAt(0));
if(modifiers == 0)
return KeyStroke.getKeyStroke(ch);
else
return KeyStroke.getKeyStroke(ch,modifiers);
}
else if(key.length() == 0)
{
System.err.println("Invalid key stroke: " + keyStroke);
return null;
}
else
{
int ch;
try
{
ch = KeyEvent.class.getField("VK_".concat(key))
.getInt(null);
}
catch(Exception e)
{
System.err.println("Invalid key stroke: "
+ keyStroke);
return null;
}
return KeyStroke.getKeyStroke(ch,modifiers);
}
}
// private members
private Hashtable bindings;
private Hashtable currentBindings;
private DefaultInputHandler(DefaultInputHandler copy)
{
bindings = currentBindings = copy.bindings;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,139 +0,0 @@
/*
* KeywordMap.java - Fast keyword->id map
* Copyright (C) 1998, 1999 Slava Pestov
* Copyright (C) 1999 Mike Dillon
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import javax.swing.text.Segment;
/**
* A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
* to values. However, the `keys' are Swing segments. This allows lookups of
* text substrings without the overhead of creating a new string object.
* <p>
* This class is used by <code>CTokenMarker</code> to map keywords to ids.
*
* @author Slava Pestov, Mike Dillon
*/
public class KeywordMap
{
/**
* Creates a new <code>KeywordMap</code>.
* @param ignoreCase True if keys are case insensitive
*/
public KeywordMap(boolean ignoreCase)
{
this(ignoreCase, 52);
this.ignoreCase = ignoreCase;
}
/**
* Creates a new <code>KeywordMap</code>.
* @param ignoreCase True if the keys are case insensitive
* @param mapLength The number of `buckets' to create.
* A value of 52 will give good performance for most maps.
*/
public KeywordMap(boolean ignoreCase, int mapLength)
{
this.mapLength = mapLength;
this.ignoreCase = ignoreCase;
map = new Keyword[mapLength];
}
/**
* Looks up a key.
* @param text The text segment
* @param offset The offset of the substring within the text segment
* @param length The length of the substring
*/
public byte lookup(Segment text, int offset, int length)
{
if(length == 0)
return Token.NULL;
Keyword k = map[getSegmentMapKey(text, offset, length)];
while(k != null)
{
if(length != k.keyword.length)
{
k = k.next;
continue;
}
if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
k.keyword))
return k.id;
k = k.next;
}
return Token.NULL;
}
/**
* Adds a key-value mapping.
* @param keyword The key
* @param id The value
*/
public void add(String keyword, byte id)
{
int key = getStringMapKey(keyword);
map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
}
/**
* Returns true if the keyword map is set to be case insensitive,
* false otherwise.
*/
public boolean getIgnoreCase()
{
return ignoreCase;
}
/**
* Sets if the keyword map should be case insensitive.
* @param ignoreCase True if the keyword map should be case
* insensitive, false otherwise
*/
public void setIgnoreCase(boolean ignoreCase)
{
this.ignoreCase = ignoreCase;
}
// protected members
protected int mapLength;
protected int getStringMapKey(String s)
{
return (Character.toUpperCase(s.charAt(0)) +
Character.toUpperCase(s.charAt(s.length()-1)))
% mapLength;
}
protected int getSegmentMapKey(Segment s, int off, int len)
{
return (Character.toUpperCase(s.array[off]) +
Character.toUpperCase(s.array[off + len - 1]))
% mapLength;
}
// private members
class Keyword
{
public Keyword(char[] keyword, byte id, Keyword next)
{
this.keyword = keyword;
this.id = id;
this.next = next;
}
public char[] keyword;
public byte id;
public Keyword next;
}
private Keyword[] map;
private boolean ignoreCase;
}

View File

@@ -24,106 +24,158 @@
package processing.app.syntax;
import processing.app.*;
import cc.arduino.contributions.libraries.ContributedLibrary;
import org.fife.ui.rsyntaxtextarea.TokenMap;
import org.fife.ui.rsyntaxtextarea.TokenTypes;
import processing.app.Base;
import processing.app.BaseNoGui;
import processing.app.legacy.PApplet;
import processing.app.packages.Library;
import java.io.*;
import java.util.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
public class PdeKeywords extends CTokenMarker {
public class PdeKeywords {
// lookup table for the TokenMarker subclass, handles coloring
static KeywordMap keywordColoring;
private static final Map<String, Integer> KNOWN_TOKEN_TYPES = new HashMap<String, Integer>();
private static final Pattern ALPHA = Pattern.compile("\\w");
// lookup table that maps keywords to their html reference pages
static Hashtable keywordToReference;
public PdeKeywords() {
super(false, getKeywords());
static {
KNOWN_TOKEN_TYPES.put("RESERVED_WORD", TokenTypes.RESERVED_WORD);
KNOWN_TOKEN_TYPES.put("RESERVED_WORD_2", TokenTypes.RESERVED_WORD_2);
KNOWN_TOKEN_TYPES.put("VARIABLE", TokenTypes.VARIABLE);
KNOWN_TOKEN_TYPES.put("OPERATOR", TokenTypes.OPERATOR);
KNOWN_TOKEN_TYPES.put("DATA_TYPE", TokenTypes.DATA_TYPE);
KNOWN_TOKEN_TYPES.put("LITERAL_BOOLEAN", TokenTypes.LITERAL_BOOLEAN);
KNOWN_TOKEN_TYPES.put("LITERAL_CHAR", TokenTypes.LITERAL_CHAR);
}
// lookup table for the TokenMarker subclass, handles coloring
private final TokenMap keywordTokenType;
private final Map<String, String> keywordOldToken;
private final Map<String, String> keywordTokenTypeAsString;
// lookup table that maps keywords to their html reference pages
private final Map<String, String> keywordToReference;
public PdeKeywords() {
this.keywordTokenType = new TokenMap();
this.keywordOldToken = new HashMap<String, String>();
this.keywordTokenTypeAsString = new HashMap<String, String>();
this.keywordToReference = new HashMap<String, String>();
}
/**
* Handles loading of keywords file.
* <P>
* <p/>
* Uses getKeywords() method because that's part of the
* TokenMarker classes.
* <P>
* <p/>
* It is recommended that a # sign be used for comments
* inside keywords.txt.
*/
static public KeywordMap getKeywords() {
if (keywordColoring == null) {
try {
keywordColoring = new KeywordMap(false);
keywordToReference = new Hashtable();
getKeywords(Base.getLibStream("keywords.txt"));
for (Library lib : Base.getLibraries()) {
File keywords = new File(lib.getFolder(), "keywords.txt");
if (keywords.exists()) getKeywords(new FileInputStream(keywords));
public void reload() {
try {
parseKeywordsTxt(new File(BaseNoGui.getContentFile("lib"), "keywords.txt"));
for (ContributedLibrary lib : Base.getLibraries()) {
File keywords = new File(lib.getInstalledFolder(), "keywords.txt");
if (keywords.exists()) {
parseKeywordsTxt(keywords);
}
} catch (Exception e) {
Base.showError("Problem loading keywords",
"Could not load keywords.txt,\n" +
"please re-install Arduino.", e);
System.exit(1);
}
} catch (Exception e) {
Base.showError("Problem loading keywords", "Could not load keywords.txt,\nplease re-install Arduino.", e);
System.exit(1);
}
return keywordColoring;
}
static private void getKeywords(InputStream input) throws Exception {
InputStreamReader isr = new InputStreamReader(input);
BufferedReader reader = new BufferedReader(isr);
String line = null;
while ((line = reader.readLine()) != null) {
//System.out.println("line is " + line);
// in case there's any garbage on the line
//if (line.trim().length() == 0) continue;
private void parseKeywordsTxt(File input) throws Exception {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(input)));
String pieces[] = PApplet.split(line, '\t');
if (pieces.length >= 2) {
//int tab = line.indexOf('\t');
// any line with no tab is ignored
// meaning that a comment is any line without a tab
//if (tab == -1) continue;
String line;
while ((line = reader.readLine()) != null) {
//System.out.println("line is " + line);
// in case there's any garbage on the line
line = line.trim();
if (line.length() == 0 || line.startsWith("#")) {
continue;
}
String pieces[] = PApplet.split(line, '\t');
String keyword = pieces[0].trim();
//String keyword = line.substring(0, tab).trim();
//String second = line.substring(tab + 1);
//tab = second.indexOf('\t');
//String coloring = second.substring(0, tab).trim();
//String htmlFilename = second.substring(tab + 1).trim();
String coloring = pieces[1].trim();
if (coloring.length() > 0 && Character.isDigit(coloring.charAt(coloring.length() - 1))) {
// text will be KEYWORD or LITERAL
boolean isKey = (coloring.charAt(0) == 'K');
// KEYWORD1 -> 0, KEYWORD2 -> 1, etc
int num = coloring.charAt(coloring.length() - 1) - '1';
byte id = (byte)
((isKey ? Token.KEYWORD1 : Token.LITERAL1) + num);
//System.out.println("got " + (isKey ? "keyword" : "literal") +
// (num+1) + " for " + keyword);
keywordColoring.add(keyword, id);
if (pieces.length >= 2) {
keywordOldToken.put(keyword, pieces[1]);
}
if (pieces.length >= 3) {
String htmlFilename = pieces[2].trim();
if (htmlFilename.length() > 0) {
keywordToReference.put(keyword, htmlFilename);
}
parseHTMLReferenceFileName(pieces[2], keyword);
}
if (pieces.length >= 4) {
parseRSyntaxTextAreaTokenType(pieces[3], keyword);
}
}
fillMissingTokenType();
} finally {
if (reader != null) {
reader.close();
}
}
}
private void fillMissingTokenType() {
for (Map.Entry<String, String> oldTokenEntry : keywordOldToken.entrySet()) {
String keyword = oldTokenEntry.getKey();
if (!keywordTokenTypeAsString.containsKey(keyword)) {
if ("KEYWORD1".equals(oldTokenEntry.getValue())) {
parseRSyntaxTextAreaTokenType("DATA_TYPE", keyword);
} else {
parseRSyntaxTextAreaTokenType("FUNCTION", keyword);
}
}
}
reader.close();
}
private void parseRSyntaxTextAreaTokenType(String tokenTypeAsString, String keyword) {
if (!ALPHA.matcher(keyword).find()) {
return;
}
static public String getReference(String keyword) {
return (String) keywordToReference.get(keyword);
if (KNOWN_TOKEN_TYPES.containsKey(tokenTypeAsString)) {
keywordTokenType.put(keyword, KNOWN_TOKEN_TYPES.get(tokenTypeAsString));
keywordTokenTypeAsString.put(keyword, tokenTypeAsString);
} else {
keywordTokenType.put(keyword, TokenTypes.FUNCTION);
keywordTokenTypeAsString.put(keyword, "FUNCTION");
}
}
private void parseHTMLReferenceFileName(String piece, String keyword) {
String htmlFilename = piece.trim();
if (htmlFilename.length() > 0) {
keywordToReference.put(keyword, htmlFilename);
}
}
public String getReference(String keyword) {
return keywordToReference.get(keyword);
}
public String getTokenTypeAsString(String keyword) {
return keywordTokenTypeAsString.get(keyword);
}
public int getTokenType(char[] array, int start, int end) {
return keywordTokenType.get(array, start, end);
}
}

View File

@@ -1,211 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
PdeTextAreaDefaults - grabs font/color settings for the editor
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2001-03 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.syntax;
import processing.app.*;
import processing.app.helpers.OSUtils;
public class PdeTextAreaDefaults extends TextAreaDefaults {
public PdeTextAreaDefaults() {
inputHandler = new DefaultInputHandler();
//inputHandler.addDefaultKeyBindings(); // 0122
// use option on mac for text edit controls that are ctrl on windows/linux
String mod = OSUtils.isMacOS() ? "A" : "C";
// right now, ctrl-up/down is select up/down, but mod should be
// used instead, because the mac expects it to be option(alt)
inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE);
// for 0122, shift-backspace is delete, for 0176, it's now a preference,
// to prevent holy warriors from attacking me for it.
if (Preferences.getBoolean("editor.keys.shift_backspace_is_delete")) {
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE);
} else {
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
}
inputHandler.addKeyBinding("DELETE", InputHandler.DELETE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
// the following two were changing for 0122 for better mac/pc compatability
inputHandler.addKeyBinding(mod+"+BACK_SPACE", InputHandler.BACKSPACE_WORD);
inputHandler.addKeyBinding(mod+"+DELETE", InputHandler.DELETE_WORD);
// handled by listener, don't bother here
//inputHandler.addKeyBinding("ENTER", InputHandler.INSERT_BREAK);
//inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE);
// http://dev.processing.org/bugs/show_bug.cgi?id=162
// added for 0176, though the bindings do not appear relevant for osx
if (Preferences.getBoolean("editor.keys.alternative_cut_copy_paste")) {
inputHandler.addKeyBinding("C+INSERT", InputHandler.CLIPBOARD_COPY);
inputHandler.addKeyBinding("S+INSERT", InputHandler.CLIPBOARD_PASTE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.CLIPBOARD_CUT);
}
// disabling for 0122, not sure what this does
//inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
// for 0122, these have been changed for better compatibility
// HOME and END now mean the beginning/end of the document
// for 0176 changed this to a preference so that the Mac OS X people
// can get the "normal" behavior as well if they prefer.
if (Preferences.getBoolean("editor.keys.home_and_end_travel_far")) {
inputHandler.addKeyBinding("HOME", InputHandler.DOCUMENT_HOME);
inputHandler.addKeyBinding("END", InputHandler.DOCUMENT_END);
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_DOC_END);
} else {
// for 0123 added the proper windows defaults
inputHandler.addKeyBinding("HOME", InputHandler.HOME);
inputHandler.addKeyBinding("END", InputHandler.END);
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_HOME);
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_END);
inputHandler.addKeyBinding("C+HOME", InputHandler.DOCUMENT_HOME);
inputHandler.addKeyBinding("C+END", InputHandler.DOCUMENT_END);
inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_DOC_END);
}
if (OSUtils.isMacOS()) {
inputHandler.addKeyBinding("M+LEFT", InputHandler.HOME);
inputHandler.addKeyBinding("M+RIGHT", InputHandler.END);
inputHandler.addKeyBinding("MS+LEFT", InputHandler.SELECT_HOME); // 0122
inputHandler.addKeyBinding("MS+RIGHT", InputHandler.SELECT_END); // 0122
} else {
inputHandler.addKeyBinding("C+LEFT", InputHandler.HOME); // 0122
inputHandler.addKeyBinding("C+RIGHT", InputHandler.END); // 0122
inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_HOME); // 0122
inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_END); // 0122
}
inputHandler.addKeyBinding("PAGE_UP", InputHandler.PREV_PAGE);
inputHandler.addKeyBinding("PAGE_DOWN", InputHandler.NEXT_PAGE);
inputHandler.addKeyBinding("S+PAGE_UP", InputHandler.SELECT_PREV_PAGE);
inputHandler.addKeyBinding("S+PAGE_DOWN", InputHandler.SELECT_NEXT_PAGE);
inputHandler.addKeyBinding("LEFT", InputHandler.PREV_CHAR);
inputHandler.addKeyBinding("S+LEFT", InputHandler.SELECT_PREV_CHAR);
inputHandler.addKeyBinding(mod + "+LEFT", InputHandler.PREV_WORD);
inputHandler.addKeyBinding(mod + "S+LEFT", InputHandler.SELECT_PREV_WORD);
inputHandler.addKeyBinding("RIGHT", InputHandler.NEXT_CHAR);
inputHandler.addKeyBinding("S+RIGHT", InputHandler.SELECT_NEXT_CHAR);
inputHandler.addKeyBinding(mod + "+RIGHT", InputHandler.NEXT_WORD);
inputHandler.addKeyBinding(mod + "S+RIGHT", InputHandler.SELECT_NEXT_WORD);
inputHandler.addKeyBinding("UP", InputHandler.PREV_LINE);
inputHandler.addKeyBinding(mod + "+UP", InputHandler.PREV_LINE); // p5
inputHandler.addKeyBinding("S+UP", InputHandler.SELECT_PREV_LINE);
inputHandler.addKeyBinding("DOWN", InputHandler.NEXT_LINE);
inputHandler.addKeyBinding(mod + "+DOWN", InputHandler.NEXT_LINE); // p5
inputHandler.addKeyBinding("S+DOWN", InputHandler.SELECT_NEXT_LINE);
inputHandler.addKeyBinding("MS+UP", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("CS+UP", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("MS+DOWN", InputHandler.SELECT_DOC_END);
inputHandler.addKeyBinding("CS+DOWN", InputHandler.SELECT_DOC_END);
inputHandler.addKeyBinding(mod + "+ENTER", InputHandler.REPEAT);
document = new SyntaxDocument();
editable = true;
electricScroll = 3;
cols = 80;
rows = 15;
// moved from SyntaxUtilities
//DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
styles = new SyntaxStyle[Token.ID_COUNT];
// comments
styles[Token.COMMENT1] = Theme.getStyle("comment1");
styles[Token.COMMENT2] = Theme.getStyle("comment2");
// abstract, final, private
styles[Token.KEYWORD1] = Theme.getStyle("keyword1");
// beginShape, point, line
styles[Token.KEYWORD2] = Theme.getStyle("keyword2");
// byte, char, short, color
styles[Token.KEYWORD3] = Theme.getStyle("keyword3");
// constants: null, true, this, RGB, TWO_PI
styles[Token.LITERAL1] = Theme.getStyle("literal1");
// p5 built in variables: mouseX, width, pixels
styles[Token.LITERAL2] = Theme.getStyle("literal2");
// ??
styles[Token.LABEL] = Theme.getStyle("label");
// http://arduino.cc/
styles[Token.URL] = Theme.getStyle("url");
// + - = /
styles[Token.OPERATOR] = Theme.getStyle("operator");
// area that's not in use by the text (replaced with tildes)
styles[Token.INVALID] = Theme.getStyle("invalid");
// moved from TextAreaPainter
font = Preferences.getFont("editor.font");
fgcolor = Theme.getColor("editor.fgcolor");
bgcolor = Theme.getColor("editor.bgcolor");
caretVisible = true;
caretBlinks = Preferences.getBoolean("editor.caret.blink");
caretColor = Theme.getColor("editor.caret.color");
selectionColor = Theme.getColor("editor.selection.color");
lineHighlight =
Theme.getBoolean("editor.linehighlight");
lineHighlightColor =
Theme.getColor("editor.linehighlight.color");
bracketHighlight =
Theme.getBoolean("editor.brackethighlight");
bracketHighlightColor =
Theme.getColor("editor.brackethighlight.color");
eolMarkers = Theme.getBoolean("editor.eolmarkers");
eolMarkerColor = Theme.getColor("editor.eolmarkers.color");
paintInvalid = Theme.getBoolean("editor.invalid");
}
}

View File

@@ -0,0 +1,474 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br)
* Copyright 2015 Arduino LLC
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rsyntaxtextarea.Token;
import org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextAreaUI;
import org.fife.ui.rtextarea.RUndoManager;
import processing.app.*;
import javax.swing.*;
import javax.swing.event.EventListenerList;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Segment;
import javax.swing.undo.UndoManager;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
/**
* Arduino Sketch code editor based on RSyntaxTextArea (http://fifesoft.com/rsyntaxtextarea)
*
* @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
* @date 20/04/2015
* @since 1.6.4
*/
public class SketchTextArea extends RSyntaxTextArea {
private final static Logger LOG = Logger.getLogger(SketchTextArea.class.getName());
/**
* The last docTooltip displayed.
*/
private FocusableTip docTooltip;
private EditorListener editorListener;
private final PdeKeywords pdeKeywords;
public SketchTextArea(PdeKeywords pdeKeywords) throws IOException {
this.pdeKeywords = pdeKeywords;
installFeatures();
}
protected void installFeatures() throws IOException {
setTheme(PreferencesData.get("editor.syntax_theme", "default"));
setLinkGenerator(new DocLinkGenerator(pdeKeywords));
fixControlTab();
setSyntaxEditingStyle(SYNTAX_STYLE_CPLUSPLUS);
}
public void setTheme(String name) throws IOException {
FileInputStream defaultXmlInputStream = null;
try {
defaultXmlInputStream = new FileInputStream(new File(BaseNoGui.getContentFile("lib"), "theme/syntax/" + name + ".xml"));
Theme theme = Theme.load(defaultXmlInputStream);
theme.apply(this);
} finally {
if (defaultXmlInputStream != null) {
defaultXmlInputStream.close();
}
}
setForeground(processing.app.Theme.getColor("editor.fgcolor"));
setBackground(processing.app.Theme.getColor("editor.bgcolor"));
setCurrentLineHighlightColor(processing.app.Theme.getColor("editor.linehighlight.color"));
setCaretColor(processing.app.Theme.getColor("editor.caret.color"));
setSelectedTextColor(null);
setUseSelectedTextColor(false);
setSelectionColor(processing.app.Theme.getColor("editor.selection.color"));
setMatchedBracketBorderColor(processing.app.Theme.getColor("editor.brackethighlight.color"));
setHyperlinkForeground((Color) processing.app.Theme.getStyledFont("url", getFont()).get("color"));
setSyntaxTheme(TokenTypes.DATA_TYPE, "data_type");
setSyntaxTheme(TokenTypes.FUNCTION, "function");
setSyntaxTheme(TokenTypes.RESERVED_WORD, "reserved_word");
setSyntaxTheme(TokenTypes.RESERVED_WORD_2, "reserved_word_2");
setSyntaxTheme(TokenTypes.VARIABLE, "variable");
setSyntaxTheme(TokenTypes.OPERATOR, "operator");
setSyntaxTheme(TokenTypes.COMMENT_DOCUMENTATION, "comment1");
setSyntaxTheme(TokenTypes.COMMENT_EOL, "comment1");
setSyntaxTheme(TokenTypes.COMMENT_KEYWORD, "comment1");
setSyntaxTheme(TokenTypes.COMMENT_MARKUP, "comment1");
setSyntaxTheme(TokenTypes.LITERAL_CHAR, "literal_char");
setSyntaxTheme(TokenTypes.LITERAL_STRING_DOUBLE_QUOTE, "literal_string_double_quote");
}
private void setSyntaxTheme(int tokenType, String id) {
Style style = getSyntaxScheme().getStyle(tokenType);
Map<String, Object> styledFont = processing.app.Theme.getStyledFont(id, style.font);
style.foreground = (Color) styledFont.get("color");
style.font = (Font) styledFont.get("font");
getSyntaxScheme().setStyle(tokenType, style);
}
// Removing the default focus traversal keys
// This is because the DefaultKeyboardFocusManager handles the keypress and consumes the event
protected void fixControlTab() {
removeCTRLTabFromFocusTraversal();
removeCTRLSHIFTTabFromFocusTraversal();
}
private void removeCTRLSHIFTTabFromFocusTraversal() {
KeyStroke ctrlShiftTab = KeyStroke.getKeyStroke("ctrl shift TAB");
Set<AWTKeyStroke> backwardKeys = new HashSet<AWTKeyStroke>(this.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
backwardKeys.remove(ctrlShiftTab);
}
private void removeCTRLTabFromFocusTraversal() {
KeyStroke ctrlTab = KeyStroke.getKeyStroke("ctrl TAB");
Set<AWTKeyStroke> forwardKeys = new HashSet<AWTKeyStroke>(this.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
forwardKeys.remove(ctrlTab);
this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);
}
@Override
public void select(int selectionStart, int selectionEnd) {
super.select(selectionStart, selectionEnd);
}
public boolean isSelectionActive() {
return this.getSelectedText() != null;
}
public void setSelectedText(String text) {
int old = getTextMode();
setTextMode(OVERWRITE_MODE);
replaceSelection(text);
setTextMode(old);
}
public void processKeyEvent(KeyEvent evt) {
// this had to be added because the menu key events weren't making it up to the frame.
switch (evt.getID()) {
case KeyEvent.KEY_TYPED:
if (editorListener != null) editorListener.keyTyped(evt);
break;
case KeyEvent.KEY_PRESSED:
if (editorListener != null) editorListener.keyPressed(evt);
break;
case KeyEvent.KEY_RELEASED:
// inputHandler.keyReleased(evt);
break;
}
if (!evt.isConsumed()) {
super.processKeyEvent(evt);
}
}
public void switchDocument(Document document, UndoManager newUndo) {
// HACK: Dont discard changes on curret UndoManager.
// BUG: https://github.com/bobbylight/RSyntaxTextArea/issues/84
setUndoManager(null); // bypass reset current undo manager...
super.setDocument(document);
setUndoManager((RUndoManager) newUndo);
// HACK: Complement previous hack (hide code folding on switch) | Drawback: Lose folding state
// if(sketch.getCodeCount() > 1 && textarea.isCodeFoldingEnabled()){
// textarea.setCodeFoldingEnabled(false);
// textarea.setCodeFoldingEnabled(true);
// }
}
@Override
protected JPopupMenu createPopupMenu() {
JPopupMenu menu = super.createPopupMenu();
return menu;
}
@Override
protected void configurePopupMenu(JPopupMenu popupMenu) {
super.configurePopupMenu(popupMenu);
}
@Override
protected RTAMouseListener createMouseListener() {
return new SketchTextAreaMouseListener(this);
}
public void getTextLine(int line, Segment segment) {
try {
int offset = getLineStartOffset(line);
int end = getLineEndOffset(line);
getDocument().getText(offset, end - offset, segment);
} catch (BadLocationException e) {
}
}
public String getTextLine(int line) {
try {
int offset = getLineStartOffset(line);
int end = getLineEndOffset(line);
return getDocument().getText(offset, end - offset);
} catch (BadLocationException e) {
return null;
}
}
public void setEditorListener(EditorListener editorListener) {
this.editorListener = editorListener;
}
private static class DocLinkGenerator implements LinkGenerator {
private final PdeKeywords pdeKeywords;
public DocLinkGenerator(PdeKeywords pdeKeywords) {
this.pdeKeywords = pdeKeywords;
}
@Override
public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, final int offs) {
final Token token = textArea.modelToToken(offs);
final String reference = pdeKeywords.getReference(token.getLexeme());
// LOG.fine("reference: " + reference + ", match: " + (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION));
if (token != null && (reference != null || (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION))) {
LinkGeneratorResult generatorResult = new LinkGeneratorResult() {
@Override
public int getSourceOffset() {
return offs;
}
@Override
public HyperlinkEvent execute() {
LOG.fine("Open Reference: " + reference);
Base.showReference("Reference/" + reference);
return null;
}
};
return generatorResult;
}
return null;
}
}
/**
* Handles http hyperlinks.
* NOTE (@Ricardo JL Rufino): Workaround to enable hyperlinks by default: https://github.com/bobbylight/RSyntaxTextArea/issues/119
*/
private class SketchTextAreaMouseListener extends RTextAreaMutableCaretEvent {
private Insets insets;
private boolean isScanningForLinks;
private int hoveredOverLinkOffset = -1;
protected SketchTextAreaMouseListener(RTextArea textArea) {
super(textArea);
insets = new Insets(0, 0, 0, 0);
}
/**
* Notifies all listeners that have registered interest for notification
* on this event type. The listener list is processed last to first.
*
* @param e The event to fire.
* @see EventListenerList
*/
private void fireHyperlinkUpdate(HyperlinkEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == HyperlinkListener.class) {
((HyperlinkListener) listeners[i + 1]).hyperlinkUpdate(e);
}
}
}
private HyperlinkEvent createHyperlinkEvent(MouseEvent e) {
HyperlinkEvent he = null;
Token t = viewToToken(e.getPoint());
if (t != null) {
// Copy token, viewToModel() unfortunately modifies Token
t = new TokenImpl(t);
}
if (t != null && t.isHyperlink()) {
URL url = null;
String desc = null;
try {
String temp = t.getLexeme();
// URI's need "http://" prefix for web URL's to work.
if (temp.startsWith("www.")) {
temp = "http://" + temp;
}
url = new URL(temp);
} catch (MalformedURLException mue) {
desc = mue.getMessage();
}
he = new HyperlinkEvent(SketchTextArea.this, HyperlinkEvent.EventType.ACTIVATED, url, desc);
}
return he;
}
@Override
public void mouseClicked(MouseEvent e) {
if (getHyperlinksEnabled()) {
HyperlinkEvent he = createHyperlinkEvent(e);
if (he != null) {
fireHyperlinkUpdate(he);
}
}
}
@Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
if (!getHyperlinksEnabled()) {
return;
}
// LinkGenerator linkGenerator = getLinkGenerator();
// GitHub issue RSyntaxTextArea/#25 - links identified at "edges" of editor
// should not be activated if mouse is in margin insets.
insets = getInsets(insets);
if (insets != null) {
int x = e.getX();
int y = e.getY();
if (x <= insets.left || y < insets.top) {
if (isScanningForLinks) {
stopScanningForLinks();
}
return;
}
}
isScanningForLinks = true;
Token t = viewToToken(e.getPoint());
if (t != null) {
// Copy token, viewToModel() unfortunately modifies Token
t = new TokenImpl(t);
}
Cursor c2 = null;
if (t != null && t.isHyperlink()) {
if (hoveredOverLinkOffset == -1 ||
hoveredOverLinkOffset != t.getOffset()) {
hoveredOverLinkOffset = t.getOffset();
repaint();
}
c2 = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}
// else if (t!=null && linkGenerator!=null) {
// int offs = viewToModel(e.getPoint());
// LinkGeneratorResult newResult = linkGenerator.
// isLinkAtOffset(SketchTextArea.this, offs);
// if (newResult!=null) {
// // Repaint if we're at a new link now.
// if (linkGeneratorResult==null ||
// !equal(newResult, linkGeneratorResult)) {
// repaint();
// }
// linkGeneratorResult = newResult;
// hoveredOverLinkOffset = t.getOffset();
// c2 = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
// }
// else {
// // Repaint if we've moved off of a link.
// if (linkGeneratorResult!=null) {
// repaint();
// }
// c2 = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
// hoveredOverLinkOffset = -1;
// linkGeneratorResult = null;
// }
// }
else {
c2 = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
hoveredOverLinkOffset = -1;
// linkGeneratorResult = null;
}
if (getCursor() != c2) {
setCursor(c2);
// TODO: Repaint just the affected line(s).
repaint(); // Link either left or went into.
}
}
private void stopScanningForLinks() {
if (isScanningForLinks) {
Cursor c = getCursor();
isScanningForLinks = false;
if (c != null && c.getType() == Cursor.HAND_CURSOR) {
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
repaint(); // TODO: Repaint just the affected line.
}
}
}
}
@Override
protected RTextAreaUI createRTextAreaUI() {
return new SketchTextAreaUI(this);
}
}

View File

@@ -0,0 +1,43 @@
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaDefaultInputMap;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextAreaEditorKit;
import processing.app.PreferencesData;
import javax.swing.*;
import javax.swing.text.DefaultEditorKit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class SketchTextAreaDefaultInputMap extends RSyntaxTextAreaDefaultInputMap {
public SketchTextAreaDefaultInputMap() {
int defaultModifier = getDefaultModifier();
int alt = InputEvent.ALT_MASK;
boolean isOSX = RTextArea.isOSX();
int moveByWordMod = isOSX ? alt : defaultModifier;
remove(KeyStroke.getKeyStroke(KeyEvent.VK_K, defaultModifier));
if (PreferencesData.getBoolean("editor.advanced")) {
put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, alt), RTextAreaEditorKit.rtaLineDownAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, alt), RTextAreaEditorKit.rtaLineUpAction);
} else {
remove(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, alt));
remove(KeyStroke.getKeyStroke(KeyEvent.VK_UP, alt));
}
remove(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, defaultModifier));
put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, moveByWordMod), RTextAreaEditorKit.rtaDeletePrevWordAction);
if (isOSX) {
put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, defaultModifier), SketchTextAreaEditorKit.rtaDeleteLineToCursorAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, defaultModifier), DefaultEditorKit.beginAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, defaultModifier), DefaultEditorKit.endAction);
remove(KeyStroke.getKeyStroke(KeyEvent.VK_J, defaultModifier));
}
}
}

View File

@@ -0,0 +1,103 @@
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RecordableTextAction;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.ActionEvent;
public class SketchTextAreaEditorKit extends RSyntaxTextAreaEditorKit {
public static final String rtaDeleteNextWordAction = "RTA.DeleteNextWordAction";
public static final String rtaDeleteLineToCursorAction = "RTA.DeleteLineToCursorAction";
private static final Action[] defaultActions = {
new DeleteNextWordAction(),
new DeleteLineToCursorAction()
};
@Override
public Action[] getActions() {
return TextAction.augmentList(super.getActions(), SketchTextAreaEditorKit.defaultActions);
}
public static class DeleteNextWordAction extends RecordableTextAction {
public DeleteNextWordAction() {
super(rtaDeleteNextWordAction);
}
@Override
public void actionPerformedImpl(ActionEvent e, RTextArea textArea) {
if (!textArea.isEditable() || !textArea.isEnabled()) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
return;
}
try {
int start = textArea.getSelectionStart();
int end = getNextWordStart(textArea, start);
if (end > start) {
textArea.getDocument().remove(start, end - start);
}
} catch (BadLocationException ex) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
}
}
@Override
public String getMacroID() {
return rtaDeleteNextWordAction;
}
/**
* Returns the starting offset to delete. Exists so subclasses can
* override.
*/
protected int getNextWordStart(RTextArea textArea, int end)
throws BadLocationException {
return Utilities.getNextWord(textArea, end);
}
}
public static class DeleteLineToCursorAction extends RecordableTextAction {
public DeleteLineToCursorAction() {
super(rtaDeleteLineToCursorAction);
}
@Override
public void actionPerformedImpl(ActionEvent e, RTextArea textArea) {
if (!textArea.isEditable() || !textArea.isEnabled()) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
return;
}
try {
// We use the elements instead of calling getLineOfOffset(),
// etc. to speed things up just a tad (i.e. micro-optimize).
Document document = textArea.getDocument();
int caretPosition = textArea.getCaretPosition();
Element map = document.getDefaultRootElement();
int currentLineNum = map.getElementIndex(caretPosition);
Element currentLineElement = map.getElement(currentLineNum);
int currentLineStart = currentLineElement.getStartOffset();
if (caretPosition > currentLineStart) {
document.remove(currentLineStart, caretPosition - currentLineStart);
}
} catch (BadLocationException ble) {
ble.printStackTrace();
}
}
@Override
public String getMacroID() {
return rtaDeleteLineToCursorAction;
}
}
}

View File

@@ -0,0 +1,21 @@
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaUI;
import javax.swing.*;
import javax.swing.text.EditorKit;
import javax.swing.text.JTextComponent;
public class SketchTextAreaUI extends RSyntaxTextAreaUI {
private static final EditorKit defaultKit = new SketchTextAreaEditorKit();
public SketchTextAreaUI(JComponent rSyntaxTextArea) {
super(rSyntaxTextArea);
}
@Override
public EditorKit getEditorKit(JTextComponent tc) {
return defaultKit;
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br)
* Copyright 2015 Arduino LLC
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.modes.CPlusPlusTokenMaker;
import java.util.Arrays;
/**
* Controls the syntax highlighting of {@link SketchTextArea} based on the {@link PdeKeywords}
*
* @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
* @date 20/04/2015
* @since 1.6.4
*/
public class SketchTokenMaker extends CPlusPlusTokenMaker {
private final PdeKeywords pdeKeywords;
public SketchTokenMaker(PdeKeywords pdeKeywords) {
this.pdeKeywords = pdeKeywords;
}
@Override
public void addToken(char[] array, int start, int end, int tokenType, int startOffset, boolean hyperlink) {
// This assumes all of your extra tokens would normally be scanned as IDENTIFIER.
int newType = pdeKeywords.getTokenType(array, start, end);
if (newType > -1) {
tokenType = newType;
}
super.addToken(array, start, end, tokenType, startOffset, hyperlink);
}
}

View File

@@ -1,165 +0,0 @@
/*
* SyntaxDocument.java - Document that can be tokenized
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.undo.UndoableEdit;
/**
* A document implementation that can be tokenized by the syntax highlighting
* system.
*
* @author Slava Pestov
*/
public class SyntaxDocument extends PlainDocument
{
/**
* Returns the token marker that is to be used to split lines
* of this document up into tokens. May return null if this
* document is not to be colorized.
*/
public TokenMarker getTokenMarker()
{
return tokenMarker;
}
/**
* Sets the token marker that is to be used to split lines of
* this document up into tokens. May throw an exception if
* this is not supported for this type of document.
* @param tm The new token marker
*/
public void setTokenMarker(TokenMarker tm)
{
tokenMarker = tm;
if(tm == null)
return;
tokenMarker.insertLines(0,getDefaultRootElement()
.getElementCount());
tokenizeLines();
}
/**
* Reparses the document, by passing all lines to the token
* marker. This should be called after the document is first
* loaded.
*/
public void tokenizeLines()
{
tokenizeLines(0,getDefaultRootElement().getElementCount());
}
/**
* Reparses the document, by passing the specified lines to the
* token marker. This should be called after a large quantity of
* text is first inserted.
* @param start The first line to parse
* @param len The number of lines, after the first one to parse
*/
public void tokenizeLines(int start, int len)
{
if(tokenMarker == null || !tokenMarker.supportsMultilineTokens())
return;
Segment lineSegment = new Segment();
Element map = getDefaultRootElement();
len += start;
try
{
for(int i = start; i < len; i++)
{
Element lineElement = map.getElement(i);
int lineStart = lineElement.getStartOffset();
getText(lineStart,lineElement.getEndOffset()
- lineStart - 1,lineSegment);
tokenMarker.markTokens(lineSegment,i);
}
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
}
/**
* Starts a compound edit that can be undone in one operation.
* Subclasses that implement undo should override this method;
* this class has no undo functionality so this method is
* empty.
*/
public void beginCompoundEdit() {}
/**
* Ends a compound edit that can be undone in one operation.
* Subclasses that implement undo should override this method;
* this class has no undo functionality so this method is
* empty.
*/
public void endCompoundEdit() {}
/**
* Adds an undoable edit to this document's undo list. The edit
* should be ignored if something is currently being undone.
* @param edit The undoable edit
*
* @since jEdit 2.2pre1
*/
public void addUndoableEdit(UndoableEdit edit) {}
// protected members
protected TokenMarker tokenMarker;
/**
* We overwrite this method to update the token marker
* state immediately so that any event listeners get a
* consistent token marker.
*/
protected void fireInsertUpdate(DocumentEvent evt)
{
if(tokenMarker != null)
{
DocumentEvent.ElementChange ch = evt.getChange(
getDefaultRootElement());
if(ch != null)
{
tokenMarker.insertLines(ch.getIndex() + 1,
ch.getChildrenAdded().length -
ch.getChildrenRemoved().length);
}
}
super.fireInsertUpdate(evt);
}
/**
* We overwrite this method to update the token marker
* state immediately so that any event listeners get a
* consistent token marker.
*/
protected void fireRemoveUpdate(DocumentEvent evt)
{
if(tokenMarker != null)
{
DocumentEvent.ElementChange ch = evt.getChange(
getDefaultRootElement());
if(ch != null)
{
tokenMarker.deleteLines(ch.getIndex() + 1,
ch.getChildrenRemoved().length -
ch.getChildrenAdded().length);
}
}
super.fireRemoveUpdate(evt);
}
}

View File

@@ -1,163 +0,0 @@
/*
* SyntaxStyle.java - A simple text style class
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.util.Hashtable;
import java.util.Map;
import javax.swing.JComponent;
/**
* A simple text style class. It can specify the color, italic flag,
* and bold flag of a run of text.
* @author Slava Pestov
*/
public class SyntaxStyle
{
/**
* Creates a new SyntaxStyle.
* @param color The text color
* @param italic True if the text should be italics
* @param bold True if the text should be bold
*/
public SyntaxStyle(Color color, boolean italic, boolean bold, boolean underlined)
{
this.color = color;
this.italic = italic;
this.bold = bold;
this.underlined = underlined;
}
/**
* Returns the color specified in this style.
*/
public Color getColor()
{
return color;
}
/**
* Returns true if no font styles are enabled.
*/
public boolean isPlain()
{
return !(bold || italic || underlined);
}
/**
* Returns true if italics is enabled for this style.
*/
public boolean isItalic()
{
return italic;
}
/**
* Returns true if boldface is enabled for this style.
*/
public boolean isBold()
{
return bold;
}
/**
* @return true if underline is enabled for this style.
*/
public boolean isUnderlined() {
return underlined;
}
/**
* Returns the specified font, but with the style's bold, underline and
* italic flags applied.
*/
public Font getStyledFont(Font font)
{
if(font == null)
throw new NullPointerException("font param must not"
+ " be null");
if(font.equals(lastFont))
return lastStyledFont;
lastFont = font;
lastStyledFont = new Font(font.getFamily(),
(bold ? Font.BOLD : 0)
| (italic ? Font.ITALIC : 0),
font.getSize());
if (underlined) {
Map<TextAttribute, Object> attr = new Hashtable<TextAttribute, Object>();
attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
lastStyledFont = lastStyledFont.deriveFont(attr);
}
return lastStyledFont;
}
/**
* Returns the font metrics for the styled font.
*/
public FontMetrics getFontMetrics(Font font, JComponent comp)
{
if(font == null)
throw new NullPointerException("font param must not"
+ " be null");
if(font.equals(lastFont) && fontMetrics != null)
return fontMetrics;
lastFont = font;
lastStyledFont = new Font(font.getFamily(),
(bold ? Font.BOLD : 0)
| (italic ? Font.ITALIC : 0),
font.getSize());
if (underlined) {
Map<TextAttribute, Object> attr = new Hashtable<TextAttribute, Object>();
attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
lastStyledFont = lastStyledFont.deriveFont(attr);
}
//fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont);
fontMetrics = comp.getFontMetrics(lastStyledFont);
return fontMetrics;
}
/**
* Sets the foreground color and font of the specified graphics
* context to that specified in this style.
* @param gfx The graphics context
* @param font The font to add the styles to
*/
public void setGraphicsFlags(Graphics gfx, Font font)
{
Font _font = getStyledFont(font);
gfx.setFont(_font);
gfx.setColor(color);
}
/**
* Returns a string representation of this object.
*/
public String toString()
{
return getClass().getName() + "[color=" + color +
(italic ? ",italic" : "") +
(bold ? ",bold" : "") +
(underlined ? ",underlined" : "") +
"]";
}
// private members
private Color color;
private boolean italic;
private boolean bold;
private boolean underlined;
private Font lastFont;
private Font lastStyledFont;
private FontMetrics fontMetrics;
}

View File

@@ -1,226 +0,0 @@
/*
* SyntaxUtilities.java - Utility functions used by syntax colorizing
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import javax.swing.text.*;
import java.awt.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class with several utility functions used by jEdit's syntax colorizing
* subsystem.
*
* @author Slava Pestov
*/
public class SyntaxUtilities
{
/**
* Checks if a subregion of a <code>Segment</code> is equal to a
* string.
* @param ignoreCase True if case should be ignored, false otherwise
* @param text The segment
* @param offset The offset into the segment
* @param match The string to match
*/
public static boolean regionMatches(boolean ignoreCase, Segment text,
int offset, String match)
{
int length = offset + match.length();
char[] textArray = text.array;
if(length > text.offset + text.count)
return false;
for(int i = offset, j = 0; i < length; i++, j++)
{
char c1 = textArray[i];
char c2 = match.charAt(j);
if(ignoreCase)
{
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
}
if(c1 != c2)
return false;
}
return true;
}
/**
* Checks if a subregion of a <code>Segment</code> is equal to a
* character array.
* @param ignoreCase True if case should be ignored, false otherwise
* @param text The segment
* @param offset The offset into the segment
* @param match The character array to match
*/
public static boolean regionMatches(boolean ignoreCase, Segment text,
int offset, char[] match)
{
int length = offset + match.length;
char[] textArray = text.array;
if(length > text.offset + text.count)
return false;
for(int i = offset, j = 0; i < length; i++, j++)
{
char c1 = textArray[i];
char c2 = match[j];
if(ignoreCase)
{
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
}
if(c1 != c2)
return false;
}
return true;
}
/**
* Returns the default style table. This can be passed to the
* <code>setStyles()</code> method of <code>SyntaxDocument</code>
* to use the default syntax styles.
*/
public static SyntaxStyle[] getDefaultSyntaxStyles()
{
SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false,false);
styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false,false);
styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true,false);
styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false,false);
styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false,false);
styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false,false);
styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true,false);
styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true,false);
styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true,false);
styles[Token.URL] = new SyntaxStyle(Color.blue,true,false,false);
styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true,false);
return styles;
}
/**
* Paints the specified line onto the graphics context. Note that this
* method munges the offset and count values of the segment.
* @param line The line segment
* @param tokens The token list for the line
* @param styles The syntax style list
* @param expander The tab expander used to determine tab stops. May
* be null
* @param gfx The graphics context
* @param x The x co-ordinate
* @param y The y co-ordinate
* @return The x co-ordinate, plus the width of the painted string
*/
public static int paintSyntaxLine(Segment line, Token tokens,
SyntaxStyle[] styles,
TabExpander expander, Graphics gfx,
int x, int y)
{
Font defaultFont = gfx.getFont();
Color defaultColor = gfx.getColor();
for(;;)
{
byte id = tokens.id;
if(id == Token.END)
break;
int length = tokens.length;
if(id == Token.NULL)
{
if(!defaultColor.equals(gfx.getColor()))
gfx.setColor(defaultColor);
if(!defaultFont.equals(gfx.getFont()))
gfx.setFont(defaultFont);
}
else
styles[id].setGraphicsFlags(gfx,defaultFont);
line.count = length;
if (id == Token.COMMENT1 || id == Token.COMMENT2)
x = drawTabbedCommentsText(line, x, y, gfx, expander, styles, styles[id]);
else
x = Utilities.drawTabbedText(line, x, y, gfx, expander, 0);
line.offset += length;
tokens = tokens.next;
}
return x;
}
/**
* Parse comments and identify "@schematics <b>&lt;something&gt;</b>" pattern.
*
* @param line
* A string to parse
* @return <b>null</b> if the pattern is not found, otherwise an array of
* String is returned: the elements with index 0, 1 and 2 are
* respectively the preamble, the <b>&lt;something&gt;</b> stuff, and
* the remaining part of the string.
*/
public static String[] parseCommentUrls(String line) {
Matcher m = urlPattern.matcher(line.toString());
if (!m.find())
return null;
String res[] = new String[3];
res[0] = line.substring(0, m.start(1));
res[1] = line.substring(m.start(1), m.end(1));
res[2] = line.substring(m.end(1));
// System.out.println("0 =>"+res[0]+"<\n1 =>"+res[1]+"< \n2 =>"+res[2]+"<");
return res;
}
static private Pattern urlPattern = Pattern.compile(
"((?:https?|ftp)://" + // ( Protocol
"(?:(?:[\\w_\\-]+:)?[\\w_\\-]+@)?" + // Username and password
"(?:[\\w_\\-]+\\.)+[\\w_\\-]+" + // Domain name
"(?::[0-9]{1,5})?" + // Port
"(?:/[\\w_\\-./?%&=+]*)?)" + // Path )
"(?:\\s|$)"); // whitespace or EOL
public static Segment stringToSegment(String v) {
return new Segment(v.toCharArray(), 0, v.length());
}
private static int drawTabbedCommentsText(Segment line, int x, int y,
Graphics gfx, TabExpander expander, SyntaxStyle[] styles,
SyntaxStyle commentStyle) {
String parse[] = parseCommentUrls(line.toString());
if (parse == null)
// Revert to plain writing.
return Utilities.drawTabbedText(line, x, y, gfx, expander, 0);
Segment pre = stringToSegment(parse[0]);
Segment tag = stringToSegment(parse[1]);
Segment post = stringToSegment(parse[2]);
if (pre.count>0)
x = Utilities.drawTabbedText(pre, x, y, gfx, expander, 0);
Font f = gfx.getFont();
styles[Token.URL].setGraphicsFlags(gfx, f);
x = Utilities.drawTabbedText(tag, x, y, gfx, expander, 0);
commentStyle.setGraphicsFlags(gfx, f);
if (post.count>0)
x = Utilities.drawTabbedText(post, x, y, gfx, expander, 0);
return x;
}
// private members
private SyntaxUtilities() {}
}

View File

@@ -1,90 +0,0 @@
/*
* TextAreaDefaults.java - Encapsulates default values for various settings
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import java.awt.*;
//import javax.swing.JPopupMenu;
/**
* Encapsulates default settings for a text area. This can be passed
* to the constructor once the necessary fields have been filled out.
* The advantage of doing this over calling lots of set() methods after
* creating the text area is that this method is faster.
*/
public class TextAreaDefaults
{
private static TextAreaDefaults DEFAULTS;
public InputHandler inputHandler;
public SyntaxDocument document;
public boolean editable;
public boolean caretVisible;
public boolean caretBlinks;
public boolean blockCaret;
public int electricScroll;
public int cols;
public int rows;
public SyntaxStyle[] styles;
public Color caretColor;
public Color selectionColor;
public Color lineHighlightColor;
public boolean lineHighlight;
public Color bracketHighlightColor;
public boolean bracketHighlight;
public Color eolMarkerColor;
public boolean eolMarkers;
public boolean paintInvalid;
// moved from TextAreaPainter [fry]
public Font font;
public Color fgcolor;
public Color bgcolor;
//public JPopupMenu popup;
/**
* Returns a new TextAreaDefaults object with the default values filled
* in.
*/
public static TextAreaDefaults getDefaults()
{
if (DEFAULTS == null) {
DEFAULTS = new TextAreaDefaults();
DEFAULTS.inputHandler = new DefaultInputHandler();
DEFAULTS.inputHandler.addDefaultKeyBindings();
DEFAULTS.document = new SyntaxDocument();
DEFAULTS.editable = true;
DEFAULTS.caretVisible = true;
DEFAULTS.caretBlinks = true;
DEFAULTS.electricScroll = 3;
DEFAULTS.cols = 80;
DEFAULTS.rows = 25;
DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
DEFAULTS.caretColor = Color.red;
DEFAULTS.selectionColor = new Color(0xccccff);
DEFAULTS.lineHighlightColor = new Color(0xe0e0e0);
DEFAULTS.lineHighlight = true;
DEFAULTS.bracketHighlightColor = Color.black;
DEFAULTS.bracketHighlight = true;
DEFAULTS.eolMarkerColor = new Color(0x009999);
DEFAULTS.eolMarkers = true;
DEFAULTS.paintInvalid = true;
}
return DEFAULTS;
}
}

View File

@@ -1,106 +0,0 @@
/*
* TextAreaLineNumbers.java - Show line numbers for the open file in the editor
* Copyright (C) 2013 Cayci Gorlitsky
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.border.MatteBorder;
public class TextAreaLineNumbers extends TextAreaPainter {
private final int LEFT_INDENT = 6;
private final int RIGHT_INDENT = 6;
private final int RIGHT_BORDER_WIDTH = 1;
private final int PADDING_WIDTH = LEFT_INDENT + RIGHT_INDENT + RIGHT_BORDER_WIDTH;
private final int MIN_WIDTH;
private final int DIGIT_WIDTH;
private final int MIN_NUM_DIGITS = 2;
private int currStartNum = 0;
private int currEndNum = 0;
private int currNumDigits = MIN_NUM_DIGITS;
public TextAreaLineNumbers(JEditTextArea textArea, TextAreaDefaults defaults) {
super(textArea, defaults);
DIGIT_WIDTH = getFontMetrics(getFont()).stringWidth("0");
MIN_WIDTH = DIGIT_WIDTH * MIN_NUM_DIGITS + PADDING_WIDTH;
setEnabled(false);
setBorder(new MatteBorder(0, 0, 0, RIGHT_BORDER_WIDTH, new Color(240, 240, 240)));
}
public void updateLineNumbers(int startNum, int endNum) {
if (currStartNum == startNum && currEndNum == endNum) {
return;
}
currStartNum = startNum;
currEndNum = endNum;
invalidate();
repaint();
}
@Override
public void paint(Graphics gfx) {
super.paint(gfx);
getBorder().paintBorder(this, gfx, 0, 0, getSize().width, getSize().height);
}
@Override
protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
int line, int x)
{
currentLineIndex = line;
gfx.setFont(getFont());
gfx.setColor(Color.GRAY);
int y = textArea.lineToY(line);
int startX = getBounds().x + getBounds().width;
if (line >= 0 && line < textArea.getLineCount()) {
String lineNumberString = String.valueOf(line+1);
int lineStartX = startX - RIGHT_BORDER_WIDTH - RIGHT_INDENT - fm.stringWidth(lineNumberString);
gfx.drawString(lineNumberString,lineStartX,y + fm.getHeight());
}
}
public void updateWidthForNumDigits(int numDigits) {
if (currNumDigits == numDigits) {
return;
}
currNumDigits = numDigits;
if (isVisible()) {
updateBounds();
invalidate();
repaint();
}
}
public void setDisplayLineNumbers(boolean displayLineNumbers) {
setVisible(displayLineNumbers);
if (displayLineNumbers) {
updateBounds();
} else {
setBounds(new Rectangle(0, getHeight()));
}
invalidate();
repaint();
}
private void updateBounds() {
if (isVisible()) {
setBounds(new Rectangle(Math.max(MIN_WIDTH, DIGIT_WIDTH * currNumDigits + PADDING_WIDTH), getHeight()));
textArea.validate();
}
}
}

View File

@@ -1,787 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* TextAreaPainter.java - Paints the text area
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import processing.app.*;
import processing.app.syntax.im.CompositionTextPainter;
import javax.swing.ToolTipManager;
import javax.swing.text.*;
import javax.swing.JComponent;
import java.awt.event.MouseEvent;
import java.awt.*;
import java.awt.print.*;
/**
* The text area repaint manager. It performs double buffering and paints
* lines of text.
* @author Slava Pestov
*/
public class TextAreaPainter extends JComponent
implements TabExpander, Printable
{
/** True if inside printing, will handle disabling the highlight */
boolean printing;
/** Current setting for editor.antialias preference */
boolean antialias;
/** A specific painter composed by the InputMethod.*/
protected CompositionTextPainter compositionTextPainter;
/**
* Creates a new repaint manager. This should be not be called
* directly.
*/
public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
{
this.textArea = textArea;
setAutoscrolls(true);
setDoubleBuffered(true);
setOpaque(true);
ToolTipManager.sharedInstance().registerComponent(this);
currentLine = new Segment();
currentLineIndex = -1;
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
setFont(defaults.font);
setForeground(defaults.fgcolor);
setBackground(defaults.bgcolor);
antialias = Preferences.getBoolean("editor.antialias");
blockCaret = defaults.blockCaret;
styles = defaults.styles;
cols = defaults.cols;
rows = defaults.rows;
caretColor = defaults.caretColor;
selectionColor = defaults.selectionColor;
lineHighlightColor = defaults.lineHighlightColor;
lineHighlight = defaults.lineHighlight;
bracketHighlightColor = defaults.bracketHighlightColor;
bracketHighlight = defaults.bracketHighlight;
paintInvalid = defaults.paintInvalid;
eolMarkerColor = defaults.eolMarkerColor;
eolMarkers = defaults.eolMarkers;
}
/**
* Get CompositionTextPainter. if CompositionTextPainter is not created, create it.
*/
public CompositionTextPainter getCompositionTextpainter(){
if(compositionTextPainter == null){
compositionTextPainter = new CompositionTextPainter(textArea);
}
return compositionTextPainter;
}
/**
* Returns if this component can be traversed by pressing the
* Tab key. This returns false.
*/
// public final boolean isManagingFocus()
// {
// return false;
// }
/**
* Returns the syntax styles used to paint colorized text. Entry <i>n</i>
* will be used to paint tokens with id = <i>n</i>.
* @see processing.app.syntax.Token
*/
public final SyntaxStyle[] getStyles()
{
return styles;
}
/**
* Sets the syntax styles used to paint colorized text. Entry <i>n</i>
* will be used to paint tokens with id = <i>n</i>.
* @param styles The syntax styles
* @see processing.app.syntax.Token
*/
public final void setStyles(SyntaxStyle[] styles)
{
this.styles = styles;
repaint();
}
/**
* Returns the caret color.
*/
public final Color getCaretColor()
{
return caretColor;
}
/**
* Sets the caret color.
* @param caretColor The caret color
*/
public final void setCaretColor(Color caretColor)
{
this.caretColor = caretColor;
invalidateSelectedLines();
}
/**
* Returns the selection color.
*/
public final Color getSelectionColor()
{
return selectionColor;
}
/**
* Sets the selection color.
* @param selectionColor The selection color
*/
public final void setSelectionColor(Color selectionColor)
{
this.selectionColor = selectionColor;
invalidateSelectedLines();
}
/**
* Returns the line highlight color.
*/
public final Color getLineHighlightColor()
{
return lineHighlightColor;
}
/**
* Sets the line highlight color.
* @param lineHighlightColor The line highlight color
*/
public final void setLineHighlightColor(Color lineHighlightColor)
{
this.lineHighlightColor = lineHighlightColor;
invalidateSelectedLines();
}
/**
* Returns true if line highlight is enabled, false otherwise.
*/
public final boolean isLineHighlightEnabled()
{
return lineHighlight;
}
/**
* Enables or disables current line highlighting.
* @param lineHighlight True if current line highlight
* should be enabled, false otherwise
*/
public final void setLineHighlightEnabled(boolean lineHighlight)
{
this.lineHighlight = lineHighlight;
invalidateSelectedLines();
}
/**
* Returns the bracket highlight color.
*/
public final Color getBracketHighlightColor()
{
return bracketHighlightColor;
}
/**
* Sets the bracket highlight color.
* @param bracketHighlightColor The bracket highlight color
*/
public final void setBracketHighlightColor(Color bracketHighlightColor)
{
this.bracketHighlightColor = bracketHighlightColor;
invalidateLine(textArea.getBracketLine());
}
/**
* Returns true if bracket highlighting is enabled, false otherwise.
* When bracket highlighting is enabled, the bracket matching the
* one before the caret (if any) is highlighted.
*/
public final boolean isBracketHighlightEnabled()
{
return bracketHighlight;
}
/**
* Enables or disables bracket highlighting.
* When bracket highlighting is enabled, the bracket matching the
* one before the caret (if any) is highlighted.
* @param bracketHighlight True if bracket highlighting should be
* enabled, false otherwise
*/
public final void setBracketHighlightEnabled(boolean bracketHighlight)
{
this.bracketHighlight = bracketHighlight;
invalidateLine(textArea.getBracketLine());
}
/**
* Returns true if the caret should be drawn as a block, false otherwise.
*/
public final boolean isBlockCaretEnabled()
{
return blockCaret;
}
/**
* Sets if the caret should be drawn as a block, false otherwise.
* @param blockCaret True if the caret should be drawn as a block,
* false otherwise.
*/
public final void setBlockCaretEnabled(boolean blockCaret)
{
this.blockCaret = blockCaret;
invalidateSelectedLines();
}
/**
* Returns the EOL marker color.
*/
public final Color getEOLMarkerColor()
{
return eolMarkerColor;
}
/**
* Sets the EOL marker color.
* @param eolMarkerColor The EOL marker color
*/
public final void setEOLMarkerColor(Color eolMarkerColor)
{
this.eolMarkerColor = eolMarkerColor;
repaint();
}
/**
* Returns true if EOL markers are drawn, false otherwise.
*/
public final boolean getEOLMarkersPainted()
{
return eolMarkers;
}
/**
* Sets if EOL markers are to be drawn.
* @param eolMarkers True if EOL markers should be drawn, false otherwise
*/
public final void setEOLMarkersPainted(boolean eolMarkers)
{
this.eolMarkers = eolMarkers;
repaint();
}
/**
* Returns true if invalid lines are painted as red tildes (~),
* false otherwise.
*/
public boolean getInvalidLinesPainted()
{
return paintInvalid;
}
/**
* Sets if invalid lines are to be painted as red tildes.
* @param paintInvalid True if invalid lines should be drawn, false otherwise
*/
public void setInvalidLinesPainted(boolean paintInvalid)
{
this.paintInvalid = paintInvalid;
}
/**
* Adds a custom highlight painter.
* @param highlight The highlight
*/
public void addCustomHighlight(Highlight highlight)
{
highlight.init(textArea,highlights);
highlights = highlight;
}
/**
* Highlight interface.
*/
public interface Highlight
{
/**
* Called after the highlight painter has been added.
* @param textArea The text area
* @param next The painter this one should delegate to
*/
void init(JEditTextArea textArea, Highlight next);
/**
* This should paint the highlight and delgate to the
* next highlight painter.
* @param gfx The graphics context
* @param line The line number
* @param y The y co-ordinate of the line
*/
void paintHighlight(Graphics gfx, int line, int y);
/**
* Returns the tool tip to display at the specified
* location. If this highlighter doesn't know what to
* display, it should delegate to the next highlight
* painter.
* @param evt The mouse event
*/
String getToolTipText(MouseEvent evt);
}
/**
* Returns the tool tip to display at the specified location.
* @param evt The mouse event
*/
public String getToolTipText(MouseEvent evt)
{
if(highlights != null)
return highlights.getToolTipText(evt);
else
return null;
}
/**
* Returns the font metrics used by this component.
*/
public FontMetrics getFontMetrics()
{
return fm;
}
/**
* Sets the font for this component. This is overridden to update the
* cached font metrics and to recalculate which lines are visible.
* @param font The font
*/
public void setFont(Font font)
{
super.setFont(font);
fm = super.getFontMetrics(font);
textArea.recalculateVisibleLines();
}
/**
* Repaints the text.
* @param gfx The graphics context
*/
public void paint(Graphics gfx)
{
Graphics2D g2 = (Graphics2D) gfx;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
antialias ?
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue();
Rectangle clipRect = gfx.getClipBounds();
gfx.setColor(getBackground());
gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
// We don't use yToLine() here because that method doesn't
// return lines past the end of the document
int height = fm.getHeight();
int firstLine = textArea.getFirstLine();
int firstInvalid = firstLine + clipRect.y / height;
// Because the clipRect's height is usually an even multiple
// of the font height, we subtract 1 from it, otherwise one
// too many lines will always be painted.
int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
try {
TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
int x = textArea.getHorizontalOffset();
for (int line = firstInvalid; line <= lastInvalid; line++) {
paintLine(gfx,tokenMarker,line,x);
}
if (tokenMarker != null && tokenMarker.isNextLineRequested()) {
int h = clipRect.y + clipRect.height;
repaint(0,h,getWidth(),getHeight() - h);
}
} catch (Exception e) {
System.err.println("Error repainting line"
+ " range {" + firstInvalid + ","
+ lastInvalid + "}:");
e.printStackTrace();
}
}
public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
int lineHeight = fm.getHeight();
int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
int lineCount = textArea.getLineCount();
int lastPage = lineCount / linesPerPage;
if (pageIndex > lastPage) {
return NO_SUCH_PAGE;
} else {
Graphics2D g2d = (Graphics2D)g;
TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
int firstLine = pageIndex*linesPerPage;
g2d.translate(Math.max(54, pageFormat.getImageableX()),
pageFormat.getImageableY() - firstLine*lineHeight);
printing = true;
for (int line = firstLine; line < firstLine + linesPerPage; line++) {
paintLine(g2d, tokenMarker, line, 0);
}
printing = false;
return PAGE_EXISTS;
}
}
/**
* Marks a line as needing a repaint.
* @param line The line to invalidate
*/
public final void invalidateLine(int line)
{
repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
getWidth(),fm.getHeight());
}
/**
* Marks a range of lines as needing a repaint.
* @param firstLine The first line to invalidate
* @param lastLine The last line to invalidate
*/
public final void invalidateLineRange(int firstLine, int lastLine)
{
repaint(0,textArea.lineToY(firstLine) +
fm.getMaxDescent() + fm.getLeading(),
getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
}
/**
* Repaints the lines containing the selection.
*/
public final void invalidateSelectedLines()
{
invalidateLineRange(textArea.getSelectionStartLine(),
textArea.getSelectionStopLine());
}
/**
* Implementation of TabExpander interface. Returns next tab stop after
* a specified point.
* @param x The x co-ordinate
* @param tabOffset Ignored
* @return The next tab stop after <i>x</i>
*/
public float nextTabStop(float x, int tabOffset)
{
int offset = textArea.getHorizontalOffset();
int ntabs = ((int)x - offset) / tabSize;
return (ntabs + 1) * tabSize + offset;
}
/**
* Returns the painter's preferred size.
*/
public Dimension getPreferredSize()
{
Dimension dim = new Dimension();
dim.width = fm.charWidth('w') * cols;
dim.height = fm.getHeight() * rows;
return dim;
}
/**
* Returns the painter's minimum size.
*/
public Dimension getMinimumSize()
{
Dimension dim = new Dimension();
dim.width = fm.charWidth('w') * 10;
dim.height = fm.getHeight() * 4;
return dim;
}
// package-private members
int currentLineIndex;
Token currentLineTokens;
Segment currentLine;
/**
* Accessor used by tools that want to hook in and grab the formatting.
*/
public int getCurrentLineIndex() {
return currentLineIndex;
}
/**
* Accessor used by tools that want to hook in and grab the formatting.
*/
public void setCurrentLineIndex(int what) {
currentLineIndex = what;
}
/**
* Accessor used by tools that want to hook in and grab the formatting.
*/
public Token getCurrentLineTokens() {
return currentLineTokens;
}
/**
* Accessor used by tools that want to hook in and grab the formatting.
*/
public void setCurrentLineTokens(Token tokens) {
currentLineTokens = tokens;
}
/**
* Accessor used by tools that want to hook in and grab the formatting.
*/
public Segment getCurrentLine() {
return currentLine;
}
// protected members
protected JEditTextArea textArea;
protected SyntaxStyle[] styles;
protected Color caretColor;
protected Color selectionColor;
protected Color lineHighlightColor;
protected Color bracketHighlightColor;
protected Color eolMarkerColor;
protected boolean blockCaret;
protected boolean lineHighlight;
protected boolean bracketHighlight;
protected boolean paintInvalid;
protected boolean eolMarkers;
protected int cols;
protected int rows;
protected int tabSize;
protected FontMetrics fm;
protected Highlight highlights;
protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
int line, int x)
{
Font defaultFont = getFont();
Color defaultColor = getForeground();
currentLineIndex = line;
int y = textArea.lineToY(line);
if (line < 0 || line >= textArea.getLineCount()) {
if (paintInvalid) {
paintHighlight(gfx,line,y);
styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
gfx.drawString("~",0,y + fm.getHeight());
}
} else if(tokenMarker == null) {
paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
} else {
paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
defaultColor,x,y);
}
}
protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
Color defaultColor, int x, int y)
{
paintHighlight(gfx,line,y);
textArea.getLineText(line,currentLine);
gfx.setFont(defaultFont);
gfx.setColor(defaultColor);
y += fm.getHeight();
x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
/*
* Draw characters via input method.
*/
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
compositionTextPainter.draw(gfx, lineHighlightColor);
}
if (eolMarkers) {
gfx.setColor(eolMarkerColor);
gfx.drawString(".",x,y);
}
}
protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
int line, Font defaultFont,
Color defaultColor, int x, int y)
{
textArea.getLineText(currentLineIndex,currentLine);
currentLineTokens = tokenMarker.markTokens(currentLine,
currentLineIndex);
paintHighlight(gfx,line,y);
gfx.setFont(defaultFont);
gfx.setColor(defaultColor);
y += fm.getHeight();
x = SyntaxUtilities.paintSyntaxLine(currentLine,
currentLineTokens,
styles, this, gfx, x, y);
/*
* Draw characters via input method.
*/
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
compositionTextPainter.draw(gfx, lineHighlightColor);
}
if (eolMarkers) {
gfx.setColor(eolMarkerColor);
gfx.drawString(".",x,y);
}
}
protected void paintHighlight(Graphics gfx, int line, int y)
{
if (!printing) {
if (line >= textArea.getSelectionStartLine()
&& line <= textArea.getSelectionStopLine())
paintLineHighlight(gfx,line,y);
if (highlights != null)
highlights.paintHighlight(gfx,line,y);
if (bracketHighlight && line == textArea.getBracketLine())
paintBracketHighlight(gfx,line,y);
if (line == textArea.getCaretLine())
paintCaret(gfx,line,y);
}
}
protected void paintLineHighlight(Graphics gfx, int line, int y)
{
int height = fm.getHeight();
y += fm.getLeading() + fm.getMaxDescent();
int selectionStart = textArea.getSelectionStart();
int selectionEnd = textArea.getSelectionStop();
if (selectionStart == selectionEnd) {
if (lineHighlight) {
gfx.setColor(lineHighlightColor);
gfx.fillRect(0,y,getWidth(),height);
}
} else {
gfx.setColor(selectionColor);
int selectionStartLine = textArea.getSelectionStartLine();
int selectionEndLine = textArea.getSelectionStopLine();
int lineStart = textArea.getLineStartOffset(line);
int x1, x2;
if (textArea.isSelectionRectangular()) {
int lineLen = textArea.getLineLength(line);
x1 = textArea._offsetToX(line,Math.min(lineLen, selectionStart - textArea.getLineStartOffset(selectionStartLine)));
x2 = textArea._offsetToX(line,Math.min(lineLen, selectionEnd - textArea.getLineStartOffset(selectionEndLine)));
if (x1 == x2)
x2++;
} else if(selectionStartLine == selectionEndLine) {
x1 = textArea._offsetToX(line, selectionStart - lineStart);
x2 = textArea._offsetToX(line, selectionEnd - lineStart);
} else if(line == selectionStartLine) {
x1 = textArea._offsetToX(line, selectionStart - lineStart);
x2 = getWidth();
} else if(line == selectionEndLine) {
//x1 = 0;
// hack from stendahl to avoid doing weird side selection thing
x1 = textArea._offsetToX(line, 0);
// attempt at getting the gutter too, but doesn't seem to work
//x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
x2 = textArea._offsetToX(line, selectionEnd - lineStart);
} else {
//x1 = 0;
// hack from stendahl to avoid doing weird side selection thing
x1 = textArea._offsetToX(line, 0);
// attempt at getting the gutter too, but doesn't seem to work
//x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
x2 = getWidth();
}
// "inlined" min/max()
gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
(x1 - x2) : (x2 - x1),height);
}
}
protected void paintBracketHighlight(Graphics gfx, int line, int y)
{
int position = textArea.getBracketPosition();
if(position == -1)
return;
y += fm.getLeading() + fm.getMaxDescent();
int x = textArea._offsetToX(line,position);
gfx.setColor(bracketHighlightColor);
// Hack!!! Since there is no fast way to get the character
// from the bracket matching routine, we use ( since all
// brackets probably have the same width anyway
gfx.drawRect(x,y,fm.charWidth('(') - 1,
fm.getHeight() - 1);
}
protected void paintCaret(Graphics gfx, int line, int y)
{
//System.out.println("painting caret " + line + " " + y);
if (textArea.isCaretVisible()) {
//System.out.println("caret is visible");
int offset =
textArea.getCaretPosition() - textArea.getLineStartOffset(line);
int caretX = textArea._offsetToX(line, offset);
int caretWidth = ((blockCaret ||
textArea.isOverwriteEnabled()) ?
fm.charWidth('w') : 1);
y += fm.getLeading() + fm.getMaxDescent();
int height = fm.getHeight();
//System.out.println("caretX, width = " + caretX + " " + caretWidth);
gfx.setColor(caretColor);
if (textArea.isOverwriteEnabled()) {
gfx.fillRect(caretX,y + height - 1, caretWidth,1);
} else {
// some machines don't like the drawRect for the single
// pixel caret.. this caused a lot of hell because on that
// minority of machines, the caret wouldn't show up past
// the first column. the fix is to use drawLine() in
// those cases, as a workaround.
if (caretWidth == 1) {
gfx.drawLine(caretX, y, caretX, y + height - 1);
} else {
gfx.drawRect(caretX, y, caretWidth - 1, height - 1);
}
//gfx.drawRect(caretX, y, caretWidth, height - 1);
}
}
}
}

View File

@@ -1,183 +0,0 @@
/*
* TextUtilities.java - Utility functions used by the text area classes
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import javax.swing.text.*;
/**
* Class with several utility functions used by the text area component.
* @author Slava Pestov
*/
public class TextUtilities
{
/**
* Returns the offset of the bracket matching the one at the
* specified offset of the document, or -1 if the bracket is
* unmatched (or if the character is not a bracket).
* @param doc The document
* @param offset The offset
* @exception BadLocationException If an out-of-bounds access
* was attempted on the document text
*/
public static int findMatchingBracket(Document doc, int offset)
throws BadLocationException
{
if(doc.getLength() == 0)
return -1;
char c = doc.getText(offset,1).charAt(0);
char cprime; // c` - corresponding character
boolean direction; // true = back, false = forward
switch(c)
{
case '(': cprime = ')'; direction = false; break;
case ')': cprime = '('; direction = true; break;
case '[': cprime = ']'; direction = false; break;
case ']': cprime = '['; direction = true; break;
case '{': cprime = '}'; direction = false; break;
case '}': cprime = '{'; direction = true; break;
default: return -1;
}
int count;
// How to merge these two cases is left as an exercise
// for the reader.
// Go back or forward
if(direction)
{
// Count is 1 initially because we have already
// `found' one closing bracket
count = 1;
// Get text[0,offset-1];
String text = doc.getText(0,offset);
// Scan backwards
for(int i = offset - 1; i >= 0; i--)
{
// If text[i] == c, we have found another
// closing bracket, therefore we will need
// two opening brackets to complete the
// match.
char x = text.charAt(i);
if(x == c)
count++;
// If text[i] == cprime, we have found a
// opening bracket, so we return i if
// --count == 0
else if(x == cprime)
{
if(--count == 0)
return i;
}
}
}
else
{
// Count is 1 initially because we have already
// `found' one opening bracket
count = 1;
// So we don't have to + 1 in every loop
offset++;
// Number of characters to check
int len = doc.getLength() - offset;
// Get text[offset+1,len];
String text = doc.getText(offset,len);
// Scan forwards
for(int i = 0; i < len; i++)
{
// If text[i] == c, we have found another
// opening bracket, therefore we will need
// two closing brackets to complete the
// match.
char x = text.charAt(i);
if(x == c)
count++;
// If text[i] == cprime, we have found an
// closing bracket, so we return i if
// --count == 0
else if(x == cprime)
{
if(--count == 0)
return i + offset;
}
}
}
// Nothing found
return -1;
}
/**
* Locates the start of the word at the specified position.
* @param line The text
* @param pos The position
*/
public static int findWordStart(String line, int pos, String noWordSep)
{
char ch = line.charAt(pos - 1);
if(noWordSep == null)
noWordSep = "";
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
&& noWordSep.indexOf(ch) == -1);
int wordStart = 0;
for(int i = pos - 1; i >= 0; i--)
{
ch = line.charAt(i);
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1))
{
wordStart = i + 1;
break;
}
}
return wordStart;
}
/**
* Locates the end of the word at the specified position.
* @param line The text
* @param pos The position
*/
public static int findWordEnd(String line, int pos, String noWordSep)
{
char ch = line.charAt(pos);
if(noWordSep == null)
noWordSep = "";
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
&& noWordSep.indexOf(ch) == -1);
int wordEnd = line.length();
for(int i = pos; i < line.length(); i++)
{
ch = line.charAt(i);
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1))
{
wordEnd = i;
break;
}
}
return wordEnd;
}
}

View File

@@ -1,341 +0,0 @@
/*
* TokenMarker.java - Generic token marker
* Copyright (C) 1998, 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
package processing.app.syntax;
import javax.swing.text.Segment;
/**
* A token marker that splits lines of text into tokens. Each token carries
* a length field and an indentification tag that can be mapped to a color
* for painting that token.<p>
*
* For performance reasons, the linked list of tokens is reused after each
* line is tokenized. Therefore, the return value of <code>markTokens</code>
* should only be used for immediate painting. Notably, it cannot be
* cached.
*
* @author Slava Pestov
*/
public abstract class TokenMarker
{
/**
* A wrapper for the lower-level <code>markTokensImpl</code> method
* that is called to split a line up into tokens.
* @param line The line
* @param lineIndex The line number
*/
public Token markTokens(Segment line, int lineIndex)
{
if(lineIndex >= length)
{
throw new IllegalArgumentException("Tokenizing invalid line: "
+ lineIndex);
}
lastToken = null;
LineInfo info = lineInfo[lineIndex];
LineInfo prev;
if(lineIndex == 0)
prev = null;
else
prev = lineInfo[lineIndex - 1];
byte oldToken = info.token;
byte token = markTokensImpl(prev == null ?
Token.NULL : prev.token,line,lineIndex);
info.token = token;
/*
* This is a foul hack. It stops nextLineRequested
* from being cleared if the same line is marked twice.
*
* Why is this necessary? It's all JEditTextArea's fault.
* When something is inserted into the text, firing a
* document event, the insertUpdate() method shifts the
* caret (if necessary) by the amount inserted.
*
* All caret movement is handled by the select() method,
* which eventually pipes the new position to scrollTo()
* and calls repaint().
*
* Note that at this point in time, the new line hasn't
* yet been painted; the caret is moved first.
*
* scrollTo() calls offsetToX(), which tokenizes the line
* unless it is being called on the last line painted
* (in which case it uses the text area's painter cached
* token list). What scrollTo() does next is irrelevant.
*
* After scrollTo() has done it's job, repaint() is
* called, and eventually we end up in paintLine(), whose
* job is to paint the changed line. It, too, calls
* markTokens().
*
* The problem was that if the line started a multiline
* token, the first markTokens() (done in offsetToX())
* would set nextLineRequested (because the line end
* token had changed) but the second would clear it
* (because the line was the same that time) and therefore
* paintLine() would never know that it needed to repaint
* subsequent lines.
*
* This bug took me ages to track down, that's why I wrote
* all the relevant info down so that others wouldn't
* duplicate it.
*/
if(!(lastLine == lineIndex && nextLineRequested))
nextLineRequested = (oldToken != token);
lastLine = lineIndex;
addToken(0,Token.END);
return firstToken;
}
/**
* An abstract method that splits a line up into tokens. It
* should parse the line, and call <code>addToken()</code> to
* add syntax tokens to the token list. Then, it should return
* the initial token type for the next line.<p>
*
* For example if the current line contains the start of a
* multiline comment that doesn't end on that line, this method
* should return the comment token type so that it continues on
* the next line.
*
* @param token The initial token type for this line
* @param line The line to be tokenized
* @param lineIndex The index of the line in the document,
* starting at 0
* @return The initial token type for the next line
*/
protected abstract byte markTokensImpl(byte token, Segment line,
int lineIndex);
/**
* Returns if the token marker supports tokens that span multiple
* lines. If this is true, the object using this token marker is
* required to pass all lines in the document to the
* <code>markTokens()</code> method (in turn).<p>
*
* The default implementation returns true; it should be overridden
* to return false on simpler token markers for increased speed.
*/
public boolean supportsMultilineTokens()
{
return true;
}
/**
* Informs the token marker that lines have been inserted into
* the document. This inserts a gap in the <code>lineInfo</code>
* array.
* @param index The first line number
* @param lines The number of lines
*/
public void insertLines(int index, int lines)
{
if(lines <= 0)
return;
length += lines;
ensureCapacity(length);
int len = index + lines;
System.arraycopy(lineInfo,index,lineInfo,len,
lineInfo.length - len);
for(int i = index + lines - 1; i >= index; i--)
{
lineInfo[i] = new LineInfo();
}
}
/**
* Informs the token marker that line have been deleted from
* the document. This removes the lines in question from the
* <code>lineInfo</code> array.
* @param index The first line number
* @param lines The number of lines
*/
public void deleteLines(int index, int lines)
{
if (lines <= 0)
return;
int len = index + lines;
length -= lines;
System.arraycopy(lineInfo,len,lineInfo,
index,lineInfo.length - len);
}
/**
* Returns the number of lines in this token marker.
*/
public int getLineCount()
{
return length;
}
/**
* Returns true if the next line should be repainted. This
* will return true after a line has been tokenized that starts
* a multiline token that continues onto the next line.
*/
public boolean isNextLineRequested()
{
return nextLineRequested;
}
// protected members
/**
* The first token in the list. This should be used as the return
* value from <code>markTokens()</code>.
*/
protected Token firstToken;
/**
* The last token in the list. New tokens are added here.
* This should be set to null before a new line is to be tokenized.
*/
protected Token lastToken;
/**
* An array for storing information about lines. It is enlarged and
* shrunk automatically by the <code>insertLines()</code> and
* <code>deleteLines()</code> methods.
*/
protected LineInfo[] lineInfo;
/**
* The number of lines in the model being tokenized. This can be
* less than the length of the <code>lineInfo</code> array.
*/
protected int length;
/**
* The last tokenized line.
*/
protected int lastLine;
/**
* True if the next line should be painted.
*/
protected boolean nextLineRequested;
/**
* Creates a new <code>TokenMarker</code>. This DOES NOT create
* a lineInfo array; an initial call to <code>insertLines()</code>
* does that.
*/
protected TokenMarker()
{
lastLine = -1;
}
/**
* Ensures that the <code>lineInfo</code> array can contain the
* specified index. This enlarges it if necessary. No action is
* taken if the array is large enough already.<p>
*
* It should be unnecessary to call this under normal
* circumstances; <code>insertLine()</code> should take care of
* enlarging the line info array automatically.
*
* @param index The array index
*/
protected void ensureCapacity(int index)
{
if(lineInfo == null)
lineInfo = new LineInfo[index + 1];
else if(lineInfo.length <= index)
{
LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
System.arraycopy(lineInfo,0,lineInfoN,0,
lineInfo.length);
lineInfo = lineInfoN;
}
}
/**
* Adds a token to the token list.
* @param length The length of the token
* @param id The id of the token
*/
protected void addToken(int length, byte id)
{
if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
throw new InternalError("Invalid id: " + id);
if(length == 0 && id != Token.END)
return;
if(firstToken == null)
{
firstToken = new Token(length,id);
lastToken = firstToken;
}
else if(lastToken == null)
{
lastToken = firstToken;
firstToken.length = length;
firstToken.id = id;
}
else if(lastToken.next == null)
{
lastToken.next = new Token(length,id);
lastToken = lastToken.next;
}
else
{
lastToken = lastToken.next;
lastToken.length = length;
lastToken.id = id;
}
}
/**
* Inner class for storing information about tokenized lines.
*/
public class LineInfo
{
/**
* Creates a new LineInfo object with token = Token.NULL
* and obj = null.
*/
public LineInfo()
{
}
/**
* Creates a new LineInfo object with the specified
* parameters.
*/
public LineInfo(byte token, Object obj)
{
this.token = token;
this.obj = obj;
}
/**
* The id of the last token of the line.
*/
public byte token;
/**
* This is for use by the token marker implementations
* themselves. It can be used to store anything that
* is an object and that needs to exist on a per-line
* basis.
*/
public Object obj;
}
}

View File

@@ -1,198 +0,0 @@
package processing.app.syntax.im;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.text.BadLocationException;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.TextAreaPainter;
/**
* This class Manage texts from input method
* by begin-process-end steps.
*
* First, if a user start inputing via input method,
* beginCompositionText is called from InputMethodSupport.
* Second, the user continues from input method, processCompositionText is called
* and reflect user inputs to text area.
* Finally the user try to commit text, endCompositionText is called.
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class CompositionTextManager {
private JEditTextArea textArea;
private String prevComposeString;
private int prevCommittedCount;
private boolean isInputProcess;
private int initialCaretPosition;
public static final int COMPOSING_UNDERBAR_HEIGHT = 5;
/**
* Create text manager class with a textarea.
* @param textArea texarea component for PDE.
*/
public CompositionTextManager(JEditTextArea textArea) {
this.textArea = textArea;
prevComposeString = "";
isInputProcess = false;
prevCommittedCount = 0;
}
/**
* Get this text manager is whether in input process or not.
*/
public boolean getIsInputProcess() {
return isInputProcess;
}
/**
* Insert full width space
*/
public void insertFullWidthSpace() {
initialCaretPosition = textArea.getCaretPosition();
int layoutCaretPosition = initialCaretPosition;
try {
textArea.getDocument().insertString(layoutCaretPosition, "\u3000", null);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
/**
* Called when a user begins input from input method.
* This method initializes text manager.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void beginCompositionText(AttributedCharacterIterator text, int committed_count) {
isInputProcess = true;
prevComposeString = "";
initialCaretPosition = textArea.getCaretPosition();
processCompositionText(text, committed_count);
}
/**
* Called when a user processing input characters and
* select candidates from input method.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void processCompositionText(AttributedCharacterIterator text, int committed_count) {
int layoutCaretPosition = initialCaretPosition + committed_count;
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
compositionPainter.setComposedTextLayout(getTextLayout(text, committed_count), layoutCaretPosition);
int textLength = text.getEndIndex() - text.getBeginIndex() - committed_count;
StringBuffer unCommitedStringBuf = new StringBuffer(textLength);
char c;
for (c = text.setIndex(committed_count); c != AttributedCharacterIterator.DONE
&& textLength > 0; c = text.next(), --textLength) {
unCommitedStringBuf.append(c);
}
String unCommittedString = unCommitedStringBuf.toString();
try {
if(canRemovePreviousInput(committed_count)){
textArea.getDocument().remove(layoutCaretPosition, prevComposeString.length());
}
textArea.getDocument().insertString(layoutCaretPosition, unCommittedString, null);
if(committed_count > 0){
initialCaretPosition = initialCaretPosition + committed_count;
}
prevComposeString = unCommittedString;
prevCommittedCount = committed_count;
} catch (BadLocationException e) {
e.printStackTrace();
}
}
private boolean canRemovePreviousInput(int committed_count){
return (prevCommittedCount == committed_count || prevCommittedCount > committed_count);
}
/**
* Called when a user fixed text from input method or delete all
* composition text. This method resets CompositionTextPainter.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void endCompositionText(AttributedCharacterIterator text, int committed_count) {
/*
* If there are no committed characters, remove it all from textarea.
* This case will happen if a user delete all composing characters by backspace or delete key.
* If it does, these previous characters are needed to be deleted.
*/
if(committed_count == 0){
removeNotCommittedText(text);
}
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
compositionPainter.invalidateComposedTextLayout(initialCaretPosition + committed_count);
prevComposeString = "";
isInputProcess = false;
}
private void removeNotCommittedText(AttributedCharacterIterator text){
if (prevComposeString.length() == 0) {
return;
}
try {
textArea.getDocument().remove(initialCaretPosition, prevComposeString.length());
} catch (BadLocationException e) {
e.printStackTrace();
}
}
private TextLayout getTextLayout(AttributedCharacterIterator text, int committed_count) {
AttributedString composed = new AttributedString(text, committed_count, text.getEndIndex());
Font font = textArea.getPainter().getFont();
FontRenderContext context = ((Graphics2D) (textArea.getPainter().getGraphics())).getFontRenderContext();
composed.addAttribute(TextAttribute.FONT, font);
TextLayout layout = new TextLayout(composed.getIterator(), context);
return layout;
}
private Point getCaretLocation() {
Point loc = new Point();
TextAreaPainter painter = textArea.getPainter();
FontMetrics fm = painter.getFontMetrics();
int offsetY = fm.getHeight() - COMPOSING_UNDERBAR_HEIGHT;
int lineIndex = textArea.getCaretLine();
loc.y = lineIndex * fm.getHeight() + offsetY;
int offsetX = textArea.getCaretPosition()
- textArea.getLineStartOffset(lineIndex);
loc.x = textArea.offsetToX(lineIndex, offsetX);
return loc;
}
public Rectangle getTextLocation() {
Point caret = getCaretLocation();
return getCaretRectangle(caret.x, caret.y);
}
private Rectangle getCaretRectangle(int x, int y) {
TextAreaPainter painter = textArea.getPainter();
Point origin = painter.getLocationOnScreen();
int height = painter.getFontMetrics().getHeight();
return new Rectangle(origin.x + x, origin.y + y, 0, height);
}
public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex) {
int length = endIndex - beginIndex;
String textAreaString = textArea.getText(beginIndex, length);
return new AttributedString(textAreaString).getIterator();
}
public int getInsertPositionOffset() {
return textArea.getCaretPosition() * -1;
}
}

View File

@@ -1,124 +0,0 @@
package processing.app.syntax.im;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.font.TextLayout;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.TextAreaPainter;
/**
* Paint texts from input method. Text via input method are transmitted by
* AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter
* to handle AttributedCaharacterIterator.
*
* For practical purposes, paint to textarea is done by TextLayout class.
* Because TextLayout class is easy to draw composing texts. (For example,
* draw underline composing texts, focus when select from candidates text.)
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class CompositionTextPainter {
private TextLayout composedTextLayout;
private int composedBeginCaretPosition = 0;
private JEditTextArea textArea;
/**
* Constructor for painter.
* @param textarea textarea used by PDE.
*/
public CompositionTextPainter(JEditTextArea textArea) {
this.textArea = textArea;
composedTextLayout = null;
}
/**
* Check the painter has TextLayout.
* If a user input via InputMethod, this result will return true.
* @param textarea textarea used by PDE.
*/
public boolean hasComposedTextLayout() {
return (composedTextLayout != null);
}
/**
* Set TextLayout to the painter.
* TextLayout will be created and set by CompositionTextManager.
*
* @see CompositionTextManager
* @param textarea textarea used by PDE.
*/
public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) {
this.composedTextLayout = composedTextLayout;
this.composedBeginCaretPosition = composedStartCaretPosition;
}
/**
* Invalidate this TextLayout to set null.
* If a user end input via InputMethod, this method will called from CompositionTextManager.endCompositionText
*/
public void invalidateComposedTextLayout(int composedEndCaretPosition) {
this.composedTextLayout = null;
this.composedBeginCaretPosition = composedEndCaretPosition;
//this.composedBeginCaretPosition = textArea.getCaretPosition();
}
/**
* Draw text via input method with composed text information.
* This method can draw texts with some underlines to illustrate converting characters.
*
* This method is workaround for TextAreaPainter.
* Because, TextAreaPainter can't treat AttributedCharacterIterator directly.
* AttributedCharacterIterator has very important information when composing text.
* It has a map where are converted characters and committed characters.
* Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!!
* So I choose to write some code as a workaround.
*
* This draw method is proceeded with the following steps.
* 1. Original TextAreaPainter draws characters.
* 2. This refillComposedArea method erase previous paint characters by textarea's background color.
* The refill area is only square that width and height defined by characters with input method.
* 3. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout.
*
* @param gfx set TextAreaPainter's Graphics object.
* @param fillBackGroundColor set textarea's background.
*/
public void draw(Graphics gfx, Color fillBackGroundColor) {
assert(composedTextLayout != null);
Point composedLoc = getCaretLocation();
refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
}
/**
* Fill color to erase characters drawn by original TextAreaPainter.
*
* @param fillColor fill color to erase characters drawn by original TextAreaPainter method.
* @param x x-coordinate where to fill.
* @param y y-coordinate where to fill.
*/
private void refillComposedArea(Color fillColor, int x, int y) {
Graphics gfx = textArea.getPainter().getGraphics();
gfx.setColor(fillColor);
FontMetrics fm = textArea.getPainter().getFontMetrics();
int newY = y - (fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT);
int paintHeight = fm.getHeight();
int paintWidth = (int) composedTextLayout.getBounds().getWidth();
gfx.fillRect(x, newY, paintWidth, paintHeight);
}
private Point getCaretLocation() {
Point loc = new Point();
TextAreaPainter painter = textArea.getPainter();
FontMetrics fm = painter.getFontMetrics();
int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT;
int lineIndex = textArea.getCaretLine();
loc.y = lineIndex * fm.getHeight() + offsetY;
int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex);
loc.x = textArea.offsetToX(lineIndex, offsetX);
return loc;
}
}

View File

@@ -1,120 +0,0 @@
package processing.app.syntax.im;
import java.awt.Rectangle;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;
import java.awt.font.TextHitInfo;
import java.awt.im.InputMethodRequests;
import java.text.AttributedCharacterIterator;
import processing.app.syntax.JEditTextArea;
/**
* Support in-line Japanese input for PDE. (Maybe Chinese, Korean and more)
* This class is implemented by Java Input Method Framework and handles
* If you would like to know more about Java Input Method Framework,
* Please see http://java.sun.com/j2se/1.5.0/docs/guide/imf/
*
* This class is implemented to fix Bug #854.
* http://dev.processing.org/bugs/show_bug.cgi?id=854
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class InputMethodSupport implements InputMethodRequests,
InputMethodListener {
private int committed_count = 0;
private CompositionTextManager textManager;
public InputMethodSupport(JEditTextArea textArea) {
textManager = new CompositionTextManager(textArea);
textArea.enableInputMethods(true);
textArea.addInputMethodListener(this);
}
public Rectangle getTextLocation(TextHitInfo offset) {
return textManager.getTextLocation();
}
public TextHitInfo getLocationOffset(int x, int y) {
return null;
}
public int getInsertPositionOffset() {
return textManager.getInsertPositionOffset();
}
public AttributedCharacterIterator getCommittedText(int beginIndex,
int endIndex, AttributedCharacterIterator.Attribute[] attributes) {
return textManager.getCommittedText(beginIndex, endIndex);
}
public int getCommittedTextLength() {
return committed_count;
}
public AttributedCharacterIterator cancelLatestCommittedText(
AttributedCharacterIterator.Attribute[] attributes) {
return null;
}
public AttributedCharacterIterator getSelectedText(
AttributedCharacterIterator.Attribute[] attributes) {
return null;
}
/**
* Handles events from InputMethod.
* This method judges whether beginning of input or
* progress of input or end and call related method.
*
* @param event event from Input Method.
*/
public void inputMethodTextChanged(InputMethodEvent event) {
AttributedCharacterIterator text = event.getText();
committed_count = event.getCommittedCharacterCount();
if(isFullWidthSpaceInput(text)){
textManager.insertFullWidthSpace();
caretPositionChanged(event);
return;
}
if(isBeginInputProcess(text, textManager)){
textManager.beginCompositionText(text, committed_count);
caretPositionChanged(event);
return;
}
if (isInputProcess(text)){
textManager.processCompositionText(text, committed_count);
caretPositionChanged(event);
return;
}
textManager.endCompositionText(text, committed_count);
caretPositionChanged(event);
}
private boolean isFullWidthSpaceInput(AttributedCharacterIterator text){
if(text == null)
return false;
if(textManager.getIsInputProcess())
return false;
return (String.valueOf(text.first()).equals("\u3000"));
}
private boolean isBeginInputProcess(AttributedCharacterIterator text, CompositionTextManager textManager){
if(text == null)
return false;
if(textManager.getIsInputProcess())
return false;
return (isInputProcess(text));
}
private boolean isInputProcess(AttributedCharacterIterator text){
if(text == null)
return false;
return (text.getEndIndex() - (text.getBeginIndex() + committed_count) > 0);
}
public void caretPositionChanged(InputMethodEvent event) {
event.consume();
}
}

View File

@@ -1,46 +0,0 @@
OLDSYNTAX PACKAGE README
I am placing the jEdit 2.2.1 syntax highlighting package in the public
domain. This means it can be integrated into commercial programs, etc.
This package requires at least Java 1.1 and Swing 1.1. Syntax
highlighting for the following file types is supported:
- C++, C
- CORBA IDL
- Eiffel
- HTML
- Java
- Java properties
- JavaScript
- MS-DOS INI
- MS-DOS batch files
- Makefile
- PHP
- Perl
- Python
- TeX
- Transact-SQL
- Unix patch/diff
- Unix shell script
- XML
This package is undocumented; read the source (start by taking a look at
JEditTextArea.java) to find out how to use it; it's really simple. Feel
free to e-mail questions, queries, etc. to me, but keep in mind that
this code is very old and I no longer maintain it. So if you find a bug,
don't bother me about it; fix it yourself.
* Copyright
The jEdit 2.2.1 syntax highlighting package contains code that is
Copyright 1998-1999 Slava Pestov, Artur Biesiadowski, Clancy Malcolm,
Jonathan Revusky, Juha Lindfors and Mike Dillon.
You may use and modify this package for any purpose. Redistribution is
permitted, in both source and binary form, provided that this notice
remains intact in all source distributions of this package.
-- Slava Pestov
25 September 2000
<sp@gjt.org>

View File

@@ -440,7 +440,7 @@ public class AutoFormat implements Tool {
// Adding an additional newline as a hack around other errors
String originalText = editor.getText() + "\n";
strOut = new StringBuffer();
indentValue = Preferences.getInteger("editor.tabs.size");
indentValue = PreferencesData.getInteger("editor.tabs.size");
indentChar = new String(" ");
lineNumber = 0;

View File

@@ -25,11 +25,14 @@ package processing.app.tools;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Segment;
import org.fife.ui.rsyntaxtextarea.Token;
import processing.app.*;
import processing.app.syntax.*;
import processing.app.legacy.PApplet;
/**
* Format for Discourse Tool
@@ -44,6 +47,8 @@ import processing.app.legacy.PApplet;
* <p/>
* Updated for 0144 to only format the selected lines.
* <p/>
* Updated for 1.5.8 - Simplification, using RSyntaxTextArea TokenImpl formatter (08 dec 2014 - Ricardo JL Rufino)
* <p/>
* Notes from the original source:
* Discourse.java This is a dirty-mix source.
* NOTE that: No macs and no keyboard. Unreliable source.
@@ -54,7 +59,7 @@ public class DiscourseFormat {
private Editor editor;
// JTextArea of the actual Editor
private JEditTextArea textarea;
private SketchTextArea textarea;
private boolean html;
@@ -78,10 +83,16 @@ public class DiscourseFormat {
StringBuilder cf = new StringBuilder(html ? "<pre>\n" : "[code]\n");
int selStart = textarea.getSelectionStart();
int selStop = textarea.getSelectionStop();
int selStop = textarea.getSelectionEnd();
int startLine = textarea.getSelectionStartLine();
int stopLine = textarea.getSelectionStopLine();
int startLine;
int stopLine;
try {
startLine = textarea.getLineOfOffset(selStart);
stopLine = textarea.getLineOfOffset(selStop);
} catch (BadLocationException e) {
return;
}
// If no selection, convert all the lines
if (selStart == selStop) {
@@ -89,8 +100,11 @@ public class DiscourseFormat {
stopLine = textarea.getLineCount() - 1;
} else {
// Make sure the selection doesn't end at the beginning of the last line
if (textarea.getLineStartOffset(stopLine) == selStop) {
stopLine--;
try {
if (textarea.getLineStartOffset(stopLine) == selStop) {
stopLine--;
}
} catch (BadLocationException e) {
}
}
@@ -139,23 +153,15 @@ public class DiscourseFormat {
public void appendFormattedLine(StringBuilder cf, int line) {
Segment segment = new Segment();
TextAreaPainter painter = textarea.getPainter();
TokenMarker tokenMarker = textarea.getTokenMarker();
// Use painter's cached info for speed
// FontMetrics fm = painter.getFontMetrics();
// get line text from parent text area
textarea.getLineText(line, segment);
textarea.getTextLine(line, segment);
char[] segmentArray = segment.array;
int limit = segment.getEndIndex();
int segmentOffset = segment.offset;
int segmentCount = segment.count;
// int width = 0;
// If syntax coloring is disabled, do simple translation
if (tokenMarker == null) {
if (!html) {
for (int j = 0; j < segmentCount; j++) {
char c = segmentArray[j + segmentOffset];
appendToHTML(c, cf);
@@ -169,82 +175,19 @@ public class DiscourseFormat {
}
} else {
// If syntax coloring is enabled, we have to do this
// because tokens can vary in width
Token tokens;
if ((painter.getCurrentLineIndex() == line) &&
(painter.getCurrentLineTokens() != null)) {
tokens = painter.getCurrentLineTokens();
} else {
painter.setCurrentLineIndex(line);
painter.setCurrentLineTokens(tokenMarker.markTokens(segment, line));
tokens = painter.getCurrentLineTokens();
}
int offset = 0;
// Font defaultFont = painter.getFont();
SyntaxStyle[] styles = painter.getStyles();
for (;;) {
byte id = tokens.id;
if (id == Token.END) {
char c = segmentArray[segmentOffset + offset];
if (segmentOffset + offset < limit) {
appendToHTML(c, cf);
} else {
cf.append('\n');
}
return; // cf.toString();
}
if (id == Token.NULL) {
// fm = painter.getFontMetrics();
} else {
// Place open tags []
if (html) {
cf.append("<span style=\"color: #");
cf.append(PApplet.hex(styles[id].getColor().getRGB() & 0xFFFFFF, 6));
cf.append(";\">");
}
if (html && styles[id].isBold())
cf.append("<b>");
// fm = styles[id].getFontMetrics(defaultFont);
}
int length = tokens.length;
for (int j = 0; j < length; j++) {
char c = segmentArray[segmentOffset + offset + j];
if (offset == 0 && c == ' ') {
// Works on Safari but not Camino 1.6.3 or Firefox 2.x on OS X.
cf.append(html ? "&nbsp;" : '\u00A0'); // &nbsp;
// if ((j % 2) == 1) {
// cf.append("[b]\u00A0[/b]");
// } else {
// cf.append(' ');
// }
} else {
appendToHTML(c, cf);
}
// Place close tags [/]
if (html && j == (length - 1) && id != Token.NULL && styles[id].isBold())
cf.append("</b>");
if (html && j == (length - 1) && id != Token.NULL)
cf.append("</span>");
// int charWidth;
// if (c == '\t') {
// charWidth = (int) painter
// .nextTabStop(width, offset + j)
// - width;
// } else {
// charWidth = fm.charWidth(c);
// }
// width += charWidth;
}
offset += length;
tokens = tokens.next;
Token tokenList = textarea.getTokenListForLine(line);
while(tokenList != null){
if(tokenList.getType() == Token.NULL){
cf.append('\n');
}else if(tokenList.isPaintable()){
tokenList.appendHTMLRepresentation(cf, textarea, false);
}
tokenList = tokenList.getNextToken();
}
}
}
}