From ba5d6dc781355a8e037f4f072876c71c70bccd72 Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 28 Feb 2012 12:16:04 +0400 Subject: [PATCH 01/43] IDEA-81981 svn: command line client + update single file does not work --- .../idea/svn/commandLine/SvnCommandLineUpdateClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java index 7f13c0487ede..0b3296955b6b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java @@ -83,7 +83,8 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient { new CommandLineAuthenticator(myProject, new CommandLineAuthenticator.AuthenticationRequiringCommand() { @Override public void run(File configDir) throws SVNException { - final File base = myCommonAncestor == null ? paths[0] : new File(myCommonAncestor.getPath()); + File base = myCommonAncestor == null ? paths[0] : new File(myCommonAncestor.getPath()); + base = base.isDirectory() ? base : base.getParentFile(); final SvnLineCommand command = new SvnLineCommand(myProject, base, SvnCommandName.up); if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { command.addParameters("-r", revision.toString()); From 626e8c62e081ef36250826e9133c98818675fa89 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 28 Feb 2012 12:31:15 +0400 Subject: [PATCH 02/43] IDEA-81587: Make "Mark as 'In Progress'" persistant on Open Task dialog --- .../src/com/intellij/tasks/actions/ActivateTaskDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/ActivateTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/ActivateTaskDialog.java index 066628101f1f..0f736e68e697 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/ActivateTaskDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/ActivateTaskDialog.java @@ -179,7 +179,7 @@ public class ActivateTaskDialog extends DialogWrapper { } } } - myMarkAsInProgressBox.setSelected(myMarkAsInProgress && isMarkAsInProgressApplicable()); + myMarkAsInProgressBox.setSelected(myMarkAsInProgress); // refresh change lists ChangeListManager changeListManager = ChangeListManager.getInstance(myProject); From 21bd8dc5bdf833cc013acfe59a3b8dce3c37206a Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 28 Feb 2012 12:36:42 +0400 Subject: [PATCH 03/43] SVN: do not refresh current revision when copying history session object --- .../idea/svn/history/SvnHistoryProvider.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 25e2d4606f81..3529b93e07a4 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -137,7 +137,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto @NotNull List revisions, @NotNull FilePath filePath, VcsRevisionNumber currentRevision) { - return new MyHistorySession(revisions, filePath, aBoolean, currentRevision); + return new MyHistorySession(revisions, filePath, aBoolean, currentRevision, false); } class MyHistorySession extends VcsAbstractHistorySession { @@ -145,11 +145,13 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto private final boolean mySupports15; private MyHistorySession(final List revisions, final FilePath committedPath, final boolean supports15, - @Nullable final VcsRevisionNumber currentRevision) { + @Nullable final VcsRevisionNumber currentRevision, boolean skipRefreshOnStart) { super(revisions, currentRevision); myCommittedPath = committedPath; mySupports15 = supports15; - shouldBeRefreshed(); + if (! skipRefreshOnStart) { + shouldBeRefreshed(); + } } public HistoryAsTreeProvider getHistoryAsTreeProvider() { @@ -179,7 +181,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto @Override public VcsHistorySession copy() { - return new MyHistorySession(getRevisionList(), myCommittedPath, mySupports15, getCurrentRevisionNumber()); + return new MyHistorySession(getRevisionList(), myCommittedPath, mySupports15, getCurrentRevisionNumber(), true); } } @@ -212,7 +214,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto logLoader.initSupports15(); final MyHistorySession historySession = - new MyHistorySession(Collections.emptyList(), committedPath, Boolean.TRUE.equals(logLoader.mySupport15), null); + new MyHistorySession(Collections.emptyList(), committedPath, Boolean.TRUE.equals(logLoader.mySupport15), null, false); final Ref sessionReported = new Ref(); final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); From 93d246cdbbbcfaffce1e289deb16b0a8fe8cb573 Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 28 Feb 2012 12:50:59 +0400 Subject: [PATCH 04/43] SVN: correct current revision ("committed") for history session --- .../idea/svn/history/SvnHistoryProvider.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 3529b93e07a4..85e799818441 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -163,7 +163,23 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto if (myCommittedPath == null) { return null; } - return getCurrentRevision(myCommittedPath); + if (myCommittedPath.isNonLocal()) { + // technically, it does not make sense, since there's no "current" revision for non-local history (if look how it's used) + // but ok, lets keep it for now + return new SvnRevisionNumber(SVNRevision.HEAD); + } + try { + SVNWCClient wcClient = myVcs.createWCClient(); + SVNInfo info = wcClient.doInfo(new File(myCommittedPath.getPath()), SVNRevision.UNDEFINED); + if (info != null) { + return new SvnRevisionNumber(info.getCommittedRevision()); + } else { + return null; + } + } + catch (SVNException e) { + return null; + } } public FilePath getCommittedPath() { From fa30a66cff66f3a96bb6017b095b1853f6aa6476 Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 28 Feb 2012 12:52:20 +0400 Subject: [PATCH 05/43] SVN: correct last revision ("committed") for the case when we take revision number from remote info --- .../svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java index ad5b4a674f9c..841c7d6d9272 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java @@ -168,7 +168,7 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin { LOG.info("No SVN status returned for " + file.getPath()); return defaultResult(); } - return createResult(info.getRevision(), true, false); + return createResult(info.getCommittedRevision(), true, false); } final boolean exists = ! SVNStatusType.STATUS_DELETED.equals(svnStatus.getRemoteContentsStatus()) && ! SVNStatusType.STATUS_DELETED.equals(svnStatus.getRemoteNodeStatus()); From 4c2bf73c5eb482fc38c69d169bfa8a4ed175a837 Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Tue, 28 Feb 2012 13:02:38 +0400 Subject: [PATCH 06/43] Add mnemonics to Mvc Run target dialog. --- .../org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.form | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.form b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.form index 24fe4fbd6ccd..3d086ca296b6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.form +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.form @@ -58,7 +58,7 @@ - + @@ -66,7 +66,7 @@ - + From 89107f184bda7fc7ea3ef69976d8a2c6a55890c8 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 28 Feb 2012 09:47:07 +0100 Subject: [PATCH 07/43] IDEA-81896 obsolete todos --- plugins/copyright/docs/todo.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 plugins/copyright/docs/todo.txt diff --git a/plugins/copyright/docs/todo.txt b/plugins/copyright/docs/todo.txt deleted file mode 100644 index d619fcc94845..000000000000 --- a/plugins/copyright/docs/todo.txt +++ /dev/null @@ -1,2 +0,0 @@ -Features: -- Groovy support From 6c72162109a52c11a29834dbf6a97bb84b6ae909 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 28 Feb 2012 13:06:10 +0400 Subject: [PATCH 08/43] progress msg --- .../src/org/jetbrains/jps/incremental/IncProjectBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index bf35e4b2d1e9..15ddc319accb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -170,11 +170,11 @@ public class IncProjectBuilder { runTasks(context, myBuilderRegistry.getBeforeTasks()); context.setCompilingTests(false); - context.processMessage(new ProgressMessage("Building production sources")); + context.processMessage(new ProgressMessage("Checking production sources")); buildChunks(context, myProductionChunks); context.setCompilingTests(true); - context.processMessage(new ProgressMessage("Building test sources")); + context.processMessage(new ProgressMessage("Checking test sources")); buildChunks(context, myTestChunks); context.processMessage(new ProgressMessage("Building project")); From cc9caa13ba80032d0b65d4b6b174dd807c81f6ed Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 28 Feb 2012 13:15:01 +0400 Subject: [PATCH 09/43] ping interval configurable vi registry; do not auto-shut down server if there are active builds --- .../compiler/CompileServerManager.java | 23 ++++++--- .../jetbrains/jps/api/AsyncTaskExecutor.java | 16 ++++++ .../org/jetbrains/jps/api/GlobalOptions.java | 3 +- .../jps/api/SequentialTaskExecutor.java | 4 -- .../jps/client/CompileServerClient.java | 24 +++++---- .../client/ProtobufClientMessageHandler.java | 12 ++++- .../jps/client/SimpleProtobufClient.java | 50 +++++++++---------- .../jps/javac/JavacServerClient.java | 12 ++++- .../src/org/jetbrains/jps/server/Server.java | 36 +++++++------ .../jps/server/ServerMessageHandler.java | 13 ++--- .../src/misc/registry.properties | 3 ++ 11 files changed, 126 insertions(+), 70 deletions(-) create mode 100644 jps/jps-builders/src/org/jetbrains/jps/api/AsyncTaskExecutor.java diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index ced65cfc37f5..94d0a2bd858a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -92,8 +92,9 @@ public class CompileServerManager implements ApplicationComponent{ private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml"; private volatile OSProcessHandler myProcessHandler; private final File mySystemDirectory; - private volatile CompileServerClient myClient = new CompileServerClient(); - private final SequentialTaskExecutor myTaskExecutor = new SequentialTaskExecutor(new SequentialTaskExecutor.AsyncTaskExecutor() { + @Nullable + private volatile CompileServerClient myClient; + private final SequentialTaskExecutor myTaskExecutor = new SequentialTaskExecutor(new AsyncTaskExecutor() { public void submit(Runnable runnable) { ApplicationManager.getApplication().executeOnPooledThread(runnable); } @@ -102,6 +103,12 @@ public class CompileServerManager implements ApplicationComponent{ private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/; private final Map myAutomakeFutures = new HashMap(); private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager(); + private final AsyncTaskExecutor myAsyncExec = new AsyncTaskExecutor() { + @Override + public void submit(Runnable runnable) { + ApplicationManager.getApplication().executeOnPooledThread(runnable); + } + }; public CompileServerManager(final ProjectManager projectManager) { myProjectManager = projectManager; @@ -394,7 +401,8 @@ public class CompileServerManager implements ApplicationComponent{ } final int port = NetUtils.findAvailableSocketPort(); - final Process process = launchServer(port); + final long serverPingInterval = Registry.intValue("compiler.server.ping.interval", -1) * 1000L; + final Process process = launchServer(port, serverPingInterval); final OSProcessHandler processHandler = new OSProcessHandler(process, null) { protected boolean shouldDestroyProcessRecursively() { @@ -451,7 +459,7 @@ public class CompileServerManager implements ApplicationComponent{ throw new Exception("Server startup failed: " + startupMsg); } - CompileServerClient client = new CompileServerClient(); + CompileServerClient client = new CompileServerClient(serverPingInterval, myAsyncExec); boolean connected = false; try { connected = client.connect(NetUtils.getLocalHostString(), port); @@ -545,7 +553,7 @@ public class CompileServerManager implements ApplicationComponent{ // commandLine.add((launcherUsed? "-J" : "") + "-D" + CharsetToolkit.FILE_ENCODING_PROPERTY + "=" + CharsetToolkit.getDefaultSystemCharset().name()); //} - private Process launchServer(final int port) throws ExecutionException { + private Process launchServer(final int port, long pingInterval) throws ExecutionException { // validate tools.jar presence final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler(); if (systemCompiler == null) { @@ -561,7 +569,10 @@ public class CompileServerManager implements ApplicationComponent{ cmdLine.addParameter("-XX:ReservedCodeCacheSize=64m"); cmdLine.addParameter("-Xmx" + Registry.intValue("compiler.server.heap.size") + "m"); cmdLine.addParameter("-Djava.awt.headless=true"); - //cmdLine.addParameter("-DuseJavaUtilZip"); + //noinspection ConstantConditions + if (pingInterval > 0L) { + cmdLine.addParameter("-D" + GlobalOptions.PING_INTERVAL_MS_OPTION + "=" + pingInterval); + } final String additionalOptions = Registry.stringValue("compiler.server.vm.options"); if (!StringUtil.isEmpty(additionalOptions)) { final StringTokenizer tokenizer = new StringTokenizer(additionalOptions, " ", false); diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/AsyncTaskExecutor.java b/jps/jps-builders/src/org/jetbrains/jps/api/AsyncTaskExecutor.java new file mode 100644 index 000000000000..745834c7de69 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/api/AsyncTaskExecutor.java @@ -0,0 +1,16 @@ +package org.jetbrains.jps.api; + +/** +* @author Eugene Zhuravlev +* Date: 2/28/12 +*/ +public interface AsyncTaskExecutor { + AsyncTaskExecutor DEFAULT = new AsyncTaskExecutor() { + @Override + public void submit(Runnable runnable) { + new Thread(runnable).start(); + } + }; + + void submit(Runnable runnable); +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java b/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java index 3c3a59dcb7dd..547f8135d93d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java @@ -10,6 +10,5 @@ public interface GlobalOptions { String USE_EXTERNAL_JAVAC_OPTION = "use.external.javac.process"; String HOSTNAME_OPTION = "localhost.name"; String VM_EXE_PATH_OPTION = "vm.executable.path"; - - long SERVER_PING_PERIOD = 2000L; // 2 sec + String PING_INTERVAL_MS_OPTION = "server.ping.interval"; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/SequentialTaskExecutor.java b/jps/jps-builders/src/org/jetbrains/jps/api/SequentialTaskExecutor.java index 38ce49434cab..de47b287cca2 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/SequentialTaskExecutor.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/SequentialTaskExecutor.java @@ -31,10 +31,6 @@ public class SequentialTaskExecutor { } }; - public interface AsyncTaskExecutor { - void submit(Runnable runnable); - } - public SequentialTaskExecutor(AsyncTaskExecutor executor) { myExecutor = executor; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java b/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java index 2b731ae08aac..c7ab7dedfc46 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java +++ b/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java @@ -18,15 +18,17 @@ import java.util.concurrent.TimeUnit; public class CompileServerClient extends SimpleProtobufClient { private static final ScheduledThreadPoolExecutor ourPingService = ConcurrencyUtil.newSingleScheduledThreadExecutor("Compile server ping thread", Thread.MIN_PRIORITY); private volatile ScheduledFuture myPingFuture; + private final long myServerPingInterval; - public CompileServerClient() { - super(JpsRemoteProto.Message.getDefaultInstance(), new UUIDGetter() { + public CompileServerClient(long serverPingInterval, final AsyncTaskExecutor asyncExec) { + super(JpsRemoteProto.Message.getDefaultInstance(), asyncExec, new UUIDGetter() { @NotNull public UUID getSessionUUID(@NotNull MessageEvent e) { final JpsRemoteProto.Message message = (JpsRemoteProto.Message)e.getMessage(); return ProtoUtil.fromProtoUUID(message.getSessionId()); } }); + myServerPingInterval = serverPingInterval; } @NotNull @@ -89,15 +91,17 @@ public class CompileServerClient extends SimpleProtobufClient 0L) { + myPingFuture = ourPingService.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + final JpsRemoteProto.Message.Request ping = ProtoUtil.createPingRequest(); + if (isConnected()) { + sendRequest(ping, null); + } } - } - }, GlobalOptions.SERVER_PING_PERIOD, GlobalOptions.SERVER_PING_PERIOD, TimeUnit.MILLISECONDS); + }, myServerPingInterval, myServerPingInterval, TimeUnit.MILLISECONDS); + } } @Override diff --git a/jps/jps-builders/src/org/jetbrains/jps/client/ProtobufClientMessageHandler.java b/jps/jps-builders/src/org/jetbrains/jps/client/ProtobufClientMessageHandler.java index 226c82b3ae06..9c6477f29512 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/client/ProtobufClientMessageHandler.java +++ b/jps/jps-builders/src/org/jetbrains/jps/client/ProtobufClientMessageHandler.java @@ -6,6 +6,7 @@ import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.api.AsyncTaskExecutor; import org.jetbrains.jps.api.RequestFuture; import java.util.ArrayList; @@ -21,10 +22,12 @@ final class ProtobufClientMessageHandler exte @NotNull private final UUIDGetter myUuidGetter; private final SimpleProtobufClient myClient; + private final AsyncTaskExecutor myAsyncExec; - public ProtobufClientMessageHandler(@NotNull UUIDGetter uuidGetter, SimpleProtobufClient client) { + public ProtobufClientMessageHandler(@NotNull UUIDGetter uuidGetter, SimpleProtobufClient client, AsyncTaskExecutor asyncExec) { myUuidGetter = uuidGetter; myClient = client; + myAsyncExec = asyncExec; } public final void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { @@ -89,7 +92,12 @@ final class ProtobufClientMessageHandler exte } finally { // make sure the client is in disconnected state - myClient.scheduleDisconnect(); + myAsyncExec.submit(new Runnable() { + @Override + public void run() { + myClient.disconnect(); + } + }); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/client/SimpleProtobufClient.java b/jps/jps-builders/src/org/jetbrains/jps/client/SimpleProtobufClient.java index 6aeb15c3fd31..8c762adf18b8 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/client/SimpleProtobufClient.java +++ b/jps/jps-builders/src/org/jetbrains/jps/client/SimpleProtobufClient.java @@ -10,6 +10,7 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.api.AsyncTaskExecutor; import org.jetbrains.jps.api.RequestFuture; import java.net.InetSocketAddress; @@ -36,8 +37,8 @@ public class SimpleProtobufClient { protected ChannelFuture myConnectFuture; private final ProtobufClientMessageHandler myMessageHandler; - public SimpleProtobufClient(final MessageLite msgDefaultInstance, final UUIDGetter uuidGetter) { - myMessageHandler = new ProtobufClientMessageHandler(uuidGetter, this); + public SimpleProtobufClient(final MessageLite msgDefaultInstance, final AsyncTaskExecutor asyncExec, final UUIDGetter uuidGetter) { + myMessageHandler = new ProtobufClientMessageHandler(uuidGetter, this, asyncExec); myChannelFactory = new NioClientSocketChannelFactory(ourExecutor, ourExecutor, 1); myPipelineFactory = new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { @@ -105,15 +106,6 @@ public class SimpleProtobufClient { protected void onDisconnect() { } - public final void scheduleDisconnect() { - ourExecutor.submit(new Runnable() { - @Override - public void run() { - disconnect(); - } - }); - } - public final void disconnect() { if (myState.compareAndSet(State.CONNECTED, State.DISCONNECTING)) { try { @@ -154,23 +146,31 @@ public class SimpleProtobufClient { public final RequestFuture sendMessage(final UUID messageId, MessageLite message, @Nullable final T responseHandler, @Nullable final RequestFuture.CancelAction cancelAction) { final RequestFuture requestFuture = new RequestFuture(responseHandler, messageId, cancelAction); myMessageHandler.registerFuture(messageId, requestFuture); - final ChannelFuture channelFuture = Channels.write(myConnectFuture.getChannel(), message); - channelFuture.addListener(new ChannelFutureListener() { - public void operationComplete(ChannelFuture future) throws Exception { - if (!future.isSuccess()) { - try { - myMessageHandler.removeFuture(messageId); - if (responseHandler != null) { - responseHandler.sessionTerminated(); - } - } - finally { - requestFuture.setDone(); + final Channel channel = myConnectFuture.getChannel(); + if (channel.isConnected()) { + Channels.write(channel, message).addListener(new ChannelFutureListener() { + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + notifyTerminated(messageId, requestFuture, responseHandler); } } - } - }); + }); + } + else { + notifyTerminated(messageId, requestFuture, responseHandler); + } return requestFuture; } + private void notifyTerminated(UUID messageId, RequestFuture requestFuture, @Nullable T responseHandler) { + try { + myMessageHandler.removeFuture(messageId); + if (responseHandler != null) { + responseHandler.sessionTerminated(); + } + } + finally { + requestFuture.setDone(); + } + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java index a737e67c5481..75a3e7cb6e1d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java @@ -2,21 +2,31 @@ package org.jetbrains.jps.javac; import org.jboss.netty.channel.MessageEvent; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.api.AsyncTaskExecutor; import org.jetbrains.jps.api.RequestFuture; import org.jetbrains.jps.client.SimpleProtobufClient; import org.jetbrains.jps.client.UUIDGetter; import java.io.File; import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * @author Eugene Zhuravlev * Date: 1/22/12 */ public class JavacServerClient extends SimpleProtobufClient{ + private static final ExecutorService ourExecutors = Executors.newCachedThreadPool(); + private static final AsyncTaskExecutor ASYNC_EXEC = new AsyncTaskExecutor() { + @Override + public void submit(Runnable runnable) { + ourExecutors.submit(runnable); + } + }; public JavacServerClient() { - super(JavacRemoteProto.Message.getDefaultInstance(), new UUIDGetter() { + super(JavacRemoteProto.Message.getDefaultInstance(), ASYNC_EXEC, new UUIDGetter() { @NotNull public UUID getSessionUUID(@NotNull MessageEvent e) { final JavacRemoteProto.Message message = (JavacRemoteProto.Message)e.getMessage(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java index fad3563ebb70..715a70edd32b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java @@ -38,6 +38,7 @@ public class Server { public static final String SERVER_SUCCESS_START_MESSAGE = "Compile Server started successfully. Listening on port: "; public static final String SERVER_ERROR_START_MESSAGE = "Error starting Compile Server: "; private static final String LOG_FILE_NAME = "log.xml"; + private static final long PING_INTERVAL = Long.parseLong(System.getProperty(GlobalOptions.PING_INTERVAL_MS_OPTION, "-1")); private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("compile-server"); private final ChannelFactory myChannelFactory; @@ -45,6 +46,7 @@ public class Server { private final ExecutorService myBuildsExecutor; private volatile long myLastPingTime = -1L; private final ScheduledExecutorService myScheduler; + private final ServerMessageHandler myMessageHandler; public Server(File systemDir) { Paths.getInstance().setSystemRoot(systemDir); @@ -53,7 +55,7 @@ public class Server { myBuildsExecutor = Executors.newFixedThreadPool(MAX_SIMULTANEOUS_BUILD_SESSIONS); myChannelFactory = new NioServerSocketChannelFactory(threadPool, threadPool, 1); final ChannelRegistrar channelRegistrar = new ChannelRegistrar(); - final ServerMessageHandler messageHandler = new ServerMessageHandler(myBuildsExecutor, this); + myMessageHandler = new ServerMessageHandler(myBuildsExecutor, this); myPipelineFactory = new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( @@ -62,7 +64,7 @@ public class Server { new ProtobufDecoder(JpsRemoteProto.Message.getDefaultInstance()), new ProtobufVarint32LengthFieldPrepender(), new ProtobufEncoder(), - messageHandler + myMessageHandler ); } }; @@ -76,11 +78,14 @@ public class Server { final Channel serverChannel = bootstrap.bind(new InetSocketAddress(listenPort)); myAllOpenChannels.add(serverChannel); - startIdleMonitor(); + startActivityMonitor(); } - private void startIdleMonitor() { - final long allowedIdlePeriod = 2 * GlobalOptions.SERVER_PING_PERIOD; + private void startActivityMonitor() { + if (PING_INTERVAL <= 0L) { + return; + } + final long allowedIdlePeriod = 2 * PING_INTERVAL; myScheduler.scheduleAtFixedRate(new Runnable() { private long myStartTime; @Override @@ -90,16 +95,16 @@ public class Server { if (lastPing > 0L) { final long elapsed = now - lastPing; if (elapsed > allowedIdlePeriod) { - doStop(); + doStop(elapsed); } } else { final long start = myStartTime; if (start > 0) { final long elapsed = now - start; - if (elapsed > 5 * GlobalOptions.SERVER_PING_PERIOD) { + if (elapsed > 5 * PING_INTERVAL) { // no pings received since start - doStop(); + doStop(elapsed); } } else { @@ -108,12 +113,15 @@ public class Server { } } - private void doStop() { - try { - stop(); - } - finally { - System.exit(0); + private void doStop(long elapsedTime) { + if (!myMessageHandler.hasRunningBuilds()) { + try { + System.out.println("Stopping compile server; reason: no pings from client received in " + elapsedTime + " ms"); + stop(); + } + finally { + System.exit(0); + } } } }, allowedIdlePeriod, allowedIdlePeriod, TimeUnit.MILLISECONDS); diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java index aec4665a0292..fa4f3e93db9b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java @@ -36,6 +36,7 @@ class ServerMessageHandler extends SimpleChannelHandler { } public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { + myServer.pingReceived(); final JpsRemoteProto.Message message = (JpsRemoteProto.Message)e.getMessage(); final UUID sessionId = ProtoUtil.fromProtoUUID(message.getSessionId()); @@ -86,7 +87,6 @@ class ServerMessageHandler extends SimpleChannelHandler { break; case SHUTDOWN_COMMAND : - // todo pay attention to policy myBuildsExecutor.submit(new Runnable() { public void run() { final List futures = new ArrayList(); @@ -139,7 +139,6 @@ class ServerMessageHandler extends SimpleChannelHandler { reply = ProtoUtil.toMessage(sessionId, ProtoUtil.createCommandCompletedEvent(null)); break; case PING: - myServer.pingReceived(); reply = ProtoUtil.toMessage(sessionId, ProtoUtil.createCommandCompletedEvent(null)); default: reply = ProtoUtil.toMessage(sessionId, ProtoUtil.createFailure("Unknown request: " + message)); @@ -213,7 +212,7 @@ class ServerMessageHandler extends SimpleChannelHandler { synchronized (myTaskExecutors) { SequentialTaskExecutor executor = myTaskExecutors.get(projectId); if (executor == null) { - executor = new SequentialTaskExecutor(new SequentialTaskExecutor.AsyncTaskExecutor() { + executor = new SequentialTaskExecutor(new AsyncTaskExecutor() { @Override public void submit(Runnable runnable) { myBuildsExecutor.submit(runnable); @@ -226,12 +225,14 @@ class ServerMessageHandler extends SimpleChannelHandler { } public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - if (this == ctx.getPipeline().getLast()) { - LOG.error(e); - } + LOG.error(e); ctx.sendUpstream(e); } + public boolean hasRunningBuilds() { + return !myBuildsInProgress.isEmpty(); + } + private class CompilationTask implements Runnable, CanceledStatus { private final UUID mySessionId; diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 7a709b1179ae..58b11b17dbb5 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -145,6 +145,9 @@ compiler.server.use.memory.temp.cache.description=Store temporary data in memory compiler.server.use.external.javac.process=true compiler.server.use.external.javac.process.description=Run javac compiler in external process (allows to run compile server with smaller heap size) +compiler.server.ping.interval=5 +compiler.server.ping.interval.description=Interval in seconds between ping requests the IDE periodically sends to server. If server does not receive pings for some time, it shuts down. Specify -1 to disable this feature. + compiler.server.debug.port=-1 #compiler.server.javac.debug.port=-1 From 1bf468951f641f3ea39244a3aac6e1461c359765 Mon Sep 17 00:00:00 2001 From: "andrey.zaytsev" Date: Mon, 27 Feb 2012 22:44:37 +0400 Subject: [PATCH 10/43] OC-2454 Debugger: Everything that is supposed to evaluate an expression should use common expression converter (currently GDBEvaluationUtil) --- .../xdebugger/evaluation/XDebuggerEvaluator.java | 12 ++++++++++++ .../impl/evaluate/XDebuggerEvaluationDialog.java | 2 +- .../xdebugger/impl/ui/XDebuggerEditorBase.java | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java b/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java index 2278aa06af48..a72e1f38e8c1 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java @@ -70,6 +70,18 @@ public abstract class XDebuggerEvaluator { evaluate(expression, callback); } + /** + * Start evaluating expression. + * + * called from evaluation dialog + * @param expression expression to evaluate + * @param callback used to notify that the expression has been evaluated or an error occurs + * @param mode code fragment or expression + */ + public void evaluate(@NotNull String expression, XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition, @Nullable EvaluationMode mode) { + evaluate(expression, callback, expressionPosition); + } + /** * @deprecated override {@link #evaluate(String, XEvaluationCallback, com.intellij.xdebugger.XSourcePosition)} instead */ diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java index b5ed27e4d15c..08fca2be4fee 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java @@ -182,7 +182,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { final XDebuggerEditorBase inputEditor = myInputComponent.getInputEditor(); inputEditor.saveTextInHistory(); String expression = inputEditor.getText(); - myEvaluator.evaluate(expression, evaluationCallback, null); + myEvaluator.evaluate(expression, evaluationCallback, null, inputEditor.getMode()); } public JComponent getPreferredFocusedComponent() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java index fb0a6c53ff95..febd85a11b27 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java @@ -52,6 +52,10 @@ public abstract class XDebuggerEditorBase { mySourcePosition = sourcePosition; } + public EvaluationMode getMode() { + return myMode; + } + public abstract JComponent getComponent(); protected abstract void doSetText(String text); From 4de9ac09267065bfd23494834581d002093f0e1e Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 28 Feb 2012 13:40:48 +0400 Subject: [PATCH 11/43] IDEA-25610: "Move to another changelist" dialog: sort existing changelists alphabetically --- .../MoveChangesToAnotherListAction.java | 10 ++++++---- .../changes/ui/ChangeListChooserPanel.java | 20 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java index 7abc37a88f20..0f204236add2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java @@ -16,13 +16,15 @@ package com.intellij.openapi.vcs.changes.actions; import com.intellij.idea.ActionsBundle; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.Project; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.ProjectLevelVcsManager; -import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.changes.ui.ChangeListChooser; @@ -135,7 +137,7 @@ public class MoveChangesToAnotherListAction extends AnAction implements DumbAwar final ChangeListManagerImpl listManager = ChangeListManagerImpl.getInstanceImpl(project); final List lists = listManager.getChangeLists(); ChangeListChooser chooser = new ChangeListChooser(project, getPreferredLists(lists, changes, true), guessPreferredList(lists, changes), - VcsBundle.message("changes.changelist.chooser.title"), null); + ActionsBundle.message("action.ChangesView.Move.text"), null); chooser.show(); LocalChangeList resultList = chooser.getSelectedList(); if (resultList != null) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java index 4d34202343f2..5da2fa8ae403 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java @@ -25,6 +25,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vcs.changes.committed.CommittedChangeListRenderer; import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer; +import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.HtmlListCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Consumer; @@ -36,12 +37,20 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.Collection; +import java.util.*; +import java.util.List; /** * @author yole */ public class ChangeListChooserPanel extends JPanel { + private static final Comparator CHANGE_LIST_COMPARATOR = new Comparator() { + @Override + public int compare(ChangeList o1, ChangeList o2) { + return o1.getName().compareToIgnoreCase(o2.getName()); + } + }; + private JPanel myPanel; private JRadioButton myRbExisting; private JRadioButton myRbNew; @@ -94,12 +103,9 @@ public class ChangeListChooserPanel extends JPanel { } public void setChangeLists(Collection changeLists) { - final DefaultComboBoxModel model = new DefaultComboBoxModel(); - for (ChangeList list : changeLists) { - model.addElement(list); - } - - myExistingListsCombo.setModel(model); + List list = new ArrayList(changeLists); + Collections.sort(list, CHANGE_LIST_COMPARATOR); + myExistingListsCombo.setModel(new CollectionComboBoxModel(list, null)); } public void setDefaultName(String name) { From e3bf5d6765505462ac71165ba06666e57bb2f868 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 28 Feb 2012 10:43:32 +0100 Subject: [PATCH 12/43] Unified empty editor screen --- .../fileEditor/impl/EditorsSplitters.java | 23 +++------ .../util/src/com/intellij/util/ui/UIUtil.java | 49 ++++++++++++++----- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java index 1d8cdac84ed6..be81bbc8b2ea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.intellij.openapi.fileEditor.impl; +import com.google.common.collect.Lists; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.KeyboardShortcut; import com.intellij.openapi.actionSystem.Shortcut; @@ -65,8 +66,8 @@ import java.util.List; */ public class EditorsSplitters extends JPanel { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.EditorsSplitters"); + private EditorWindow myCurrentWindow; - private VirtualFile myCurrentFile; private final FileEditorManagerImpl myManager; private Element mySplittersElement; // temporarily used during initialization int myInsideChange = 0; @@ -97,7 +98,6 @@ public class EditorsSplitters extends JPanel { removeAll(); myWindows.clear(); setCurrentWindow(null); - myCurrentFile = null; repaint (); // revalidate doesn't repaint correctly after "Close All" } @@ -151,13 +151,12 @@ public class EditorsSplitters extends JPanel { } if (showEmptyText()) { - final boolean darkerColors = UIUtil.isUnderAquaLookAndFeel() || UIUtil.isUnderGTKLookAndFeel(); UIUtil.applyRenderingHints(g); - g.setColor(darkerColors ? Gray._100 : Color.DARK_GRAY); + g.setColor(Gray._100); g.setFont(UIUtil.getLabelFont().deriveFont(18f)); - final UIUtil.TextPainter painter = new UIUtil.TextPainter(1.4f); - painter.appendLine("No files are open").underlined(darkerColors ? Gray._150 : Color.DARK_GRAY); + final UIUtil.TextPainter painter = new UIUtil.TextPainter().withShadow(true).withLineSpacing(1.4f); + painter.appendLine("No files are open").underlined(Gray._150); if (!isProjectViewVisible()) { painter.appendLine("Open Project View with " + KeymapUtil.getShortcutText(new KeyboardShortcut( @@ -325,8 +324,7 @@ public class EditorsSplitters extends JPanel { window = findWindowWith(panel); LOG.assertTrue(window != null); } - //noinspection unchecked - final List children = new ArrayList(leaf.getChildren("file")); + @SuppressWarnings("unchecked") final List children = Lists.newArrayList(leaf.getChildren("file")); VirtualFile currentFile = null; if (UISettings.getInstance().ACTIVATE_RIGHT_EDITOR_ON_CLOSE) { @@ -506,7 +504,7 @@ public class EditorsSplitters extends JPanel { return myInsideChange > 0; } - private void setCurrentWindow(final EditorWindow currentWindow) { + private void setCurrentWindow(@Nullable final EditorWindow currentWindow) { myCurrentWindow = currentWindow; } @@ -785,16 +783,11 @@ public class EditorsSplitters extends JPanel { private final class MyFocusWatcher extends FocusWatcher { protected void focusedComponentChanged(final Component component, final AWTEvent cause) { EditorWindow newWindow = null; - VirtualFile newFile = null; if (component != null) { newWindow = findWindowWith(component); - if (newWindow != null) { - newFile = newWindow.getSelectedFile(); - } } - myCurrentFile = newFile; setCurrentWindow(newWindow); setCurrentWindow(newWindow, false); } diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 962822d61445..5f5d154880c7 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2308,25 +2308,48 @@ public class UIUtil { public static class TextPainter { private List> myLines = new ArrayList>(); - private boolean myDrawMacShadow; - private Color myMacShadowColor; + private boolean myDrawShadow; + private Color myShadowColor; private float myLineSpacing; - public TextPainter() { - this(true, Gray._220, 1.0f); + myDrawShadow = isUnderAquaLookAndFeel(); + myShadowColor = Gray._220; + myLineSpacing = 1.0f; } + /** @deprecated use {@linkplain #withLineSpacing(float)} (to remove in IDEA 12) */ + @SuppressWarnings("UnusedDeclaration") public TextPainter(final float lineSpacing) { - this(true, Gray._220, lineSpacing); + myDrawShadow = isUnderAquaLookAndFeel(); + myShadowColor = Gray._220; + myLineSpacing = lineSpacing; } - public TextPainter(final boolean drawMacShadow, final Color shadowColor, final float lineSpacing) { - myDrawMacShadow = drawMacShadow; - myMacShadowColor = shadowColor; + /** @deprecated use {@linkplain #withShadow(boolean, java.awt.Color)} and {@linkplain #withLineSpacing(float)} (to remove in IDEA 12) */ + @SuppressWarnings("UnusedDeclaration") + public TextPainter(final boolean drawShadow, final Color shadowColor, final float lineSpacing) { + myDrawShadow = drawShadow; + myShadowColor = shadowColor; myLineSpacing = lineSpacing; } + public TextPainter withShadow(final boolean drawShadow) { + myDrawShadow = drawShadow; + return this; + } + + public TextPainter withShadow(final boolean drawShadow, final Color shadowColor) { + myDrawShadow = drawShadow; + myShadowColor = shadowColor; + return this; + } + + public TextPainter withLineSpacing(final float lineSpacing) { + myLineSpacing = lineSpacing; + return this; + } + public TextPainter appendLine(final String text) { if (text == null || text.length() == 0) return this; myLines.add(Pair.create(text, new LineInfo())); @@ -2432,9 +2455,9 @@ public class UIUtil { xOffset = x + (maxWidth[0] - fm.stringWidth(pair.getFirst())) / 2; } - if (myDrawMacShadow && UIUtil.isUnderAquaLookAndFeel()) { + if (myDrawShadow) { final Color oldColor = g.getColor(); - g.setColor(myMacShadowColor); + g.setColor(myShadowColor); if (info.withBullet) { g.drawString(info.bulletChar + " ", x - fm.stringWidth(" " + info.bulletChar), yOffset[0] + 1); @@ -2462,9 +2485,9 @@ public class UIUtil { g.setColor(c); } - if (myDrawMacShadow && UIUtil.isUnderAquaLookAndFeel()) { + if (myDrawShadow) { c = g.getColor(); - g.setColor(myMacShadowColor); + g.setColor(myShadowColor); g.drawLine(x - maxBulletWidth[0] - 10, yOffset[0] + fm.getDescent() + 1, x + maxWidth[0] + 10, yOffset[0] + fm.getDescent() + 1); g.setColor(c); } From 9721462232d59f64359f288bc6d4ecbf7ed0ed04 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 28 Feb 2012 13:47:29 +0400 Subject: [PATCH 13/43] optimization --- .../src/org/jetbrains/jps/incremental/IncProjectBuilder.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 15ddc319accb..a0b17aaa6acb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -290,10 +290,12 @@ public class IncProjectBuilder { if (context.isMake()) { // cleanup outputs final Set allChunkRemovedSources = new HashSet(); - final SourceToFormMapping sourceToFormMap = context.getDataManager().getSourceToFormMap(); for (Module module : chunk.getModules()) { final Collection deletedPaths = myProjectDescriptor.fsState.getDeletedPaths(module, context.isCompilingTests()); + if (deletedPaths.isEmpty()) { + continue; + } allChunkRemovedSources.addAll(deletedPaths); final String moduleName = module.getName().toLowerCase(Locale.US); @@ -327,6 +329,7 @@ public class IncProjectBuilder { sourceToOutputStorage.remove(deletedSource); } // check if deleted source was associated with a form + final SourceToFormMapping sourceToFormMap = context.getDataManager().getSourceToFormMap(); final String formPath = sourceToFormMap.getState(deletedSource); if (formPath != null) { final File formFile = new File(formPath); From 6557f9b346af2a5c7ebfaa37d363e97f2d467ddc Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 28 Feb 2012 14:00:13 +0400 Subject: [PATCH 14/43] short diff in changes: check change toolwindow for being disposed when checking if it is visible --- .../openapi/vcs/changes/ui/ChangesViewContentManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java index 342056c8607f..030f97347299 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java @@ -166,7 +166,7 @@ public class ChangesViewContentManager extends AbstractProjectComponent implemen } public boolean isToolwindowVisible() { - return myToolWindow.isVisible(); + return ! myToolWindow.isDisposed() && myToolWindow.isVisible(); } public void projectClosed() { From 77b136252279c658fbd9712d929f659b6e425ebd Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 28 Feb 2012 14:01:07 +0400 Subject: [PATCH 15/43] IDEA-81569 Poor performance when moving lines in web.xml (Alt-Shift-DOWN/UP) while the web.xml is displayed in change details (Changes tool window) --- .../impl/highlighting/EditorPlaceHolder.java | 23 +++++++++++++++++-- .../vcs/impl/ContentRevisionCache.java | 4 ++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/EditorPlaceHolder.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/EditorPlaceHolder.java index 070b236c06dd..151049de08a7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/EditorPlaceHolder.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/EditorPlaceHolder.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl.highlighting; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffContent; import com.intellij.openapi.diff.impl.ContentChangeListener; @@ -24,7 +25,9 @@ import com.intellij.openapi.diff.impl.DiffVersionComponent; import com.intellij.openapi.diff.impl.util.ContentDocumentListener; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorProvider; import com.intellij.openapi.fileEditor.TextEditor; @@ -65,11 +68,11 @@ class EditorPlaceHolder extends DiffMarkup implements DiffVersionComponent { } public void setContent(final DiffContent content) { - runRegisteredDisposables(); myContent = content; if (myContent != null) { - Document document = myContent.getDocument(); + final Document document = myContent.getDocument(); if (myContent.isBinary() || document == null || myContent.getContentType() instanceof UIBasedFileType) { + runRegisteredDisposables(); final VirtualFile file = myContent.getFile(); if (file != null) { final FileEditorProvider[] providers = FileEditorProviderManager.getInstance().getProviders(getProject(), file); @@ -93,6 +96,22 @@ class EditorPlaceHolder extends DiffMarkup implements DiffVersionComponent { } } else { + if (myEditor != null) { + final DocumentEx doc = ((EditorImpl)myEditor).getDocument(); + if (doc != null) { + final boolean wasWriteable = doc.isWritable(); + doc.setReadOnly(false); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + doc.setText(document.getText()); + } + }); + doc.setReadOnly(! wasWriteable); + return; + } + } + runRegisteredDisposables(); final EditorFactory editorFactory = EditorFactory.getInstance(); myEditor = DiffUtil.createEditor(document, getProject(), false); addDisposable(new Disposable() { diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java b/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java index 5efcb347f1cb..ad1e50a3b3ae 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java @@ -220,6 +220,10 @@ public class ContentRevisionCache { Pair loaded; while (true) { currentRevision = putIntoCurrentCache(cache, path, vcsKey, loader); + final byte[] cachedCurrent = cache.getBytes(path, currentRevision, vcsKey, UniqueType.REPOSITORY_CONTENT); + if (cachedCurrent != null) { + return new Pair(currentRevision, cachedCurrent); + } loaded = loader.get(); if (loaded.getFirst().equals(currentRevision)) break; } From 889a9b789e12733da8abce49de5e93a07277f6e1 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 28 Feb 2012 14:18:45 +0400 Subject: [PATCH 16/43] cleanup --- .../src/com/intellij/tasks/context/WorkingContextManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/WorkingContextManager.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/WorkingContextManager.java index a3e4cfb3f47b..e34d1c745248 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/WorkingContextManager.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/WorkingContextManager.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.tasks.Task; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; @@ -153,7 +154,7 @@ public class WorkingContextManager { private boolean loadContext(String zipPostfix, String entryName) { try { JBZipFile archive = getTasksArchive(zipPostfix); - JBZipEntry entry = archive.getEntry(entryName.startsWith("/") ? entryName : "/" + entryName); + JBZipEntry entry = archive.getEntry(StringUtil.startsWithChar(entryName, '/') ? entryName : "/" + entryName); if (entry != null) { byte[] bytes = entry.getData(); Document document = JDOMUtil.loadDocument(new String(bytes)); From 13eca45e00e772f3c2485cb94684df4a9869bea1 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 28 Feb 2012 14:21:38 +0400 Subject: [PATCH 17/43] IDEA-58429: Task management: don't allow to create changelists for tasks in non-versioned projects --- .../com/intellij/tasks/actions/CreateChangelistAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java index 3c11f114324f..e72679b48e42 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java @@ -34,7 +34,7 @@ public class CreateChangelistAction extends BaseTaskAction { TaskManager manager = getTaskManager(event); Presentation presentation = event.getPresentation(); - if (manager == null || !manager.getOpenChangelists(manager.getActiveTask()).isEmpty()) { + if (manager == null || !manager.isVcsEnabled() || !manager.getOpenChangelists(manager.getActiveTask()).isEmpty()) { presentation.setText(getTemplatePresentation().getText()); presentation.setEnabled(false); } else { @@ -46,7 +46,7 @@ public class CreateChangelistAction extends BaseTaskAction { @Override public void actionPerformed(AnActionEvent e) { Task activeTask = getActiveTask(e); - String name = Messages.showInputDialog(getProject(e), "Changelist name:", "Create changelist", null, TaskUtil.getChangeListName(activeTask), null); + String name = Messages.showInputDialog(getProject(e), "Changelist name:", "Create Changelist", null, TaskUtil.getChangeListName(activeTask), null); if (name != null) { TaskManagerImpl manager = (TaskManagerImpl)getTaskManager(e); assert manager != null; From cc62d087be3f6b9dcb9fe5ffd37f239e5f2e93d7 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 28 Feb 2012 14:47:47 +0400 Subject: [PATCH 18/43] IDEA-55045: When creating a new task with a changelist, add "track context" option --- .../tasks/tasks-api/src/com/intellij/tasks/LocalTask.java | 2 ++ .../com/intellij/tasks/actions/CreateChangelistAction.java | 4 ++-- .../src/com/intellij/tasks/impl/LocalTaskImpl.java | 1 + .../src/com/intellij/tasks/impl/TaskManagerImpl.java | 7 ++++--- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/LocalTask.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/LocalTask.java index ce35feaf4c1d..d4361ea25e0f 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/LocalTask.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/LocalTask.java @@ -44,4 +44,6 @@ public abstract class LocalTask extends Task { public boolean isDefault() { return false; } + + public abstract void setAssociatedChangelistId(String associatedChangelistId); } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java index e72679b48e42..c72a4d9d9658 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CreateChangelistAction.java @@ -19,8 +19,8 @@ package com.intellij.tasks.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.ui.Messages; +import com.intellij.tasks.LocalTask; import com.intellij.tasks.TaskManager; -import com.intellij.tasks.Task; import com.intellij.tasks.impl.TaskManagerImpl; import com.intellij.tasks.impl.TaskUtil; @@ -45,7 +45,7 @@ public class CreateChangelistAction extends BaseTaskAction { @Override public void actionPerformed(AnActionEvent e) { - Task activeTask = getActiveTask(e); + LocalTask activeTask = getActiveTask(e); String name = Messages.showInputDialog(getProject(e), "Changelist name:", "Create Changelist", null, TaskUtil.getChangeListName(activeTask), null); if (name != null) { TaskManagerImpl manager = (TaskManagerImpl)getTaskManager(e); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java index 712f66923670..67e4d8ed66a1 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java @@ -196,6 +196,7 @@ public class LocalTaskImpl extends LocalTask { myChangeLists = changeLists; } + @Override public void setAssociatedChangelistId(String associatedChangelistId) { myAssociatedChangelistId = associatedChangelistId; } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java index 2c9edabd7362..d88957dfe397 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java @@ -310,7 +310,7 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe } myContextManager.restoreContext(origin); - final Task task = doActivate(origin, true); + final LocalTask task = doActivate(origin, true); if (isVcsEnabled()) { List changeLists = getOpenChangelists(task); @@ -340,17 +340,18 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe myActiveTask.setUpdated(new Date()); } - public void createChangeList(Task task, String name) { + public void createChangeList(LocalTask task, String name) { String comment = TaskUtil.getChangeListComment(this, task); createChangeList(task, name, comment); } - public void createChangeList(Task task, String name, String comment) { + public void createChangeList(LocalTask task, String name, String comment) { LocalChangeList changeList = myChangeListManager.findChangeList(name); if (changeList == null) { changeList = myChangeListManager.addChangeList(name, comment); } myChangeListManager.setDefaultChangeList(changeList); + task.setAssociatedChangelistId(changeList.getId()); getOpenChangelists(task).add(new ChangeListInfo(changeList)); } From f1eec242b77f902469ea21c5c568fcf62128fc44 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 28 Feb 2012 11:48:23 +0100 Subject: [PATCH 19/43] use less memory --- .../changeBrowser/CvsCommittedChangesProvider.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/changeBrowser/CvsCommittedChangesProvider.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/changeBrowser/CvsCommittedChangesProvider.java index 99ad4dd3cff5..7a7904a04683 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/changeBrowser/CvsCommittedChangesProvider.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/changeBrowser/CvsCommittedChangesProvider.java @@ -37,6 +37,7 @@ import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; +import gnu.trove.TObjectLongHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.netbeans.lib.cvsclient.admin.Entry; @@ -73,8 +74,8 @@ public class CvsCommittedChangesProvider implements CachingCommittedChangesProvi } private static class MyZipper extends VcsCommittedListsZipperAdapter { - private long lastNumber = 0; - private final Map numberCache = new HashMap(); + private long lastNumber = 1; + private final TObjectLongHashMap numberCache = new TObjectLongHashMap(); private MyZipper() { super(new GroupCreator() { @@ -98,12 +99,12 @@ public class CvsCommittedChangesProvider implements CachingCommittedChangesProvi final long time = list.getCommitDate().getTime(); final Long roundedTime = Long.valueOf(time - (time % CvsChangeList.SUITABLE_DIFF)); final CommittedChangeListKey key = new CommittedChangeListKey(list.getCommitterName(), roundedTime, list.getComment()); - final Long number = numberCache.get(key); - if (number == null) { - numberCache.put(key, Long.valueOf(lastNumber)); + final long number = numberCache.get(key); + if (number == 0) { + numberCache.put(key, lastNumber); return lastNumber++; } - return number.longValue(); + return number; } } From 6901466e29aecf0f1b6f9b46b6a353e89ba54e93 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 28 Feb 2012 11:53:09 +0100 Subject: [PATCH 20/43] forbid inplace introduce inside jsp scripts (IDEA-72167) --- .../IntroduceVariableBase.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 1cceb6037fb3..39beb34dba95 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -45,6 +45,8 @@ import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; import com.intellij.psi.codeStyle.*; import com.intellij.psi.impl.PsiDiamondTypeUtil; +import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock; +import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy; import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil; import com.intellij.psi.util.PsiExpressionTrimRenderer; @@ -534,11 +536,11 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { supportProvider != null && editor.getSettings().isVariableInplaceRenameEnabled() && supportProvider.isInplaceIntroduceAvailable(expr, nameSuggestionContext) && - !ApplicationManager.getApplication().isUnitTestMode(); + !ApplicationManager.getApplication().isUnitTestMode() && + !isInJspHolderMethod(expr); final boolean inFinalContext = occurenceManager.isInFinalContext(); final InputValidator validator = new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurenceManager); final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, originalType, expr, occurrences); - final boolean[] wasSucceed = new boolean[]{true}; final Pass callback = new Pass() { @Override @@ -599,6 +601,17 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { return wasSucceed[0]; } + private static boolean isInJspHolderMethod(PsiExpression expr) { + final PsiElement parent1 = expr.getParent(); + if (parent1 == null) { + return false; + } + final PsiElement parent2 = parent1.getParent(); + if (!(parent2 instanceof JspCodeBlock)) return false; + final PsiElement parent3 = parent2.getParent(); + return parent3 instanceof JspHolderMethod; + } + /** * @return true if write usages found */ From 89263d24ac6c48dda56491fb94584bfb076e6a71 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 28 Feb 2012 14:41:07 +0400 Subject: [PATCH 21/43] fix NPE --- .../jps/incremental/IncProjectBuilder.java | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index a0b17aaa6acb..7a7fc8c112a9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -306,28 +306,29 @@ public class IncProjectBuilder { // deleting outputs corresponding to non-existing source final Collection outputs = sourceToOutputStorage.getState(deletedSource); - if (LOG.isDebugEnabled()) { - if (outputs.size() > 0) { - final String[] buffer = new String[outputs.size()]; - int i = 0; - for (final String o : outputs) { - buffer[i++] = o; - } - Arrays.sort(buffer); - LOG.info("Cleaning output files:"); - for(final String o : buffer) { - LOG.info(o); - } - LOG.info("End of files"); - } - } - if (outputs != null) { + if (LOG.isDebugEnabled()) { + if (outputs.size() > 0) { + final String[] buffer = new String[outputs.size()]; + int i = 0; + for (final String o : outputs) { + buffer[i++] = o; + } + Arrays.sort(buffer); + LOG.info("Cleaning output files:"); + for(final String o : buffer) { + LOG.info(o); + } + LOG.info("End of files"); + } + } + for (String output : outputs) { FileUtil.delete(new File(output)); } sourceToOutputStorage.remove(deletedSource); } + // check if deleted source was associated with a form final SourceToFormMapping sourceToFormMap = context.getDataManager().getSourceToFormMap(); final String formPath = sourceToFormMap.getState(deletedSource); From 52b391f0063af5092a3f790a6ceafd13d3b868d6 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 28 Feb 2012 15:00:07 +0400 Subject: [PATCH 22/43] IDEA-81958 Compile server: Make after package rename doesn't remove old classes --- .../impl/TranslatingCompilerFilesMonitor.java | 28 +++++++++++++++++-- .../storage/AbstractStateStorage.java | 1 + .../storage/SourceToOutputMapping.java | 2 ++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index ce7446774d6b..b999691ff11c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -1414,13 +1414,35 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { private class MyVfsListener extends VirtualFileAdapter { public void propertyChanged(final VirtualFilePropertyEvent event) { if (VirtualFile.PROP_NAME.equals(event.getPropertyName())) { - final VirtualFile file = event.getFile(); + final VirtualFile eventFile = event.getFile(); final VirtualFile parent = event.getParent(); if (parent != null) { final String oldName = (String)event.getOldValue(); - CompileServerManager.getInstance().notifyFilesDeleted(Collections.singleton(parent.getPath() + "/" + oldName)); + final String root = parent.getPath() + "/" + oldName; + final Set toMark; + if (eventFile.isDirectory()) { + toMark = new HashSet(); + new Object() { + void process(VirtualFile file, String filePath) { + if (file.isDirectory()) { + for (VirtualFile child : file.getChildren()) { + process(child, filePath + "/" + child.getName()); + } + } + else { + toMark.add(filePath); + } + } + }.process(eventFile, root); + } + else { + toMark = Collections.singleton(root); + } + if (!toMark.isEmpty()) { + CompileServerManager.getInstance().notifyFilesDeleted(toMark); + } } - markDirtyIfSource(file, false); + markDirtyIfSource(eventFile, false); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java index cefe772c13c5..7ed499296634 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java @@ -92,6 +92,7 @@ public abstract class AbstractStateStorage { } } + @Nullable public T getState(Key key) throws IOException { synchronized (myDataLock) { return myMap.get(key); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java index af699e81ed42..dfbc9bae28fe 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java @@ -5,6 +5,7 @@ import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; import com.intellij.util.io.IOUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.*; import java.util.ArrayList; @@ -46,6 +47,7 @@ public final class SourceToOutputMapping extends AbstractStateStorage getState(@NotNull String srcPath) throws IOException { return super.getState(FileUtil.toSystemIndependentName(srcPath)); From d6b70e5a951e638ca8875f8a0aa95aeeba2fa0ac Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Tue, 28 Feb 2012 15:12:34 +0400 Subject: [PATCH 23/43] Small optimization in integrate (compile-server). --- jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index cc67d6620648..058870f86f18 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -1629,7 +1629,7 @@ public class Mappings { myClassToSourceFile.putAll(delta.myClassToSourceFile); } - if (delta.isDifferentiated() && false) { + if (delta.isDifferentiated()) { for (DependencyContext.S f : delta.getChangedFiles()) { mySourceFileToClasses.remove(f); final Collection classes = delta.mySourceFileToClasses.get(f); From f9f00fcc39dd84e546bed794f954e90e430f863c Mon Sep 17 00:00:00 2001 From: Evgeny Zakrevsky Date: Tue, 28 Feb 2012 15:51:36 +0400 Subject: [PATCH 24/43] JSTestDriver. Some layout improvements. --- .../util/src/com/intellij/util/ui/UIUtil.java | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 962822d61445..c273a0d355b4 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -19,10 +19,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.ColorUtil; -import com.intellij.ui.Gray; -import com.intellij.ui.PanelWithAnchor; -import com.intellij.ui.SideBorder; +import com.intellij.ui.*; import com.intellij.util.ArrayUtil; import com.intellij.util.PairFunction; import com.intellij.util.Processor; @@ -2533,23 +2530,30 @@ public class UIUtil { return false; } - public static void mergeComponentsWithAnchor(PanelWithAnchor c1, PanelWithAnchor c2) { - if (c1 == null || c2 == null) return; - - if (c1.getAnchor() == null) { - c1.setAnchor(c2.getAnchor()); - } else { - if (c2.getAnchor() == null) { - c2.setAnchor(c1.getAnchor()); - } else { - JComponent anchor = c1.getAnchor().getPreferredSize().getWidth() > c2.getAnchor().getPreferredSize().getWidth() ? - c1.getAnchor() : c2.getAnchor(); - c2.setAnchor(anchor); - c1.setAnchor(anchor); - } - } + @Nullable + public static JComponent mergeComponentsWithAnchor(PanelWithAnchor...panels) { + return mergeComponentsWithAnchor(Arrays.asList(panels)); } + @Nullable + public static JComponent mergeComponentsWithAnchor(Collection panels) { + JComponent tempAnchor = null; + int maxWidth = 0; + for (PanelWithAnchor panel : panels) { + if (panel == null) continue; + if (panel.getAnchor() == null) continue; + if (maxWidth < panel.getAnchor().getPreferredSize().width) { + maxWidth = panel.getAnchor().getPreferredSize().width; + tempAnchor = panel.getAnchor(); + } + } + for (PanelWithAnchor panel : panels) { + if (panel == null) continue; + panel.setAnchor(tempAnchor); + } + return tempAnchor; + } + public static void setNotOpaqueRecursively(@NotNull Component component) { if (!isUnderAquaLookAndFeel()) return; From e01867ac8cd249491e24df280e6ac75a6a418cff Mon Sep 17 00:00:00 2001 From: Evgeny Zakrevsky Date: Tue, 28 Feb 2012 15:52:12 +0400 Subject: [PATCH 25/43] IDEA-78905 Run configuration must be unreasonably wide --- .../impl/ConfigurationSettingsEditorWrapper.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java index 76169fa0771b..6a8b5f35018d 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java @@ -96,7 +96,17 @@ public class ConfigurationSettingsEditorWrapper extends SettingsEditor Date: Mon, 27 Feb 2012 21:23:51 +0400 Subject: [PATCH 26/43] OC-2974: More correct definition of what's outside the project (takes certain extension points into an account) --- .../com/intellij/psi/search/scope/NonProjectFilesScope.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-api/src/com/intellij/psi/search/scope/NonProjectFilesScope.java b/platform/lang-api/src/com/intellij/psi/search/scope/NonProjectFilesScope.java index e7a9c5557845..ca2e3c6eb61f 100644 --- a/platform/lang-api/src/com/intellij/psi/search/scope/NonProjectFilesScope.java +++ b/platform/lang-api/src/com/intellij/psi/search/scope/NonProjectFilesScope.java @@ -18,6 +18,7 @@ package com.intellij.psi.search.scope; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.scope.packageSet.AbstractPackageSet; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; @@ -37,8 +38,7 @@ public class NonProjectFilesScope extends NamedScope { super(NAME, new AbstractPackageSet("NonProject") { public boolean contains(VirtualFile file, NamedScopesHolder holder) { if (file == null) return true; - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(holder.getProject()).getFileIndex(); - return !(holder.getProject().isInitialized() && !fileIndex.isIgnored(file) && fileIndex.getContentRootForFile(file) != null); + return !ProjectScope.getProjectScope(holder.getProject()).contains(file); } }); } From cd1a56a6798dc00192f1519ea9d95e233a43ea29 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Mon, 27 Feb 2012 21:29:17 +0400 Subject: [PATCH 27/43] OC-2970 Default key mapping for 'close' in Xcode scheme --- platform/platform-resources/src/idea/Keymap_Xcode.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-resources/src/idea/Keymap_Xcode.xml b/platform/platform-resources/src/idea/Keymap_Xcode.xml index 8beab27de036..17b81e175451 100644 --- a/platform/platform-resources/src/idea/Keymap_Xcode.xml +++ b/platform/platform-resources/src/idea/Keymap_Xcode.xml @@ -38,8 +38,8 @@ - - + + From cb2fc3de63b98e11a6339b57c1d933ac42886ac0 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Tue, 28 Feb 2012 14:59:51 +0400 Subject: [PATCH 28/43] OC-2684. Xcode seem to save dirty files asynchronously, after it actually lost focus to AppCode. --- .../src/com/intellij/ide/SaveAndSyncHandler.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandler.java b/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandler.java index 1ff03c99cda6..661a20a207d5 100644 --- a/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandler.java +++ b/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandler.java @@ -30,6 +30,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.RefreshQueue; import com.intellij.openapi.vfs.newvfs.RefreshSession; +import com.intellij.util.Alarm; import org.jetbrains.annotations.NotNull; import java.beans.PropertyChangeEvent; @@ -48,6 +49,7 @@ public class SaveAndSyncHandler implements ApplicationComponent { private final AtomicInteger myBlockSaveOnFrameDeactivationCount = new AtomicInteger(); private final AtomicInteger myBlockSyncOnFrameActivationCount = new AtomicInteger(); + private final Alarm myRefreshDelayAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); public static SaveAndSyncHandler getInstance(){ return ApplicationManager.getApplication().getComponent(SaveAndSyncHandler.class); @@ -157,7 +159,8 @@ public class SaveAndSyncHandler implements ApplicationComponent { } - ApplicationManager.getApplication().invokeLater(new Runnable() { + myRefreshDelayAlarm.cancelAllRequests(); + myRefreshDelayAlarm.addRequest(new Runnable() { @Override public void run() { if (canSyncOrSave()) { @@ -166,7 +169,7 @@ public class SaveAndSyncHandler implements ApplicationComponent { maybeRefresh(ModalityState.NON_MODAL); } - }, ModalityState.NON_MODAL); + }, 300, ModalityState.NON_MODAL); if (LOG.isDebugEnabled()) { LOG.debug("exit: synchronize()"); @@ -213,4 +216,4 @@ public class SaveAndSyncHandler implements ApplicationComponent { public void unblockSyncOnFrameActivation() { myBlockSyncOnFrameActivationCount.decrementAndGet(); } -} \ No newline at end of file +} From 26418b37a180165ee6cddc1005139060d7145558 Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 28 Feb 2012 18:18:11 +0400 Subject: [PATCH 29/43] compile server: added extension to provide additional source roots --- .../idea/AdditionalRootsProviderService.java | 22 +++++++++++++++++++ .../jps/idea/IdeaProjectLoader.groovy | 10 +++++++++ 2 files changed, 32 insertions(+) create mode 100644 jps/model/src/org/jetbrains/jps/idea/AdditionalRootsProviderService.java diff --git a/jps/model/src/org/jetbrains/jps/idea/AdditionalRootsProviderService.java b/jps/model/src/org/jetbrains/jps/idea/AdditionalRootsProviderService.java new file mode 100644 index 000000000000..7687d3cf75f2 --- /dev/null +++ b/jps/model/src/org/jetbrains/jps/idea/AdditionalRootsProviderService.java @@ -0,0 +1,22 @@ +package org.jetbrains.jps.idea; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.Module; + +import java.util.Collections; +import java.util.List; + +/** + * @author nik + */ +public abstract class AdditionalRootsProviderService { + @NotNull + public List getAdditionalSourceRoots(@NotNull Module module) { + return Collections.emptyList(); + } + + @NotNull + public List getAdditionalTestSourceRoots(@NotNull Module module) { + return Collections.emptyList(); + } +} diff --git a/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy b/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy index 96bab165bc75..cb2c7f76b102 100644 --- a/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy +++ b/jps/model/src/org/jetbrains/jps/idea/IdeaProjectLoader.groovy @@ -16,6 +16,7 @@ public class IdeaProjectLoader { private Map pathVariables private ProjectMacroExpander projectMacroExpander private ProjectLoadingErrorReporter errorReporter + private static final OwnServiceLoader rootsProviderLoader = OwnServiceLoader.load(AdditionalRootsProviderService.class) public static String guessHome(Script script) { File home = new File(script["gant.file"].substring("file:".length())) @@ -508,6 +509,15 @@ public class IdeaProjectLoader { currentModule.languageLevel = convertLanguageLevel(languageLevel) } + rootsProviderLoader.each {AdditionalRootsProviderService service -> + def sourceRoots = service.getAdditionalSourceRoots(currentModule) + def testSourceRoots = service.getAdditionalTestSourceRoots(currentModule) + currentModule.sourceRoots.addAll(sourceRoots) + currentModule.testRoots.addAll(testSourceRoots) + if (!sourceRoots.isEmpty() || !testSourceRoots.isEmpty()) { + srcFolderExists = true + } + } if (srcFolderExists) { if (componentTag."@inherit-compiler-output" == "true") { if (projectOutputPath == null) { From 671d31cfbb94cf9a354696c0d2f11a72ae848eab Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 28 Feb 2012 15:35:31 +0100 Subject: [PATCH 30/43] edt save --- .../ide/diff/VirtualFileDiffElement.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java b/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java index 90ec7c08a626..7ad3430e1848 100644 --- a/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java +++ b/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java @@ -19,8 +19,7 @@ import com.intellij.ide.presentation.VirtualFilePresentation; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diff.DiffRequest; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileChooser.FileChooserDescriptor; @@ -275,15 +274,14 @@ public class VirtualFileDiffElement extends DiffElement { } if (!docsToSave.isEmpty()) { - AccessToken token = WriteAction.start(); - try { - for (Document document : docsToSave) { - manager.saveDocument(document); + ApplicationManagerEx.getApplicationEx().runEdtSafeAction(new Runnable() { + @Override + public void run() { + for (Document document : docsToSave) { + manager.saveDocument(document); + } } - } - finally { - token.finish(); - } + }); } if (!FileWatcher.getInstance().isWatched(virtualFile)) { ((NewVirtualFile)virtualFile).markDirtyRecursively(); From 6f2922669b27a75ef7a77502fee4c1572437fb99 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 28 Feb 2012 15:51:24 +0100 Subject: [PATCH 31/43] p4: apply patch to a newly created changelist should really move all files to that changelist --- .../intellij/openapi/vcs/changes/VcsDirtyScopeManager.java | 4 ++-- .../src/com/intellij/util/ui/VcsBackgroundTask.java | 7 ------- .../openapi/vcs/changes/VcsDirtyScopeManagerImpl.java | 4 ++-- .../openapi/vcs/changes/VcsDirtyScopeManagerProxy.java | 4 ++-- .../src/com/intellij/openapi/vcs/changes/VcsGuess.java | 5 +++-- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManager.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManager.java index ce42d25f3ec2..60caeb50e53a 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManager.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManager.java @@ -46,14 +46,14 @@ public abstract class VcsDirtyScopeManager { * * @param file the file for which the status update is requested. */ - public abstract void fileDirty(VirtualFile file); + public abstract void fileDirty(@NotNull VirtualFile file); /** * Requests an asynchronous file status update for the specified file path. Must be called from a read action. * * @param file the file path for which the status update is requested. */ - public abstract void fileDirty(FilePath file); + public abstract void fileDirty(@NotNull FilePath file); /** * Requests an asynchronous file status update for all files under the specified directory. diff --git a/platform/vcs-api/src/com/intellij/util/ui/VcsBackgroundTask.java b/platform/vcs-api/src/com/intellij/util/ui/VcsBackgroundTask.java index 78a5f6abb0a2..06cc1a094892 100644 --- a/platform/vcs-api/src/com/intellij/util/ui/VcsBackgroundTask.java +++ b/platform/vcs-api/src/com/intellij/util/ui/VcsBackgroundTask.java @@ -32,22 +32,15 @@ import java.util.List; * @author yole */ public abstract class VcsBackgroundTask extends Task.ConditionalModal { - @NotNull private final PerformInBackgroundOption myBackgroundOption; private final Collection myItems; private final List myExceptions = new ArrayList(); public VcsBackgroundTask(final Project project, @NotNull final String title, @NotNull final PerformInBackgroundOption backgroundOption, final Collection itemsToProcess) { super(project, title, false, backgroundOption); - myBackgroundOption = backgroundOption; myItems = itemsToProcess; } - @NotNull - public PerformInBackgroundOption getBackgroundOption() { - return myBackgroundOption; - } - public void run(@NotNull ProgressIndicator indicator) { for(T item: myItems) { try { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java index decb13a4393a..8ffa72209ea7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java @@ -252,7 +252,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr } } - public void fileDirty(final VirtualFile file) { + public void fileDirty(@NotNull final VirtualFile file) { try { final AbstractVcs vcs = myGuess.getVcsForDirty(file); if (vcs == null) return; @@ -269,7 +269,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr } } - public void fileDirty(final FilePath file) { + public void fileDirty(@NotNull final FilePath file) { try { final AbstractVcs vcs = myGuess.getVcsForDirty(file); if (vcs == null) return; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerProxy.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerProxy.java index 135d73f7fa4e..fdcf04749ef8 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerProxy.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerProxy.java @@ -54,11 +54,11 @@ class VcsDirtyScopeManagerProxy extends VcsDirtyScopeManager { myFiles.clear(); } - public void fileDirty(final VirtualFile file) { + public void fileDirty(@NotNull final VirtualFile file) { myVFiles.add(file); } - public void fileDirty(final FilePath file) { + public void fileDirty(@NotNull final FilePath file) { myFiles.add(file); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java index 93bd355171fe..2ce7ea62b1fe 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java @@ -27,6 +27,7 @@ import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class VcsGuess { @@ -41,7 +42,7 @@ public class VcsGuess { } @Nullable - public AbstractVcs getVcsForDirty(final VirtualFile file) { + public AbstractVcs getVcsForDirty(@NotNull final VirtualFile file) { if (!file.isInLocalFileSystem()) { return null; } @@ -56,7 +57,7 @@ public class VcsGuess { } @Nullable - public AbstractVcs getVcsForDirty(final FilePath filePath) { + public AbstractVcs getVcsForDirty(@NotNull final FilePath filePath) { if (filePath.isNonLocal()) { return null; } From ee3c392e33216821f435e1b5624f2b2b544b3054 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 28 Feb 2012 16:15:19 +0100 Subject: [PATCH 32/43] complete private members on second invocation in groovy --- .../expressions/CompleteReferenceExpression.java | 3 ++- .../groovy/completion/GroovyCompletionTest.groovy | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index cba92f066030..431bd788388b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -384,7 +384,8 @@ public class CompleteReferenceExpression { } GroovyResolveResult result = (GroovyResolveResult)o; - if (!result.isStaticsOK() || !result.isAccessible()) return; + if (!result.isStaticsOK()) return; + if (!result.isAccessible() && myParameters.getInvocationCount() < 2) return; if (mySkipPackages && result.getElement() instanceof PsiPackage) return; PsiElement element = result.getElement(); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index bd693a882af2..058d28cc9305 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -1172,4 +1172,15 @@ class Base { new Base().@prefixField''') } + public void testPrivateFieldOnSecondInvocation() { + myFixture.configureByText('_a.groovy', '''\ +class Base { + private int field1 +} + +new Base().fiex''') + myFixture.complete(CompletionType.BASIC, 2) + assert myFixture.lookupElementStrings == ['field1'] + } + } \ No newline at end of file From 5bedec59de09f672434d71d64e4da1021eef1605 Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 28 Feb 2012 19:22:43 +0400 Subject: [PATCH 33/43] IDEA-81569 Poor performance when moving lines in web.xml (Alt-Shift-DOWN/UP) while the web.xml is displayed in change details (Changes tool window) --- .../vcs/changes/TodoForBaseRevision.java | 60 +++++++++++++++++ .../vcs/changes/TodoForExistingFile.java | 67 +++++++++++++++++++ .../openapi/vcs/changes/TodoForRanges.java | 50 ++++++++------ .../vcs/impl/ContentRevisionCache.java | 16 +++++ .../FragmentedDiffRequestFromChange.java | 7 +- .../changes/PreparedFragmentedContent.java | 44 +++++++++--- 6 files changed, 211 insertions(+), 33 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForBaseRevision.java create mode 100644 platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForExistingFile.java diff --git a/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForBaseRevision.java b/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForBaseRevision.java new file mode 100644 index 000000000000..63ddf87e0c60 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForBaseRevision.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.intellij.openapi.vcs.changes; + +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.TodoItem; +import com.intellij.util.Consumer; + +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/28/12 + * Time: 6:06 PM + */ +public class TodoForBaseRevision extends TodoForRanges { + private final Getter myGetter; + private final Consumer mySaver; + + public TodoForBaseRevision(Project project, + List ranges, + int additionalOffset, + String name, + String text, + boolean revision, FileType type, final Getter cacheGetter, + final Consumer cacheSaver) { + super(project, ranges, additionalOffset, name, text, revision, type); + myGetter = cacheGetter; + mySaver = cacheSaver; + } + + @Override + protected TodoItem[] getTodoItems() { + final TodoItem[] items = (TodoItem[])myGetter.get(); + if (items != null) return items; + final TodoItem[] todoItems = getTodoForText(PsiSearchHelper.SERVICE.getInstance(myProject)); + if (todoItems != null) { + mySaver.consume(todoItems); + } + return todoItems; + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForExistingFile.java b/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForExistingFile.java new file mode 100644 index 000000000000..5a0f02dae3bc --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForExistingFile.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.intellij.openapi.vcs.changes; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.PsiManager; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.TodoItem; + +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/28/12 + * Time: 4:48 PM + */ +public class TodoForExistingFile extends TodoForRanges { + private final VirtualFile myFile; + + public TodoForExistingFile(Project project, + List ranges, + int additionalOffset, + String name, + String text, + boolean revision, FileType type, VirtualFile file) { + super(project, ranges, additionalOffset, name, text, revision, type); + myFile = file; + } + + protected TodoItem[] getTodoItems() { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public TodoItem[] compute() { + final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(myProject); + + PsiFile psiFile = myFile == null ? null : PsiManager.getInstance(myProject).findFile(myFile); + if (psiFile != null) { + return helper.findTodoItems(psiFile); + } + + return getTodoForText(helper); + } + }); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForRanges.java b/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForRanges.java index 8cbe705310e2..a6e65a39fa68 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForRanges.java +++ b/platform/platform-impl/src/com/intellij/openapi/vcs/changes/TodoForRanges.java @@ -41,36 +41,32 @@ import java.util.List; * Date: 9/9/11 * Time: 9:55 AM */ -public class TodoForRanges { - private final Project myProject; - private final String myFileName; - private final String myText; - private final boolean myOldRevision; +public abstract class TodoForRanges { + protected final Project myProject; private final List myRanges; - private final FileType myFileType; private final int myAdditionalOffset; + protected final String myFileName; + protected final String myText; + protected final boolean myOldRevision; + protected final FileType myFileType; - public TodoForRanges(final Project project, final String fileName, final String text, final boolean oldRevision, - final List ranges, FileType fileType, int additionalOffset) { + protected TodoForRanges(final Project project, + final List ranges, + int additionalOffset, + String name, + String text, + boolean revision, FileType type) { myProject = project; - myFileName = fileName; - myText = text; - myOldRevision = oldRevision; myRanges = ranges; - myFileType = fileType; myAdditionalOffset = additionalOffset; + myFileName = name; + myText = text; + myOldRevision = revision; + myFileType = type; } public List> execute() { - final TodoItem[] todoItems = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public TodoItem[] compute() { - final PsiFile psiFile = PsiFileFactory.getInstance(myProject).createFileFromText((myOldRevision ? "old" : "") + myFileName, myFileType, myText); - - final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(myProject); - return helper.findTodoItemsLight(psiFile); - } - }); + final TodoItem[] todoItems = getTodoItems(); final StepIntersection stepIntersection = new StepIntersection(new Convertor() { @@ -105,4 +101,16 @@ public class TodoForRanges { } return result; } + + protected abstract TodoItem[] getTodoItems(); + + protected TodoItem[] getTodoForText(PsiSearchHelper helper) { + final PsiFile psiFile = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiFile compute() { + return PsiFileFactory.getInstance(myProject).createFileFromText((myOldRevision ? "old" : "") + myFileName, myFileType, myText); + } + }); + return helper.findTodoItemsLight(psiFile); + } } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java b/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java index ad1e50a3b3ae..5dc1948d8da6 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/impl/ContentRevisionCache.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vcs.impl; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Throwable2Computable; import com.intellij.openapi.vcs.FilePath; @@ -48,12 +49,14 @@ public class ContentRevisionCache { private final Object myLock; private final SLRUMap myCache; private final SLRUMap myCurrentRevisionsCache; + private final SLRUMap, Object> myCustom; private long myCounter; public ContentRevisionCache() { myLock = new Object(); myCache = new SLRUMap(100, 50); myCurrentRevisionsCache = new SLRUMap(200, 50); + myCustom = new SLRUMap, Object>(30,30); myCounter = 0; } @@ -73,6 +76,19 @@ public class ContentRevisionCache { } } + public void putCustom(FilePath path, VcsRevisionNumber number, final Object o) { + synchronized (myLock) { + myCustom.put(new Pair(path, number), o); + } + } + + @Nullable + public Object getCustom(FilePath path, VcsRevisionNumber number) { + synchronized (myLock) { + return myCustom.get(new Pair(path, number)); + } + } + public void clearAllCurrent() { synchronized (myLock) { ++ myCounter; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java index f867efc436ad..0b84302699fb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java @@ -81,14 +81,15 @@ public class FragmentedDiffRequestFromChange { final FileStatus fs = change.getFileStatus(); fragmentedContent.setIsAddition(FileStatus.ADDED.equals(fs)); fragmentedContent.setOneSide(FileStatus.ADDED.equals(fs) || FileStatus.DELETED.equals(fs)); - final PreparedFragmentedContent preparedFragmentedContent = new PreparedFragmentedContent(myProject, fragmentedContent, - filePath.getName(), filePath.getFileType()); VirtualFile file = filePath.getVirtualFile(); if (file == null) { filePath.hardRefresh(); file = filePath.getVirtualFile(); } - preparedFragmentedContent.setVirtualFile(file); + final PreparedFragmentedContent preparedFragmentedContent = new PreparedFragmentedContent(myProject, fragmentedContent, + filePath.getName(), filePath.getFileType(), + change.getBeforeRevision() == null ? null : change.getBeforeRevision().getRevisionNumber(), + change.getAfterRevision() == null ? null : change.getAfterRevision().getRevisionNumber(), filePath, file); return preparedFragmentedContent; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java index 71c6b4a4acab..9f1d666f9b17 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java @@ -24,11 +24,18 @@ import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsConfiguration; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; +import com.intellij.openapi.vcs.impl.ContentRevisionCache; +import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.BeforeAfter; +import com.intellij.util.Consumer; import java.util.ArrayList; import java.util.Collections; @@ -60,14 +67,25 @@ public class PreparedFragmentedContent { private final FragmentedContent myFragmentedContent; private final String myFileName; private final FileType myFileType; + private final VcsRevisionNumber myBeforeNumber; + private final VcsRevisionNumber myAfterNumber; private VirtualFile myFile; + private FilePath myFilePath; public PreparedFragmentedContent(final Project project, final FragmentedContent fragmentedContent, final String fileName, - final FileType fileType) { + final FileType fileType, + VcsRevisionNumber beforeNumber, + VcsRevisionNumber afterNumber, + FilePath path, + VirtualFile file) { + myFile = file; myProject = project; myFragmentedContent = fragmentedContent; myFileName = fileName; myFileType = fileType; + myBeforeNumber = beforeNumber; + myAfterNumber = afterNumber; + myFilePath = path; oldConvertor = new LineNumberConvertor(); newConvertor = new LineNumberConvertor(); sbOld = new StringBuilder(); @@ -301,18 +319,26 @@ public class PreparedFragmentedContent { } private void setTodoHighlighting(final Document oldDocument, final Document document) { - final List> beforeTodoRanges = new TodoForRanges(myProject, myFileName, oldDocument.getText(), true, - getBeforeFragments(), myFileType, 1).execute(); - final List> afterTodoRanges = new TodoForRanges(myProject, myFileName, document.getText(), false, - getAfterFragments(), myFileType, 1).execute(); + final ContentRevisionCache cache = ProjectLevelVcsManager.getInstance(myProject).getContentRevisionCache(); + final List> beforeTodoRanges = myBeforeNumber == null ? Collections.>emptyList() : + new TodoForBaseRevision(myProject, getBeforeFragments(), 1, myFileName, oldDocument.getText(), true, myFileType, new Getter() { + @Override + public Object get() { + return cache.getCustom(myFilePath, myBeforeNumber); + } + }, new Consumer() { + @Override + public void consume(Object items) { + cache.putCustom(myFilePath, myBeforeNumber, items); + } + }).execute(); + + final List> afterTodoRanges = new TodoForExistingFile(myProject, getAfterFragments(), 1, + myFileName, document.getText(), false, myFileType, myFile).execute(); setBeforeTodoRanges(beforeTodoRanges); setAfterTodoRanges(afterTodoRanges); } - public void setVirtualFile(VirtualFile file) { - myFile = file; - } - public VirtualFile getFile() { return myFile; } From 675e8056dd433732cb1defa017ff0daacc678570 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Tue, 28 Feb 2012 19:35:40 +0400 Subject: [PATCH 34/43] RUBY-10527 SCSS Editor is already broken --- .../editorActions/enter/BaseIndentEnterHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java index e96aa03e9c21..da9e2e01c431 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.editorActions.enter; import com.intellij.lang.Language; +import com.intellij.lang.LanguageFormatting; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Document; @@ -122,6 +123,9 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter { return Result.Stop; } + if (LanguageFormatting.INSTANCE.forLanguage(myLanguage) != null) { + return Result.Continue; + } EditorModificationUtil.insertStringAtCaret(editor, "\n" + lineIndent); editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(lineNumber + 1, lineIndent.length())); return Result.Stop; From 2e2b1decc71331978cfa208f94b87bda9049734e Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Tue, 28 Feb 2012 19:47:03 +0400 Subject: [PATCH 35/43] Rolling back integrate speedup (compile-server). --- .../org/jetbrains/ether/dependencyView/Mappings.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index 058870f86f18..e793168989ab 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -260,8 +260,10 @@ public class Mappings { private abstract class PostPass { boolean myPerformed = false; + abstract void perform(); - void run () { + + void run() { if (!myPerformed) { myPerformed = true; perform(); @@ -1605,7 +1607,7 @@ public class Mappings { } } - if (delta.isDifferentiated() && false) { + if (delta.isDifferentiated()) { for (DependencyContext.S c : delta.getChangedClasses()) { myClassToSubclasses.remove(c); @@ -1629,7 +1631,7 @@ public class Mappings { myClassToSourceFile.putAll(delta.myClassToSourceFile); } - if (delta.isDifferentiated()) { + if (delta.isDifferentiated() && false) { for (DependencyContext.S f : delta.getChangedFiles()) { mySourceFileToClasses.remove(f); final Collection classes = delta.mySourceFileToClasses.get(f); @@ -1767,9 +1769,9 @@ public class Mappings { @Override public void registerImports(final String className, final Collection imports, Collection staticImports) { - for (String s: staticImports) { + for (String s : staticImports) { int i = s.length() - 1; - for (; s.charAt(i) != '.'; i--); + for (; s.charAt(i) != '.'; i--) ; imports.add(s.substring(0, i)); } From c547cd8064da86bc66ab1c6bc3f3299a00bbde1b Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Mon, 27 Feb 2012 21:58:24 +0400 Subject: [PATCH 36/43] replace AndroidClassesAndJarsStateStorage by more generic AndroidFileSetStorage --- .../android/AndroidClassesAndJarsState.java | 60 ------------------- .../AndroidClassesAndJarsStateStorage.java | 43 ------------- .../jps/android/AndroidDexBuilder.java | 23 +++---- .../jps/android/AndroidFileSetState.java | 7 ++- .../jetbrains/jps/android/AndroidJpsUtil.java | 10 ++++ .../AndroidLibraryPackagingBuilder.java | 7 +-- .../AndroidResourcePackagingBuilder.java | 6 +- 7 files changed, 34 insertions(+), 122 deletions(-) delete mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsState.java delete mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsStateStorage.java diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsState.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsState.java deleted file mode 100644 index 3a6c4bbeccd1..000000000000 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsState.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.jetbrains.jps.android; - -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.Processor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.incremental.storage.ValidityState; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Eugene.Kudelevsky - */ -class AndroidClassesAndJarsState implements ValidityState { - private Map myFiles; - - public AndroidClassesAndJarsState(@NotNull Collection roots) { - myFiles = new HashMap(); - - for (String rootPath : roots) { - AndroidJpsUtil.processClassFilesAndJarsRecursively(rootPath, new Processor() { - @Override - public boolean process(File file) { - myFiles.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified()); - return true; - } - }); - } - } - - public AndroidClassesAndJarsState(@NotNull DataInput in) throws IOException { - myFiles = new HashMap(); - int size = in.readInt(); - - while (size-- > 0) { - final String path = in.readUTF(); - final long timestamp = in.readLong(); - myFiles.put(path, timestamp); - } - } - - public boolean equalsTo(ValidityState otherState) { - return otherState instanceof AndroidClassesAndJarsState - && myFiles.equals(((AndroidClassesAndJarsState)otherState).myFiles); - } - - public void save(DataOutput out) throws IOException { - out.writeInt(myFiles.size()); - - for (String path : myFiles.keySet()) { - out.writeUTF(path); - out.writeLong(myFiles.get(path)); - } - } -} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsStateStorage.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsStateStorage.java deleted file mode 100644 index cb765dd8a35c..000000000000 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidClassesAndJarsStateStorage.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.jetbrains.jps.android; - -import com.intellij.util.io.DataExternalizer; -import com.intellij.util.io.EnumeratorStringDescriptor; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.incremental.storage.AbstractStateStorage; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.File; -import java.io.IOException; - -/** - * @author Eugene.Kudelevsky - */ -public class AndroidClassesAndJarsStateStorage extends AbstractStateStorage { - - @NonNls private static final String CLASSES_AND_JARS_STORAGE = "classes_and_jars"; - - public AndroidClassesAndJarsStateStorage(@NotNull File dataStorageRoot, @NotNull String suffix) throws IOException { - super(getStorageFile(dataStorageRoot, suffix), new EnumeratorStringDescriptor(), new MyDataExternalizer()); - } - - @NotNull - private static File getStorageFile(@NotNull File dataStorageRoot, @NotNull String suffix) { - return new File(new File(new File(dataStorageRoot, AndroidJpsUtil.ANDROID_STORAGE_DIR), CLASSES_AND_JARS_STORAGE + suffix), - CLASSES_AND_JARS_STORAGE); - } - - private static class MyDataExternalizer implements DataExternalizer { - - @Override - public void save(DataOutput out, AndroidClassesAndJarsState value) throws IOException { - value.save(out); - } - - @Override - public AndroidClassesAndJarsState read(DataInput in) throws IOException { - return new AndroidClassesAndJarsState(in); - } - } -} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java index 35e4c6dfb139..8cc59ebf9254 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java @@ -55,11 +55,12 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { private static void doBuild(CompileContext context) throws IOException, ProjectBuildException { final File root = context.getDataManager().getDataStorageRoot(); - AndroidClassesAndJarsStateStorage dexStateStorage = null; - AndroidClassesAndJarsStateStorage proguardStateStorage = null; + AndroidFileSetStorage dexStateStorage = null; + AndroidFileSetStorage proguardStateStorage = null; try { - dexStateStorage = new AndroidClassesAndJarsStateStorage(root, "_dex"); - proguardStateStorage = new AndroidClassesAndJarsStateStorage(root, "_proguard"); + dexStateStorage = new AndroidFileSetStorage(root, "dex"); + proguardStateStorage = new AndroidFileSetStorage(root, "proguard"); + if (!doDexBuild(context, dexStateStorage, proguardStateStorage)) { throw new ProjectBuildException(); } @@ -75,8 +76,8 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { } private static boolean doDexBuild(@NotNull CompileContext context, - @NotNull AndroidClassesAndJarsStateStorage dexStateStorage, - @NotNull AndroidClassesAndJarsStateStorage proguardStateStorage) { + @NotNull AndroidFileSetStorage dexStateStorage, + @NotNull AndroidFileSetStorage proguardStateStorage) { boolean success = true; for (Module module : context.getProject().getModules().values()) { @@ -145,10 +146,10 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { } } } - final AndroidClassesAndJarsState newState = new AndroidClassesAndJarsState(fileSet); + final AndroidFileSetState newState = new AndroidFileSetState(fileSet, AndroidJpsUtil.CLASSES_AND_JARS_FILTER); if (context.isMake()) { - final AndroidClassesAndJarsState oldState = dexStateStorage.getState(module.getName()); + final AndroidFileSetState oldState = dexStateStorage.getState(module.getName()); if (oldState != null && oldState.equalsTo(newState)) { continue; } @@ -254,7 +255,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { @NotNull CompileContext context, @NotNull String outputJarPath, @NotNull String proguardCfgPath, - @NotNull AndroidClassesAndJarsStateStorage proguardStateStorage) throws IOException { + @NotNull AndroidFileSetStorage proguardStateStorage) throws IOException { final Module module = facet.getModule(); final File proguardCfgFile = new File(proguardCfgPath); @@ -294,8 +295,8 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { allFiles.addAll(libClassFilesDirs); allFiles.addAll(externalJars); - final AndroidClassesAndJarsState newState = new AndroidClassesAndJarsState(allFiles); - final AndroidClassesAndJarsState oldState = proguardStateStorage.getState(module.getName()); + final AndroidFileSetState newState = new AndroidFileSetState(allFiles, AndroidJpsUtil.CLASSES_AND_JARS_FILTER); + final AndroidFileSetState oldState = proguardStateStorage.getState(module.getName()); if (context.getTimestampStorage().getStamp(proguardCfgFile) == proguardCfgFile.lastModified() && newState.equalsTo(oldState)) { return true; diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java index 925e71361fac..17e5210c4452 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java @@ -1,5 +1,6 @@ package org.jetbrains.jps.android; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.Processor; import com.intellij.util.containers.HashMap; @@ -19,14 +20,16 @@ import java.util.Map; public class AndroidFileSetState implements ValidityState { private final Map myTimestamps; - public AndroidFileSetState(@NotNull Collection roots) { + public AndroidFileSetState(@NotNull Collection roots, @NotNull final Condition filter) { myTimestamps = new HashMap(); for (String resourceDir : roots) { FileUtil.processFilesRecursively(new File(resourceDir), new Processor() { @Override public boolean process(File file) { - myTimestamps.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified()); + if (filter.value(file)) { + myTimestamps.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified()); + } return true; } }); diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java index 0d254ac1e252..3027a7b49e34 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java @@ -3,6 +3,7 @@ package org.jetbrains.jps.android; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.ArrayUtil; @@ -34,9 +35,18 @@ import java.util.regex.Matcher; */ class AndroidJpsUtil { private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.android.AndroidJpsUtil"); + @NonNls public static final String ANDROID_STORAGE_DIR = "android"; @NonNls private static final String RESOURCE_CACHE_STORAGE = "res-cache"; + public static final Condition CLASSES_AND_JARS_FILTER = new Condition() { + @Override + public boolean value(File file) { + final String ext = FileUtil.getExtension(file.getName()); + return "jar".equals(ext) || "class".equals(ext); + } + }; + private AndroidJpsUtil() { } diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java index 7b09dc105286..303cc2793b4a 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java @@ -45,8 +45,7 @@ public class AndroidLibraryPackagingBuilder extends ModuleLevelBuilder { private static ModuleLevelBuilder.ExitCode doBuild(CompileContext context, ModuleChunk chunk) throws IOException { boolean success = true; - final AndroidClassesAndJarsStateStorage storage = - new AndroidClassesAndJarsStateStorage(context.getDataManager().getDataStorageRoot(), "_libs"); + final AndroidFileSetStorage storage = new AndroidFileSetStorage(context.getDataManager().getDataStorageRoot(), "libs_packaging"); try { for (Module module : chunk.getModules()) { @@ -73,8 +72,8 @@ public class AndroidLibraryPackagingBuilder extends ModuleLevelBuilder { final Set subdirs = new HashSet(); AndroidJpsUtil.addSubdirectories(classesDir, subdirs); - final AndroidClassesAndJarsState newState = new AndroidClassesAndJarsState(subdirs); - final AndroidClassesAndJarsState oldState = storage.getState(module.getName()); + final AndroidFileSetState newState = new AndroidFileSetState(subdirs, AndroidJpsUtil.CLASSES_AND_JARS_FILTER); + final AndroidFileSetState oldState = storage.getState(module.getName()); if (oldState != null && oldState.equalsTo(newState)) { continue; diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java index b44f58920990..96cdbfeadf63 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java @@ -1,6 +1,7 @@ package org.jetbrains.jps.android; import com.android.sdklib.IAndroidTarget; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.util.containers.HashMap; import org.jetbrains.android.compiler.tools.AndroidApt; @@ -64,6 +65,7 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { } } + @SuppressWarnings("unchecked") private static void fillStates(@NotNull Collection modules, @NotNull Map resourcesStates, @NotNull Map assetsStates) throws IOException { @@ -75,13 +77,13 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { final List resourceDirs = resourceDir != null ? Arrays.asList(resourceDir.getPath()) : Collections.emptyList(); - resourcesStates.put(module, new AndroidFileSetState(resourceDirs)); + resourcesStates.put(module, new AndroidFileSetState(resourceDirs, Condition.TRUE)); final File assetsDir = facet.getAssetsDir(); final List assetDirs = assetsDir != null ? Arrays.asList(assetsDir.getPath()) : Collections.emptyList(); - assetsStates.put(module, new AndroidFileSetState(assetDirs)); + assetsStates.put(module, new AndroidFileSetState(assetDirs, Condition.TRUE)); } } } From 899b8219129b9dedbcb5da97a6ef11c6445ebe71 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Mon, 27 Feb 2012 22:55:43 +0400 Subject: [PATCH 37/43] move AndroidApkBuilder to android-rt module to use by android-jps plugin --- .../messages/AndroidBundle.properties | 1 - plugins/android/rt/android-rt.iml | 4 + .../compiler/tools/AndroidApkBuilder.java | 225 ++++++++---------- .../android/util/AndroidCommonUtils.java | 4 + plugins/android/src/META-INF/plugin.xml | 8 + .../actions/RunAndroidAvdManagerAction.java | 4 +- .../actions/RunAndroidSdkManagerAction.java | 4 +- .../android/compiler/AndroidCompileUtil.java | 36 +++ .../compiler/AndroidPackagingCompiler.java | 41 ++-- .../compiler/ExcludedSourcesFilter.java | 23 ++ .../android/exportSignedPackage/ApkStep.java | 4 +- .../jetbrains/android/facet/AndroidFacet.java | 4 +- .../newProject/AndroidModuleBuilder.java | 3 +- .../org/jetbrains/android/run/AvdChooser.java | 3 +- .../jetbrains/android/sdk/AndroidSdkData.java | 2 +- .../android/sdk/AndroidSdkUtils.java | 4 - 16 files changed, 211 insertions(+), 159 deletions(-) rename plugins/android/{ => rt}/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java (62%) create mode 100644 plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java diff --git a/plugins/android/resources/messages/AndroidBundle.properties b/plugins/android/resources/messages/AndroidBundle.properties index 321c9738d4b4..873713f765d3 100644 --- a/plugins/android/resources/messages/AndroidBundle.properties +++ b/plugins/android/resources/messages/AndroidBundle.properties @@ -139,7 +139,6 @@ avd.not.valid.error=AVD {0} is not valid avd.not.compatible.error=Build target of AVD {0} is not compatible with your build target avd.cannot.be.loaded.error=Cannot load virtual devices navigate.to.android.resource.action=Navigate to Android resource definition -android.debug.certificate.expired.error=Debug certificate expired on {0}. Cannot regenerate it, please delete file \"{1}\" manually. android.identifier.expected={0} is not an identifier android.directory.cannot.be.found.error="{0}" directory cannot be found create.run.configuration.question=Do you want to create run configuration for module {0}? diff --git a/plugins/android/rt/android-rt.iml b/plugins/android/rt/android-rt.iml index 1b33185c2722..a45948b193fb 100644 --- a/plugins/android/rt/android-rt.iml +++ b/plugins/android/rt/android-rt.iml @@ -14,11 +14,15 @@ + + + + diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java similarity index 62% rename from plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java rename to plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index 9eee93725d1b..16fadec427af 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -20,25 +20,15 @@ import com.android.jarutils.JavaResourceFilter; import com.android.jarutils.SignedJarBuilder; import com.android.prefs.AndroidLocation; import com.android.sdklib.SdkConstants; -import com.intellij.ide.highlighter.ArchiveFileType; -import com.intellij.openapi.compiler.CompilerManager; -import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import com.intellij.util.text.DateFormatUtil; -import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.facet.AndroidFacet; -import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.sdk.AndroidSdkUtils; -import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.AndroidCompilerMessageKind; +import org.jetbrains.android.util.AndroidExecutionUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,7 +44,7 @@ import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import static com.intellij.openapi.compiler.CompilerMessageCategory.*; +import static org.jetbrains.android.util.AndroidCompilerMessageKind.*; /** * @author yole @@ -68,7 +58,7 @@ public class AndroidApkBuilder { private AndroidApkBuilder() { } - private static Map> filterUsingKeystoreMessages(Map> messages) { + private static Map> filterUsingKeystoreMessages(Map> messages) { List infoMessages = messages.get(INFORMATION); if (infoMessages == null) { infoMessages = new ArrayList(); @@ -118,48 +108,49 @@ public class AndroidApkBuilder { } } - public static Map> execute(Project project, - @NotNull String resPackagePath, - @NotNull String dexPath, - @NotNull VirtualFile[] sourceRoots, - @NotNull String[] externalJars, - @NotNull VirtualFile[] nativeLibsFolders, - @NotNull String finalApk, - boolean unsigned, - @NotNull String sdkPath, - @Nullable String customKeystorePath) throws IOException { + public static Map> execute(@NotNull String resPackagePath, + @NotNull String dexPath, + @NotNull String[] sourceRoots, + @NotNull String[] externalJars, + @NotNull String[] nativeLibsFolders, + @NotNull String finalApk, + boolean unsigned, + @NotNull String sdkPath, + @Nullable String customKeystorePath, + @NotNull Condition resourceFilter) throws IOException { if (unsigned) { return filterUsingKeystoreMessages( - finalPackage(project, dexPath, sourceRoots, externalJars, nativeLibsFolders, finalApk, resPackagePath, customKeystorePath, false)); + finalPackage(dexPath, sourceRoots, externalJars, nativeLibsFolders, finalApk, resPackagePath, customKeystorePath, false, + resourceFilter)); } - final Map> map = new HashMap>(); - final String zipAlignPath = sdkPath + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_ZIPALIGN); + final Map> map = new HashMap>(); + final String zipAlignPath = sdkPath + File.separator + AndroidCommonUtils.toolPath(SdkConstants.FN_ZIPALIGN); boolean withAlignment = new File(zipAlignPath).exists(); String unalignedApk = finalApk + UNALIGNED_SUFFIX; - Map> map2 = filterUsingKeystoreMessages( - finalPackage(project, dexPath, sourceRoots, externalJars, nativeLibsFolders, withAlignment ? unalignedApk : finalApk, resPackagePath, - customKeystorePath, true)); + Map> map2 = filterUsingKeystoreMessages( + finalPackage(dexPath, sourceRoots, externalJars, nativeLibsFolders, withAlignment ? unalignedApk : finalApk, resPackagePath, + customKeystorePath, true, resourceFilter)); map.putAll(map2); if (withAlignment && map.get(ERROR).size() == 0) { - map2 = AndroidCompileUtil.execute(zipAlignPath, "-f", "4", unalignedApk, finalApk); + map2 = AndroidExecutionUtil.doExecute(zipAlignPath, "-f", "4", unalignedApk, finalApk); map.putAll(map2); } return map; } - private static Map> finalPackage(Project project, - @NotNull String dexPath, - @NotNull VirtualFile[] sourceRoots, - @NotNull String[] externalJars, - @NotNull VirtualFile[] nativeLibsFolders, - @NotNull String outputApk, - @NotNull String apkPath, - @Nullable String customKeystorePath, - boolean signed) { - final Map> result = new HashMap>(); + private static Map> finalPackage(@NotNull String dexPath, + @NotNull String[] sourceRoots, + @NotNull String[] externalJars, + @NotNull String[] nativeLibsFolders, + @NotNull String outputApk, + @NotNull String apkPath, + @Nullable String customKeystorePath, + boolean signed, + @NotNull Condition resourceFilter) { + final Map> result = new HashMap>(); result.put(ERROR, new ArrayList()); result.put(INFORMATION, new ArrayList()); result.put(WARNING, new ArrayList()); @@ -187,35 +178,36 @@ public class AndroidApkBuilder { if (certificate != null && certificate.getNotAfter().compareTo(new Date()) < 0) { String date = DateFormatUtil.formatPrettyDateTime(certificate.getNotAfter()); - result.get(ERROR).add(AndroidBundle.message("android.debug.certificate.expired.error", date, keyStoreOsPath)); + result.get(ERROR).add( + ("Debug certificate expired on " + date + ". Cannot regenerate it, please delete file \"" + keyStoreOsPath + "\" manually.")); return result; } PrivateKey key = provider.getDebugKey(); if (key == null) { - result.get(ERROR).add(AndroidBundle.message("android.cannot.create.new.key.error")); + result.get(ERROR).add("Cannot create new key or keystore"); return result; } if (!new File(apkPath).exists()) { - result.get(CompilerMessageCategory.ERROR).add("File " + apkPath + " not found. Try to rebuild project"); + result.get(ERROR).add("File " + apkPath + " not found. Try to rebuild project"); return result; } File dexEntryFile = new File(dexPath); if (!dexEntryFile.exists()) { - result.get(CompilerMessageCategory.ERROR).add("File " + dexEntryFile.getPath() + " not found. Try to rebuild project"); + result.get(ERROR).add("File " + dexEntryFile.getPath() + " not found. Try to rebuild project"); return result; } for (String externalJar : externalJars) { if (new File(externalJar).isDirectory()) { - result.get(CompilerMessageCategory.ERROR).add(externalJar + " is directory. Directory libraries are not supported"); + result.get(ERROR).add(externalJar + " is directory. Directory libraries are not supported"); } } - if (result.get(CompilerMessageCategory.ERROR).size() > 0) { + if (result.get(ERROR).size() > 0) { return result; } @@ -233,9 +225,10 @@ public class AndroidApkBuilder { builder.writeFile(dexEntryFile, AndroidCommonUtils.CLASSES_FILE_NAME); final HashSet added = new HashSet(); - for (VirtualFile sourceRoot : sourceRoots) { - final HashSet sourceFolderResources = new HashSet(); - collectStandardSourceFolderResources(sourceRoot, new HashSet(), sourceFolderResources, project); + for (String sourceRootPath : sourceRoots) { + final HashSet sourceFolderResources = new HashSet(); + final File sourceRoot = new File(sourceRootPath); + collectStandardSourceFolderResources(sourceRoot, sourceFolderResources, resourceFilter); writeStandardSourceFolderResources(sourceFolderResources, sourceRoot, builder, added); } @@ -246,7 +239,7 @@ public class AndroidApkBuilder { } for (String duplicate : duplicates) { - result.get(CompilerMessageCategory.WARNING).add("Duplicate entry " + duplicate + ". The file won't be added"); + result.get(WARNING).add("Duplicate entry " + duplicate + ". The file won't be added"); } MyResourceFilter filter = new MyResourceFilter(duplicates); @@ -262,9 +255,14 @@ public class AndroidApkBuilder { } final HashSet nativeLibs = new HashSet(); - for (VirtualFile nativeLibsFolder : nativeLibsFolders) { - for (VirtualFile child : nativeLibsFolder.getChildren()) { - writeNativeLibraries(builder, nativeLibsFolder, child, signed, nativeLibs); + for (String nativeLibsFolderPath : nativeLibsFolders) { + final File nativeLibsFolder = new File(nativeLibsFolderPath); + final File[] children = nativeLibsFolder.listFiles(); + + if (children != null) { + for (File child : children) { + writeNativeLibraries(builder, nativeLibsFolder, child, signed, nativeLibs); + } } } builder.close(); @@ -305,7 +303,7 @@ public class AndroidApkBuilder { return result; } - private static DebugKeyProvider createDebugKeyProvider(final Map> result, String path) throws + private static DebugKeyProvider createDebugKeyProvider(final Map> result, String path) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, @@ -326,18 +324,20 @@ public class AndroidApkBuilder { } private static void writeNativeLibraries(SignedJarBuilder builder, - VirtualFile nativeLibsFolder, - VirtualFile child, + File nativeLibsFolder, + File child, boolean debugBuild, Set added) throws IOException { - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList(); collectNativeLibraries(child, list, debugBuild); - for (VirtualFile file : list) { - String relativePath = VfsUtilCore.getRelativePath(file, nativeLibsFolder, File.separatorChar); + + for (File file : list) { + final String relativePath = FileUtil.getRelativePath(nativeLibsFolder, file); String path = FileUtil.toSystemIndependentName(SdkConstants.FD_APK_NATIVE_LIBS + File.separator + relativePath); + if (added.add(path)) { - builder.writeFile(toIoFile(file), path); + builder.writeFile(file, path); LOG.info("Native lib file added to APK: " + file.getPath()); } else { @@ -346,104 +346,73 @@ public class AndroidApkBuilder { } } - private static Map> addExceptionMessage(Exception e, - Map> result) { + private static Map> addExceptionMessage(Exception e, + Map> result) { LOG.info(e); String simpleExceptionName = e.getClass().getCanonicalName(); result.get(ERROR).add(simpleExceptionName + ": " + e.getMessage()); return result; } - public static void collectNativeLibraries(@NotNull VirtualFile file, @NotNull List result, boolean debugBuild) { + public static void collectNativeLibraries(@NotNull File file, @NotNull List result, boolean debugBuild) { if (!file.isDirectory()) { - String ext = file.getExtension(); + String ext = FileUtil.getExtension(file.getName()); // some users store jars and *.so libs in the same directory. Do not pack JARs to APK's "lib" folder! if (EXT_NATIVE_LIB.equalsIgnoreCase(ext) || - (debugBuild && !(file.getFileType() instanceof ArchiveFileType))) { + (debugBuild && !("jar".equals(ext)))) { result.add(file); } } else if (JavaResourceFilter.checkFolderForPackaging(file.getName())) { - for (VirtualFile child : file.getChildren()) { - collectNativeLibraries(child, result, debugBuild); + final File[] children = file.listFiles(); + + if (children != null) { + for (File child : children) { + collectNativeLibraries(child, result, debugBuild); + } } } } - public static void collectStandardSourceFolderResources(VirtualFile sourceFolder, - Set visited, - Set result, - @Nullable Project project) { - visited.add(sourceFolder); - - for (VirtualFile child : sourceFolder.getChildren()) { - if (child.exists()) { - if (child.isDirectory()) { - if (!visited.contains(child) && - JavaResourceFilter.checkFolderForPackaging(child.getName()) && !isExcludedFromCompilation(child, project)) { - collectStandardSourceFolderResources(child, visited, result, project); + public static void collectStandardSourceFolderResources(@NotNull File sourceFolder, + @NotNull Collection result, + @NotNull Condition filter) { + final File[] children = sourceFolder.listFiles(); + + if (children != null) { + for (File child : children) { + if (child.exists()) { + if (child.isDirectory()) { + if (JavaResourceFilter.checkFolderForPackaging(child.getName()) && !filter.value(child)) { + collectStandardSourceFolderResources(child, result, filter); + } + } + else if (checkFileForPackaging(child) && !filter.value(child)) { + result.add(child); } } - else if (checkFileForPackaging(child) && !isExcludedFromCompilation(child, project)) { - result.add(child); - } } } } - private static boolean isExcludedFromCompilation(VirtualFile child, @Nullable Project project) { - final CompilerManager compilerManager = project != null ? CompilerManager.getInstance(project) : null; - - if (compilerManager == null) { - return false; - } - - if (!compilerManager.isExcludedFromCompilation(child)) { - return false; - } - - final Module module = ModuleUtil.findModuleForFile(child, project); - if (module == null) { - return true; - } - - final AndroidFacet facet = AndroidFacet.getInstance(module); - if (facet == null || !facet.getConfiguration().LIBRARY_PROJECT) { - return true; - } - - final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); - if (platform == null) { - return true; - } - - // we exclude sources of library modules automatically for tools r7 or previous - return platform.getSdkData().getPlatformToolsRevision() > 7; - } - - private static void writeStandardSourceFolderResources(Collection resources, - VirtualFile sourceRoot, + private static void writeStandardSourceFolderResources(Collection resources, + File sourceRoot, SignedJarBuilder jarBuilder, Set added) throws IOException { - for (VirtualFile child : resources) { - final String relativePath = FileUtil.toSystemIndependentName(VfsUtilCore.getRelativePath(child, sourceRoot, File.separatorChar)); - if (!added.contains(relativePath)) { - File file = toIoFile(child); - jarBuilder.writeFile(file, FileUtil.toSystemIndependentName(relativePath)); + for (File child : resources) { + final String relativePath = FileUtil.getRelativePath(sourceRoot, child); + if (relativePath != null && !added.contains(relativePath)) { + jarBuilder.writeFile(child, FileUtil.toSystemIndependentName(relativePath)); added.add(relativePath); } } } - private static File toIoFile(VirtualFile child) { - return new File(FileUtil.toSystemDependentName(child.getPath())).getAbsoluteFile(); - } - - private static boolean checkFileForPackaging(VirtualFile file) { - String fileName = file.getNameWithoutExtension(); + private static boolean checkFileForPackaging(File file) { + String fileName = FileUtil.getNameWithoutExtension(file); if (fileName.length() > 0) { - return JavaResourceFilter.checkFileForPackaging(fileName, file.getExtension()); + return JavaResourceFilter.checkFileForPackaging(fileName, FileUtil.getExtension(file.getName())); } return false; } diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java index 763c9a4c90f0..f6ea4e35cf36 100644 --- a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -343,4 +343,8 @@ public class AndroidCommonUtils { return FileUtil.toSystemDependentName(inputJar.getPath()); } + + public static String toolPath(@NotNull String toolFileName) { + return SdkConstants.OS_SDK_TOOLS_FOLDER + toolFileName; + } } diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index 104af71b4115..978846c81b1f 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -205,6 +205,14 @@ + + + + + + + + diff --git a/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java b/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java index a87b5ff15869..5560def58061 100644 --- a/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java @@ -20,8 +20,8 @@ import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.android.util.ExecutionStatus; import org.jetbrains.annotations.NotNull; @@ -47,7 +47,7 @@ public class RunAndroidAvdManagerAction extends AndroidRunSdkToolAction { ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - final String toolPath = sdkPath + File.separator + AndroidSdkUtils.toolPath(SdkConstants.androidCmdName()); + final String toolPath = sdkPath + File.separator + AndroidCommonUtils.toolPath(SdkConstants.androidCmdName()); GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.setExePath(toolPath); commandLine.addParameter("avd"); diff --git a/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java b/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java index f2fed28b4bc6..52029d98ca81 100644 --- a/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java @@ -20,8 +20,8 @@ import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.android.util.ExecutionStatus; import org.jetbrains.annotations.NotNull; @@ -43,7 +43,7 @@ public class RunAndroidSdkManagerAction extends AndroidRunSdkToolAction { ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - final String toolPath = sdkPath + File.separator + AndroidSdkUtils.toolPath(SdkConstants.androidCmdName()); + final String toolPath = sdkPath + File.separator + AndroidCommonUtils.toolPath(SdkConstants.androidCmdName()); GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.setExePath(toolPath); commandLine.addParameter("sdk"); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index 4e001e29c78e..3b69b90b5b00 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -35,6 +35,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; @@ -769,4 +770,39 @@ public class AndroidCompileUtil { if (compilerOutput == null) return null; return new File(compilerOutput.getPath(), getApkName(module)).getPath(); } + + public static boolean isExcludedFromCompilation(@NotNull File file, @Nullable Project project) { + final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file); + return vFile != null && isExcludedFromCompilation(vFile, project); + } + + public static boolean isExcludedFromCompilation(VirtualFile child, @Nullable Project project) { + final CompilerManager compilerManager = project != null ? CompilerManager.getInstance(project) : null; + + if (compilerManager == null) { + return false; + } + + if (!compilerManager.isExcludedFromCompilation(child)) { + return false; + } + + final Module module = ModuleUtil.findModuleForFile(child, project); + if (module == null) { + return true; + } + + final AndroidFacet facet = AndroidFacet.getInstance(module); + if (facet == null || !facet.getConfiguration().LIBRARY_PROJECT) { + return true; + } + + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + return true; + } + + // we exclude sources of library modules automatically for tools r7 or previous + return platform.getSdkData().getPlatformToolsRevision() > 7; + } } \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java index bb10c2191d2d..f116300d4be1 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java @@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.DependencyScope; import com.intellij.openapi.roots.ModuleOrderEntry; import com.intellij.openapi.roots.ModuleRootManager; @@ -233,9 +234,15 @@ public class AndroidPackagingCompiler implements PackagingCompiler { ? item.getFinalPath() + UNSIGNED_SUFFIX : item.getFinalPath(); - final Map> messages = AndroidApkBuilder - .execute(context.getProject(), resPackagePath, item.getClassesDexPath(), item.getSourceRoots(), externalLibPaths, item.getNativeLibsFolders(), - finalPath, unsigned, item.mySdkPath, item.getCustomKeystorePath()); + final String[] sourceRoots = AndroidCompileUtil.toOsPaths(item.getSourceRoots()); + final String[] nativeLibsFolders = AndroidCompileUtil.toOsPaths(item.getNativeLibsFolders()); + final Project project = context.getProject(); + + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidApkBuilder.execute(resPackagePath, item.getClassesDexPath(), sourceRoots, externalLibPaths, + nativeLibsFolders, finalPath, unsigned, item.mySdkPath, item.getCustomKeystorePath(), + new ExcludedSourcesFilter(project))); + AndroidCompileUtil.addMessages(context, messages); } catch (final IOException e) { @@ -296,7 +303,7 @@ public class AndroidPackagingCompiler implements PackagingCompiler { private final boolean myGenerateUnsigendApk; private final Module myModule; private boolean myReleaseBuild; - + private final String myCustomKeystorePath; private AptPackagingItem(String sdkPath, @@ -375,8 +382,8 @@ public class AndroidPackagingCompiler implements PackagingCompiler { @Nullable public ValidityState getValidityState() { - return new MyValidityState(myResPackagePath, myClassesDexPath, myFinalPath, myGenerateUnsigendApk, myReleaseBuild, - mySourceRoots, myExternalLibraries, myNativeLibsFolders, myCustomKeystorePath); + return new MyValidityState(myModule.getProject(), myResPackagePath, myClassesDexPath, myFinalPath, myGenerateUnsigendApk, + myReleaseBuild, mySourceRoots, myExternalLibraries, myNativeLibsFolders, myCustomKeystorePath); } } @@ -400,7 +407,8 @@ public class AndroidPackagingCompiler implements PackagingCompiler { myCustomKeystorePath = CompilerIOUtil.readString(is); } - MyValidityState(String resPackagePath, + MyValidityState(Project project, + String resPackagePath, String classesDexPath, String apkPath, boolean generateUnsignedApk, @@ -416,25 +424,26 @@ public class AndroidPackagingCompiler implements PackagingCompiler { myReleaseBuild = releaseBuild; myCustomKeystorePath = customKeystorePath != null ? customKeystorePath : ""; - final HashSet resourcesFromSourceRoot = new HashSet(); + final HashSet resourcesFromSourceRoot = new HashSet(); for (VirtualFile sourceRoot : sourceRoots) { - AndroidApkBuilder.collectStandardSourceFolderResources(sourceRoot, new HashSet(), resourcesFromSourceRoot, null); + AndroidApkBuilder.collectStandardSourceFolderResources(new File(sourceRoot.getPath()), resourcesFromSourceRoot, + new ExcludedSourcesFilter(project)); } - for (VirtualFile resource : resourcesFromSourceRoot) { - myResourceTimestamps.put(resource.getPath(), resource.getTimeStamp()); + for (File resource : resourcesFromSourceRoot) { + myResourceTimestamps.put(FileUtil.toSystemIndependentName(resource.getPath()), resource.lastModified()); } for (VirtualFile externalLib : externalLibs) { myResourceTimestamps.put(externalLib.getPath(), externalLib.getTimeStamp()); } - ArrayList nativeLibs = new ArrayList(); + ArrayList nativeLibs = new ArrayList(); for (VirtualFile nativeLibFolder : nativeLibFolders) { for (VirtualFile child : nativeLibFolder.getChildren()) { - AndroidApkBuilder.collectNativeLibraries(child, nativeLibs, !releaseBuild); + AndroidApkBuilder.collectNativeLibraries(new File(child.getPath()), nativeLibs, !releaseBuild); } } - for (VirtualFile nativeLib : nativeLibs) { - myResourceTimestamps.put(nativeLib.getPath(), nativeLib.getTimeStamp()); + for (File nativeLib : nativeLibs) { + myResourceTimestamps.put(FileUtil.toSystemIndependentName(nativeLib.getPath()), nativeLib.lastModified()); } } @@ -447,7 +456,7 @@ public class AndroidPackagingCompiler implements PackagingCompiler { return mvs.myGenerateUnsignedApk == myGenerateUnsignedApk && mvs.myReleaseBuild == myReleaseBuild && mvs.myResourceTimestamps.equals(myResourceTimestamps) && - mvs.myApkPath.equals(myApkPath) && + mvs.myApkPath.equals(myApkPath) && mvs.myCustomKeystorePath.equals(myCustomKeystorePath); } diff --git a/plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java b/plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java new file mode 100644 index 000000000000..0b5d756cf6d7 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java @@ -0,0 +1,23 @@ +package org.jetbrains.android.compiler; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** +* @author Eugene.Kudelevsky +*/ +class ExcludedSourcesFilter implements Condition { + private final Project myProject; + + public ExcludedSourcesFilter(@NotNull Project project) { + myProject = project; + } + + @Override + public boolean value(File file) { + return AndroidCompileUtil.isExcludedFromCompilation(file, myProject); + } +} diff --git a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java index ef5dbc269b2d..caa4c355b524 100644 --- a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java +++ b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java @@ -51,8 +51,8 @@ import org.jetbrains.android.compiler.AndroidProguardCompiler; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.SaveFileListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -196,7 +196,7 @@ class ApkStep extends ExportSignedPackageWizardStep { AndroidPlatform platform = myWizard.getFacet().getConfiguration().getAndroidPlatform(); assert platform != null; String sdkPath = platform.getSdkData().getLocation(); - String zipAlignPath = sdkPath + File.separatorChar + AndroidSdkUtils.toolPath(SdkConstants.FN_ZIPALIGN); + String zipAlignPath = sdkPath + File.separatorChar + AndroidCommonUtils.toolPath(SdkConstants.FN_ZIPALIGN); File zipalign = new File(zipAlignPath); final boolean runZipAlign = zipalign.isFile(); File destFile = null; diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java index bc00911c7862..41b18b479b30 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java @@ -81,6 +81,7 @@ import org.jetbrains.android.resourceManagers.ResourceManager; import org.jetbrains.android.resourceManagers.SystemResourceManager; import org.jetbrains.android.sdk.*; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.android.util.ResourceEntry; import org.jetbrains.annotations.NotNull; @@ -392,7 +393,8 @@ public class AndroidFacet extends Facet { public void launchEmulator(@Nullable final String avdName, @NotNull final String commands, @Nullable ProcessHandler handler) { AndroidPlatform platform = getConfiguration().getAndroidPlatform(); if (platform != null) { - final String emulatorPath = platform.getSdkData().getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_EMULATOR); + final String emulatorPath = platform.getSdkData().getLocation() + File.separator + AndroidCommonUtils + .toolPath(SdkConstants.FN_EMULATOR); final GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.setExePath(FileUtil.toSystemDependentName(emulatorPath)); if (avdName != null) { diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java index 4c834de25152..40d6e70d5618 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java @@ -63,6 +63,7 @@ import org.jetbrains.android.run.testing.AndroidTestRunConfigurationType; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -218,7 +219,7 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { IAndroidTarget target = platform.getTarget(); final String androidToolPath = - platform.getSdkData().getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.androidCmdName()); + platform.getSdkData().getLocation() + File.separator + AndroidCommonUtils.toolPath(SdkConstants.androidCmdName()); if (!new File(androidToolPath).exists()) { return false; diff --git a/plugins/android/src/org/jetbrains/android/run/AvdChooser.java b/plugins/android/src/org/jetbrains/android/run/AvdChooser.java index aedabf9da3b4..7b7fa2d1e8df 100644 --- a/plugins/android/src/org/jetbrains/android/run/AvdChooser.java +++ b/plugins/android/src/org/jetbrains/android/run/AvdChooser.java @@ -30,6 +30,7 @@ import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.android.util.BooleanCellRenderer; import org.jetbrains.annotations.NotNull; @@ -71,7 +72,7 @@ public class AvdChooser extends DialogWrapper { AndroidSdkData sdkData = facet.getConfiguration().getAndroidSdk(); if (sdkData == null) return null; String androidCmd = SdkConstants.androidCmdName(); - return sdkData.getLocation() + File.separator + AndroidSdkUtils.toolPath(androidCmd); + return sdkData.getLocation() + File.separator + AndroidCommonUtils.toolPath(androidCmd); } public AvdChooser(@NotNull final Project project, diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java index e7e71b61bf4e..a55e43cf8812 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java @@ -300,7 +300,7 @@ public class AndroidSdkData { private String getAdbPath() { String path = getLocation() + File.separator + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + SdkConstants.FN_ADB; if (!new File(path).exists()) { - return getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_ADB); + return getLocation() + File.separator + AndroidCommonUtils.toolPath(SdkConstants.FN_ADB); } return path; } diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java index 812bf196a652..9ec7dcb35697 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java @@ -423,10 +423,6 @@ public class AndroidSdkUtils { }; } - public static String toolPath(@NotNull String toolFileName) { - return SdkConstants.OS_SDK_TOOLS_FOLDER + toolFileName; - } - @Nullable public static Sdk findAppropriateAndroidPlatform(@NotNull IAndroidTarget target, @NotNull AndroidSdkData sdkData) { for (Sdk library : ProjectJdkTable.getInstance().getAllJdks()) { From 29382675d513d24881623b7fe3a0de14191dd725 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 28 Feb 2012 19:35:40 +0400 Subject: [PATCH 38/43] android-jps: read APK_PATH, CUSTOM_DEBUG_KEYSTORE_PATH and LIBS_FOLDER_RELATIVE_PATH options --- .../src/org/jetbrains/jps/android/AndroidFacet.groovy | 9 +++++++++ .../org/jetbrains/jps/android/AndroidFacetType.groovy | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy index ab62251c4642..b2d76d583f29 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy @@ -23,6 +23,10 @@ class AndroidFacet extends Facet { boolean useCustomManifestForCompilation; boolean packTestCode; + String apkRelativePath; + String customDebugKeyStorePath; + String nativeLibsFolderRelativePath; + AndroidFacet(Module module, String name) { this.module = module this.name = name; @@ -54,6 +58,11 @@ class AndroidFacet extends Facet { return manifestFile != null ? manifestFile.getCanonicalFile() : null; } + File getNativeLibsDir() throws IOException { + def nativeLibsFolder = findFileByRelativeModulePath(nativeLibsFolderRelativePath, false); + return nativeLibsFolder != null ? nativeLibsFolder.getCanonicalFile() : null; + } + private File findFileByRelativeModulePath(String relativePath, boolean lookInContentRoot) { if (module.basePath != null) { def absPath = FileUtil.toSystemIndependentName(module.basePath + relativePath) diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy index e8a35c562df1..3fe084ef291a 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy @@ -4,6 +4,7 @@ import org.jetbrains.jps.MacroExpander import org.jetbrains.jps.Module import org.jetbrains.jps.idea.Facet import org.jetbrains.jps.idea.FacetTypeService +import org.jetbrains.jps.idea.IdeaProjectLoadingUtil /** * @author Eugene.Kudelevsky @@ -49,6 +50,16 @@ class AndroidFacetType extends FacetTypeService { break case "ASSETS_FOLDER_RELATIVE_PATH": facet.assetsFolderRelativePath = value + break + case "APK_PATH": + facet.apkRelativePath = value + break + case "CUSTOM_DEBUG_KEYSTORE_PATH": + facet.customDebugKeyStorePath = IdeaProjectLoadingUtil.pathFromUrl(value) + break + case "LIBS_FOLDER_RELATIVE_PATH": + facet.nativeLibsFolderRelativePath = value + break } } return facet; From d4266b854395518eb46427494a014cbd1d581762 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 28 Feb 2012 19:37:34 +0400 Subject: [PATCH 39/43] android-jps: support apk builder --- .../src/messages/AndroidJpsBundle.properties | 4 +- .../android/AndroidApkBuilderConfigState.java | 42 +++ .../AndroidApkBuilderConfigStateStorage.java | 38 +++ .../jps/android/AndroidDexBuilder.java | 14 +- .../jps/android/AndroidFileSetState.java | 28 +- .../jetbrains/jps/android/AndroidJpsUtil.java | 84 ++++- .../AndroidLibraryPackagingBuilder.java | 2 +- .../AndroidResourcePackagingBuilder.java | 290 ++++++++++++++---- .../AndroidSourceGeneratingBuilder.java | 42 +-- .../compiler/tools/AndroidApkBuilder.java | 4 +- .../compiler/ExcludedSourcesFilter.java | 2 +- 11 files changed, 426 insertions(+), 124 deletions(-) create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigState.java create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigStateStorage.java diff --git a/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties b/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties index a41ec5f6e526..0acb4f447d8c 100644 --- a/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties +++ b/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties @@ -13,4 +13,6 @@ android.jps.errors.package.not.specified=Package is not specified in AndroidMani android.jps.progress.library.packaging=Packaging Android libraries for module {0} android.jps.errors.main.content.root.not.found=Cannot find main content root for module {0} android.jps.progress.proguard=Executing ProGuard for module {0} -android.jps.progress.res.caching=Caching resources for module {0} \ No newline at end of file +android.jps.progress.res.caching=Caching resources for module {0} +android.jps.progress.packaging=Packaging {0} +android.jps.progress.packaging.resources=Packaging resources for module {0} \ No newline at end of file diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigState.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigState.java new file mode 100644 index 000000000000..0bc4758d373a --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigState.java @@ -0,0 +1,42 @@ +package org.jetbrains.jps.android; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.incremental.storage.ValidityState; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidApkBuilderConfigState implements ValidityState { + private final String myOutputApkPath; + private final String myCustomKeystorePath; + + public AndroidApkBuilderConfigState(@NotNull String outputApkPath, @NotNull String customKeystorePath) { + myOutputApkPath = outputApkPath; + myCustomKeystorePath = customKeystorePath; + } + + public AndroidApkBuilderConfigState(DataInput in) throws IOException { + myOutputApkPath = in.readUTF(); + myCustomKeystorePath = in.readUTF(); + } + + @Override + public boolean equalsTo(ValidityState otherState) { + if (!(otherState instanceof AndroidApkBuilderConfigState)) { + return false; + } + final AndroidApkBuilderConfigState apkBuilderConfigState = (AndroidApkBuilderConfigState)otherState; + return apkBuilderConfigState.myOutputApkPath.equals(myOutputApkPath) && + apkBuilderConfigState.myCustomKeystorePath.equals(myCustomKeystorePath); + } + + @Override + public void save(DataOutput out) throws IOException { + out.writeUTF(myOutputApkPath); + out.writeUTF(myCustomKeystorePath); + } +} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigStateStorage.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigStateStorage.java new file mode 100644 index 000000000000..06a43f38332d --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidApkBuilderConfigStateStorage.java @@ -0,0 +1,38 @@ +package org.jetbrains.jps.android; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.incremental.storage.AbstractStateStorage; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.File; +import java.io.IOException; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidApkBuilderConfigStateStorage extends AbstractStateStorage { + public AndroidApkBuilderConfigStateStorage(@NotNull File dataStorageRoot, @NotNull String storageName) throws IOException { + super(getStorageFile(dataStorageRoot, storageName), new EnumeratorStringDescriptor(), new MyDataExternalizer()); + } + + @NotNull + private static File getStorageFile(@NotNull File dataStorageRoot, @NotNull String storageName) { + return new File(new File(new File(dataStorageRoot, AndroidJpsUtil.ANDROID_STORAGE_DIR), storageName), storageName); + } + + private static class MyDataExternalizer implements DataExternalizer { + + @Override + public void save(DataOutput out, AndroidApkBuilderConfigState value) throws IOException { + value.save(out); + } + + @Override + public AndroidApkBuilderConfigState read(DataInput in) throws IOException { + return new AndroidApkBuilderConfigState(in); + } + } +} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java index 8cc59ebf9254..62c00c78e32b 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java @@ -146,7 +146,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { } } } - final AndroidFileSetState newState = new AndroidFileSetState(fileSet, AndroidJpsUtil.CLASSES_AND_JARS_FILTER); + final AndroidFileSetState newState = new AndroidFileSetState(fileSet, AndroidJpsUtil.CLASSES_AND_JARS_FILTER, true); if (context.isMake()) { final AndroidFileSetState oldState = dexStateStorage.getState(module.getName()); @@ -193,11 +193,11 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { return "Android Dex Builder"; } - public static boolean runDex(@NotNull AndroidSdk sdk, - @NotNull IAndroidTarget target, - @NotNull String outputDir, - @NotNull String[] compileTargets, - @NotNull CompileContext context) throws IOException { + private static boolean runDex(@NotNull AndroidSdk sdk, + @NotNull IAndroidTarget target, + @NotNull String outputDir, + @NotNull String[] compileTargets, + @NotNull CompileContext context) throws IOException { @SuppressWarnings("deprecation") final String dxJarPath = FileUtil.toSystemDependentName(target.getPath(IAndroidTarget.DX_JAR)); @@ -295,7 +295,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { allFiles.addAll(libClassFilesDirs); allFiles.addAll(externalJars); - final AndroidFileSetState newState = new AndroidFileSetState(allFiles, AndroidJpsUtil.CLASSES_AND_JARS_FILTER); + final AndroidFileSetState newState = new AndroidFileSetState(allFiles, AndroidJpsUtil.CLASSES_AND_JARS_FILTER, true); final AndroidFileSetState oldState = proguardStateStorage.getState(module.getName()); if (context.getTimestampStorage().getStamp(proguardCfgFile) == proguardCfgFile.lastModified() && newState.equalsTo(oldState)) { diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java index 17e5210c4452..4a6efad7f9f7 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFileSetState.java @@ -20,23 +20,29 @@ import java.util.Map; public class AndroidFileSetState implements ValidityState { private final Map myTimestamps; - public AndroidFileSetState(@NotNull Collection roots, @NotNull final Condition filter) { + public AndroidFileSetState(@NotNull Collection roots, @NotNull final Condition filter, boolean recursively) { myTimestamps = new HashMap(); - for (String resourceDir : roots) { - FileUtil.processFilesRecursively(new File(resourceDir), new Processor() { - @Override - public boolean process(File file) { - if (filter.value(file)) { - myTimestamps.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified()); + for (String rootPath : roots) { + final File root = new File(rootPath); + + if (recursively) { + FileUtil.processFilesRecursively(root, new Processor() { + @Override + public boolean process(File file) { + if (filter.value(file)) { + myTimestamps.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified()); + } + return true; } - return true; - } - }); + }); + } + else if (filter.value(root)) { + myTimestamps.put(FileUtil.toSystemIndependentName(root.getPath()), root.lastModified()); + } } } - public AndroidFileSetState(DataInput in) throws IOException { final int resourcesCount = in.readInt(); myTimestamps = new HashMap(resourcesCount); diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java index 3027a7b49e34..a8aada3c883f 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java @@ -116,6 +116,19 @@ class AndroidJpsUtil { return result; } + @NotNull + public static List toPaths(@NotNull Collection files) { + if (files.size() == 0) { + return Collections.emptyList(); + } + + final List result = new ArrayList(files.size()); + for (File file : files) { + result.add(file.getPath()); + } + return result; + } + @Nullable public static File getOutputDirectoryForPackagedFiles(@NotNull ProjectPaths paths, @NotNull Module module) { // todo: return build directory for mavenized modules to place .dex and .apk files into target dir (not target/classes) @@ -160,6 +173,7 @@ class AndroidJpsUtil { } if (libraries != null) { + // todo: do not include provided libs there for (ClasspathItem item : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE, exportedLibrariesOnly)) { if (item instanceof Library && !(item instanceof Sdk)) { for (String filePath : item.getClasspathRoots(ClasspathKind.PRODUCTION_COMPILE)) { @@ -190,7 +204,7 @@ class AndroidJpsUtil { if (depLibrary) { final File packagedClassesJar = new File(depClassDir, AndroidCommonUtils.CLASSES_JAR_FILE_NAME); - if (packagedClassesJar.isDirectory()) { + if (packagedClassesJar.isFile()) { outputDirs.add(packagedClassesJar.getPath()); } } @@ -412,4 +426,72 @@ class AndroidJpsUtil { final File androidStorage = new File(context.getDataManager().getDataStorageRoot(), ANDROID_STORAGE_DIR); return new File(new File(androidStorage, RESOURCE_CACHE_STORAGE), module.getName()); } + + private static void fillSourceRoots(@NotNull Module module, @NotNull Set visited, @NotNull Set result) + throws IOException { + visited.add(module); + final AndroidFacet facet = getFacet(module); + File resDir = null; + File resDirForCompilation = null; + + if (facet != null) { + resDir = facet.getResourceDir(); + resDirForCompilation = facet.getResourceDirForCompilation(); + } + + for (String sourceRootPath : module.getSourceRoots()) { + final File sourceRoot = new File(sourceRootPath).getCanonicalFile(); + + if (!sourceRoot.equals(resDir) && !sourceRoot.equals(resDirForCompilation)) { + result.add(sourceRoot); + } + } + + if (facet != null && facet.isPackTestCode()) { + for (String testRootPath : module.getTestRoots()) { + final File testRoot = new File(testRootPath).getCanonicalFile(); + + if (!testRoot.equals(resDir) && !testRoot.equals(resDirForCompilation)) { + result.add(testRoot); + } + } + } + + for (ClasspathItem classpathItem : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE)) { + if (classpathItem instanceof Module) { + final Module depModule = (Module)classpathItem; + + if (!visited.contains(depModule)) { + fillSourceRoots(depModule, visited, result); + } + } + } + } + + @NotNull + public static File[] getSourceRootsForModuleAndDependencies(@NotNull Module module) throws IOException { + Set result = new HashSet(); + fillSourceRoots(module, new HashSet(), result); + return result.toArray(new File[result.size()]); + } + + @Nullable + public static String getApkPath(@NotNull AndroidFacet facet, @NotNull File outputDirForPackagedArtifacts) { + final String apkRelativePath = facet.getApkRelativePath(); + final Module module = facet.getModule(); + + if (apkRelativePath.length() == 0) { + return new File(outputDirForPackagedArtifacts, getApkName(module)).getPath(); + } + final String moduleDirPath = module.getBasePath(); + + return moduleDirPath != null + ? FileUtil.toSystemDependentName(moduleDirPath + apkRelativePath) + : null; + } + + @NotNull + public static String getApkName(@NotNull Module module) { + return module.getName() + ".apk"; + } } diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java index 303cc2793b4a..0720446f5288 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidLibraryPackagingBuilder.java @@ -72,7 +72,7 @@ public class AndroidLibraryPackagingBuilder extends ModuleLevelBuilder { final Set subdirs = new HashSet(); AndroidJpsUtil.addSubdirectories(classesDir, subdirs); - final AndroidFileSetState newState = new AndroidFileSetState(subdirs, AndroidJpsUtil.CLASSES_AND_JARS_FILTER); + final AndroidFileSetState newState = new AndroidFileSetState(subdirs, AndroidJpsUtil.CLASSES_AND_JARS_FILTER, true); final AndroidFileSetState oldState = storage.getState(module.getName()); if (oldState != null && oldState.equalsTo(newState)) { diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java index 96cdbfeadf63..cf7bb6bacdb1 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java @@ -3,13 +3,20 @@ package org.jetbrains.jps.android; import com.android.sdklib.IAndroidTarget; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; +import org.jetbrains.android.compiler.tools.AndroidApkBuilder; import org.jetbrains.android.compiler.tools.AndroidApt; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.CompilerExcludes; import org.jetbrains.jps.Module; +import org.jetbrains.jps.Project; +import org.jetbrains.jps.ProjectPaths; import org.jetbrains.jps.incremental.CompileContext; import org.jetbrains.jps.incremental.ProjectBuildException; import org.jetbrains.jps.incremental.ProjectLevelBuilder; @@ -26,6 +33,8 @@ import java.util.*; */ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { @NonNls private static final String BUILDER_NAME = "android-packager"; + @NonNls private static final String RELEASE_SUFFIX = ".release"; + @NonNls private static final String UNSIGNED_SUFFIX = ".unsigned"; @Override public String getName() { @@ -53,7 +62,11 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { throw new ProjectBuildException(); } - if (!doPackaging(context, modules, resourcesStates, assetsStates)) { + if (!doResourcePackaging(context, modules, resourcesStates, assetsStates)) { + throw new ProjectBuildException(); + } + + if (!doPackaging(context, modules)) { throw new ProjectBuildException(); } } @@ -77,13 +90,13 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { final List resourceDirs = resourceDir != null ? Arrays.asList(resourceDir.getPath()) : Collections.emptyList(); - resourcesStates.put(module, new AndroidFileSetState(resourceDirs, Condition.TRUE)); + resourcesStates.put(module, new AndroidFileSetState(resourceDirs, Condition.TRUE, true)); final File assetsDir = facet.getAssetsDir(); final List assetDirs = assetsDir != null ? Arrays.asList(assetsDir.getPath()) : Collections.emptyList(); - assetsStates.put(module, new AndroidFileSetState(assetDirs, Condition.TRUE)); + assetsStates.put(module, new AndroidFileSetState(assetDirs, Condition.TRUE, true)); } } } @@ -121,17 +134,18 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { @Nullable AndroidFileSetState state) throws IOException { final AndroidFileSetState savedState = storage.getState(module.getName()); - if (savedState != null && savedState.equalsTo(state)) { + if (context.isMake() && savedState != null && savedState.equalsTo(state)) { return true; } - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO, - AndroidJpsBundle.message("android.jps.progress.res.caching", module.getName()))); final AndroidFacet facet = AndroidJpsUtil.getFacet(module); if (facet == null) { return true; } + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO, + AndroidJpsBundle.message("android.jps.progress.res.caching", module.getName()))); + final File resourceDir = AndroidJpsUtil.getResourceDirForCompilationPath(facet); if (resourceDir == null) { return true; @@ -164,54 +178,220 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { return success; } - private static boolean doPackaging(@NotNull CompileContext context, - @NotNull Collection modules, - @NotNull Map resourcesStates, - @NotNull Map assetsStates) throws IOException { + private static boolean doResourcePackaging(@NotNull CompileContext context, + @NotNull Collection modules, + @NotNull Map resourcesStates, + @NotNull Map assetsStates) throws IOException { boolean success = true; final File dataStorageRoot = context.getDataManager().getDataStorageRoot(); - AndroidFileSetStorage devResourcesStorage = null; - AndroidFileSetStorage releaseResourcesStorage = null; - AndroidFileSetStorage devAssetsStorage = null; - AndroidFileSetStorage releaseAssetsStorage = null; + final boolean releaseBuild = AndroidJpsUtil.isReleaseBuild(context); + AndroidFileSetStorage resourcesStorage = null; + AndroidFileSetStorage assetsStorage = null; try { - devResourcesStorage = new AndroidFileSetStorage(dataStorageRoot, "resources_packaging_dev"); - releaseResourcesStorage = new AndroidFileSetStorage(dataStorageRoot, "resources_packaging_release"); + final String resourcesStorageName = releaseBuild ? "resources_packaging_release" : "resources_packaging_dev"; + resourcesStorage = new AndroidFileSetStorage(dataStorageRoot, resourcesStorageName); - devAssetsStorage = new AndroidFileSetStorage(dataStorageRoot, "assets_packaging_dev"); - releaseAssetsStorage = new AndroidFileSetStorage(dataStorageRoot, "assets_packaging_release"); + final String assetsStorageName = releaseBuild ? "assets_packaging_release" : "assets_packaging_dev"; + assetsStorage = new AndroidFileSetStorage(dataStorageRoot, assetsStorageName); for (Module module : modules) { final AndroidFacet facet = AndroidJpsUtil.getFacet(module); - if (facet == null || facet.isLibrary()) { + if (facet == null) { continue; } - if (!packageResources(facet, context, devResourcesStorage, devAssetsStorage, releaseResourcesStorage, releaseAssetsStorage, - resourcesStates, assetsStates)) { + boolean updateState = true; + + if (!facet.isLibrary() && + !(context.isMake() && + checkUpToDate(module, resourcesStates, resourcesStorage) && + checkUpToDate(module, assetsStates, assetsStorage))) { + + updateState = packageResources(facet, context); + + if (!updateState) { + success = false; + } + } + resourcesStorage.update(module.getName(), updateState ? resourcesStates.get(module) : null); + assetsStorage.update(module.getName(), updateState ? assetsStates.get(module) : null); + } + } + finally { + if (resourcesStorage != null) { + resourcesStorage.close(); + } + + if (assetsStorage != null) { + assetsStorage.close(); + } + } + return success; + } + + private static boolean doPackaging(@NotNull CompileContext context, @NotNull Collection modules) throws IOException { + final boolean release = AndroidJpsUtil.isReleaseBuild(context); + final File dataStorageRoot = context.getDataManager().getDataStorageRoot(); + + boolean success = true; + + AndroidFileSetStorage apkFileSetStorage = null; + AndroidApkBuilderConfigStateStorage apkBuilderConfigStateStorage = null; + try { + final String apkFileSetStorageName = "apk_builder_file_set" + (release ? "_release" : "_dev"); + apkFileSetStorage = new AndroidFileSetStorage(dataStorageRoot, apkFileSetStorageName); + + final String apkBuilderStateStorageName = "apk_builder_config" + (release ? "_release" : "_dev"); + apkBuilderConfigStateStorage = new AndroidApkBuilderConfigStateStorage(dataStorageRoot, apkBuilderStateStorageName); + + for (Module module : modules) { + try { + if (!doPackagingForModule(context, module, apkFileSetStorage, apkBuilderConfigStateStorage, release)) { + success = false; + } + } + catch (IOException e) { + AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); success = false; } } } finally { - if (devResourcesStorage != null) { - devResourcesStorage.close(); + if (apkFileSetStorage != null) { + apkFileSetStorage.close(); } - if (releaseResourcesStorage != null) { - releaseResourcesStorage.close(); - } - if (devAssetsStorage != null) { - devAssetsStorage.close(); - } - if (releaseAssetsStorage != null) { - releaseAssetsStorage.close(); + + if (apkBuilderConfigStateStorage != null) { + apkBuilderConfigStateStorage.close(); } } + return success; } + private static boolean doPackagingForModule(@NotNull CompileContext context, + @NotNull Module module, + @NotNull AndroidFileSetStorage apkFileSetStorage, + @NotNull AndroidApkBuilderConfigStateStorage apkBuilderConfigStateStorage, + boolean release) throws IOException { + final AndroidFacet facet = AndroidJpsUtil.getFacet(module); + if (facet == null || facet.isLibrary()) { + return true; + } + + final String[] sourceRoots = AndroidJpsUtil.toPaths(AndroidJpsUtil.getSourceRootsForModuleAndDependencies(module)); + final ProjectPaths paths = context.getProjectPaths(); + + final File outputDir = AndroidJpsUtil.getOutputDirectoryForPackagedFiles(paths, module); + if (outputDir == null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, AndroidJpsBundle + .message("android.jps.errors.output.dir.not.specified", module.getName()))); + return false; + } + + final Pair pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME); + if (pair == null) { + return false; + } + + final Set externalJarsSet = AndroidJpsUtil.getExternalLibraries(paths, module); + final File resPackage = getPackagedResourcesFile(module, outputDir); + + final File classesDexFile = new File(outputDir.getPath(), AndroidCommonUtils.CLASSES_FILE_NAME); + + final String sdkPath = pair.getFirst().getSdkPath(); + final String outputPath = AndroidJpsUtil.getApkPath(facet, outputDir); + if (outputPath == null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + "Cannot compute output path for file " + AndroidJpsUtil.getApkName(module))); + return false; + } + final String customKeyStorePath = FileUtil.toSystemDependentName(facet.getCustomDebugKeyStorePath()); + final String[] nativeLibDirs = collectNativeLibsFolders(facet); + + final String resPackagePath = release ? resPackage.getPath() + RELEASE_SUFFIX : resPackage.getPath(); + final String outputApkPath = release ? outputPath + UNSIGNED_SUFFIX : outputPath; + final String classesDexFilePath = classesDexFile.getPath(); + final String[] externalJars = ArrayUtil.toStringArray(externalJarsSet); + + final AndroidFileSetState currentFileSetState = + buildCurrentApkBuilderState(context.getProject(), resPackagePath, classesDexFilePath, nativeLibDirs, + sourceRoots, externalJars, release); + + final AndroidApkBuilderConfigState currentApkBuilderConfigState = + new AndroidApkBuilderConfigState(outputApkPath, customKeyStorePath); + + final AndroidFileSetState savedApkFileSetState = apkFileSetStorage.getState(module.getName()); + final AndroidApkBuilderConfigState savedApkBuilderConfigState = apkBuilderConfigStateStorage.getState(module.getName()); + + if (context.isMake() && + currentFileSetState.equalsTo(savedApkFileSetState) && + currentApkBuilderConfigState.equalsTo(savedApkBuilderConfigState)) { + return true; + } + context + .processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.packaging", AndroidJpsUtil.getApkName(module)))); + + final Map> messages = AndroidApkBuilder + .execute(resPackagePath, classesDexFilePath, sourceRoots, externalJars, nativeLibDirs, outputApkPath, + release, sdkPath, customKeyStorePath, new MyExcludedSourcesFilter(context.getProject())); + + AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME); + final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).isEmpty(); + + apkFileSetStorage.update(module.getName(), success ? currentFileSetState : null); + apkBuilderConfigStateStorage.update(module.getName(), success ? currentApkBuilderConfigState : null); + return success; + } + + @SuppressWarnings("unchecked") + private static AndroidFileSetState buildCurrentApkBuilderState(@NotNull Project project, + @NotNull String resPackagePath, + @NotNull String classesDexFilePath, + @NotNull String[] nativeLibDirs, + @NotNull String[] sourceRoots, + @NotNull String[] externalJars, + boolean release) { + final List roots = new ArrayList(); + roots.add(resPackagePath); + roots.add(classesDexFilePath); + roots.addAll(Arrays.asList(externalJars)); + + for (String sourceRootPath : sourceRoots) { + final List files = new ArrayList(); + AndroidApkBuilder.collectStandardSourceFolderResources(new File(sourceRootPath), files, new MyExcludedSourcesFilter(project)); + roots.addAll(AndroidJpsUtil.toPaths(files)); + } + + for (String nativeLibDir : nativeLibDirs) { + final List files = new ArrayList(); + AndroidApkBuilder.collectNativeLibraries(new File(nativeLibDir), files, !release); + roots.addAll(AndroidJpsUtil.toPaths(files)); + } + + return new AndroidFileSetState(roots, Condition.TRUE, false); + } + + @NotNull + private static String[] collectNativeLibsFolders(@NotNull AndroidFacet facet) throws IOException { + final List result = new ArrayList(); + final File libsDir = facet.getNativeLibsDir(); + + if (libsDir != null) { + result.add(libsDir.getPath()); + } + + for (AndroidFacet depFacet : AndroidJpsUtil.getAllDependentAndroidLibraries(facet.getModule())) { + final File depLibsDir = depFacet.getNativeLibsDir(); + if (depLibsDir != null) { + result.add(depLibsDir.getPath()); + } + } + return ArrayUtil.toStringArray(result); + } + private static boolean checkUpToDate(@NotNull Module module, @NotNull Map module2state, @NotNull AndroidFileSetStorage storage) throws IOException { @@ -233,26 +413,11 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { return true; } - private static boolean packageResources(@NotNull AndroidFacet facet, - @NotNull CompileContext context, - @NotNull AndroidFileSetStorage devResourcesStorage, - @NotNull AndroidFileSetStorage devAssetsStorage, - @NotNull AndroidFileSetStorage releaseResourcesStorage, - @NotNull AndroidFileSetStorage releaseAssetsStorage, - @NotNull Map resourcesStates, - @NotNull Map assetsStates) { + private static boolean packageResources(@NotNull AndroidFacet facet, @NotNull CompileContext context) { final Module module = facet.getModule(); - final boolean releaseBuild = AndroidJpsUtil.isReleaseBuild(context); - final AndroidFileSetStorage resourcesStorage = releaseBuild ? releaseResourcesStorage : devResourcesStorage; - final AndroidFileSetStorage assetsStorage = releaseBuild ? releaseAssetsStorage : devAssetsStorage; - try { - if (checkUpToDate(module, resourcesStates, resourcesStorage) && - checkUpToDate(module, assetsStates, assetsStorage)) { - return true; - } - context.processMessage(new ProgressMessage("Packaging resources for module " + module.getName())); + context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.packaging.resources", module.getName()))); final File manifestFile = AndroidJpsUtil.getManifestFileForCompilationPath(facet); if (manifestFile == null) { @@ -275,18 +440,12 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { } final IAndroidTarget target = pair.getSecond(); - final String outputFilePath = getOutputFile(module, outputDir).getPath(); + final String outputFilePath = getPackagedResourcesFile(module, outputDir).getPath(); final String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null; final String[] resourceDirPaths = AndroidJpsUtil.collectResourceDirsForCompilation(facet, true, context); - if (!doPackageResources(context, manifestFile, target, resourceDirPaths, assetsDirPath, outputFilePath, releaseBuild)) { - resourcesStorage.update(module.getName(), null); - assetsStorage.update(module.getName(), null); - return false; - } - resourcesStorage.update(module.getName(), resourcesStates.get(module)); - assetsStorage.update(module.getName(), assetsStates.get(module)); - return true; + return doPackageResources(context, manifestFile, target, resourceDirPaths, assetsDirPath, outputFilePath, + AndroidJpsUtil.isReleaseBuild(context)); } catch (IOException e) { AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); @@ -303,7 +462,7 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { boolean releasePackage) { try { final String outputPath = releasePackage - ? outputFilePath + ".release" + ? outputFilePath + RELEASE_SUFFIX : outputFilePath; final Map> messages = AndroidApt .packageResources(target, -1, manifestFile.getPath(), resourceDirPaths, assetsDirPath, outputPath, null, !releasePackage, 0); @@ -318,7 +477,20 @@ public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { } @NotNull - static File getOutputFile(@NotNull Module module, @NotNull File outputDir) { + private static File getPackagedResourcesFile(@NotNull Module module, @NotNull File outputDir) { return new File(outputDir.getPath(), module.getName() + ".apk.res"); } + + private static class MyExcludedSourcesFilter implements Condition { + private final CompilerExcludes myExcludes; + + public MyExcludedSourcesFilter(@NotNull Project project) { + myExcludes = project.getCompilerConfiguration().getExcludes(); + } + + @Override + public boolean value(File file) { + return !myExcludes.isExcluded(file); + } + } } diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java index 0a5772e09cb8..8a7068105be8 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java @@ -18,8 +18,6 @@ import org.jetbrains.android.util.ValueResourcesFileParser; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.ClasspathItem; -import org.jetbrains.jps.ClasspathKind; import org.jetbrains.jps.Module; import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.incremental.*; @@ -153,7 +151,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final IAndroidTarget target = moduleData.getAndroidTarget(); try { - final File[] sourceRoots = getSourceRootsForModuleAndDependencies(module); + final File[] sourceRoots = AndroidJpsUtil.getSourceRootsForModuleAndDependencies(module); final String[] sourceRootPaths = AndroidJpsUtil.toPaths(sourceRoots); final String packageName = computePackageForFile(context, file); @@ -569,44 +567,6 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { return FileUtil.toSystemIndependentName(relPath).replace('/', '.'); } - private static void fillSourceRoots(@NotNull Module module, @NotNull Set visited, @NotNull Set result) - throws IOException { - visited.add(module); - final AndroidFacet facet = AndroidJpsUtil.getFacet(module); - File resDir = null; - File resDirForCompilation = null; - - if (facet != null) { - resDir = facet.getResourceDir(); - resDirForCompilation = facet.getResourceDirForCompilation(); - } - - for (String sourceRootPath : module.getSourceRoots()) { - final File sourceRoot = new File(sourceRootPath).getCanonicalFile(); - - if (!sourceRoot.equals(resDir) && !sourceRoot.equals(resDirForCompilation)) { - result.add(sourceRoot); - } - } - - for (ClasspathItem classpathItem : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE)) { - if (classpathItem instanceof Module) { - final Module depModule = (Module)classpathItem; - - if (!visited.contains(depModule)) { - fillSourceRoots(depModule, visited, result); - } - } - } - } - - @NotNull - public static File[] getSourceRootsForModuleAndDependencies(@NotNull Module module) throws IOException { - Set result = new HashSet(); - fillSourceRoots(module, new HashSet(), result); - return result.toArray(new File[result.size()]); - } - @Override public String getDescription() { return "Android Source Generating Builder"; diff --git a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index 16fadec427af..70daf97f8e74 100644 --- a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -384,11 +384,11 @@ public class AndroidApkBuilder { for (File child : children) { if (child.exists()) { if (child.isDirectory()) { - if (JavaResourceFilter.checkFolderForPackaging(child.getName()) && !filter.value(child)) { + if (JavaResourceFilter.checkFolderForPackaging(child.getName()) && filter.value(child)) { collectStandardSourceFolderResources(child, result, filter); } } - else if (checkFileForPackaging(child) && !filter.value(child)) { + else if (checkFileForPackaging(child) && filter.value(child)) { result.add(child); } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java b/plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java index 0b5d756cf6d7..1d3a8db262bf 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java +++ b/plugins/android/src/org/jetbrains/android/compiler/ExcludedSourcesFilter.java @@ -18,6 +18,6 @@ class ExcludedSourcesFilter implements Condition { @Override public boolean value(File file) { - return AndroidCompileUtil.isExcludedFromCompilation(file, myProject); + return !AndroidCompileUtil.isExcludedFromCompilation(file, myProject); } } From 2c8169e36608fe502a3e940f4696fcd3830b52b8 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 28 Feb 2012 19:39:03 +0400 Subject: [PATCH 40/43] rename AndroidResourcePackagingBuilder -> AndroidPackagingBuilder --- .../src/org/jetbrains/jps/android/AndroidBuilderService.java | 2 +- ...sourcePackagingBuilder.java => AndroidPackagingBuilder.java} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename plugins/android/jps-plugin/src/org/jetbrains/jps/android/{AndroidResourcePackagingBuilder.java => AndroidPackagingBuilder.java} (99%) diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java index 39d38ef9bcdb..9a3bc389b6ea 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java @@ -24,6 +24,6 @@ public class AndroidBuilderService extends BuilderService { @Override public List createProjectLevelBuilders() { return Arrays.asList(new AndroidDexBuilder(), - new AndroidResourcePackagingBuilder()); + new AndroidPackagingBuilder()); } } diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidPackagingBuilder.java similarity index 99% rename from plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java rename to plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidPackagingBuilder.java index cf7bb6bacdb1..276f45c32357 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidResourcePackagingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidPackagingBuilder.java @@ -31,7 +31,7 @@ import java.util.*; /** * @author Eugene.Kudelevsky */ -public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder { +public class AndroidPackagingBuilder extends ProjectLevelBuilder { @NonNls private static final String BUILDER_NAME = "android-packager"; @NonNls private static final String RELEASE_SUFFIX = ".release"; @NonNls private static final String UNSIGNED_SUFFIX = ".unsigned"; From 095b65512ab1618ec6fcec56afb0d90cbe1650c1 Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Tue, 28 Feb 2012 16:46:34 +0400 Subject: [PATCH 41/43] Add button to run interactive console. --- .../plugins/groovy/mvc/MvcFramework.java | 7 ++++ .../groovy/mvc/MvcRunTargetDialog.java | 41 ++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java index c92d5b61b675..8b0510528336 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java @@ -115,6 +115,13 @@ public abstract class MvcFramework { } } + public boolean isInteractiveConsoleSupport(@NotNull Module module) { + return false; + } + + public void runInteractiveConsole(@NotNull Module module) { + throw new UnsupportedOperationException(); + } public abstract void upgradeFramework(@NotNull Module module); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.java index f9c4ff502463..f6a802abc6c7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcRunTargetDialog.java @@ -54,15 +54,49 @@ public class MvcRunTargetDialog extends DialogWrapper { private ComboBox myTargetField; private Module myModule; - public MvcRunTargetDialog(@NotNull Module module, MvcFramework framework) { + private final MvcFramework myFramework; + + private Action myInteractiveRunAction; + + public MvcRunTargetDialog(@NotNull Module module, @NotNull MvcFramework framework) { super(module.getProject(), true); myModule = module; + myFramework = framework; setTitle("Run " + framework.getDisplayName() + " target"); setUpDialog(); setModal(true); init(); } + @Override + protected Action[] createLeftSideActions() { + boolean hasOneSupportedModule = false; + for (Module module : ModuleManager.getInstance(myModule.getProject()).getModules()) { + if (module == myModule || myFramework.hasSupport(module)) { + if (myFramework.isInteractiveConsoleSupport(module)) { + hasOneSupportedModule = true; + break; + } + } + } + + if (hasOneSupportedModule) { + myInteractiveRunAction = new DialogWrapperAction("&Run Interactive Console") { + @Override + protected void doAction(ActionEvent e) { + myFramework.runInteractiveConsole(getSelectedModule()); + doCancelAction(); + } + }; + + myInteractiveRunAction.setEnabled(myFramework.isInteractiveConsoleSupport(myModule)); + + return new Action[]{myInteractiveRunAction}; + } + + return new Action[0]; + } + private void setUpDialog() { myTargetLabel.setLabelFor(myTargetField); myTargetField.setFocusable(true); @@ -72,7 +106,7 @@ public class MvcRunTargetDialog extends DialogWrapper { List mvcModules = new ArrayList(); for (Module module : ModuleManager.getInstance(myModule.getProject()).getModules()) { - if (module == myModule || MvcFramework.getInstance(module) != null) { + if (module == myModule || myFramework.hasSupport(module)) { mvcModules.add(module); } } @@ -85,6 +119,9 @@ public class MvcRunTargetDialog extends DialogWrapper { @Override public void actionPerformed(ActionEvent e) { myModule = (Module)myModuleBox.getSelectedItem(); + if (myInteractiveRunAction != null) { + myInteractiveRunAction.setEnabled(myFramework.isInteractiveConsoleSupport(myModule)); + } } }); From a8ba60bfe0ad60e68afa34996f5304fe970fa768 Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Tue, 28 Feb 2012 20:00:45 +0400 Subject: [PATCH 42/43] Bug fix: Optimize imports invoked on directory reformats entire project. --- .../com/intellij/codeInsight/actions/OptimizeImportsAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/OptimizeImportsAction.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/OptimizeImportsAction.java index 416e2e4bc09b..2b162e02c80e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/OptimizeImportsAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/OptimizeImportsAction.java @@ -107,7 +107,7 @@ public class OptimizeImportsAction extends AnAction { if (ApplicationManager.getApplication().isUnitTestMode()) { includeSubdirectories = processDirectory = false; } - else if (!EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG) { + else if (!EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG && file != null) { includeSubdirectories = processDirectory = false; } else { From 433aeadc0d3d327adfd3603e5df3d44af6a81bf5 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 28 Feb 2012 17:48:01 +0100 Subject: [PATCH 43/43] resize problems --- .../src/com/intellij/openapi/ui/DialogWrapper.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index 8ddf512c3376..4d04608abd92 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -142,6 +142,7 @@ public abstract class DialogWrapper { }; private List myOptionsButtons = new ArrayList(); private int myCurrentOptionsButtonIndex = -1; + private boolean myResizeInProgress = false; protected String getDoNotShowMessage() { return CommonBundle.message("dialog.options.do.not.show"); @@ -167,6 +168,14 @@ public abstract class DialogWrapper { */ protected DialogWrapper(Project project, boolean canBeParent) { myPeer = createPeer(project, canBeParent); + myPeer.getWindow().addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + if (!myResizeInProgress) { + myActualSize = myPeer.getSize(); + } + } + }); createDefaultActions(); } @@ -1611,8 +1620,10 @@ public abstract class DialogWrapper { private void resizeWithAnimation(final Dimension size) { //todo[kb]: fix this PITA + myResizeInProgress = true; if (!Registry.is("enable.animation.on.dialogs")) { setSize(size.width, size.height); + myResizeInProgress = false; return; } @@ -1637,6 +1648,7 @@ public abstract class DialogWrapper { if (myErrorText.shouldBeVisible()) { myErrorText.setVisible(true); } + myResizeInProgress = false; } }.start(); }