id "com.diffplug.gradle.spotless" version "3.28.0"
id 'com.github.johnrengelman.shadow' version '4.0.3'
id 'com.install4j.gradle' version '9.0.6'
- id 'com.dorongold.task-tree' version '1.5' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
+ id 'com.dorongold.task-tree' version '2.1.0' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
id 'com.palantir.git-version' version '0.13.0' apply false
}
return sections
}
+
+task copyHelp(type: Copy) {
+ def inputDir = helpSourceDir
+ def outputDir = "${helpBuildDir}/${help_dir}"
+ from(inputDir) {
+ include('**/*.txt')
+ include('**/*.md')
+ include('**/*.html')
+ include('**/*.hs')
+ include('**/*.xml')
+ include('**/*.jhm')
+ filter(ReplaceTokens,
+ beginToken: '$$',
+ endToken: '$$',
+ tokens: [
+ 'Version-Rel': JALVIEW_VERSION,
+ 'Year-Rel': getDate("yyyy")
+ ]
+ )
+ }
+ from(inputDir) {
+ exclude('**/*.txt')
+ exclude('**/*.md')
+ exclude('**/*.html')
+ exclude('**/*.hs')
+ exclude('**/*.xml')
+ exclude('**/*.jhm')
+ }
+ into outputDir
+
+ inputs.dir(inputDir)
+ outputs.files(helpFile)
+ outputs.dir(outputDir)
+}
+
+
task releasesTemplates {
group "help"
description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
+ dependsOn copyHelp
+
def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
- def releasesHtmlFile = file("${helpSourceDir}/${releases_html}")
- def whatsnewHtmlFile = file("${helpSourceDir}/${whatsnew_html}")
+ def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
+ def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
def releasesMdDir = "${jalviewDir}/${releases_dir}"
def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
}
def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
- def lm = null
- def rContentProcessed = ""
- rContent.eachLine { line ->
- if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
- line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
- } else if (lm = line =~ /^###([^#]+.*)$/) {
- line = "_${lm[0][1].trim()}_"
- }
- rContentProcessed += line + "\n"
+ def lm = null
+ def rContentProcessed = ""
+ rContent.eachLine { line ->
+ if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
+ line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
+ } else if (lm = line =~ /^###([^#]+.*)$/) {
+ line = "_${lm[0][1].trim()}_"
}
+ rContentProcessed += line + "\n"
+ }
def rContentSections = getMdSections(rContentProcessed)
def rVersion = versionTemplate
DISPLAY_DATE: wnDisplayDate
]
)
+ } else if (gradle.taskGraph.hasTask(":linkCheck")) {
+ whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
}
}
}
-task copyHelp(type: Copy) {
- dependsOn releasesTemplates
-
- def inputDir = helpSourceDir
- def outputDir = "${helpBuildDir}/${help_dir}"
- from(inputDir) {
- include('**/*.txt')
- include('**/*.md')
- include('**/*.html')
- include('**/*.hs')
- include('**/*.xml')
- include('**/*.jhm')
- filter(ReplaceTokens,
- beginToken: '$$',
- endToken: '$$',
- tokens: [
- 'Version-Rel': JALVIEW_VERSION,
- 'Year-Rel': getDate("yyyy")
- ]
- )
- }
- from(inputDir) {
- exclude('**/*.txt')
- exclude('**/*.md')
- exclude('**/*.html')
- exclude('**/*.hs')
- exclude('**/*.xml')
- exclude('**/*.jhm')
- }
- into outputDir
-
- inputs.dir(inputDir)
- outputs.files(helpFile)
- outputs.dir(outputDir)
-}
-
-
task copyResources(type: Copy) {
group = "build"
description = "Copy (and make text substitutions in) the resources dir to the build area"
dependsOn buildResources
dependsOn copyDocs
dependsOn copyHelp
+ dependsOn releasesTemplates
dependsOn convertMdFiles
dependsOn buildIndices
}
def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
classpath = files("${jalviewDir}/${utils_dir}")
main = "HelpLinksChecker"
- workingDir = jalviewDir
+ workingDir = "${helpBuildDir}"
args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
allows sequences to be located via gene name, keywords, or even
<em>via</em> manual cross-referencing from UniProt or other
bioinformatics websites.
+ <br/>
+ <br />
+ <strong>Please Note:</strong>Versions of Jalview older than 2.11.2.3 may need a configuration change
+ in order to access freetext search. Please see this post:
+ <a
+ href="https://discourse.jalview.org/t/uniprot-free-text-search-not-working-in-jalview-2-11-2-2-and-earlier/1825">https://discourse.jalview.org/t/uniprot-free-text-search-not-working-in-jalview-2-11-2-2-and-earlier/1825</a>
+ in Jalview's discussion forum for a workaround.
+ <br />
<p>
To open the UniProt Sequence Fetcher, select UniProt as the database
from any <a href="seqfetch.html">Sequence Fetcher</a> dialog (opened
## New Features
+
+- <!-- JAL-1988,JAL-3416 --> "Do you really want to Quit ?" prompt on OSX/Java 8
- <!-- JAL-4004 --> Release notes and what's new documentation pages now generated from individual markdown files
- <!-- JAL-3989 --> Release process generates Hugo friendly JSON metadata to use when publishing releases on www.jalview.org
- <!-- JAL-3553 --> New gradle tasks for publishing to the Jalview version archive
- <!-- JAL-4023 --> Tree branch labels shown using Scientific notation for very small or large lengths
+- <!-- JAL-4036 --> Uniprot Free Text Search now uses legacy.uniprot.org rather than main Uniprot query service
## Issues Resolved
+- <!-- JAL-4036 --> Uniprot Free Text Search in Jalview 2.11.2.2 and earlier stopped working on 29th June 2022
- <!-- JAL-4008 --> Validation fails when trying to configure custom JABAWS server
- <!-- JAL-4020 --> Jalview doesn't call PymolWIN.exe correctly - improved recognition of binaries on Windows
- <!-- JAL-4024 --> Jumping from left to far right via rapid drag of scroll bar or clicking the overview window can cause Jalview to temporarily hang when working with alignments with more than 10 thousand columns
-Jalview 2.11.2.3 is the third patch release in the 2.11.2 series. It addresses a critical bugs affecting users working with very wide alignments and those needing to use alternate JABAWS servers, support for display of very small and large tree lengths with scientific notation, and essential improvements to the build and release notes documentation system.
+Jalview 2.11.2.3 is the third patch release in the 2.11.2 series. It addresses a critical bugs affecting Uniprot free text search, users working with very wide alignments and those needing to use alternate JABAWS servers, support for display of very small and large tree lengths with scientific notation, and essential improvements to the build and release notes documentation system.
*/
package jalview.bin;
+import java.awt.Color;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
+import com.formdev.flatlaf.FlatLightLaf;
+import com.formdev.flatlaf.util.SystemInfo;
import com.threerings.getdown.util.LaunchUtil;
//import edu.stanford.ejalbert.launching.IBrowserLaunching;
private static void setLookAndFeel()
{
- // property laf = "crossplatform", "system", "gtk", "metal", "nimbus" or
- // "mac"
+ // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
+ // "mac" or "flat"
// If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
// try Quaqua/Vaqua.
String lafProp = System.getProperty("laf");
Console.error("Could not set requested laf=" + laf);
}
break;
+ case "flat":
+ lafSet = setFlatLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
case "quaqua":
lafSet = setQuaquaLookAndFeel();
if (!lafSet)
"javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
}
+ private static boolean setFlatLookAndFeel()
+ {
+ boolean set = setSpecificLookAndFeel("flatlaf light",
+ "com.formdev.flatlaf.FlatLightLaf", false);
+ if (set)
+ {
+ if (Platform.isMac())
+ {
+ System.setProperty("apple.laf.useScreenMenuBar", "true");
+ System.setProperty("apple.awt.application.name",
+ ChannelProperties.getProperty("app_name"));
+ System.setProperty("apple.awt.application.appearance", "system");
+ if (SystemInfo.isMacFullWindowContentSupported
+ && Desktop.desktop != null)
+ {
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.fullWindowContent", true);
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.transparentTitleBar", true);
+ }
+
+ SwingUtilities.invokeLater(() -> {
+ FlatLightLaf.setup();
+ });
+ }
+
+ UIManager.put("TabbedPane.showTabSeparators", true);
+ UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
+ UIManager.put("TabbedPane.tabsOverlapBorder", true);
+ // UIManager.put("TabbedPane.hasFullBorder", true);
+ UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
+ UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
+ UIManager.put("TabbedPane.smoothScrolling", true);
+ UIManager.put("TabbedPane.tabWidthMode", "compact");
+ UIManager.put("TabbedPane.selectedBackground", Color.white);
+ }
+ return set;
+ }
+
private static boolean setQuaquaLookAndFeel()
{
return setSpecificLookAndFeel("quaqua",
package jalview.fts.service.uniprot;
-import jalview.bin.Cache;
-import jalview.fts.api.FTSData;
-import jalview.fts.api.FTSDataColumnI;
-import jalview.fts.api.FTSRestClientI;
-import jalview.fts.core.FTSRestClient;
-import jalview.fts.core.FTSRestRequest;
-import jalview.fts.core.FTSRestResponse;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.DefaultClientConfig;
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
public class UniProtFTSRestClient extends FTSRestClient
{
- private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org";
+ private static final String DEFAULT_UNIPROT_DOMAIN = "https://legacy.uniprot.org";
static
{
.queryParam("limit", String.valueOf(responseSize))
.queryParam("offset", String.valueOf(offSet))
.queryParam("sort", "score").queryParam("query", query);
+ if (Console.isDebugEnabled())
+ {
+ Console.debug("Uniprot FTS Request: " + webResource.toString());
+ }
// Execute the REST request
ClientResponse clientResponse = webResource
.accept(MediaType.TEXT_PLAIN).get(clientResponseClass);
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview 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 3
- * of the License, or (at your option) any later version.
- *
- * Jalview 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 Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.gui;
-
-import jalview.bin.Cache;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-
-import java.awt.Desktop;
-import java.awt.desktop.AboutEvent;
-import java.awt.desktop.AboutHandler;
-import java.awt.desktop.PreferencesEvent;
-import java.awt.desktop.PreferencesHandler;
-import java.awt.desktop.QuitEvent;
-import java.awt.desktop.QuitHandler;
-import java.awt.desktop.QuitResponse;
-import java.awt.desktop.QuitStrategy;
-
-import javax.swing.JOptionPane;
-
-public class APQHandlers
-{
- private static boolean setAPQHandlers = false;
-
- public APQHandlers()
- {
- }
-
- protected static boolean setAPQHandlers(
- jalview.gui.Desktop jalviewDesktop)
- {
- // flagging this test to avoid unnecessary reflection
- if (!setAPQHandlers)
- {
- // see if the Quit, About and Preferences handlers are available
- Class desktopClass = Desktop.class;
- Desktop hdesktop = Desktop.getDesktop();
-
- try
- {
- Float specversion = Float.parseFloat(
- System.getProperty("java.specification.version"));
-
- if (specversion >= 9)
- {
- if (Platform.isAMacAndNotJS())
- {
- if (desktopClass.getDeclaredMethod("setAboutHandler",
- new Class[]
- { AboutHandler.class }) != null)
- {
-
- hdesktop.setAboutHandler(new AboutHandler()
- {
- @Override
- public void handleAbout(AboutEvent e)
- {
- jalviewDesktop.aboutMenuItem_actionPerformed(null);
- }
- });
-
- }
-
- if (desktopClass.getDeclaredMethod("setPreferencesHandler",
- new Class[]
- { PreferencesHandler.class }) != null)
- {
-
- hdesktop.setPreferencesHandler(new PreferencesHandler()
- {
- @Override
- public void handlePreferences(PreferencesEvent e)
- {
- jalviewDesktop.preferences_actionPerformed(null);
- }
- });
-
- }
-
- if (desktopClass.getDeclaredMethod("setQuitHandler",
- new Class[]
- { QuitHandler.class }) != null)
- {
-
- hdesktop.setQuitHandler(new QuitHandler()
- {
- @Override
- public void handleQuitRequestWith(QuitEvent e,
- QuitResponse r)
- {
- boolean confirmQuit = Cache.getDefault(
- jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
- int n;
- if (confirmQuit)
- {
- n = JOptionPane.showConfirmDialog(null,
- MessageManager.getString("label.quit_jalview"),
- MessageManager.getString("action.quit"),
- JOptionPane.OK_CANCEL_OPTION,
- JOptionPane.PLAIN_MESSAGE, null);
- }
- else
- {
- n = JOptionPane.OK_OPTION;
- }
- if (n == JOptionPane.OK_OPTION)
- {
- System.out.println("Shortcut Quit confirmed by user");
- jalviewDesktop.quit();
- r.performQuit(); // probably won't reach this line, but just
- // in
- // case
- }
- else
- {
- r.cancelQuit();
- System.out.println("Shortcut Quit cancelled by user");
- }
- }
- });
- hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
-
- }
- }
- setAPQHandlers = true;
- }
- else
- {
- System.out.println(
- "Not going to try setting APQ Handlers as java.spec.version is "
- + specversion);
- }
-
- } catch (Exception e)
- {
- System.out.println(
- "Exception when looking for About, Preferences, Quit Handlers");
- // e.printStackTrace();
- } catch (Throwable t)
- {
- System.out.println(
- "Throwable when looking for About, Preferences, Quit Handlers");
- // t.printStackTrace();
- }
-
- }
-
- return setAPQHandlers;
- }
-
-}
*/
package jalview.gui;
-import java.util.Locale;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
+import java.util.Locale;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
- protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
+ public static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
public static HashMap<String, FileWriter> savingFiles = new HashMap<String, FileWriter>();
}
}
- /**
- * APQHandlers sets handlers for About, Preferences and Quit actions
- * peculiar to macOS's application menu. APQHandlers will check to see if a
- * handler is supported before setting it.
- */
- try
- {
- APQHandlers.setAPQHandlers(this);
- } catch (Exception e)
- {
- System.out.println("Cannot set APQHandlers");
- // e.printStackTrace();
- } catch (Throwable t)
- {
- jalview.bin.Console
- .warn("Error setting APQHandlers: " + t.toString());
- jalview.bin.Console.trace(Cache.getStackTraceString(t));
- }
setIconImages(ChannelProperties.getIconList());
addWindowListener(new WindowAdapter()
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview 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 Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.jbgui;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+import com.formdev.flatlaf.extras.FlatDesktop;
+import com.formdev.flatlaf.extras.FlatDesktop.Action;
+
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
+public class APQHandlers
+{
+ public static boolean setAbout = false;
+
+ public static boolean setPreferences = false;
+
+ public static boolean setQuit = false;
+
+ public static boolean setAPQHandlers(GDesktop desktop)
+ {
+ if (Platform.isJS())
+ {
+ return false;
+ }
+ if (FlatDesktop.isSupported(Action.APP_ABOUT))
+ {
+ FlatDesktop.setAboutHandler(() -> {
+ desktop.aboutMenuItem_actionPerformed(null);
+ });
+ setAbout = true;
+ }
+ if (FlatDesktop.isSupported(Action.APP_PREFERENCES))
+ {
+ FlatDesktop.setPreferencesHandler(() -> {
+ desktop.preferences_actionPerformed(null);
+ });
+ setPreferences = true;
+ }
+ if (FlatDesktop.isSupported(Action.APP_QUIT_HANDLER))
+ {
+ FlatDesktop.setQuitHandler(response -> {
+ boolean confirmQuit = jalview.bin.Cache.getDefault(
+ jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
+ boolean canQuit = !confirmQuit;
+ int n;
+ if (confirmQuit)
+ {
+ // ensure Jalview window is brought to front for Quit confirmation
+ // window to be visible
+
+ // this method of raising the Jalview window is broken in java
+ // jalviewDesktop.setVisible(true);
+ // jalviewDesktop.toFront();
+
+ // a better hack which works instead
+ JFrame dialogParent = new JFrame();
+ dialogParent.setAlwaysOnTop(true);
+
+ n = JOptionPane.showConfirmDialog(dialogParent,
+ MessageManager.getString("label.quit_jalview"),
+ MessageManager.getString("action.quit"),
+ JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
+ null);
+
+ dialogParent.setAlwaysOnTop(false);
+ dialogParent.dispose();
+ }
+ else
+ {
+ n = JOptionPane.OK_OPTION;
+ }
+ canQuit = (n == JOptionPane.OK_OPTION);
+ if (canQuit)
+ {
+ response.performQuit();
+ }
+ else
+ {
+ response.cancelQuit();
+ }
+ });
+ setQuit = true;
+ }
+ // if we got to here, no exceptions occurred when we set the handlers.
+ return setAbout || setPreferences || setQuit;
+ }
+
+}
*/
package jalview.jbgui;
-import jalview.api.AlignmentViewPanel;
-import jalview.io.FileFormatException;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
+import jalview.api.AlignmentViewPanel;
+import jalview.bin.Cache;
+import jalview.io.FileFormatException;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
/**
* DOCUMENT ME!
*
*/
private void jbInit() throws Exception
{
+ boolean apqHandlersSet = false;
+ /**
+ * APQHandlers sets handlers for About, Preferences and Quit actions
+ * peculiar to macOS's application menu. APQHandlers will check to see if a
+ * handler is supported before setting it.
+ */
+ try
+ {
+ apqHandlersSet = APQHandlers.setAPQHandlers(this);
+ } catch (Exception e)
+ {
+ System.out.println("Cannot set APQHandlers");
+ // e.printStackTrace();
+ } catch (Throwable t)
+ {
+ jalview.bin.Console
+ .warn("Error setting APQHandlers: " + t.toString());
+ jalview.bin.Console.trace(Cache.getStackTraceString(t));
+ }
+
setName("jalview-desktop");
FileMenu.setText(MessageManager.getString("action.file"));
HelpMenu.setText(MessageManager.getString("action.help"));
}
});
- Float specversion = Platform.isJS() ? Float.valueOf(8)
- : Float.parseFloat(
- System.getProperty("java.specification.version"));
-
desktopMenubar.add(FileMenu);
desktopMenubar.add(toolsMenu);
desktopMenubar.add(HelpMenu);
FileMenu.add(saveAsState);
FileMenu.add(loadState);
FileMenu.addSeparator();
- FileMenu.add(quit);
- HelpMenu.add(aboutMenuItem);
+ if (!APQHandlers.setQuit)
+ {
+ FileMenu.add(quit);
+ }
+ if (!APQHandlers.setAbout)
+ {
+ HelpMenu.add(aboutMenuItem);
+ }
HelpMenu.add(documentationMenuItem);
- if (!Platform.isAMacAndNotJS() || specversion < 11)
+ if (!APQHandlers.setPreferences)
{
toolsMenu.add(preferences);
}