Merge branch 'master' of git.labs.intellij.net:idea/community
[idea/community.git] / platform / platform-impl / src / com / intellij / notification / impl / NotificationModel.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.notification.impl;
17
18 import com.intellij.notification.Notification;
19 import com.intellij.notification.NotificationType;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.util.Pair;
22 import com.intellij.util.PairFunction;
23 import com.intellij.util.containers.ContainerUtil;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26
27 import java.lang.reflect.Array;
28 import java.util.*;
29
30 /**
31  * @author spleaner
32  */
33 public class NotificationModel {
34
35   private final Map<Notification, Pair<Project, Boolean>> myNotifications = new LinkedHashMap<Notification, Pair<Project, Boolean>>();
36   private final List<NotificationModelListener> myListeners = ContainerUtil.createEmptyCOWList();
37
38   public void addListener(@NotNull final NotificationModelListener listener) {
39     myListeners.add(listener);
40   }
41
42   public void removeListener(@NotNull final NotificationModelListener listener) {
43     myListeners.remove(listener);
44   }
45
46   public void add(@NotNull final Notification notification, final @Nullable Project project) {
47     myNotifications.put(notification, Pair.create(project, false));
48     for (NotificationModelListener listener : myListeners) {
49       listener.notificationsAdded(notification);
50     }
51   }
52
53   public void markRead() {
54     if (myNotifications.size() > 0) {
55       final Collection<Notification> tba = myNotifications.keySet();
56       for (final Map.Entry<Notification, Pair<Project, Boolean>> entry : myNotifications.entrySet()) {
57         entry.setValue(new Pair<Project, Boolean>(entry.getValue().first, true));
58       }
59
60       for (final NotificationModelListener listener : myListeners) {
61         listener.notificationsRead(tba.toArray(new Notification[tba.size()]));
62       }
63     }
64   }
65
66   @Nullable
67   public Notification remove(@NotNull final Notification notification) {
68     if (myNotifications.containsKey(notification)) {
69       myNotifications.remove(notification);
70
71       for (NotificationModelListener listener : myListeners) {
72         listener.notificationsRemoved(notification);
73       }
74     }
75
76     return notification;
77   }
78
79   public void remove(@NotNull final Notification... notifications) {
80     final List<Notification> tbr = new ArrayList<Notification>();
81     for (final Notification notification : notifications) {
82       if (myNotifications.containsKey(notification)) {
83         tbr.add(notification);
84         myNotifications.remove(notification);
85       }
86     }
87
88     if (tbr.size() > 0) {
89       for (NotificationModelListener listener : myListeners) {
90         listener.notificationsRemoved(tbr.toArray((Notification[])Array.newInstance(tbr.get(0).getClass(), tbr.size())));
91       }
92     }
93   }
94
95   @Nullable
96   public Notification get(final int index, @NotNull PairFunction<Notification, Project, Boolean> filter) {
97     final LinkedList<Notification> filtered = filterNotifications(filter);
98     if (index >= 0 && filtered.size() > index) {
99       return filtered.get(index);
100     }
101
102     return null;
103   }
104
105   private LinkedList<Notification> filterNotifications(@NotNull PairFunction<Notification, Project, Boolean> filter) {
106     final LinkedList<Notification> result = new LinkedList<Notification>();
107     final HashSet<Map.Entry<Notification, Pair<Project, Boolean>>> entries =
108       new HashSet<Map.Entry<Notification, Pair<Project, Boolean>>>(myNotifications.entrySet());
109     for (final Map.Entry<Notification, Pair<Project, Boolean>> entry : entries) {
110       if (filter.fun(entry.getKey(), entry.getValue().first)) {
111         result.addFirst(entry.getKey());
112       }
113     }
114
115     return result;
116   }
117
118   public int getCount(@NotNull PairFunction<Notification, Project, Boolean> filter) {
119     return filterNotifications(filter).size();
120   }
121
122   public boolean isEmpty(@NotNull PairFunction<Notification, Project, Boolean> filter) {
123     return getCount(filter) == 0;
124   }
125
126   @Nullable
127   public Notification getFirst(@NotNull PairFunction<Notification, Project, Boolean> filter) {
128     final LinkedList<Notification> result = filterNotifications(filter);
129     if (result.size() > 0) {
130       return result.getFirst();
131     }
132
133     return null;
134   }
135
136   public void clear(@NotNull PairFunction<Notification, Project, Boolean> filter) {
137     final LinkedList<Notification> result = filterNotifications(filter);
138     for (final Notification notification : result) {
139       myNotifications.remove(notification);
140     }
141
142     if (!result.isEmpty()) {
143       final Notification[] removed = result.toArray(new Notification[result.size()]);
144       for (NotificationModelListener listener : myListeners) {
145         listener.notificationsRemoved(removed);
146       }
147     }
148   }
149
150   public List<Notification> getByType(@Nullable final NotificationType type, @NotNull PairFunction<Notification, Project, Boolean> filter) {
151     if (type == null) {
152       return Collections.unmodifiableList(filterNotifications(filter));
153     }
154     else {
155       final List<Notification> result = new ArrayList<Notification>();
156       final LinkedList<Notification> filtered = filterNotifications(filter);
157       for (final Notification notification : filtered) {
158         if (type == notification.getType()) {
159           result.add(notification);
160         }
161       }
162
163       return result;
164     }
165   }
166
167   public boolean wasRead(final Notification notification) {
168     final Pair<Project, Boolean> pair = myNotifications.get(notification);
169     return pair != null && pair.second;
170   }
171
172   public boolean hasUnread(final PairFunction<Notification, Project, Boolean> filter) {
173     return getUnreadCount(filter) > 0;
174   }
175
176   private int getUnreadCount(final PairFunction<Notification, Project, Boolean> filter) {
177     return filterNotifications(new PairFunction<Notification, Project, Boolean>() {
178       public Boolean fun(Notification notification, Project project) {
179         return filter.fun(notification, project) && !wasRead(notification);
180       }
181     }).size();
182   }
183
184   public boolean hasRead(PairFunction<Notification, Project, Boolean> filter) {
185     return getUnreadCount(filter) < myNotifications.size();
186   }
187
188   @Nullable
189   public NotificationType getMaximumType(PairFunction<Notification, Project, Boolean> filter) {
190     final LinkedList<Notification> notifications = filterNotifications(filter);
191     NotificationType result = null;
192     for (Notification notification : notifications) {
193       if (NotificationType.ERROR == notification.getType()) {
194         return NotificationType.ERROR;
195       }
196
197       if (NotificationType.WARNING == notification.getType()) {
198         result = NotificationType.WARNING;
199       }
200       else if (result == null && NotificationType.INFORMATION == notification.getType()) {
201         result = NotificationType.INFORMATION;
202       }
203     }
204
205     return result;
206   }
207 }