ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / UpdateRequestsQueue.java
blob29cbfd9429106085a8da7c389ab0177f7a987595
1 /*
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.vcs.changes;
18 import com.intellij.ide.startup.impl.StartupManagerImpl;
19 import com.intellij.lifecycle.ControlledAlarmFactory;
20 import com.intellij.lifecycle.ScheduledSlowlyClosingAlarm;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.application.ModalityState;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.progress.SomeQueue;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.startup.StartupManager;
27 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
28 import com.intellij.util.Consumer;
30 import javax.swing.*;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.concurrent.ScheduledExecutorService;
35 /**
36 * ChangeListManager updates scheduler.
37 * Tries to zip several update requests into one (if starts and see several requests in the queue)
38 * own inner synchronization
40 @SomeQueue
41 public class UpdateRequestsQueue {
42 private final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.UpdateRequestsQueue");
43 private final Project myProject;
44 private final LocalChangesUpdater myDelegate;
45 private final Object myLock;
46 private volatile boolean myStarted;
47 private volatile boolean myStopped;
49 private boolean myRequestSubmitted;
50 private final List<Runnable> myWaitingUpdateCompletionQueue;
51 private final ProjectLevelVcsManager myPlVcsManager;
52 private boolean myUpdateUnversionedRequested;
53 private final ScheduledSlowlyClosingAlarm mySharedExecutor;
54 private final StartupManager myStartupManager;
56 public UpdateRequestsQueue(final Project project, final ScheduledExecutorService executor, final LocalChangesUpdater delegate) {
57 mySharedExecutor = ControlledAlarmFactory.createScheduledOnSharedThread(project, "Local changes update", executor);
59 myDelegate = delegate;
60 myProject = project;
61 myPlVcsManager = ProjectLevelVcsManager.getInstance(myProject);
62 myStartupManager = StartupManager.getInstance(myProject);
63 myLock = new Object();
64 myWaitingUpdateCompletionQueue = new ArrayList<Runnable>();
65 // not initialized
66 myStarted = false;
67 myStopped = false;
68 myUpdateUnversionedRequested = false;
71 public void initialized() {
72 LOG.debug("Initialized for project: " + myProject.getName());
73 myStarted = true;
76 public boolean isStopped() {
77 return myStopped;
80 public void schedule(final boolean updateUnversionedFiles) {
81 synchronized (myLock) {
82 if (! myStarted && ApplicationManager.getApplication().isUnitTestMode()) return;
84 if (! myStopped) {
85 if (! myRequestSubmitted) {
86 final MyRunnable runnable = new MyRunnable();
87 myRequestSubmitted = true;
88 mySharedExecutor.addRequest(runnable, 300);
89 LOG.debug("Scheduled for project: " + myProject.getName() + ", runnable: " + runnable.hashCode());
90 myUpdateUnversionedRequested |= updateUnversionedFiles;
91 } else if (updateUnversionedFiles && (! myUpdateUnversionedRequested)) {
92 myUpdateUnversionedRequested = true;
98 public void stop() {
99 LOG.debug("Calling stop for project: " + myProject.getName());
100 final List<Runnable> waiters = new ArrayList<Runnable>(myWaitingUpdateCompletionQueue.size());
101 synchronized (myLock) {
102 myStopped = true;
103 waiters.addAll(myWaitingUpdateCompletionQueue);
104 myWaitingUpdateCompletionQueue.clear();
106 LOG.debug("Calling runnables in stop for project: " + myProject.getName());
107 // do not run under lock
108 for (Runnable runnable : waiters) {
109 runnable.run();
111 LOG.debug("Stop finished for project: " + myProject.getName());
114 public void invokeAfterUpdate(final Runnable afterUpdate, final InvokeAfterUpdateMode mode, final String title,
115 final Consumer<VcsDirtyScopeManager> dirtyScopeManagerFiller, final ModalityState state) {
116 LOG.debug("invokeAfterUpdate for project: " + myProject.getName());
117 final CallbackData data = CallbackData.create(afterUpdate, title, state, mode, myProject);
119 VcsDirtyScopeManagerProxy managerProxy = null;
120 if (dirtyScopeManagerFiller != null) {
121 managerProxy = new VcsDirtyScopeManagerProxy();
122 dirtyScopeManagerFiller.consume(managerProxy);
125 synchronized (myLock) {
126 if (! myStopped) {
127 if (managerProxy != null) {
128 managerProxy.callRealManager(VcsDirtyScopeManager.getInstance(myProject));
131 myWaitingUpdateCompletionQueue.add(data.getCallback());
132 schedule(true);
135 // do not run under lock; stopped cannot be switched into not stopped - can check without lock
136 if (myStopped) {
137 LOG.debug("invokeAfterUpdate: stopped, invoke right now for project: " + myProject.getName());
138 SwingUtilities.invokeLater(new Runnable() {
139 public void run() {
140 afterUpdate.run();
143 return;
144 } else {
145 // invoke progress if needed
146 if (data.getWrapperStarter() != null) {
147 data.getWrapperStarter().run();
150 LOG.debug("invokeAfterUpdate: exit for project: " + myProject.getName());
153 private class MyRunnable implements Runnable {
154 public void run() {
155 boolean updateUnversioned;
156 final List<Runnable> copy = new ArrayList<Runnable>(myWaitingUpdateCompletionQueue.size());
158 try {
159 synchronized (myLock) {
160 if ((! myStopped) && ((! myStarted) || myPlVcsManager.isBackgroundVcsOperationRunning()) ||
161 (! ((StartupManagerImpl) myStartupManager).startupActivityPassed())) {
162 LOG.debug("MyRunnable: not started, not stopped, reschedule, project: " + myProject.getName() + ", runnable: " + hashCode());
163 myRequestSubmitted = false;
164 // try again after time
165 schedule(myUpdateUnversionedRequested);
166 return;
169 copy.addAll(myWaitingUpdateCompletionQueue);
170 myRequestSubmitted = false;
172 if (myStopped) {
173 LOG.debug("MyRunnable: STOPPED, project: " + myProject.getName() + ", runnable: " + hashCode());
174 return;
177 // take it under lock
178 updateUnversioned = myUpdateUnversionedRequested;
179 // for concurrent schedules to tigger flag correctly
180 myUpdateUnversionedRequested = false;
183 LOG.debug("MyRunnable: INVOKE, project: " + myProject.getName() + ", runnable: " + hashCode());
184 myDelegate.execute(updateUnversioned, mySharedExecutor);
185 LOG.debug("MyRunnable: invokeD, project: " + myProject.getName() + ", runnable: " + hashCode());
186 } finally {
187 synchronized (myLock) {
188 LOG.debug("MyRunnable: delete executed, project: " + myProject.getName() + ", runnable: " + hashCode());
189 if (! copy.isEmpty()) {
190 myWaitingUpdateCompletionQueue.removeAll(copy);
193 if ((! myWaitingUpdateCompletionQueue.isEmpty()) && (! myRequestSubmitted)) {
194 LOG.error("No update task to handle request(s)");
197 // do not run under lock
198 for (Runnable runnable : copy) {
199 runnable.run();
201 LOG.debug("MyRunnable: Runnables executed, project: " + myProject.getName() + ", runnable: " + hashCode());