diff --git a/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/projects/IWebAppProjectCreator.java b/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/projects/IWebAppProjectCreator.java index 0334e842..244ad181 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/projects/IWebAppProjectCreator.java +++ b/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/projects/IWebAppProjectCreator.java @@ -25,10 +25,10 @@ import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; +import java.util.List; /** * Creates web app projects populated with files relevant to the selected natures. @@ -56,10 +56,6 @@ public interface Participant { void addContainerPath(IPath containerPath); - void addFile(IPath path, InputStream inputStream); - - void addFile(IPath path, String content) throws UnsupportedEncodingException; - void addNature(String natureId); /** @@ -86,10 +82,6 @@ void create(IProgressMonitor monitor) throws CoreException, MalformedURLExceptio void setProjectName(String projectName); - void setTemplates(String... templates); - - void setTemplateSources(String... sources); - /** * Build an Ant project. * @@ -105,25 +97,24 @@ void create(IProgressMonitor monitor) throws CoreException, MalformedURLExceptio void setBuildMaven(boolean buildMaven); /** - * Returns the created Java project. This is available half way through the creation process. - * - * @return the java projeect. + * Returns the created Java projects. This is available half way through the creation process. + * @return the java project. */ - IJavaProject getCreatedJavaProject(); + List getCreatedJavaProjects(); /** * Returns build a Maven Project. * * @return Maven selected */ - boolean getBuildMaven(); + boolean isBuildMaven(); /** * Returns build an ant project. * * @return Ant selected */ - boolean getBuiltAnt(); + boolean isBuiltAnt(); /** * Returns the Creation progress monitor. diff --git a/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/resources/ProjectResources.java b/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/resources/ProjectResources.java index 514cd1a9..1cc1e0f1 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/resources/ProjectResources.java +++ b/plugins/com.gwtplugins.gdt.eclipse.core/src/com/google/gdt/eclipse/core/resources/ProjectResources.java @@ -26,19 +26,19 @@ import org.eclipse.jface.text.Document; import org.eclipse.text.edits.TextEdit; -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; import java.util.List; import java.util.Vector; /** * Generates source for files needed by web application projects. - * + * * TODO: Convert these use to use templates. */ @SuppressWarnings("restriction") @@ -128,13 +128,13 @@ public static List findFilesInDir(File directory, FilenameFilter filter) { /** * Given a java.io.File containing Java source, call the Eclipse auto-format * code on that source and write it back to disk. - * + * * @param file * @throws CoreException */ public static void reformatJavaSource(File file) throws CoreException { try { - String generatedSource = textFromFile(file); + String generatedSource = Files.readString(file.toPath(), Charset.defaultCharset()); String reformattedSource = reformatJavaSourceAsString(generatedSource); if (!reformattedSource.equals(generatedSource)) { writeStringToFile(reformattedSource, file); @@ -166,32 +166,6 @@ public static String reformatJavaSourceAsString(String source) { return source; } - /* - * TODO: These next two methods might be useful somewhere else in the - * future, but right now, this is the only place where we need to do I/O on - * java.io.Files instead of Eclipse resources. - */ - private static String textFromFile(File file) throws IOException { - char bytes[] = new char[1024]; - int nread; - StringBuilder builder = new StringBuilder(); - - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(file)); - while ((nread = reader.read(bytes, 0, 1024)) != -1) { - char toAppend[] = new char[nread]; - System.arraycopy(bytes, 0, toAppend, 0, nread); - builder.append(toAppend); - } - } finally { - if (reader != null) { - reader.close(); - } - } - return builder.toString(); - } - private static void writeStringToFile(String string, File file) throws IOException { BufferedWriter bw = null; diff --git a/plugins/com.gwtplugins.gdt.eclipse.maven/src/com/google/gdt/eclipse/maven/projects/MavenEnablingWebAppCreatorParicipant.java b/plugins/com.gwtplugins.gdt.eclipse.maven/src/com/google/gdt/eclipse/maven/projects/MavenEnablingWebAppCreatorParicipant.java index ec4dfd67..9fc0fc91 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.maven/src/com/google/gdt/eclipse/maven/projects/MavenEnablingWebAppCreatorParicipant.java +++ b/plugins/com.gwtplugins.gdt.eclipse.maven/src/com/google/gdt/eclipse/maven/projects/MavenEnablingWebAppCreatorParicipant.java @@ -17,19 +17,21 @@ import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.project.IProjectConfigurationManager; +import java.util.List; + public class MavenEnablingWebAppCreatorParicipant implements IWebAppProjectCreator.Participant { - private IJavaProject javaProject; + private List javaProjects; @Override public void updateWebAppProjectCreator(IWebAppProjectCreator webAppProjectCreator) { - boolean buildMaven = webAppProjectCreator.getBuildMaven(); + boolean buildMaven = webAppProjectCreator.isBuildMaven(); if (!buildMaven) { return; } - javaProject = webAppProjectCreator.getCreatedJavaProject(); - if (javaProject == null) { + javaProjects = webAppProjectCreator.getCreatedJavaProjects(); + if (javaProjects == null) { return; } @@ -42,7 +44,10 @@ private void runJob() { protected IStatus run(IProgressMonitor monitor) { // Turn on the Maven nature try { - NatureUtils.addNature(javaProject.getProject(), MavenUtils.MAVEN2_NATURE_ID); + for(int i=0;i=UTF-8 diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/META-INF/MANIFEST.MF b/plugins/com.gwtplugins.gdt.eclipse.suite/META-INF/MANIFEST.MF index 62eeffc1..13ef2721 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.suite/META-INF/MANIFEST.MF +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/META-INF/MANIFEST.MF @@ -40,5 +40,7 @@ Require-Bundle: com.gwtplugins.gdt.eclipse.platform, org.eclipse.equinox.common, system.bundle, - org.eclipse.core.runtime + org.eclipse.core.runtime, + org.jdom2, + org.apache.commons.commons-io Import-Package: org.eclipse.core.runtime.preferences diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/build.properties b/plugins/com.gwtplugins.gdt.eclipse.suite/build.properties index 1368b1dd..12b21073 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.suite/build.properties +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/build.properties @@ -5,6 +5,7 @@ bin.includes = META-INF/,\ plugin.xml,\ icons/,\ about.ini,\ - plugin.properties + plugin.properties,\ + project_templates/ javacSource=11 javacTarget=11 diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/plugin.xml b/plugins/com.gwtplugins.gdt.eclipse.suite/plugin.xml index bd50fda5..d318240b 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.suite/plugin.xml +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/plugin.xml @@ -200,6 +200,15 @@ id="com.gwtplugins.gdt.eclipse.suite.newWizards" name="%gwt.label.new"> + + + + + + + + + + diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/src/_PACKAGENAME_/ui.gwt.xml b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/src/_PACKAGENAME_/ui.gwt.xml new file mode 100644 index 00000000..b5d72b4b --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/src/_PACKAGENAME_/ui.gwt.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/src/_PACKAGENAME_/ui/Main.java b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/src/_PACKAGENAME_/ui/Main.java new file mode 100644 index 00000000..c63c65ee --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/src/_PACKAGENAME_/ui/Main.java @@ -0,0 +1,148 @@ +package ${PACKAGENAME}.ui; + +import ${PACKAGENAME}.shared.FieldVerifier; +import ${PACKAGENAME}.shared.GreetingService; +import ${PACKAGENAME}.shared.GreetingServiceAsync; +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.event.dom.client.KeyUpHandler; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.DialogBox; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; + +/** + * Entry point classes define onModuleLoad(). + */ +public class Main implements EntryPoint { + /** + * The message displayed to the user when the server cannot be reached or + * returns an error. + */ + private static final String SERVER_ERROR = "An error occurred while " + + "attempting to contact the server. Please check your network " + "connection and try again."; + + /** + * Create a remote service proxy to talk to the server-side Greeting service. + */ + private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class); + + /** + * This is the entry point method. + */ + public void onModuleLoad() { + final Button sendButton = new Button("Send"); + final TextBox nameField = new TextBox(); + nameField.setText("GWT User"); + final Label errorLabel = new Label(); + + // We can add style names to widgets + sendButton.addStyleName("sendButton"); + + // Add the nameField and sendButton to the RootPanel + // Use RootPanel.get() to get the entire body element + RootPanel.get("nameFieldContainer").add(nameField); + RootPanel.get("sendButtonContainer").add(sendButton); + RootPanel.get("errorLabelContainer").add(errorLabel); + + // Focus the cursor on the name field when the app loads + nameField.setFocus(true); + nameField.selectAll(); + + // Create the popup dialog box + final DialogBox dialogBox = new DialogBox(); + dialogBox.setText("Remote Procedure Call"); + dialogBox.setAnimationEnabled(true); + final Button closeButton = new Button("Close"); + // We can set the id of a widget by accessing its Element + closeButton.getElement().setId("closeButton"); + final Label textToServerLabel = new Label(); + final HTML serverResponseLabel = new HTML(); + VerticalPanel dialogVPanel = new VerticalPanel(); + dialogVPanel.addStyleName("dialogVPanel"); + dialogVPanel.add(new HTML("Sending name to the server:")); + dialogVPanel.add(textToServerLabel); + dialogVPanel.add(new HTML("
Server replies:")); + dialogVPanel.add(serverResponseLabel); + dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT); + dialogVPanel.add(closeButton); + dialogBox.setWidget(dialogVPanel); + + // Add a handler to close the DialogBox + closeButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + dialogBox.hide(); + sendButton.setEnabled(true); + sendButton.setFocus(true); + } + }); + + // Create a handler for the sendButton and nameField + class MyHandler implements ClickHandler, KeyUpHandler { + /** + * Fired when the user clicks on the sendButton. + */ + public void onClick(ClickEvent event) { + sendNameToServer(); + } + + /** + * Fired when the user types in the nameField. + */ + public void onKeyUp(KeyUpEvent event) { + if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { + sendNameToServer(); + } + } + + /** + * Send the name from the nameField to the server and wait for a response. + */ + private void sendNameToServer() { + // First, we validate the input. + errorLabel.setText(""); + String textToServer = nameField.getText(); + if (!FieldVerifier.isValidName(textToServer)) { + errorLabel.setText("Please enter at least four characters"); + return; + } + + // Then, we send the input to the server. + sendButton.setEnabled(false); + textToServerLabel.setText(textToServer); + serverResponseLabel.setText(""); + greetingService.greetServer(textToServer, new AsyncCallback() { + public void onFailure(Throwable caught) { + // Show the RPC error message to the user + dialogBox.setText("Remote Procedure Call - Failure"); + serverResponseLabel.addStyleName("serverResponseLabelError"); + serverResponseLabel.setHTML(SERVER_ERROR); + dialogBox.center(); + closeButton.setFocus(true); + } + + public void onSuccess(String result) { + dialogBox.setText("Remote Procedure Call"); + serverResponseLabel.removeStyleName("serverResponseLabelError"); + serverResponseLabel.setHTML(result); + dialogBox.center(); + closeButton.setFocus(true); + } + }); + } + } + + // Add a handler to send the name to the server + MyHandler handler = new MyHandler(); + sendButton.addClickHandler(handler); + nameField.addKeyUpHandler(handler); + } +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/WEB-INF/web.xml b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/WEB-INF/web.xml new file mode 100644 index 00000000..f294d73c --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/WEB-INF/web.xml @@ -0,0 +1,24 @@ + + + + + + greetServlet + ${PACKAGENAME}.server.GreetingServiceImpl + + + + greetServlet + /example/greet + + + + + index.html + + + diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/index.html b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/index.html new file mode 100644 index 00000000..ea276839 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + Web Application Starter Project + + + + + + + + + + + + + + + + + + + +

Web Application Starter Project

+ + + + + + + + + + + + +
Please enter your name:
+ + diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/style.css b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/style.css new file mode 100644 index 00000000..7aca7ac7 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/client/war/style.css @@ -0,0 +1,34 @@ +/** Add css rules here for your application. */ + + +/** Example rules used by the template application (remove for your app) */ +h1 { + font-size: 2em; + font-weight: bold; + color: #777777; + margin: 40px 0px 70px; + text-align: center; +} + +.sendButton { + display: block; + font-size: 16pt; +} + +/** Most GWT widgets already have a style name defined */ +.gwt-DialogBox { + width: 400px; +} + +.dialogVPanel { + margin: 5px; +} + +.serverResponseLabelError { + color: red; +} + +/** Set ids using widget.getElement().setId("idOfElement") */ +#closeButton { + margin: 15px 6px 6px; +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/config.xml b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/config.xml new file mode 100644 index 00000000..ac4dab8f --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/config.xml @@ -0,0 +1,19 @@ + + + GWT Web App (Multi Project) + + GWT Web Application with Client, Server and Shared Projects separated. + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/server/src/_PACKAGENAME_/server/GreetingServiceImpl.java b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/server/src/_PACKAGENAME_/server/GreetingServiceImpl.java new file mode 100644 index 00000000..efced2e8 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/server/src/_PACKAGENAME_/server/GreetingServiceImpl.java @@ -0,0 +1,45 @@ +package ${PACKAGENAME}.server; + +import ${PACKAGENAME}.shared.GreetingService; +import ${PACKAGENAME}.shared.FieldVerifier; +import com.google.gwt.user.server.rpc.RemoteServiceServlet; + +/** + * The server-side implementation of the RPC service. + */ +@SuppressWarnings("serial") +public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService { + + public String greetServer(String input) throws IllegalArgumentException { + // Verify that the input is valid. + if (!FieldVerifier.isValidName(input)) { + // If the input is not valid, throw an IllegalArgumentException back to + // the client. + throw new IllegalArgumentException("Name must be at least 4 characters long"); + } + + String serverInfo = getServletContext().getServerInfo(); + String userAgent = getThreadLocalRequest().getHeader("User-Agent"); + + // Escape data from the client to avoid cross-site script vulnerabilities. + input = escapeHtml(input); + userAgent = escapeHtml(userAgent); + + return "Hello, " + input + "!

I am running " + serverInfo + ".

It looks like you are using:
" + + userAgent; + } + + /** + * Escape an html string. Escaping data received from the client helps to + * prevent cross-site script vulnerabilities. + * + * @param html the html string to escape + * @return the escaped string + */ + private String escapeHtml(String html) { + if (html == null) { + return null; + } + return html.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); + } +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/FieldVerifier.java b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/FieldVerifier.java new file mode 100644 index 00000000..cfc5b533 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/FieldVerifier.java @@ -0,0 +1,42 @@ +package ${PACKAGENAME}.shared; + +/** + *

+ * FieldVerifier validates that the name the user enters is valid. + *

+ *

+ * This class is in the shared package because we use it in both + * the client code and on the server. On the client, we verify that the name is + * valid before sending an RPC request so the user doesn't have to wait for a + * network round trip to get feedback. On the server, we verify that the name is + * correct to ensure that the input is correct regardless of where the RPC + * originates. + *

+ *

+ * When creating a class that is used on both the client and the server, be sure + * that all code is translatable and does not use native JavaScript. Code that + * is not translatable (such as code that interacts with a database or the file + * system) cannot be compiled into client-side JavaScript. Code that uses native + * JavaScript (such as Widgets) cannot be run on the server. + *

+ */ +public class FieldVerifier { + + /** + * Verifies that the specified name is valid for our service. + * + * In this example, we only require that the name is at least four + * characters. In your application, you can use more complex checks to ensure + * that usernames, passwords, email addresses, URLs, and other fields have the + * proper syntax. + * + * @param name the name to validate + * @return true if valid, false if invalid + */ + public static boolean isValidName(String name) { + if (name == null) { + return false; + } + return name.length() > 3; + } +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/GreetingService.java b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/GreetingService.java new file mode 100644 index 00000000..1faabd11 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/GreetingService.java @@ -0,0 +1,12 @@ +package ${PACKAGENAME}.shared; + +import com.google.gwt.user.client.rpc.RemoteService; +import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; + +/** + * The client-side stub for the RPC service. + */ +@RemoteServiceRelativePath("greet") +public interface GreetingService extends RemoteService { + String greetServer(String name) throws IllegalArgumentException; +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/GreetingServiceAsync.java b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/GreetingServiceAsync.java new file mode 100644 index 00000000..392676c4 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/GreetingServiceAsync.java @@ -0,0 +1,10 @@ +package ${PACKAGENAME}.shared; + +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * The async counterpart of GreetingService. + */ +public interface GreetingServiceAsync { + void greetServer(String input, AsyncCallback callback) throws IllegalArgumentException; +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/_.._shared.gwt.xml b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/_.._shared.gwt.xml new file mode 100644 index 00000000..b10c205a --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/client_server_shared/shared/src/_PACKAGENAME_/shared/_.._shared.gwt.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/empty_multiproject/config.xml b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/empty_multiproject/config.xml new file mode 100644 index 00000000..b894b689 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/project_templates/empty_multiproject/config.xml @@ -0,0 +1,16 @@ + + + Empty Multi Project + + Empty Project divided into Client, Shared and Server + + + + + + + + \ No newline at end of file diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizard.java b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizard.java index 841a9bb4..c62a99d7 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizard.java +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizard.java @@ -99,8 +99,8 @@ public boolean performFinish() { packageName = newProjectWizardPage.getPackage(); locationURI = newProjectWizardPage.getCreationLocationURI(); isGenerateEmptyProject = newProjectWizardPage.isGenerateEmptyProject(); - buildAnt = newProjectWizardPage.getBuildAnt(); - buildMaven = newProjectWizardPage.getBuildMaven(); + buildAnt = newProjectWizardPage.isBuildAnt(); + buildMaven = newProjectWizardPage.isBuildMaven(); /** * HACK: We need to make sure that the DebugUITools plugin (and the DebugUIPlugin plugin) is loaded via the main diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizardPage.java b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizardPage.java index 7e0970b3..55c7d86b 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizardPage.java +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppProjectWizardPage.java @@ -597,11 +597,11 @@ private void validatePageAndSetCompletionStatus() { } } - public boolean getBuildAnt() { + boolean isBuildAnt() { return generateAntCodeCheckbox.getSelection(); } - public boolean getBuildMaven() { + boolean isBuildMaven() { return generateMavenCodeCheckbox.getSelection(); } diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppTemplateProjectWizard.java b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppTemplateProjectWizard.java new file mode 100644 index 00000000..4a030b16 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppTemplateProjectWizard.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright 2024 GWT Eclipse Plugin. All Rights Reserved. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package com.google.gdt.eclipse.suite.wizards; + +import com.google.gdt.eclipse.core.sdk.Sdk.SdkException; +import com.google.gdt.eclipse.suite.GdtPlugin; +import com.google.gdt.eclipse.suite.resources.GdtImages; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.internal.ui.wizards.NewElementWizard; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.INewWizard; +import org.eclipse.ui.IWorkbench; +import org.osgi.service.prefs.BackingStoreException; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; + +/** + * Creates a new multi project web application. + * + * TODO: The progress monitors are not being used correctly. + */ +@SuppressWarnings("restriction") +public class NewWebAppTemplateProjectWizard extends NewElementWizard implements INewWizard { + + private NewWebAppTemplateProjectWizardPage newProjectWizardPage; + private String projectName; + private boolean useGWT; + private IPath gwtSdkContainerPath; + private String packageName; + private URI locationURI; + private ProjectTemplate template; + + public NewWebAppTemplateProjectWizard() { + } + + @Override + public void addPages() { + newProjectWizardPage = new NewWebAppTemplateProjectWizardPage(); + addPage(newProjectWizardPage); + } + + @Override + public IJavaElement getCreatedElement() { + return null; + } + + @Override + public void init(IWorkbench workbench, IStructuredSelection selection) { + setHelpAvailable(false); + setWindowTitle("New GWT Template based Project"); + setNeedsProgressMonitor(true); + setDefaultPageImageDescriptor(GdtPlugin.getDefault().getImageDescriptor(GdtImages.GDT_NEW_PROJECT_LARGE)); + } + + /** + * We initialize these members here so that finishPage can access them without triggering a SWT + * InvalidThreadAccessException. + */ + @Override + public boolean performFinish() { + projectName = newProjectWizardPage.getProjectName(); + useGWT = newProjectWizardPage.useGWT(); + gwtSdkContainerPath = newProjectWizardPage.getGWTSdkContainerPath(); + packageName = newProjectWizardPage.getPackage(); + locationURI = newProjectWizardPage.getCreationLocationURI(); + template = newProjectWizardPage.getTemplate(); + + /** + * HACK: We need to make sure that the DebugUITools plugin (and the DebugUIPlugin plugin) is loaded via the main + * thread. before we call super.performFinish(). Otherwise, a race condition in Eclipse 3.5 occurs where + * LaunchConfigurationManager.loadLaunchGroups() is called from two threads. The first call comes from our query for + * launch groups in WebAppProjectCreator.createLaunchConfiguration() (which is part of a ModalContext runnable). The + * second comes about due to the initialization of the DebugUIPlugin plugin (which we cause, by accessing classes in + * this plugin through the DebugUITools plugin). + */ + DebugUITools.getLaunchGroups(); + + boolean finished = super.performFinish(); + if (finished) { + // TODO: See JavaProjectWizard to see how to switch to Java perspective + // and open new element + } + return finished; + } + + @Override + protected void finishPage(IProgressMonitor monitor) throws InterruptedException, CoreException { + try { + WebAppTemplateProjectCreator wapc = new WebAppTemplateProjectCreator(template); + wapc.setProjectName(projectName); + wapc.setPackageName(packageName); + wapc.setLocationURI(locationURI); + + if (useGWT) { + wapc.addContainerPath(gwtSdkContainerPath); + } + + wapc.create(monitor); + + } catch (MalformedURLException e) { + throw new CoreException(new Status(IStatus.ERROR, GdtPlugin.PLUGIN_ID, e.getMessage(), e)); + } catch (UnsupportedEncodingException e) { + throw new CoreException(new Status(IStatus.ERROR, GdtPlugin.PLUGIN_ID, e.getMessage(), e)); + } catch (SdkException e) { + throw new CoreException(new Status(IStatus.ERROR, GdtPlugin.PLUGIN_ID, e.getMessage(), e)); + } catch (ClassNotFoundException e) { + throw new CoreException(new Status(IStatus.ERROR, GdtPlugin.PLUGIN_ID, e.getMessage(), e)); + } catch (IOException e) { + throw new CoreException(new Status(IStatus.ERROR, GdtPlugin.PLUGIN_ID, e.getMessage(), e)); + } catch (BackingStoreException e) { + throw new CoreException(new Status(IStatus.ERROR, GdtPlugin.PLUGIN_ID, e.getMessage(), e)); + } + } +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppTemplateProjectWizardPage.java b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppTemplateProjectWizardPage.java new file mode 100644 index 00000000..a18611d9 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/NewWebAppTemplateProjectWizardPage.java @@ -0,0 +1,532 @@ +/******************************************************************************* + * Copyright 2024 GWT Eclipse Plugin. All Rights Reserved. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package com.google.gdt.eclipse.suite.wizards; + +import com.google.gdt.eclipse.core.sdk.Sdk; +import com.google.gdt.eclipse.core.sdk.SdkClasspathContainer; +import com.google.gdt.eclipse.core.ui.SdkSelectionBlock; +import com.google.gdt.eclipse.core.ui.SdkSelectionBlock.SdkSelection; +import com.google.gdt.eclipse.platform.ui.PixelConverterFactory; +import com.google.gwt.eclipse.core.preferences.GWTPreferences; +import com.google.gwt.eclipse.core.preferences.ui.GwtPreferencePage; +import com.google.gwt.eclipse.core.runtime.GWTRuntimeContainer; +import com.google.gwt.eclipse.core.runtime.GwtSdk; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.JavaConventions; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jface.window.Window; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.dialogs.PreferencesUtil; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Wizard page where the user specifies the parameters for a new GWT project. + */ +public class NewWebAppTemplateProjectWizardPage extends WizardPage { + + /** + * Select a GWT {@link Sdk} based on the set of {@link Sdk} known to the workspace. + */ + private final class GwtWorkspaceSdkSelectionBlock extends SdkSelectionBlock { + private GwtWorkspaceSdkSelectionBlock(Composite parent, int style) { + super(parent, style); + + updateSdkBlockControls(); + initializeSdkComboBox(); + setSelection(-1); + } + + @Override + protected void doConfigure() { + if (Window.OK == PreferencesUtil + .createPreferenceDialogOn(getShell(), GwtPreferencePage.ID, new String[] { GwtPreferencePage.ID }, null) + .open()) { + NewWebAppTemplateProjectWizardPage.this.updateControls(); + } + } + + @Override + protected GwtSdk doGetDefaultSdk() { + return GWTPreferences.getDefaultRuntime(); + } + + @Override + protected List doGetSpecificSdks() { + return new ArrayList<>(GWTPreferences.getSdks()); + } + } + + private final List existingProjectNames = new ArrayList<>(); + private SdkSelectionBlock gwtSelectionBlock; + private Button outDirBrowseButton; + private String outDirCustom = ""; + private Button outDirCustomButton; + private Label outDirLabel; + private Text outDirText; + private Button outDirWorkspaceButton; + private Text packageText; + private Text projectNameText; + private Button useGwtCheckbox; + private Combo templateCombo; + private final String workspaceDirectory; + private List templates; + + public NewWebAppTemplateProjectWizardPage() { + super("createProject"); + setTitle("Create a Web Application Project"); + setDescription("Create a Web Application project in the workspace or in an external location"); + + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + workspaceDirectory = workspaceRoot.getLocation().toOSString(); + + for (IProject project : workspaceRoot.getProjects()) { + existingProjectNames.add(project.getName()); + } + } + + @Override + public void createControl(Composite parent) { + + final ScrolledComposite scroller = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL); + + final GridLayout gridLayout = new GridLayout(); + + Composite containerOfComponents = new Composite(scroller, SWT.NULL); + containerOfComponents.setLayout(gridLayout); + + setControl(containerOfComponents); + + // TODO: convert these fields to use StringDialogField instead? + + // Project name + final Label projectNameLabel = new Label(containerOfComponents, SWT.NONE); + projectNameLabel.setText("Project name:"); + + projectNameText = new Text(containerOfComponents, SWT.BORDER); + final GridData gd1 = new GridData(GridData.FILL_HORIZONTAL); + gd1.horizontalSpan = 2; + projectNameText.setLayoutData(gd1); + projectNameText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + updateControls(); + } + }); + + // Package + final Label packageLabel = new Label(containerOfComponents, SWT.NONE); + packageLabel.setText("Package: (e.g. com.example.myproject)"); + + packageText = new Text(containerOfComponents, SWT.BORDER); + final GridData gd2 = new GridData(GridData.FILL_HORIZONTAL); + gd2.horizontalSpan = 2; + packageText.setLayoutData(gd2); + packageText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + updateControls(); + } + }); + final Label templateLabel = new Label(containerOfComponents, SWT.NONE); + templateLabel.setText("Select Template:"); + templateCombo = new Combo(containerOfComponents, SWT.NONE); + GridData gd3 = new GridData(GridData.FILL_HORIZONTAL); + gd3.horizontalSpan = 2; + templateCombo.setLayoutData(gd3); + try { + templates = ProjectTemplate.getTemplates(); + Collections.sort(templates); + for(int i=0;i sdkSelection = gwtSelectionBlock.getSdkSelection(); + if (sdkSelection != null) { + return sdkSelection.getSelectedSdk(); + } + } + + return null; + } + + IPath getGWTSdkContainerPath() { + return getSdkContainerPath(gwtSelectionBlock.getSdkSelection(), GWTRuntimeContainer.CONTAINER_ID); + } + + IPath getSdkContainerPath(SdkSelection sdkSelection, String containerId) { + if (sdkSelection != null) { + return SdkClasspathContainer.computeContainerPath(containerId, sdkSelection.getSelectedSdk(), + sdkSelection.isDefault() ? SdkClasspathContainer.Type.DEFAULT : SdkClasspathContainer.Type.NAMED); + } + return null; + } + + boolean useGWT() { + return useGwtCheckbox.getSelection(); + } + + private String browseForOutputDirectory() { + DirectoryDialog dlg = new DirectoryDialog(getShell(), SWT.OPEN); + dlg.setFilterPath(getOutputDirectory()); + dlg.setMessage("Choose a directory for the project contents:"); + + return dlg.open(); + } + + private int convertValidationSeverity(int severity) { + switch (severity) { + case IStatus.ERROR: + return ERROR; + case IStatus.WARNING: + return WARNING; + case IStatus.INFO: + default: + return NONE; + } + } + + private void createSdkGroup(Composite container) { + int widthIndent = PixelConverterFactory.createPixelConverter(this.getControl()).convertWidthInCharsToPixels(2); + + Group sdkGroup = new Group(container, SWT.NONE); + sdkGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + final GridLayout sdkGroupLayout = new GridLayout(); + sdkGroupLayout.verticalSpacing = 0; + sdkGroupLayout.numColumns = 1; + sdkGroup.setLayout(sdkGroupLayout); + sdkGroup.setText("SDKs"); + + SelectionListener useSdkCheckboxSelectionListener = new SelectionListener() { + @Override + public void widgetDefaultSelected(SelectionEvent e) { + updateControls(); + } + + @Override + public void widgetSelected(SelectionEvent e) { + updateControls(); + } + }; + + createGwtSdkGroup(sdkGroup, useSdkCheckboxSelectionListener, widthIndent); + + // Add a horizontal spacer + new Label(sdkGroup, SWT.HORIZONTAL); + } + + private void createGwtSdkGroup(Group sdkGroup, SelectionListener useSdkCheckboxSelectionListener, + int widthIndent) { + useGwtCheckbox = new Button(sdkGroup, SWT.CHECK); + useGwtCheckbox.addSelectionListener(useSdkCheckboxSelectionListener); + useGwtCheckbox.setText("Use GWT"); + useGwtCheckbox.setSelection(true); + + gwtSelectionBlock = new GwtWorkspaceSdkSelectionBlock(sdkGroup, SWT.NONE); + + gwtSelectionBlock.addSdkSelectionListener(new SdkSelectionBlock.SdkSelectionListener() { + @Override + public void onSdkSelection(SdkSelectionEvent e) { + updateControls(); + } + }); + + ((GridData) gwtSelectionBlock.getLayoutData()).horizontalIndent = widthIndent; + } + + private void createLocationGroup(Composite container) { + // Output directory (defaults to subdirectory under workspace) + final Group outDirGroup = new Group(container, SWT.NULL); + outDirGroup.setText("Location"); + final GridData gd3 = new GridData(GridData.FILL_HORIZONTAL); + gd3.horizontalSpan = 2; + outDirGroup.setLayoutData(gd3); + + final GridLayout outDirGridLayout = new GridLayout(); + outDirGridLayout.numColumns = 3; + outDirGroup.setLayout(outDirGridLayout); + + outDirWorkspaceButton = new Button(outDirGroup, SWT.RADIO); + outDirWorkspaceButton.setText("Create new project in workspace"); + outDirWorkspaceButton.setSelection(true); + final GridData gd4 = new GridData(); + gd4.horizontalAlignment = GridData.FILL; + gd4.grabExcessHorizontalSpace = true; + gd4.horizontalSpan = 3; + outDirWorkspaceButton.setLayoutData(gd4); + outDirWorkspaceButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateControls(); + } + }); + + outDirCustomButton = new Button(outDirGroup, SWT.RADIO); + outDirCustomButton.setText("Create new project in:"); + final GridData gd5 = new GridData(); + gd5.horizontalAlignment = GridData.FILL; + gd5.grabExcessHorizontalSpace = true; + gd5.horizontalSpan = 3; + outDirCustomButton.setLayoutData(gd5); + outDirCustomButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + outDirText.setText(outDirCustom); + updateControls(); + } + }); + + outDirLabel = new Label(outDirGroup, SWT.NONE); + outDirLabel.setText("Directory:"); + + outDirText = new Text(outDirGroup, SWT.BORDER); + final GridData gd6 = new GridData(); + gd6.horizontalAlignment = GridData.FILL; + gd6.grabExcessHorizontalSpace = true; + outDirText.setLayoutData(gd6); + outDirText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + if (outDirCustomButton.getSelection()) { + outDirCustom = getOutputDirectory(); + validatePageAndSetCompletionStatus(); + } + } + }); + + outDirBrowseButton = new Button(outDirGroup, SWT.NONE); + outDirBrowseButton.setText("Browse..."); + outDirBrowseButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + String outDir = browseForOutputDirectory(); + if (outDir != null) { + outDirText.setText(outDir); + } + } + }); + } + + private String getOutputDirectory() { + return outDirText.getText().trim(); + } + + private void updateControls() { + // Set the output directory to the workspace + if (outDirWorkspaceButton.getSelection()) { + outDirLabel.setEnabled(false); + outDirText.setEnabled(false); + outDirBrowseButton.setEnabled(true); + + String outDir = workspaceDirectory; + if (getProjectName().length() > 0) { + outDir += (System.getProperty("file.separator") + getProjectName()); + } + + outDirText.setText(outDir); + } else { + outDirLabel.setEnabled(true); + outDirText.setEnabled(true); + outDirBrowseButton.setEnabled(true); + } + + gwtSelectionBlock.setEnabled(useGwtCheckbox.getSelection()); + + validatePageAndSetCompletionStatus(); + } + + private boolean validateFromStatus(IStatus status) { + if (!status.isOK()) { + setMessage(status.getMessage(), convertValidationSeverity(status.getSeverity())); + return false; + } + + return true; + } + + private void validatePageAndSetCompletionStatus() { + IStatus status; + boolean pageComplete = false; + + try { + // Project name cannot be blank + if (getProjectName().length() == 0) { + setMessage("Enter a name for the project"); + return; + } + + // Verify that project name is valid + status = ResourcesPlugin.getWorkspace().validateName(getProjectName(), IResource.PROJECT); + if (!validateFromStatus(status)) { + return; + } + + // Make sure project doesn't already exist in workspace + if (existingProjectNames.contains(getProjectName())) { + setMessage("A project with this name already exists.", ERROR); + return; + } + + // Output directory cannot be blank + if (getOutputDirectory().length() == 0) { + setMessage("Enter the output directory"); + return; + } + + // If the user wants to use a custom output directory, + // verify that the directory exists + if (outDirCustomButton.getSelection()) { + File outDir = new Path(getOutputDirectory()).toFile(); + if (!outDir.isDirectory()) { + setMessage("The output directory does not exist", ERROR); + return; + } + } + + // Make sure resource with project's name doesn't already exist in output + // directory + IPath outPath = new Path(getOutputDirectory()); + if (outDirWorkspaceButton.getSelection()) { + if (outPath.toFile().exists()) { + setMessage("A resource with the project name already exists in the workspace root", ERROR); + return; + } + } + + // Make sure output directory doesn't already contain an Eclipse project + if (outDirCustomButton.getSelection()) { + outPath = outPath.append(IProjectDescription.DESCRIPTION_FILE_NAME); + if (outPath.toFile().exists()) { + setMessage("The output directory already contains a project file", ERROR); + return; + } + } + + // Package name cannot be blank + if (getPackage().length() == 0) { + setMessage("Enter a package name"); + return; + } + + String complianceLevel = JavaCore.getOption("org.eclipse.jdt.core.compiler.compliance"); + String sourceLevel = JavaCore.getOption("org.eclipse.jdt.core.compiler.source"); + + // Verify that package name is valid + status = JavaConventions.validatePackageName(getPackage(), complianceLevel, sourceLevel); + if (!validateFromStatus(status)) { + return; + } + + // If we are using GWT then an SDK must be selected + if (useGwtCheckbox.getSelection()) { + + IStatus gwtRuntimeValidationStatus; + GwtSdk selectedGwtRuntime = getSelectedGwtSdk(); + if (selectedGwtRuntime == null) { + setMessage("Please configure a GWT SDK.", ERROR); + return; + } else if (!(gwtRuntimeValidationStatus = selectedGwtRuntime.validate()).isOK()) { + setMessage("The selected GWT SDK is not valid: " + gwtRuntimeValidationStatus.getMessage(), ERROR); + return; + } + } + + pageComplete = true; + setMessage(null); + } finally { + setPageComplete(pageComplete); + } + } +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/ProjectTemplate.java b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/ProjectTemplate.java new file mode 100644 index 00000000..15110839 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/ProjectTemplate.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright 2024 GWT Eclipse Plugin. All Rights Reserved. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package com.google.gdt.eclipse.suite.wizards; + +import org.apache.commons.io.FileUtils; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jdt.core.JavaCore; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.input.SAXBuilder; +import org.osgi.framework.Bundle; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * This class loads and parses the template files. + */ +public class ProjectTemplate implements Comparable{ + private static final String GWT_TEMPLATE_DIR = "GWT_TEMPLATE_DIR"; + private Document config; + private File dir; + + /** + * @throws IOException + * @throws JDOMException + */ + public ProjectTemplate(File config) throws JDOMException, IOException { + this.config = parseTemplate(config); + dir = config.getParentFile(); + } + + /** + * Get a List of all templates. + * @return + * @throws IOException + */ + public static final List getTemplates() throws IOException { + List templates = new ArrayList<>(); + try { + Bundle bundle = Platform.getBundle("com.gwtplugins.gdt.eclipse.suite"); + URL url = bundle.getResource("/project_templates"); + url = FileLocator.toFileURL(url); + File templatesDir = new File(new URI(url.toString())); + List list = readTemplates(templatesDir); + templates.addAll(list); + //Load custom templates + String tmp = System.getenv(GWT_TEMPLATE_DIR); + if(tmp != null) + { + list = readTemplates(new File(tmp)); + templates.addAll(list); + } + } + catch(Exception ex) { + throw new IOException("Unable to read templates" , ex); + } + return templates; + } + + private static List readTemplates(File templatesDir) throws JDOMException, IOException + { + List templates = new ArrayList<>(); + if(templatesDir.exists()) + { + File[] dirs = templatesDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + for(File dir : dirs) + { + File config = new File(dir, "config.xml"); + if(config.exists()) + { + ProjectTemplate temp = new ProjectTemplate(config); + templates.add(temp); + } + } + } + return templates; + } + + /** + * @param config + * @return + * @throws IOException + * @throws JDOMException + */ + private static Document parseTemplate(File config) throws JDOMException, IOException { + SAXBuilder parser = new SAXBuilder(); + Document doc = parser.build(config); + doc.getRootElement().getChildren("project"); + return doc; + } + + /** + * Returns a list of the project names that are build by this template. + * @return + */ + public List getProjectNames(String baseName) { + List names = new ArrayList<>(); + List list = config.getRootElement().getChildren("project"); + for(Element el : list) + { + String name = el.getAttributeValue("name"); + name = name.replace("_PROJECTNAME_", baseName); + names.add(name); + } + return names; + } + + /** + * Creates a copy of the template project into the destination dir. + * @param project Number of the project to copy. + * @param dir + * @throws IOException + */ + public void copyProject(int projectIndex, File dir) throws IOException { + Element project = getProjectElement(projectIndex); + File source = new File(this.dir, project.getAttributeValue("dir")); + FileUtils.copyDirectory(source, dir); + } + + private Element getProjectElement(int index) + { + return config.getRootElement().getChildren("project").get(index); + } + + public String getName() + { + return config.getRootElement().getChild("name").getTextNormalize(); + } + + /** + * @param i + * @return + */ + public List getNatureIds(int index) { + Element project = getProjectElement(index); + List natureIds = new ArrayList<>(); + natureIds.add(JavaCore.NATURE_ID); + Element natures = project.getChild("natures"); + if(natures != null) + { + for(Element nature : project.getChildren("nature")) + { + natureIds.add(nature.getAttributeValue("id")); + } + } + return natureIds; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(ProjectTemplate o) { + return getName().compareTo(o.getName()); + } + +} diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/WebAppProjectCreator.java b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/WebAppProjectCreator.java index 30cf7e55..7d9dcb51 100644 --- a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/WebAppProjectCreator.java +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/WebAppProjectCreator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2011 Google Inc. All Rights Reserved. + * Copyright 2024 GWT Eclipse Plugin. All Rights Reserved. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -17,7 +17,6 @@ import com.google.gdt.eclipse.core.ResourceUtils; import com.google.gdt.eclipse.core.StringUtilities; import com.google.gdt.eclipse.core.WebAppUtilities; -import com.google.gdt.eclipse.core.WebAppUtilities.FileInfo; import com.google.gdt.eclipse.core.natures.NatureUtils; import com.google.gdt.eclipse.core.projects.IWebAppProjectCreator; import com.google.gdt.eclipse.core.resources.ProjectResources; @@ -72,15 +71,13 @@ import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; import org.osgi.service.prefs.BackingStoreException; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -216,15 +213,13 @@ private static String sanitizeProjectName(String projectName) { return sanitized; } - private List containerPaths = new ArrayList(); - - private final List fileInfos = new ArrayList(); + private List containerPaths = new ArrayList<>(); private boolean isGenerateEmptyProject; private URI locationURI; - private List natureIds = new ArrayList(); + private List natureIds = new ArrayList<>(); private String packageName; @@ -260,16 +255,6 @@ public void addContainerPath(IPath containerPath) { containerPaths.add(containerPath); } - @Override - public void addFile(IPath path, InputStream inputStream) { - fileInfos.add(new FileInfo(path, inputStream)); - } - - @Override - public void addFile(IPath path, String content) throws UnsupportedEncodingException { - fileInfos.add(new FileInfo(path, new ByteArrayInputStream(content.getBytes("UTF-8")))); - } - @Override public void addNature(String natureId) { natureIds.add(natureId); @@ -287,7 +272,6 @@ public void create(IProgressMonitor monitor) throws CoreException, SdkException, ClassNotFoundException, BackingStoreException, IOException { this.monitor = monitor; boolean useGwt = natureIds.contains(GWTNature.NATURE_ID); - // TODO: Add code to update the progress monitor if (useGwt) { // Let GWT create the source files that we want, we will overwrite the @@ -327,9 +311,6 @@ public void create(IProgressMonitor monitor) */ project.refreshLocal(IResource.DEPTH_INFINITE, monitor); - // Create files - createFiles(project); - // Set all of the natures on the project NatureUtils.addNatures(project, natureIds); @@ -412,10 +393,6 @@ public List getContainerPaths() { return containerPaths; } - public List getFileInfos() { - return fileInfos; - } - public URI getLocationURI() { return locationURI; } @@ -504,33 +481,6 @@ public void setProjectName(String projectName) { this.projectName = projectName; } - @Override - public void setTemplates(String... templates) { - if (templates == null) { - this.templates = null; - } else { - this.templates = new String[templates.length]; - System.arraycopy(templates, 0, this.templates, 0, templates.length); - } - } - - @Override - public void setTemplateSources(String... templateSources) { - if (templateSources == null) { - this.templateSources = null; - } else { - this.templateSources = new String[templateSources.length]; - System.arraycopy(templateSources, 0, this.templateSources, 0, templateSources.length); - } - } - - protected void createFiles(IProject project) throws CoreException { - for (FileInfo fileInfo : fileInfos) { - ResourceUtils.createFolderStructure(project, fileInfo.path.removeLastSegments(1)); - ResourceUtils.createFile(project.getFullPath().append(fileInfo.path), fileInfo.inputStream); - } - } - protected IFolder createFolders(IProject project, boolean createWarFolders, IProgressMonitor monitor) throws CoreException { IFolder srcFolder = project.getFolder("src"); @@ -552,7 +502,7 @@ protected void createLaunchConfig(IProject project) throws CoreException { WebAppLaunchUtil.determineStartupURL(project, false), false, turnOnGwtSuperDevMode); ILaunchGroup[] groups = DebugUITools.getLaunchGroups(); - ArrayList groupsNames = new ArrayList(); + ArrayList groupsNames = new ArrayList<>(); for (ILaunchGroup group : groups) { if (IDebugUIConstants.ID_DEBUG_LAUNCH_GROUP.equals(group.getIdentifier()) || IDebugUIConstants.ID_RUN_LAUNCH_GROUP.equals(group.getIdentifier())) { @@ -599,7 +549,7 @@ protected Sdk getGWTSdk() { protected void setProjectClasspath(IJavaProject javaProject, IFolder srcFolder, IProgressMonitor monitor) throws JavaModelException { - List classpathEntries = new ArrayList(); + List classpathEntries = new ArrayList<>(); classpathEntries.add(JavaCore.newSourceEntry(srcFolder.getFullPath())); // Add the "test" folder as a src path, if it exists @@ -705,15 +655,17 @@ public IStatus runInWorkspace(IProgressMonitor monitor) { * Return the Java project created. This will only work half way through the process. */ @Override - public IJavaProject getCreatedJavaProject() { - return createdJavaProject; + public List getCreatedJavaProjects() { + List list = new ArrayList<>(); + list.add(createdJavaProject); + return Collections.unmodifiableList(list); } /** * Build a Maven project. */ @Override - public boolean getBuildMaven() { + public boolean isBuildMaven() { return buildMaven; } @@ -721,7 +673,7 @@ public boolean getBuildMaven() { * Build a Ant project. */ @Override - public boolean getBuiltAnt() { + public boolean isBuiltAnt() { return buildAnt; } diff --git a/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/WebAppTemplateProjectCreator.java b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/WebAppTemplateProjectCreator.java new file mode 100644 index 00000000..6008b295 --- /dev/null +++ b/plugins/com.gwtplugins.gdt.eclipse.suite/src/com/google/gdt/eclipse/suite/wizards/WebAppTemplateProjectCreator.java @@ -0,0 +1,443 @@ +/******************************************************************************* + * Copyright 2024 GWT Eclipse Plugin. All Rights Reserved. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package com.google.gdt.eclipse.suite.wizards; + +import com.google.gdt.eclipse.core.ResourceUtils; +import com.google.gdt.eclipse.core.WebAppUtilities; +import com.google.gdt.eclipse.core.natures.NatureUtils; +import com.google.gdt.eclipse.core.projects.IWebAppProjectCreator; +import com.google.gdt.eclipse.core.resources.ProjectResources; +import com.google.gdt.eclipse.core.sdk.Sdk; +import com.google.gdt.eclipse.core.sdk.Sdk.SdkException; +import com.google.gdt.eclipse.core.sdk.SdkClasspathContainer; +import com.google.gdt.eclipse.core.sdk.SdkManager; +import com.google.gwt.eclipse.core.preferences.GWTPreferences; +import com.google.gwt.eclipse.core.runtime.GWTRuntimeContainer; +import com.google.gwt.eclipse.core.sdk.GWTUpdateWebInfFolderCommand; + +import org.eclipse.core.filesystem.URIUtil; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathsBlock; +import org.eclipse.jdt.launching.JavaRuntime; +import org.eclipse.jdt.ui.PreferenceConstants; +import org.osgi.service.prefs.BackingStoreException; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +/** + * Web application project creator. + */ +@SuppressWarnings("restriction") +public class WebAppTemplateProjectCreator implements IWebAppProjectCreator { + /** + * FilenameFilter that matches files that have a ".java" extension. + */ + private static final FilenameFilter javaSourceFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".java"); + } + }; + + /** + * Returns true if the location URI maps onto the workspace's location URI. + */ + private static boolean isWorkspaceRootLocationURI(URI locationURI) { + return ResourcesPlugin.getWorkspace().getRoot().getLocationURI().equals(locationURI); + } + + /** + * Recursively find the .java files in the output directory and reformat them. + * + * @throws CoreException + */ + private static void reformatJavaFiles(File outDir) throws CoreException { + // If a default JRE has not yet been detected (e.g. brand new workspace), + // the compiler source compliance may be set to 1.3 (the default value from + // code). This is a problem because the generated files do not compile + // against 1.3 (e.g. they use annotations), and thus the formatting will not + // succeed. We work around this using a trick from the + // CompliancePreferencePage: Ensure there is a default JRE which in + // turn updates the compliance level. + JavaRuntime.getDefaultVMInstall(); + + List javaFiles = ProjectResources.findFilesInDir(outDir, javaSourceFilter); + + for (File file : javaFiles) { + ProjectResources.reformatJavaSource(file); + } + } + + private List containerPaths = new ArrayList<>(); + private URI locationURI; + private String packageBaseName; + private String projectBaseName; + private List createdJavaProjects; + private IProgressMonitor monitor; + private Sdk gwtSdk; + private ProjectTemplate projectTemplate; + + protected WebAppTemplateProjectCreator(ProjectTemplate projectTemplate) { + this.projectTemplate = projectTemplate; + // Initialize location URI to the workspace + IPath workspaceLoc = ResourcesPlugin.getWorkspace().getRoot().getLocation(); + if (workspaceLoc != null) { + locationURI = URIUtil.toURI(workspaceLoc); + } + } + + @Override + public void addContainerPath(IPath containerPath) { + containerPaths.add(containerPath); + } + + @Override + public void addNature(String natureId) { + } + + /** + * Creates the project per the current configuration. Note that the caller must have a workspace lock in order to + * successfully execute this method. + * + * @throws BackingStoreException + * @throws IOException + */ + @Override + public void create(IProgressMonitor monitor) + throws CoreException, SdkException, ClassNotFoundException, BackingStoreException, IOException { + this.monitor = monitor; + + List projectNames = projectTemplate.getProjectNames(projectBaseName); + IProject[] project = new IProject[projectNames.size()]; + createdJavaProjects = new ArrayList<>(); + for(int i=0;i files = new Stack<>(); + files.add(dir); + while(files.isEmpty() == false) + { + File file = files.pop(); + if(file.getName().contains("_PACKAGENAME_")) + { + file = replace(file, "_PACKAGENAME_", packageBaseName.replace('.', File.separatorChar)); + } + if(file.getName().contains("_PROJECTNAME_")) + { + file = replace(file, "_PROJECTNAME_", projectBaseName.replace('.', File.separatorChar)); + } + if(file.getName().contains("_.._")) + { + file = replace(file, "_.._", "../"); + } + if(file.isDirectory()) + { + File[] cf = file.listFiles(); + files.addAll(Arrays.asList(cf)); + } + else + { + replaceInFile(file.toString(), "\\$\\{PACKAGENAME\\}", packageBaseName); + replaceInFile(file.toString(), "\\$\\{PROJECTNAME\\}", projectBaseName); + } + } + } + + private File replace(File file, String toReplace, String replacement) throws IOException + { + String name = file.getName(); + name = name.replace(toReplace, replacement); + File newFile = new File(file.getParentFile(), name); + Files.createDirectories(newFile.getParentFile().toPath()); + boolean ret = file.renameTo(newFile); + if(ret == false) + { + throw new IOException("Could not rename"); + } + return newFile; + } + + /** + * Replaces a pattern in a File. The File is not allowed to be larger then 1.000.000 bytes. + * @param file the file, where the replacement is made. + * @param pattern a regular expression to be replaced in the whole file. + * @param replacement the replacement Text. + * @throws IOException + */ + public static void replaceInFile(String file, String pattern, String replacement) throws IOException { + Charset cset = StandardCharsets.UTF_8; + java.nio.file.Path path = Paths.get(file); + if (Files.exists(path)) { + if (Files.size(path) > 1000000) { + throw new IOException("File to large"); + } + byte[] data = Files.readAllBytes(path); + String str = new String(data, cset); + String newStr = str.replaceAll(pattern, replacement); + Files.writeString(path, newStr, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); + } + } + + /** + * @param gwtSdk + */ + private void setGwtSdk(Sdk gwtSdk) { + this.gwtSdk = gwtSdk; + } + + @Override + public Sdk getGwtSdk() { + return gwtSdk; + } + + private void includeExtensionPartipants() throws CoreException { + IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); + IExtensionPoint extensionPoint = extensionRegistry + .getExtensionPoint("com.gwtplugins.gdt.eclipse.suite.webAppCreatorParticipant"); + if (extensionPoint == null) { + return; + } + IExtension[] extensions = extensionPoint.getExtensions(); + for (IExtension extension : extensions) { + IConfigurationElement[] configurationElements = extension.getConfigurationElements(); + for (IConfigurationElement configurationElement : configurationElements) { + Object createExecutableExtension = configurationElement.createExecutableExtension("class"); + Participant participant = (Participant) createExecutableExtension; + participant.updateWebAppProjectCreator(this); + } + } + } + + @Override + public void setBuildAnt(boolean buildAnt) { + } + + @Override + public void setBuildMaven(boolean buildMaven) { + } + + @Override + public void setGenerateEmptyProject(boolean generateEmptyProject) { + } + + @Override + public void setLocationURI(URI locationURI) { + this.locationURI = locationURI; + } + + @Override + public void setPackageName(String packageName) { + this.packageBaseName = packageName; + } + + @Override + public void setProjectName(String projectName) { + this.projectBaseName = projectName; + } + + protected IFolder createFolders(IProject project, boolean createWarFolders, IProgressMonitor monitor) + throws CoreException { + IFolder srcFolder = project.getFolder("src"); + ResourceUtils.createFolderIfNonExistent(srcFolder, monitor); + + if (createWarFolders) { + // create /WEB-INF/lib + ResourceUtils.createFolderStructure(project, new Path(WebAppUtilities.DEFAULT_WAR_DIR_NAME + "/WEB-INF/lib")); + } + + return srcFolder; + } + + protected IProject createProject(IProgressMonitor monitor, String projectName) throws CoreException { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + IProject project = workspaceRoot.getProject(projectName); + if (!project.exists()) { + URI uri; + if (isWorkspaceRootLocationURI(locationURI)) { + // If you want to put a project in the workspace root then the location + // needs to be null... + uri = null; + } else { + // Non-default paths need to include the project name + IPath path = URIUtil.toPath(locationURI).append(projectName); + uri = URIUtil.toURI(path); + } + + BuildPathsBlock.createProject(project, uri, monitor); + } + return project; + } + + protected IPath findContainerPath(String containerId) { + for (IPath containerPath : containerPaths) { + if (SdkClasspathContainer.isContainerPath(containerId, containerPath)) { + return containerPath; + } + } + return null; + } + + protected Sdk getGWTSdk() { + return getSdk(GWTRuntimeContainer.CONTAINER_ID, GWTPreferences.getSdkManager()); + } + + protected void setProjectClasspath(IJavaProject javaProject, IFolder srcFolder, IProgressMonitor monitor) + throws JavaModelException { + List classpathEntries = new ArrayList<>(); + for(IClasspathEntry cp : javaProject.getRawClasspath()) + { + classpathEntries.add(cp); + } + classpathEntries.add(JavaCore.newSourceEntry(srcFolder.getFullPath())); + + // Add the "test" folder as a src path, if it exists + IProject project = javaProject.getProject(); + IFolder testFolder = project.getFolder("test"); + if (testFolder.exists()) { + classpathEntries.add(JavaCore.newSourceEntry(testFolder.getFullPath(), new IPath[0], + project.getFullPath().append("test-classes"))); + } + classpathEntries.add(JavaCore.newProjectEntry(new Path("/t1"), null, true, null, false)); + + // Add our container entries to the path + for (IPath containerPath : containerPaths) { + classpathEntries.add(JavaCore.newContainerEntry(containerPath)); + } + + classpathEntries.addAll(Arrays.asList(PreferenceConstants.getDefaultJRELibrary())); + + javaProject.setRawClasspath(classpathEntries.toArray(new IClasspathEntry[0]), monitor); + } + + private Sdk getSdk(String containerId, SdkManager sdkManager) { + Sdk sdk = null; + IPath containerPath = findContainerPath(containerId); + if (containerPath != null) { + sdk = sdkManager.findSdkForPath(containerPath); + } + + return sdk; + } + /** + * Return the Java project created. This will only work half way through the process. + */ + @Override + public List getCreatedJavaProjects() { + return Collections.unmodifiableList(createdJavaProjects); + } + + /** + * Build a Maven project. + */ + @Override + public boolean isBuildMaven() { + return false; + } + + /** + * Build a Ant project. + */ + @Override + public boolean isBuiltAnt() { + return false; + } + + @Override + public IProgressMonitor getProgressMonitor() { + return monitor; + } + +} diff --git a/plugins/com.gwtplugins.gwt.eclipse.core/src/com/google/gwt/eclipse/core/editors/java/JsniMethodBodyCompletionProposalComputer.java b/plugins/com.gwtplugins.gwt.eclipse.core/src/com/google/gwt/eclipse/core/editors/java/JsniMethodBodyCompletionProposalComputer.java index b0906014..5c80721b 100644 --- a/plugins/com.gwtplugins.gwt.eclipse.core/src/com/google/gwt/eclipse/core/editors/java/JsniMethodBodyCompletionProposalComputer.java +++ b/plugins/com.gwtplugins.gwt.eclipse.core/src/com/google/gwt/eclipse/core/editors/java/JsniMethodBodyCompletionProposalComputer.java @@ -57,7 +57,7 @@ public class JsniMethodBodyCompletionProposalComputer implements public static final String WND = "$wnd"; private static final String JSNI_METHOD_OPEN_BRACE = "/*-{"; - + private static final List NO_CONTEXTS = Collections.emptyList(); private static final List NO_PROPOSALS = Collections.emptyList(); @@ -107,7 +107,7 @@ static String createJsniBlock(IJavaProject project, String body, static int measureIndentationUnits(IDocument document, int lineOfInvocationOffset, int lineOffset, IJavaProject project) throws BadLocationException { - Map options = project.getOptions(true); + Map options = project.getOptions(true); String lineText = document.get(lineOffset, document.getLineLength(lineOfInvocationOffset)); int indentationUnits = IndentManipulation.measureIndentUnits(lineText, @@ -177,7 +177,7 @@ private static String createJsPropertyWriteExpression(String propName, } private static JavaCompletionProposal createProposal(int flags, - String replacementString, int replacementOffset, int numCharsFilled, + String replacementString, int replacementOffset, int numCharsFilled, int numCharsToOverwrite, String displayString) { Image image; GWTPlugin plugin = GWTPlugin.getDefault(); @@ -198,7 +198,7 @@ private static JavaCompletionProposal createProposal(int flags, /** * Returns true if the type can be used as an index of an indexed * property. - * + * * @param typeSignature type signature * @return true if the type can be used as an index of an indexed * property @@ -211,6 +211,7 @@ private static boolean isIndexType(String typeSignature) { || Signature.SIG_CHAR.equals(typeSignature); } + @Override public List computeCompletionProposals( ContentAssistInvocationContext context, IProgressMonitor monitor) { if (!(context instanceof JavaContentAssistInvocationContext)) { @@ -232,7 +233,7 @@ public List computeCompletionProposals( int invocationOffset = jcaic.getInvocationOffset(); IJavaElement elementAt = compilationUnit.getElementAt(invocationOffset); - + if (elementAt == null) { // Can't determine the element at the specified offset. return NO_PROPOSALS; @@ -250,32 +251,32 @@ public List computeCompletionProposals( // Don't propose anything for interfaces. return NO_PROPOSALS; } - + ISourceRange sourceRange = method.getSourceRange(); if (sourceRange == null) { // No source code. // TODO: Is this possible? return NO_PROPOSALS; } - + String methodSource = method.getSource(); int invocationIdx = invocationOffset - sourceRange.getOffset(); - - // Sometimes, if incomplete JSNI method has /* and is followed by any global + + // Sometimes, if incomplete JSNI method has /* and is followed by any global // comment of format /*..*/, compilation unit separates the code after // incomplete JSNI method's /* as a separate block from the incomplete method. // So we need to check whether the block before the invocation offset's block // is the incomplete JSNI method that we are interested in. - + IJavaElement prevElement = compilationUnit.getElementAt(sourceRange.getOffset() - 1); if (prevElement != null && IJavaElement.METHOD == prevElement.getElementType()){ - + IMethod prevMethod = (IMethod) prevElement; - + if ((prevMethod.getDeclaringType().isInterface() == false) && (Flags.isNative(prevMethod.getFlags()) == true)){ - + String prevMethodSource = prevMethod.getSource(); if (prevMethodSource.trim().endsWith(")") == true){ methodSource = prevMethodSource.concat(methodSource); @@ -290,7 +291,7 @@ public List computeCompletionProposals( // If the method is not native then no proposals. return NO_PROPOSALS; } - + // Eliminating comments that might precede native method declaration, so that // following code can safely assume first ')' found is that of function declaration. int idxMultiLineComment = methodSource.trim().indexOf("/*"); @@ -302,7 +303,7 @@ public List computeCompletionProposals( } else { invocationIdx -= methodSource.indexOf('\n') + 1; methodSource = methodSource.substring(methodSource.indexOf('\n') + 1); - } + } idxMultiLineComment = methodSource.trim().indexOf("/*"); idxSingleLineComment = methodSource.trim().indexOf("//"); } @@ -315,7 +316,7 @@ public List computeCompletionProposals( if (tempString.trim().length() != 1) { methodSource = methodSource.substring(0, jsniMethodOpenIdx - 1); } else { - int nextJsniMethodOpenIdx = + int nextJsniMethodOpenIdx = methodSource.substring(jsniMethodOpenIdx + 4).indexOf(JSNI_METHOD_OPEN_BRACE); if (nextJsniMethodOpenIdx != -1) { nextJsniMethodOpenIdx += jsniMethodOpenIdx + 4; @@ -323,21 +324,21 @@ public List computeCompletionProposals( } } } - + // Check if the JSNI method is already complete. if (methodSource.indexOf("}-*/;") != -1) { // JSNI method is complete. return NO_PROPOSALS; } - + // Check position of invocation offset. int numCharsFilled = 0, numCharsToOverwrite = 0; - + String tempString = ""; if (methodSource.substring(methodSource.indexOf(")") + 1).trim().indexOf("/") != -1){ tempString = methodSource.substring(methodSource.indexOf(")"), methodSource.indexOf("/")); } - + if ((methodSource.substring(methodSource.indexOf(")") + 1).trim().indexOf("/") == 0) && (tempString.indexOf('\n') == -1)){ @@ -347,13 +348,13 @@ public List computeCompletionProposals( // Invocation index is placed before JSNI open slash. return NO_PROPOSALS; } - + String jsniCompletedString = methodSource.substring(jsniMethodOpenSlashIdx, invocationIdx); if (jsniCompletedString.indexOf(JSNI_METHOD_OPEN_BRACE) != -1) { jsniCompletedString = jsniCompletedString.trim(); } - + if (JSNI_METHOD_OPEN_BRACE.startsWith(jsniCompletedString)) { numCharsFilled = jsniCompletedString.length(); } else { @@ -362,7 +363,7 @@ public List computeCompletionProposals( } } else { int jsniMethodCloseBracketIdx = methodSource.indexOf(")") + 1; - + if (jsniMethodCloseBracketIdx > invocationIdx) { // Invocation index is not placed after method's close bracket. return NO_PROPOSALS; @@ -372,7 +373,7 @@ public List computeCompletionProposals( return NO_PROPOSALS; } } - + methodSource = methodSource.substring(invocationIdx); int endIdx = methodSource.length(); if (methodSource.indexOf(" ") != -1) { @@ -383,9 +384,9 @@ public List computeCompletionProposals( } else if (methodSource.indexOf("\n") != -1) { endIdx = methodSource.indexOf("\n"); } - + numCharsToOverwrite = methodSource.substring(0, endIdx).trim().length(); - + IDocument document = jcaic.getDocument(); int lineOfInvocationOffset = document.getLineOfOffset(invocationOffset); int lineOffset = document.getLineOffset(lineOfInvocationOffset); @@ -417,19 +418,23 @@ public List computeCompletionProposals( return NO_PROPOSALS; } + @Override public List computeContextInformation( ContentAssistInvocationContext context, IProgressMonitor monitor) { return NO_CONTEXTS; } + @Override public String getErrorMessage() { // Default to no error reporting. return null; } + @Override public void sessionEnded() { } + @Override public void sessionStarted() { } @@ -440,7 +445,7 @@ public void sessionStarted() { private void maybeProposeIndexedPropertyRead(IJavaProject project, IMethod method, int invocationOffset, int indentationUnits, List proposals, String propertyName, - String[] parameterNames, boolean isStatic, int numCharsFilled, + String[] parameterNames, boolean isStatic, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { if (parameterNames.length != 1) { return; @@ -466,7 +471,7 @@ private void maybeProposeIndexedPropertyRead(IJavaProject project, private void maybeProposeIndexedPropertyWrite(IJavaProject project, IMethod method, String propertyName, int invocationOffset, int indentationUnits, boolean isStatic, - List proposals, int numCharsFilled, + List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { String[] parameterNames = method.getParameterNames(); if (parameterNames.length != 2) { @@ -489,7 +494,7 @@ private void maybeProposeIndexedPropertyWrite(IJavaProject project, */ private void maybeProposePropertyRead(IJavaProject project, IMethod method, String propertyName, int invocationOffset, int indentationUnits, - boolean isStatic, List proposals, int numCharsFilled, + boolean isStatic, List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { String[] parameterNames = method.getParameterNames(); if (parameterNames.length == 0 && propertyName.length() > 0) { @@ -509,7 +514,7 @@ private void maybeProposePropertyRead(IJavaProject project, IMethod method, */ private void maybeProposePropertyWrite(IJavaProject project, IMethod method, String propertyName, int invocationOffset, int indentationUnits, - boolean isStatic, List proposals, int numCharsFilled, + boolean isStatic, List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { String[] parameterNames = method.getParameterNames(); if (parameterNames.length == 1 && propertyName.length() > 0) { @@ -528,7 +533,7 @@ private void maybeProposePropertyWrite(IJavaProject project, IMethod method, */ private void proposeEmptyJsniBlock(IJavaProject project, IMethod method, int invocationOffset, int indentationUnits, - List proposals, int numCharsFilled, + List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { String code = createJsniBlock(project, "", indentationUnits); int cursorPosition = (CodeFormatterUtil.createIndentString( @@ -545,7 +550,7 @@ private void proposeEmptyJsniBlock(IJavaProject project, IMethod method, */ private void proposeGetterDelegate(IJavaProject project, IMethod method, int invocationOffset, int indentationUnits, boolean isStatic, - List proposals, int numCharsFilled, + List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { String methodName = method.getElementName(); String[] parameterNames = method.getParameterNames(); @@ -559,7 +564,7 @@ private void proposeGetterDelegate(IJavaProject project, IMethod method, private void proposeGetters(IJavaProject project, IMethod method, int invocationOffset, int indentationUnits, boolean isStatic, - List proposals, int numCharsFilled, + List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { proposeGetterDelegate(project, method, invocationOffset, indentationUnits, @@ -600,7 +605,7 @@ private void proposeGetters(IJavaProject project, IMethod method, */ private void proposeSetterDelegate(IJavaProject project, IMethod method, int invocationOffset, int indentationUnits, boolean isStatic, - List proposals, int numCharsFilled, + List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { String[] parameterNames = method.getParameterNames(); String expression = createJsMethodInvocationExpression( @@ -612,7 +617,7 @@ private void proposeSetterDelegate(IJavaProject project, IMethod method, private void proposeSetters(IJavaProject project, IMethod method, int invocationOffset, int indentationUnits, boolean isStatic, - List proposals, int numCharsFilled, + List proposals, int numCharsFilled, int numCharsToOverwrite) throws JavaModelException { proposeSetterDelegate(project, method, invocationOffset, indentationUnits, diff --git a/plugins/com.gwtplugins.gwt.eclipse.wtp/src/com/google/gwt/eclipse/wtp/projects/WtpFacetCreatorParicipant.java b/plugins/com.gwtplugins.gwt.eclipse.wtp/src/com/google/gwt/eclipse/wtp/projects/WtpFacetCreatorParicipant.java index eaf93834..89852b36 100644 --- a/plugins/com.gwtplugins.gwt.eclipse.wtp/src/com/google/gwt/eclipse/wtp/projects/WtpFacetCreatorParicipant.java +++ b/plugins/com.gwtplugins.gwt.eclipse.wtp/src/com/google/gwt/eclipse/wtp/projects/WtpFacetCreatorParicipant.java @@ -1,5 +1,7 @@ package com.google.gwt.eclipse.wtp.projects; +import java.util.List; + import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -19,14 +21,14 @@ public class WtpFacetCreatorParicipant implements IWebAppProjectCreator.Participant { - private IJavaProject javaProject; + private List javaProjects; private IFacetedProjectListener projectFacetListener; @Override public void updateWebAppProjectCreator(IWebAppProjectCreator webAppProjectCreator) { // Just in case exit early - javaProject = webAppProjectCreator.getCreatedJavaProject(); - if (javaProject == null) { + javaProjects = webAppProjectCreator.getCreatedJavaProjects(); + if (javaProjects == null) { GwtWtpPlugin.logError("Not installing the GWT Facet b/c it's not a Java project"); return; } diff --git a/pom.xml b/pom.xml index ac8bd2a6..b4e937dc 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ 3.0.1 UTF-8 - 2022-09 + 2023-09 https://download.eclipse.org/releases/${eclipse.target} @@ -257,17 +257,17 @@ - build-eclipse-2022-09 + build-eclipse-2023-09 eclipse.target - 2022-09 + 2023-09 - eclipse/2022-09 + eclipse/2023-09 @@ -278,8 +278,8 @@ com.gwtplugins.eclipse - gwt-eclipse-2022-09 - 4.25.0-SNAPSHOT + gwt-eclipse-2023-09 + 4.27.0-SNAPSHOT