| /* |
| * 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.roots.impl.libraries; |
| |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.components.PersistentStateComponent; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.roots.OrderRootType; |
| import com.intellij.openapi.roots.libraries.Library; |
| import com.intellij.openapi.roots.libraries.LibraryTable; |
| import com.intellij.openapi.roots.libraries.PersistentLibraryKind; |
| import com.intellij.openapi.util.*; |
| import com.intellij.util.EventDispatcher; |
| import com.intellij.util.containers.ContainerUtil; |
| import com.intellij.util.containers.HashSet; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.*; |
| |
| public abstract class LibraryTableBase implements PersistentStateComponent<Element>, LibraryTable, Disposable { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.libraries.LibraryTableBase"); |
| private final EventDispatcher<Listener> myDispatcher = EventDispatcher.create(Listener.class); |
| private LibraryModel myModel = new LibraryModel(); |
| private boolean myFirstLoad = true; |
| |
| @Override |
| public ModifiableModel getModifiableModel() { |
| return new LibraryModel(myModel); |
| } |
| |
| @Override |
| public Element getState() { |
| final Element element = new Element("state"); |
| try { |
| myModel.writeExternal(element); |
| } |
| catch (WriteExternalException e) { |
| LOG.error(e); |
| } |
| return element; |
| } |
| |
| @Override |
| public void loadState(final Element element) { |
| try { |
| if (myFirstLoad) { |
| myModel.readExternal(element); |
| } |
| else { |
| final LibraryModel model = new LibraryModel(); |
| model.readExternal(element); |
| commit(model); |
| } |
| |
| myFirstLoad = false; |
| } |
| catch (InvalidDataException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| @NotNull |
| public Library[] getLibraries() { |
| return myModel.getLibraries(); |
| } |
| |
| @Override |
| @NotNull |
| public Iterator<Library> getLibraryIterator() { |
| return myModel.getLibraryIterator(); |
| } |
| |
| @Override |
| public Library getLibraryByName(@NotNull String name) { |
| return myModel.getLibraryByName(name); |
| } |
| |
| @Override |
| public void addListener(Listener listener) { |
| myDispatcher.addListener(listener); |
| } |
| |
| @Override |
| public void addListener(Listener listener, Disposable parentDisposable) { |
| myDispatcher.addListener(listener, parentDisposable); |
| } |
| |
| @Override |
| public void removeListener(Listener listener) { |
| myDispatcher.removeListener(listener); |
| } |
| |
| private void fireLibraryAdded (Library library) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("fireLibraryAdded: " + library); |
| } |
| myDispatcher.getMulticaster().afterLibraryAdded(library); |
| } |
| |
| private void fireBeforeLibraryRemoved (Library library) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("fireBeforeLibraryRemoved: " + library); |
| } |
| myDispatcher.getMulticaster().beforeLibraryRemoved(library); |
| } |
| |
| @Override |
| public void dispose() { |
| for (Library library : getLibraries()) { |
| Disposer.dispose(library); |
| } |
| } |
| |
| @Override |
| public Library createLibrary() { |
| ApplicationManager.getApplication().assertWriteAccessAllowed(); |
| return createLibrary(null); |
| } |
| |
| public void fireLibraryRenamed(@NotNull LibraryImpl library) { |
| myDispatcher.getMulticaster().afterLibraryRenamed(library); |
| } |
| |
| @Override |
| public Library createLibrary(String name) { |
| final ModifiableModel modifiableModel = getModifiableModel(); |
| final Library library = modifiableModel.createLibrary(name); |
| modifiableModel.commit(); |
| return library; |
| } |
| |
| @Override |
| public void removeLibrary(@NotNull Library library) { |
| final ModifiableModel modifiableModel = getModifiableModel(); |
| modifiableModel.removeLibrary(library); |
| modifiableModel.commit(); |
| } |
| |
| private void commit(LibraryModel model) { |
| ApplicationManager.getApplication().assertWriteAccessAllowed(); |
| //todo[nik] remove LibraryImpl#equals method instead of using identity sets |
| Set<Library> addedLibraries = ContainerUtil.newIdentityTroveSet(model.myLibraries); |
| addedLibraries.removeAll(myModel.myLibraries); |
| Set<Library> removedLibraries = ContainerUtil.newIdentityTroveSet(myModel.myLibraries); |
| removedLibraries.removeAll(model.myLibraries); |
| |
| for (Library library : removedLibraries) { |
| fireBeforeLibraryRemoved(library); |
| } |
| |
| myModel = model; |
| for (Library library : removedLibraries) { |
| Disposer.dispose(library); |
| fireAfterLibraryRemoved(library); |
| } |
| for (Library library : addedLibraries) { |
| fireLibraryAdded(library); |
| } |
| } |
| |
| private void fireAfterLibraryRemoved(Library library) { |
| myDispatcher.getMulticaster().afterLibraryRemoved(library); |
| } |
| |
| public void readExternal(final Element element) throws InvalidDataException { |
| myModel = new LibraryModel(); |
| myModel.readExternal(element); |
| } |
| |
| public void writeExternal(final Element element) throws WriteExternalException { |
| myModel.writeExternal(element); |
| } |
| |
| public interface ModifiableModelEx extends ModifiableModel { |
| Library createLibrary(String name, @Nullable PersistentLibraryKind type); |
| } |
| |
| public class LibraryModel implements ModifiableModelEx, JDOMExternalizable { |
| private final ArrayList<Library> myLibraries = new ArrayList<Library>(); |
| private boolean myWritable; |
| |
| private LibraryModel() { |
| myWritable = false; |
| } |
| |
| private LibraryModel(LibraryModel that) { |
| myWritable = true; |
| myLibraries.addAll(that.myLibraries); |
| } |
| |
| @Override |
| public void commit() { |
| myWritable = false; |
| LibraryTableBase.this.commit(this); |
| } |
| |
| @Override |
| @NotNull |
| public Iterator<Library> getLibraryIterator() { |
| return Collections.unmodifiableList(myLibraries).iterator(); |
| } |
| |
| @Override |
| @Nullable |
| public Library getLibraryByName(@NotNull String name) { |
| for (Library myLibrary : myLibraries) { |
| LibraryImpl library = (LibraryImpl)myLibrary; |
| if (Comparing.equal(name, library.getName())) return library; |
| } |
| @NonNls final String libraryPrefix = "library."; |
| final String libPath = System.getProperty(libraryPrefix + name); |
| if (libPath != null) { |
| final LibraryImpl library = new LibraryImpl(name, null, LibraryTableBase.this, null); |
| library.addRoot(libPath, OrderRootType.CLASSES); |
| return library; |
| } |
| return null; |
| } |
| |
| |
| @Override |
| @NotNull |
| public Library[] getLibraries() { |
| return myLibraries.toArray(new Library[myLibraries.size()]); |
| } |
| |
| private void assertWritable() { |
| LOG.assertTrue(myWritable); |
| } |
| |
| @Override |
| public Library createLibrary(String name) { |
| return createLibrary(name, null); |
| } |
| |
| @Override |
| public Library createLibrary(String name, @Nullable PersistentLibraryKind kind) { |
| assertWritable(); |
| final LibraryImpl library = new LibraryImpl(name, kind, LibraryTableBase.this, null); |
| myLibraries.add(library); |
| return library; |
| } |
| |
| @Override |
| public void removeLibrary(@NotNull Library library) { |
| assertWritable(); |
| myLibraries.remove(library); |
| } |
| |
| @Override |
| public boolean isChanged() { |
| if (!myWritable) return false; |
| Set<Library> thisLibraries = new HashSet<Library>(myLibraries); |
| Set<Library> thatLibraries = new HashSet<Library>(myModel.myLibraries); |
| return !thisLibraries.equals(thatLibraries); |
| } |
| |
| @Override |
| public void readExternal(Element element) throws InvalidDataException { |
| HashMap<String, Library> libraries = new HashMap<String, Library>(); |
| for (Library library : myLibraries) { |
| libraries.put(library.getName(), library); |
| } |
| |
| final List libraryElements = element.getChildren(LibraryImpl.ELEMENT); |
| for (Object libraryElement1 : libraryElements) { |
| Element libraryElement = (Element)libraryElement1; |
| final LibraryImpl library = new LibraryImpl(LibraryTableBase.this, libraryElement, null); |
| if (library.getName() != null) { |
| Library oldLibrary = libraries.get(library.getName()); |
| if (oldLibrary != null) { |
| removeLibrary(oldLibrary); |
| } |
| |
| myLibraries.add(library); |
| fireLibraryAdded(library); |
| } |
| else { |
| Disposer.dispose(library); |
| } |
| } |
| } |
| |
| @Override |
| public void writeExternal(Element element) throws WriteExternalException { |
| final List<Library> libraries = ContainerUtil.findAll(myLibraries, new Condition<Library>() { |
| @Override |
| public boolean value(Library library) { |
| return !((LibraryEx)library).isDisposed(); |
| } |
| }); |
| |
| // todo: do not sort if project is directory-based |
| ContainerUtil.sort(libraries, new Comparator<Library>() { |
| @Override |
| public int compare(Library o1, Library o2) { |
| return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); |
| } |
| }); |
| |
| for (final Library library : libraries) { |
| if (library.getName() != null) { |
| library.writeExternal(element); |
| } |
| } |
| } |
| } |
| } |