blob: 78c9e2cac3a09f30f53acc4464bfaf7cb130f759 [file] [log] [blame]
/*
* Copyright 2000-2009 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.impl;
import com.intellij.notification.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import java.util.*;
public abstract class GenericNotifierImpl<T, Key> {
private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.GenericNotifier");
protected final Project myProject;
@NotNull
private final String myGroupId; //+- here
@NotNull
private final String myTitle;
@NotNull
private final NotificationType myType;
@NotNull
private final Map<Key, MyNotification> myState;
private final MyListener myListener;
private final Object myLock;
protected GenericNotifierImpl(final Project project, @NotNull String groupId, @NotNull String title, final @NotNull NotificationType type) {
myGroupId = groupId;
myTitle = title;
myType = type;
myProject = project;
myState = new HashMap<Key, MyNotification>();
myListener = new MyListener();
myLock = new Object();
}
protected abstract boolean ask(final T obj, String description);
@NotNull
protected abstract Key getKey(final T obj);
@NotNull
protected abstract String getNotificationContent(final T obj);
protected Collection<Key> getAllCurrentKeys() {
synchronized (myLock) {
return new ArrayList<Key>(myState.keySet());
}
}
protected boolean getStateFor(final Key key) {
synchronized (myLock) {
return myState.containsKey(key);
}
}
public void clear() {
final List<MyNotification> notifications;
synchronized (myLock) {
notifications = new ArrayList<MyNotification>(myState.values());
myState.clear();
}
final Application application = ApplicationManager.getApplication();
final Runnable runnable = new Runnable() {
public void run() {
for (MyNotification notification : notifications) {
notification.expire();
}
}
};
if (application.isDispatchThread()) {
runnable.run();
} else {
application.invokeLater(runnable, ModalityState.NON_MODAL, myProject.getDisposed());
}
}
private void expireNotification(final MyNotification notification) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void run() {
notification.expire();
}
});
}
public boolean ensureNotify(final T obj) {
final MyNotification notification;
synchronized (myLock) {
final Key key = getKey(obj);
if (myState.containsKey(key)) {
return false;
}
notification = new MyNotification(myGroupId, myTitle, getNotificationContent(obj), myType, myListener, obj);
myState.put(key, notification);
}
final boolean state = onFirstNotification(obj);
if (state) {
removeLazyNotification(obj);
return true;
}
Notifications.Bus.notify(notification, myProject);
return false;
}
protected boolean onFirstNotification(T obj) {
return false;
}
public void removeLazyNotificationByKey(final Key key) {
final MyNotification notification;
synchronized (myLock) {
notification = myState.get(key);
if (notification != null) {
myState.remove(key);
}
}
if (notification != null) {
expireNotification(notification);
}
}
public void removeLazyNotification(final T obj) {
final MyNotification notification;
synchronized (myLock) {
final Key key = getKey(obj);
notification = myState.get(key);
if (notification != null) {
myState.remove(key);
}
}
if (notification != null) {
expireNotification(notification);
}
}
private class MyListener implements NotificationListener {
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
final MyNotification concreteNotification = (MyNotification) notification;
final T obj = concreteNotification.getObj();
final boolean state = ask(obj, event.getDescription());
if (state) {
synchronized (myLock) {
final Key key = getKey(obj);
myState.remove(key);
}
expireNotification(concreteNotification);
}
}
}
@Nullable
protected T getObj(final Key key) {
synchronized (myLock) {
final MyNotification notification = myState.get(key);
return notification == null ? null : notification.getObj();
}
}
protected class MyNotification extends Notification {
private final T myObj;
protected MyNotification(@NotNull String groupId,
@NotNull String title,
@NotNull String content,
@NotNull NotificationType type,
@Nullable NotificationListener listener,
@NotNull final T obj) {
super(groupId, title, content, type, listener);
myObj = obj;
}
public T getObj() {
return myObj;
}
@Override
public void expire() {
super.expire();
synchronized (myLock) {
myState.remove(getKey(myObj));
}
}
}
private static void log(final String s) {
LOG.debug(s);
}
public boolean isEmpty() {
synchronized (myLock) {
return myState.isEmpty();
}
}
}