2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.wm
.impl
;
18 import com
.intellij
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.application
.ModalityState
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.util
.Condition
;
22 import com
.intellij
.openapi
.wm
.impl
.commands
.FinalizableCommand
;
23 import org
.jetbrains
.annotations
.NotNull
;
24 import org
.jetbrains
.annotations
.Nullable
;
26 import java
.util
.ArrayList
;
27 import java
.util
.List
;
29 public final class CommandProcessor
implements Runnable
{
30 private static final Logger LOG
= Logger
.getInstance("#com.intellij.openapi.wm.impl.CommandProcessor");
31 private final Object myLock
= new Object();
33 private final List
<CommandGroup
> myCommandGroupList
= new ArrayList
<CommandGroup
>();
34 private int myCommandCount
;
36 public final int getCommandCount() {
37 synchronized (myLock
) {
38 return myCommandCount
;
43 * Executes passed batch of commands. Note, that the processor surround the
44 * commands with BlockFocusEventsCmd - UnbockFocusEventsCmd. It's required to
45 * prevent focus handling of events which is caused by the commands to be executed.
47 public final void execute(@NotNull List
<FinalizableCommand
> commandList
, @NotNull Condition expired
) {
48 synchronized (myLock
) {
49 final boolean isBusy
= myCommandCount
> 0;
51 final CommandGroup commandGroup
= new CommandGroup(commandList
, expired
);
52 myCommandGroupList
.add(commandGroup
);
53 myCommandCount
+= commandList
.size();
61 public final void run() {
62 synchronized (myLock
) {
63 final CommandGroup commandGroup
= getNextCommandGroup();
64 if (commandGroup
== null || commandGroup
.isEmpty()) return;
66 final Condition conditionForGroup
= commandGroup
.getExpireCondition();
68 final FinalizableCommand command
= commandGroup
.takeNextCommand();
71 final Condition expire
= command
.getExpireCondition() != null ? command
.getExpireCondition() : conditionForGroup
;
73 if (LOG
.isDebugEnabled()) {
74 LOG
.debug("CommandProcessor.run " + command
);
76 // max. I'm not actually quite sure this should have NON_MODAL modality but it should
77 // definitely have some since runnables in command list may (and do) request some PSI activity
78 final boolean queueNext
= myCommandCount
> 0;
79 ApplicationManager
.getApplication().getInvokator().invokeLater(command
, ModalityState
.NON_MODAL
, expire
== null ? Condition
.FALSE
: expire
).doWhenDone(new Runnable() {
82 CommandProcessor
.this.run();
90 private CommandGroup
getNextCommandGroup() {
91 while (!myCommandGroupList
.isEmpty()) {
92 final CommandGroup candidate
= myCommandGroupList
.get(0);
93 if (!candidate
.isEmpty()) {
96 myCommandGroupList
.remove(candidate
);
102 private static class CommandGroup
{
103 private final List
<FinalizableCommand
> myList
;
104 private Condition myExpireCondition
;
106 private CommandGroup(@NotNull List
<FinalizableCommand
> list
, @NotNull Condition expireCondition
) {
108 myExpireCondition
= expireCondition
;
111 public Condition
getExpireCondition() {
112 return myExpireCondition
;
115 public boolean isEmpty() {
116 return myList
.isEmpty();
119 public FinalizableCommand
takeNextCommand() {
120 FinalizableCommand command
= myList
.remove(0);
122 // memory leak otherwise
123 myExpireCondition
= Condition
.TRUE
;