P4 local changes refactoring. (2)
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / ChangeListWorker.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.openapi.vcs.changes;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.util.Comparing;
21 import com.intellij.openapi.util.Pair;
22 import com.intellij.openapi.vcs.AbstractVcs;
23 import com.intellij.openapi.vcs.FilePath;
24 import com.intellij.openapi.vcs.FileStatus;
25 import com.intellij.openapi.vcs.VcsKey;
26 import com.intellij.openapi.vfs.VirtualFile;
27 import com.intellij.util.IncorrectOperationException;
28 import com.intellij.util.containers.MultiMap;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31
32 import java.io.File;
33 import java.util.*;
34
35 /** should work under _external_ lock
36 * just logic here: do modifications to group of change lists
37 */
38 public class ChangeListWorker implements ChangeListsWriteOperations {
39   private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.ChangeListWorker");
40
41   private final Project myProject;
42   private final Map<String, LocalChangeList> myMap;
43   // in fact, a kind of local change
44   private final DeletedFilesHolder myLocallyDeleted;
45   private final SwitchedFileHolder mySwitchedHolder;
46   private LocalChangeList myDefault;
47
48   private ChangeListsIndexes myIdx;
49   private final ChangesDelta myDelta;
50   private final List<String> myListsToDisappear;
51
52   public ChangeListWorker(final Project project, final PlusMinus<Pair<String, AbstractVcs>> deltaListener) {
53     myProject = project;
54     myMap = new HashMap<String, LocalChangeList>();
55     myIdx = new ChangeListsIndexes();
56     myLocallyDeleted = new DeletedFilesHolder();
57     mySwitchedHolder = new SwitchedFileHolder(project, FileHolder.HolderType.SWITCHED);
58
59     myDelta = new ChangesDelta(project, deltaListener);
60     myListsToDisappear = new LinkedList<String>();
61   }
62
63   private ChangeListWorker(final ChangeListWorker worker) {
64     myProject = worker.myProject;
65     myMap = new HashMap<String, LocalChangeList>();
66     myIdx = new ChangeListsIndexes(worker.myIdx);
67     myLocallyDeleted = worker.myLocallyDeleted.copy();
68     mySwitchedHolder = (SwitchedFileHolder) worker.mySwitchedHolder.copy();
69     myDelta = worker.myDelta;
70     myListsToDisappear = new LinkedList<String>(worker.myListsToDisappear);
71     
72     LocalChangeList defaultList = null;
73     for (LocalChangeList changeList : worker.myMap.values()) {
74       final LocalChangeList copy = changeList.copy();
75       
76       final String changeListName = copy.getName();
77       myMap.put(changeListName, copy);
78       if (copy.isDefault()) {
79         defaultList = copy;
80       }
81     }
82     if (defaultList == null) {
83       LOG.info("default list not found when copy");
84       defaultList = myMap.get(worker.getDefaultListName());
85     }
86
87     if (defaultList == null) {
88       LOG.info("default list not found when copy in original object too");
89       if (! myMap.isEmpty()) {
90         defaultList = myMap.values().iterator().next();
91       } else {
92         // can be when there's no vcs configured
93         ///LOG.error("no changelists at all");
94       }
95     }
96     myDefault = defaultList;
97   }
98
99   public void takeData(@NotNull final ChangeListWorker worker) {
100     myMap.clear();
101     myMap.putAll(worker.myMap);
102     myDefault = worker.myDefault;
103
104     myListsToDisappear.clear();
105     myListsToDisappear.addAll(worker.myListsToDisappear);
106     
107     myDelta.step(myIdx, worker.myIdx);
108     myIdx = new ChangeListsIndexes(worker.myIdx);
109     // todo +-
110     myLocallyDeleted.takeFrom(worker.myLocallyDeleted);
111     mySwitchedHolder.takeFrom(worker.mySwitchedHolder);
112   }
113
114   public ChangeListWorker copy() {
115     return new ChangeListWorker(this);
116   }
117
118   public boolean findListByName(@NotNull final String name) {
119     return myMap.containsKey(name);
120   }
121
122   @Nullable
123   public LocalChangeList getCopyByName(final String name) {
124     return myMap.get(name);
125   }
126
127   @Nullable
128   public LocalChangeList getChangeList(String id) {
129     for (LocalChangeList changeList : myMap.values()) {
130       if (changeList.getId().equals(id)) {
131         return changeList.copy();
132       }
133     }
134     return null;
135   }
136
137   /**
138    * @return if list with name exists, return previous default list name or null of there wasn't previous
139    */
140   @Nullable
141   public String setDefault(final String name) {
142     final LocalChangeList newDefault = myMap.get(name);
143     if (newDefault == null) {
144       return null;
145     }
146     String previousName = null;
147     if (myDefault != null) {
148       ((LocalChangeListImpl) myDefault).setDefault(false);
149       correctChangeListEditHandler(myDefault);
150       previousName = myDefault.getName();
151     }
152
153     ((LocalChangeListImpl) newDefault).setDefault(true);
154     myDefault = newDefault;
155
156     return previousName;
157   }
158
159   public boolean setReadOnly(final String name, final boolean value) {
160     final LocalChangeList list = myMap.get(name);
161     if (list != null) {
162       list.setReadOnly(value);
163     }
164     return list != null;
165   }
166
167   public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String description) {
168     return addChangeList(null, name, description, false);
169   }
170
171   LocalChangeList addChangeList(String id, @NotNull final String name, @Nullable final String description, final boolean inUpdate) {
172     final boolean contains = myMap.containsKey(name);
173     LOG.assertTrue(! contains, "Attempt to create duplicate changelist " + name);
174     final LocalChangeListImpl newList = (LocalChangeListImpl) LocalChangeList.createEmptyChangeList(myProject, name);
175
176     if (description != null) {
177       newList.setCommentImpl(description);
178     }
179     if (id != null) {
180       newList.setId(id);
181     }
182     myMap.put(name, newList);
183     if (inUpdate) {
184       // scope is not important: nothing had been added jet, nothing to move to "old state" members
185       newList.startProcessingChanges(myProject, null);
186     }
187     return newList.copy();
188   }
189
190   public boolean addChangeToList(@NotNull final String name, final Change change, final VcsKey vcsKey) {
191     final LocalChangeList changeList = myMap.get(name);
192     if (changeList != null) {
193       ((LocalChangeListImpl) changeList).addChange(change);
194       myIdx.changeAdded(change, vcsKey);
195       correctChangeListEditHandler(changeList);
196     }
197     return changeList != null;
198   }
199
200   public void addChangeToCorrespondingList(final Change change, final VcsKey vcsKey) {
201     assert myDefault != null;
202     for (LocalChangeList list : myMap.values()) {
203       if (list.isDefault()) continue;
204       if (((LocalChangeListImpl) list).processChange(change)) {
205         myIdx.changeAdded(change, vcsKey);
206         correctChangeListEditHandler(list);
207         return;
208       }
209     }
210     ((LocalChangeListImpl) myDefault).processChange(change);
211     myIdx.changeAdded(change, vcsKey);
212     correctChangeListEditHandler(myDefault);
213   }
214
215   public boolean removeChangeList(@NotNull String name) {
216     final LocalChangeList list = myMap.get(name);
217     if (list == null) {
218       return false;
219     }
220     if (list.isDefault()) {
221       throw new RuntimeException(new IncorrectOperationException("Cannot remove default changelist"));
222     }
223     final String listName = list.getName();
224
225     for (Change change : list.getChanges()) {
226       ((LocalChangeListImpl) myDefault).addChange(change);
227     }
228
229     myMap.remove(listName);
230     return true;
231   }
232
233   void initialized() {
234     for (LocalChangeList list : myMap.values()) {
235       correctChangeListEditHandler(list);
236     }
237   }
238
239   // since currently it is only for P4, "composite" edit handler is not created - it does not make sence
240   private void correctChangeListEditHandler(final LocalChangeList list) {
241   }
242
243   @Nullable
244   public MultiMap<LocalChangeList, Change> moveChangesTo(final String name, final Change[] changes) {
245     final LocalChangeListImpl changeList = (LocalChangeListImpl) myMap.get(name);
246     if (changeList != null) {
247       final MultiMap<LocalChangeList, Change> result = new MultiMap<LocalChangeList, Change>();
248       for (LocalChangeList list : myMap.values()) {
249         if (list.equals(changeList)) continue;
250         for (Change change : changes) {
251           final Change removedChange = ((LocalChangeListImpl)list).removeChange(change);
252           if (removedChange != null) {
253             correctChangeListEditHandler(list);
254
255             changeList.addChange(removedChange);
256             result.putValue(list, removedChange);
257           }
258         }
259       }
260       correctChangeListEditHandler(changeList);
261       return result;
262     }
263     return null;
264   }
265
266   public boolean editName(@NotNull final String fromName, @NotNull final String toName) {
267     if (fromName.equals(toName)) return false;
268     final LocalChangeList list = myMap.get(fromName);
269     final boolean canEdit = list != null && (!list.isReadOnly());
270     if (canEdit) {
271       final LocalChangeListImpl listImpl = (LocalChangeListImpl) list;
272       listImpl.setNameImpl(toName);
273       myMap.remove(fromName);
274       myMap.put(toName, list);
275       final ChangeListEditHandler editHandler = listImpl.getEditHandler();
276       if (editHandler != null) {
277         listImpl.setCommentImpl(editHandler.changeCommentOnChangeName(toName, listImpl.getComment()));
278       }
279     }
280     return canEdit;
281   }
282
283   @Nullable
284   public String editComment(@NotNull final String fromName, final String newComment) {
285     final LocalChangeList list = myMap.get(fromName);
286     if (list != null) {
287       final String oldComment = list.getComment();
288       if (! Comparing.equal(oldComment, newComment)) {
289         final LocalChangeListImpl listImpl = (LocalChangeListImpl) list;
290         listImpl.setCommentImpl(newComment);
291         final ChangeListEditHandler editHandler = listImpl.getEditHandler();
292         if (editHandler != null) {
293           listImpl.setNameImpl(editHandler.changeNameOnChangeComment(listImpl.getName(), listImpl.getComment()));
294           if (! fromName.equals(listImpl.getName())) {
295             myMap.remove(fromName);
296             myMap.put(listImpl.getName(), list);
297           }
298         }
299       }
300       return oldComment;
301     }
302     return null;
303   }
304
305   public boolean isEmpty() {
306     return myMap.isEmpty();
307   }
308
309   @Nullable
310   public LocalChangeList getDefaultListCopy() {
311     return myDefault == null ? null : myDefault.copy();
312   }
313
314   public boolean isDefaultList(LocalChangeList list) {
315     return myDefault != null && list.getId().equals(myDefault.getId());  
316   }
317
318   public Project getProject() {
319     return myProject;
320   }
321
322   // called NOT under ChangeListManagerImpl lock
323   public void notifyStartProcessingChanges(final VcsAppendableDirtyScope scope) {
324     final Collection<Change> oldChanges = new ArrayList<Change>();
325     for (LocalChangeList list : myMap.values()) {
326       final Collection<Change> affectedChanges = ((LocalChangeListImpl)list).startProcessingChanges(myProject, scope);
327       if (! affectedChanges.isEmpty()) {
328         oldChanges.addAll(affectedChanges);
329       }
330     }
331     for (Change change : oldChanges) {
332       myIdx.changeRemoved(change);
333     }
334     // scope should be modified for correct moves tracking
335     correctScopeForMoves(scope, oldChanges);
336
337     myLocallyDeleted.cleanScope(scope);
338     mySwitchedHolder.cleanScope(scope);
339   }
340
341   private void correctScopeForMoves(final VcsAppendableDirtyScope scope, final Collection<Change> changes) {
342     if (scope == null) return;
343     for (Change change : changes) {
344       if (change.isMoved() || change.isRenamed()) {
345         scope.addDirtyFile(change.getBeforeRevision().getFile());
346         scope.addDirtyFile(change.getAfterRevision().getFile());
347       }
348     }
349   }
350
351   public void notifyDoneProcessingChanges(final ChangeListListener dispatcher) {
352     List<ChangeList> changedLists = new ArrayList<ChangeList>();
353     final Map<LocalChangeListImpl, List<Change>> removedChanges = new HashMap<LocalChangeListImpl, List<Change>>();
354       for (LocalChangeList list : myMap.values()) {
355         final List<Change> removed = new ArrayList<Change>();
356         final LocalChangeListImpl listImpl = (LocalChangeListImpl)list;
357         if (listImpl.doneProcessingChanges(removed)) {
358           changedLists.add(list);
359         }
360         if (! removed.isEmpty()) {
361           removedChanges.put(listImpl, removed);
362         }
363       }
364     for (Map.Entry<LocalChangeListImpl, List<Change>> entry : removedChanges.entrySet()) {
365       dispatcher.changesRemoved(entry.getValue(), entry.getKey());
366     }
367     for(ChangeList changeList: changedLists) {
368       dispatcher.changeListChanged(changeList);
369     }
370     mySwitchedHolder.calculateChildren();
371
372     for (String name : myListsToDisappear) {
373       final LocalChangeList changeList = myMap.get(name);
374       if (changeList.getChanges().isEmpty()) {
375         removeChangeList(name);
376       }
377     }
378     myListsToDisappear.clear();
379   }
380
381   public List<LocalChangeList> getListsCopy() {
382     final List<LocalChangeList> result = new ArrayList<LocalChangeList>();
383     for (LocalChangeList list : myMap.values()) {
384       result.add(list.copy());
385     }
386     return result;
387   }
388
389   public String getDefaultListName() {
390     return myDefault == null ? null : myDefault.getName();
391   }
392
393   public List<File> getAffectedPaths() {
394     return myIdx.getAffectedPaths();
395   }
396
397   @NotNull
398   public List<VirtualFile> getAffectedFiles() {
399     final List<VirtualFile> result = new ArrayList<VirtualFile>();
400     for (LocalChangeList list : myMap.values()) {
401       for (Change change : list.getChanges()) {
402         final ContentRevision before = change.getBeforeRevision();
403         final ContentRevision after = change.getAfterRevision();
404         if (before != null) {
405           final VirtualFile file = before.getFile().getVirtualFile();
406           if (file != null) {
407             result.add(file);
408           }
409         }
410         if (after != null) {
411           final VirtualFile file = after.getFile().getVirtualFile();
412           if (file != null) {
413             result.add(file);
414           }
415         }
416       }
417     }
418     return result;
419   }
420
421   public LocalChangeList getListCopy(@NotNull final VirtualFile file) {
422     for (LocalChangeList list : myMap.values()) {
423       for (Change change : list.getChanges()) {
424         if (change.getAfterRevision() != null &&
425             Comparing.equal(change.getAfterRevision().getFile().getVirtualFile(), file)) {
426           return list.copy();
427         }
428         if (change.getBeforeRevision() != null &&
429             Comparing.equal(change.getBeforeRevision().getFile().getVirtualFile(), file)) {
430           return list.copy();
431         }
432       }
433     }
434     return null;
435   }
436
437   @Nullable
438   public Change getChangeForPath(final FilePath file) {
439     for (LocalChangeList list : myMap.values()) {
440       for (Change change : list.getChanges()) {
441         final ContentRevision afterRevision = change.getAfterRevision();
442         if (afterRevision != null && afterRevision.getFile().equals(file)) {
443           return change;
444         }
445         final ContentRevision beforeRevision = change.getBeforeRevision();
446         if (beforeRevision != null && beforeRevision.getFile().equals(file)) {
447           return change;
448         }
449       }
450     }
451     return null;
452   }
453
454   public FileStatus getStatus(final VirtualFile file) {
455     return myIdx.getStatus(file);
456   }
457
458   public DeletedFilesHolder getLocallyDeleted() {
459     return myLocallyDeleted.copy();
460   }
461
462   public SwitchedFileHolder getSwitchedHolder() {
463     return mySwitchedHolder.copy();
464   }
465
466   public void addSwitched(final VirtualFile file, @NotNull String branchName, final boolean recursive) {
467     mySwitchedHolder.addFile(file, branchName, recursive);
468   }
469
470   public void removeSwitched(final VirtualFile file) {
471     mySwitchedHolder.removeFile(file);
472   }
473
474   public String getBranchForFile(final VirtualFile file) {
475     return mySwitchedHolder.getBranchForFile(file);
476   }
477
478   public boolean isSwitched(final VirtualFile file) {
479     return mySwitchedHolder.containsFile(file);
480   }
481
482   public void addLocallyDeleted(final LocallyDeletedChange change) {
483     myLocallyDeleted.addFile(change);
484   }
485
486   public boolean isContainedInLocallyDeleted(final FilePath filePath) {
487     return myLocallyDeleted.isContainedInLocallyDeleted(filePath);
488   }
489
490   private abstract class ExternalVsInternalChangesIntersection {
491     protected final Collection<Change> myInChanges;
492     protected final Map<Pair<String, String>, LocalChangeList> myInternalMap;
493     protected final LocalChangeList myDefaultCopy;
494     protected final Map<String, LocalChangeList> myIncludedListsCopies;
495
496     protected ExternalVsInternalChangesIntersection(final Collection<Change> inChanges) {
497       myInChanges = inChanges;
498       myInternalMap = new HashMap<Pair<String, String>, LocalChangeList>();
499       myDefaultCopy = myDefault.copy();
500       myIncludedListsCopies = new HashMap<String, LocalChangeList>();
501     }
502
503     private Pair<String, String> keyForChange(final Change change) {
504       final FilePath beforePath = ChangesUtil.getBeforePath(change);
505       final String beforeKey = beforePath == null ? null : beforePath.getIOFile().getAbsolutePath();
506       final FilePath afterPath = ChangesUtil.getAfterPath(change);
507       final String afterKey = afterPath == null ? null : afterPath.getIOFile().getAbsolutePath();
508       return new Pair<String, String>(beforeKey, afterKey);
509     }
510
511     private void preparation() {
512       for (LocalChangeList list : myMap.values()) {
513         final Collection<Change> managerChanges = list.getChanges();
514         final LocalChangeList copy = list.copy();
515         for (Change change : managerChanges) {
516           myInternalMap.put(keyForChange(change), copy);
517         }
518       }
519     }
520
521     protected abstract void processInChange(final Pair<String, String> key, final Change change);
522
523     public void run() {
524       preparation();
525
526       for (Change change : myInChanges) {
527         final Pair<String, String> key = keyForChange(change);
528         processInChange(key, change);
529       }
530     }
531
532     public Map<String, LocalChangeList> getIncludedListsCopies() {
533       return myIncludedListsCopies;
534     }
535   }
536
537   private class GatherChangesVsListsInfo extends ExternalVsInternalChangesIntersection {
538     private final Map<String, List<Change>> myListToChangesMap;
539
540     private GatherChangesVsListsInfo(final Collection<Change> inChanges) {
541       super(inChanges);
542       myListToChangesMap = new HashMap<String, List<Change>>();
543     }
544
545     protected void processInChange(Pair<String, String> key, Change change) {
546       LocalChangeList tmpList = myInternalMap.get(key);
547       if (tmpList == null) {
548         tmpList = myDefaultCopy;
549       }
550       final String tmpName = tmpList.getName();
551       List<Change> list = myListToChangesMap.get(tmpName);
552       if (list == null) {
553         list = new ArrayList<Change>();
554         myListToChangesMap.put(tmpName, list);
555         myIncludedListsCopies.put(tmpName, tmpList);
556       }
557       list.add(change);
558     }
559
560     public Map<String, List<Change>> getListToChangesMap() {
561       return myListToChangesMap;
562     }
563   }
564
565   private class GatherListsFilterValidChanges extends ExternalVsInternalChangesIntersection {
566     private final List<Change> myValidChanges;
567
568     private GatherListsFilterValidChanges(final Collection<Change> inChanges) {
569       super(inChanges);
570       myValidChanges = new ArrayList<Change>();
571     }
572
573     protected void processInChange(Pair<String, String> key, Change change) {
574       final LocalChangeList list = myInternalMap.get(key);
575       if (list != null) {
576         myIncludedListsCopies.put(list.getName(), list);
577         myValidChanges.add(change);
578       }
579     }
580
581     public List<Change> getValidChanges() {
582       return myValidChanges;
583     }
584   }
585
586   @NotNull
587   public Map<String, List<Change>> listsForChanges(final Collection<Change> changes, final Map<String, LocalChangeList> lists) {
588     final GatherChangesVsListsInfo info = new GatherChangesVsListsInfo(changes);
589     info.run();
590     lists.putAll(info.getIncludedListsCopies());
591     return info.getListToChangesMap();
592   }
593
594   @NotNull
595   public Collection<LocalChangeList> getInvolvedListsFilterChanges(final Collection<Change> changes, final List<Change> validChanges) {
596     final GatherListsFilterValidChanges worker = new GatherListsFilterValidChanges(changes);
597     worker.run();
598     validChanges.addAll(worker.getValidChanges());
599     return worker.getIncludedListsCopies().values();
600   }
601
602   @Nullable
603   public LocalChangeList listForChange(final Change change) {
604     for (LocalChangeList list : myMap.values()) {
605       if (list.getChanges().contains(change)) return list.copy();
606     }
607     return null;
608   }
609
610   @Nullable
611   public String listNameIfOnlyOne(final @Nullable Change[] changes) {
612     if (changes == null || changes.length == 0) {
613       return null;
614     }
615
616     final Change first = changes[0];
617
618     for (LocalChangeList list : myMap.values()) {
619       final Collection<Change> listChanges = list.getChanges();
620       if (listChanges.contains(first)) {
621         // must contain all other
622         for (int i = 1; i < changes.length; i++) {
623           final Change change = changes[i];
624           if (! listChanges.contains(change)) {
625             return null;
626           }
627         }
628         return list.getName();
629       }
630     }
631     return null;
632   }
633
634   @NotNull
635   public Collection<Change> getChangesIn(final FilePath dirPath) {
636     List<Change> changes = new ArrayList<Change>();
637     for (ChangeList list : myMap.values()) {
638       for (Change change : list.getChanges()) {
639         final ContentRevision afterRevision = change.getAfterRevision();
640         if (afterRevision != null && afterRevision.getFile().isUnder(dirPath, false)) {
641           changes.add(change);
642           continue;
643         }
644
645         final ContentRevision beforeRevision = change.getBeforeRevision();
646         if (beforeRevision != null && beforeRevision.getFile().isUnder(dirPath, false)) {
647           changes.add(change);
648         }
649       }
650     }
651     return changes;
652   }
653
654   void setListsToDisappear(final Collection<String> names) {
655     myListsToDisappear.addAll(names);
656   }
657
658   ChangeListManagerGate createSelfGate() {
659     return new MyGate(this);
660   }
661
662   private static class MyGate implements ChangeListManagerGate {
663     private final ChangeListWorker myWorker;
664
665     private MyGate(final ChangeListWorker worker) {
666       myWorker = worker;
667     }
668
669     public List<LocalChangeList> getListsCopy() {
670       return myWorker.getListsCopy();
671     }
672
673     @Nullable
674     public LocalChangeList findChangeList(final String name) {
675       return myWorker.getCopyByName(name);
676     }
677
678     public LocalChangeList addChangeList(final String name, final String comment) {
679       return myWorker.addChangeList(null, name, comment, true);
680     }
681
682     public LocalChangeList findOrCreateList(final String name, final String comment) {
683       LocalChangeList list = myWorker.getCopyByName(name);
684       if (list == null) {
685         list = addChangeList(name, comment);
686       }
687       return list;
688     }
689
690     public void editComment(final String name, final String comment) {
691       myWorker.editComment(name, comment);
692     }
693
694     public void editName(String oldName, String newName) {
695       myWorker.editName(oldName, newName);
696     }
697
698     // todo usage allowed only when..
699     public void moveChanges(String toList, Collection<Change> changes) {
700       myWorker.moveChangesTo(toList, changes.toArray(new Change[changes.size()]));
701     }
702
703     public void setListsToDisappear(final Collection<String> names) {
704       myWorker.setListsToDisappear(names);
705     }
706   }
707 }