From e6176b3d487d1c4d01c070beb9ad98dec7e17927 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Tue, 8 May 2012 18:26:13 +0200 Subject: [PATCH 01/67] FileBasedIndex --- .../psi/impl/cache/impl/IdCacheTest.java | 6 +- .../intellij/psi/search/UpdateCacheTest.java | 5 +- .../intellij/find/impl/FindInProjectUtil.java | 3 +- .../impl/cache/impl/id/IdTableBuilding.java | 2 +- .../psi/impl/cache/impl/todo/TodoIndex.java | 2 +- .../com/intellij/psi/stubs/StubIndexImpl.java | 12 +- .../intellij/psi/stubs/StubUpdatingIndex.java | 2 +- .../util/indexing/FileBasedIndex.java | 2341 +---------------- .../util/indexing/FileBasedIndexImpl.java | 2327 ++++++++++++++++ .../FileBasedIndexProjectHandler.java | 4 +- .../util/indexing/UnindexedFilesUpdater.java | 6 +- .../src/componentSets/Lang.xml | 3 +- .../testFramework/LightPlatformTestCase.java | 3 +- 13 files changed, 2407 insertions(+), 2309 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java index 5ec392f58c23..eaf7ae618ffe 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java @@ -21,6 +21,7 @@ import com.intellij.psi.search.UsageSearchContext; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import java.io.File; import java.util.Arrays; @@ -35,9 +36,8 @@ public class IdCacheTest extends CodeInsightTestCase{ protected void setUp() throws Exception { super.setUp(); - final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance(); - fileBasedIndex.requestRebuild(IdIndex.NAME); - fileBasedIndex.requestRebuild(TodoIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(IdIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(TodoIndex.NAME); String root = JavaTestUtil.getJavaTestDataPath()+ "/psi/impl/cache/"; diff --git a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java index cd2cf6890ac3..be90964eafae 100644 --- a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java @@ -44,6 +44,7 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import org.jetbrains.annotations.NonNls; import java.io.File; @@ -55,8 +56,8 @@ public class UpdateCacheTest extends PsiTestCase{ protected void setUp() throws Exception { super.setUp(); - FileBasedIndex.requestRebuild(IdIndex.NAME); - FileBasedIndex.requestRebuild(TodoIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(IdIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(TodoIndex.NAME); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index a9c2eb118461..e5601ebb1b87 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -502,8 +502,7 @@ public class FindInProjectUtil { if (!keys.isEmpty()) { fast = true; List hits = new ArrayList(); - FileBasedIndex.getInstance() - .getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); + FileBasedIndex.getInstance().getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); for (VirtualFile hit : hits) { resultFiles.add(pm.findFile(hit)); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java index 8e09281d2675..bb8dc7f3104f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java @@ -322,7 +322,7 @@ public class IdTableBuilding { final OccurrenceConsumer occurrenceConsumer = new OccurrenceConsumer(null, true); EditorHighlighter highlighter; - final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndex.EDITOR_HIGHLIGHTER); + final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndexImpl.EDITOR_HIGHLIGHTER); if (editorHighlighter != null && checkCanUseCachedEditorHighlighter(chars, editorHighlighter)) { highlighter = editorHighlighter; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index 594436346a7d..e4c91b7904da 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -54,7 +54,7 @@ public class TodoIndex extends FileBasedIndexExtension messageBus.connect().subscribe(IndexPatternProvider.INDEX_PATTERNS_CHANGED, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - FileBasedIndex.requestRebuild(NAME); + FileBasedIndex.getInstance().requestRebuild(NAME); } }); } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java index d11e89e0f5a7..05a5e6d08e00 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java @@ -200,7 +200,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe @NotNull final Project project, @Nullable final GlobalSearchScope scope, @NotNull final Processor processor) { - final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance(); + final FileBasedIndexImpl fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance(); fileBasedIndex.ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, scope); final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); @@ -211,11 +211,11 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe try { try { // disable up-to-date check to avoid locks on attempt to acquire index write lock while holding at the same time the readLock for this index - FileBasedIndex.disableUpToDateCheckForCurrentThread(); + FileBasedIndexImpl.disableUpToDateCheckForCurrentThread(); index.getReadLock().lock(); final ValueContainer container = index.getData(key); - final FileBasedIndex.ProjectIndexableFilesFilter projectFilesFilter = fileBasedIndex.projectIndexableFiles(project); + final FileBasedIndexImpl.ProjectIndexableFilesFilter projectFilesFilter = fileBasedIndex.projectIndexableFiles(project); return container.forEach(new ValueContainer.ContainerAction() { @Override @@ -320,14 +320,14 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe } finally { index.getReadLock().unlock(); - FileBasedIndex.enableUpToDateCheckForCurrentThread(); + FileBasedIndexImpl.enableUpToDateCheckForCurrentThread(); } } catch (StorageException e) { forceRebuild(e); } catch (RuntimeException e) { - final Throwable cause = FileBasedIndex.getCauseToRebuildIndex(e); + final Throwable cause = FileBasedIndexImpl.getCauseToRebuildIndex(e); if (cause != null) { forceRebuild(cause); } @@ -354,7 +354,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe } private static void requestRebuild() { - FileBasedIndex.requestRebuild(StubUpdatingIndex.INDEX_ID); + FileBasedIndex.getInstance().requestRebuild(StubUpdatingIndex.INDEX_ID); } @Override diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 40fa9d8ac2cd..428f29dd556e 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -232,7 +232,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi } catch (StorageException e) { LOG.info(e); - FileBasedIndex.requestRebuild(INDEX_ID); + FileBasedIndex.getInstance().requestRebuild(INDEX_ID); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 6e8bcf2a307b..c2f3ad423b19 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -13,1676 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.indexing; -import com.intellij.AppTopics; -import com.intellij.history.LocalHistory; -import com.intellij.ide.caches.CacheUpdater; -import com.intellij.lang.ASTNode; -import com.intellij.notification.NotificationDisplayType; -import com.intellij.notification.NotificationGroup; -import com.intellij.notification.NotificationType; -import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ApplicationComponent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.impl.EditorHighlighterCache; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; -import com.intellij.openapi.fileTypes.*; -import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.*; -import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; -import com.intellij.openapi.project.*; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.vfs.*; -import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; -import com.intellij.openapi.vfs.newvfs.BulkFileListener; -import com.intellij.openapi.vfs.newvfs.ManagingFS; -import com.intellij.openapi.vfs.newvfs.NewVirtualFile; -import com.intellij.openapi.vfs.newvfs.events.VFileEvent; -import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon; -import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiDocumentTransactionListener; -import com.intellij.psi.impl.source.PsiFileImpl; -import com.intellij.psi.search.EverythingGlobalScope; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.stubs.SerializationManager; -import com.intellij.util.*; -import com.intellij.util.concurrency.Semaphore; -import com.intellij.util.containers.ConcurrentHashSet; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.io.*; -import com.intellij.util.io.DataOutputStream; -import com.intellij.util.io.storage.HeavyProcessLatch; -import com.intellij.util.messages.MessageBus; -import com.intellij.util.messages.MessageBusConnection; -import gnu.trove.*; +import com.intellij.util.Processor; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.io.*; -import java.lang.ref.SoftReference; -import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Collection; +import java.util.List; +import java.util.Set; /** - * @author Eugene Zhuravlev - * Date: Dec 20, 2007 + * Author: dmitrylomov */ - -public class FileBasedIndex implements ApplicationComponent { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.FileBasedIndex"); - @NonNls - private static final String CORRUPTION_MARKER_NAME = "corruption.marker"; - private final Map, Pair, InputFilter>> myIndices = new THashMap, Pair, InputFilter>>(); - private final Map, Semaphore> myUnsavedDataIndexingSemaphores = new THashMap, Semaphore>(); - private final TObjectIntHashMap> myIndexIdToVersionMap = new TObjectIntHashMap>(); - private final Set> myNotRequiringContentIndices = new THashSet>(); - private final Set> myRequiringContentIndices = new THashSet>(); - private final Set myNoLimitCheckTypes = new THashSet(); - - private final PerIndexDocumentVersionMap myLastIndexedDocStamps = new PerIndexDocumentVersionMap(); - @NotNull private final ChangedFilesCollector myChangedFilesCollector; - - private final List myIndexableSets = ContainerUtil.createEmptyCOWList(); - private final Map myIndexableSetToProjectMap = new THashMap(); - - private static final int OK = 1; - private static final int REQUIRES_REBUILD = 2; - private static final int REBUILD_IN_PROGRESS = 3; - private static final Map, AtomicInteger> ourRebuildStatus = new THashMap, AtomicInteger>(); - - private final VirtualFileManagerEx myVfManager; - private final FileDocumentManager myFileDocumentManager; - private final FileTypeManager myFileTypeManager; - private final ConcurrentHashSet> myUpToDateIndices = new ConcurrentHashSet>(); - private final Map myTransactionMap = new THashMap(); - - private static final int ALREADY_PROCESSED = 0x04; - - @Nullable private final String myConfigPath; - @Nullable private final String mySystemPath; - private final boolean myIsUnitTestMode; - @Nullable private ScheduledFuture myFlushingFuture; - private volatile int myLocalModCount; - private volatile int myFilesModCount; - - public void requestReindex(@NotNull final VirtualFile file) { - myChangedFilesCollector.invalidateIndices(file, true); - } - - public void requestReindexExcluded(@NotNull final VirtualFile file) { - myChangedFilesCollector.invalidateIndices(file, false); - } - - public FileBasedIndex(final VirtualFileManagerEx vfManager, FileDocumentManager fdm, - FileTypeManager fileTypeManager, @NotNull MessageBus bus, SerializationManager sm /*need this parameter to ensure component dependency*/) throws IOException { - myVfManager = vfManager; - myFileDocumentManager = fdm; - myFileTypeManager = fileTypeManager; - myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); - myConfigPath = calcConfigPath(PathManager.getConfigPath()); - mySystemPath = calcConfigPath(PathManager.getSystemPath()); - - final MessageBusConnection connection = bus.connect(); - connection.subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { - @Override - public void transactionStarted(final Document doc, final PsiFile file) { - if (file != null) { - synchronized (myTransactionMap) { - myTransactionMap.put(doc, file); - } - myUpToDateIndices.clear(); - } - } - - @Override - public void transactionCompleted(final Document doc, final PsiFile file) { - synchronized (myTransactionMap) { - myTransactionMap.remove(doc); - } - } - }); - - connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener() { - @Nullable private Map> myTypeToExtensionMap; - @Override - public void beforeFileTypesChanged(final FileTypeEvent event) { - cleanupProcessedFlag(); - myTypeToExtensionMap = new THashMap>(); - for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { - myTypeToExtensionMap.put(type, getExtensions(type)); - } - } - - @Override - public void fileTypesChanged(final FileTypeEvent event) { - final Map> oldExtensions = myTypeToExtensionMap; - myTypeToExtensionMap = null; - if (oldExtensions != null) { - final Map> newExtensions = new THashMap>(); - for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { - newExtensions.put(type, getExtensions(type)); - } - // we are interested only in extension changes or removals. - // addition of an extension is handled separately by RootsChanged event - if (!newExtensions.keySet().containsAll(oldExtensions.keySet())) { - rebuildAllIndices(); - return; - } - for (Map.Entry> entry : oldExtensions.entrySet()) { - FileType fileType = entry.getKey(); - Set strings = entry.getValue(); - if (!newExtensions.get(fileType).containsAll(strings)) { - rebuildAllIndices(); - return; - } - } - } - } - - @NotNull - private Set getExtensions(@NotNull FileType type) { - final Set set = new THashSet(); - for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { - set.add(matcher.getPresentableString()); - } - return set; - } - - private void rebuildAllIndices() { - for (ID indexId : myIndices.keySet()) { - try { - clearIndex(indexId); - } - catch (StorageException e) { - LOG.info(e); - } - } - scheduleIndexRebuild(true); - } - }); - - connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { - @Override - public void before(@NotNull List events) { - for (VFileEvent event : events) { - final Object requestor = event.getRequestor(); - if (requestor instanceof FileDocumentManager || requestor instanceof PsiManager || requestor == LocalHistory.VFS_EVENT_REQUESTOR) { - cleanupMemoryStorage(); - break; - } - } - } - - @Override - public void after(@NotNull List events) { - } - }); - - connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { - @Override - public void fileContentReloaded(VirtualFile file, @NotNull Document document) { - cleanupMemoryStorage(); - } - - @Override - public void unsavedDocumentsDropped() { - cleanupMemoryStorage(); - } - }); - - ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { - @Override - public void writeActionStarted(Object action) { - myUpToDateIndices.clear(); - } - }); - - myChangedFilesCollector = new ChangedFilesCollector(); - - /* - final File workInProgressFile = getMarkerFile(); - if (workInProgressFile.exists()) { - // previous IDEA session was closed incorrectly, so drop all indices - FileUtil.delete(PathManager.getIndexRoot()); - } - */ - - try { - final FileBasedIndexExtension[] extensions = Extensions.getExtensions(FileBasedIndexExtension.EXTENSION_POINT_NAME); - for (FileBasedIndexExtension extension : extensions) { - ourRebuildStatus.put(extension.getName(), new AtomicInteger(OK)); - } - - final File corruptionMarker = new File(PathManager.getIndexRoot(), CORRUPTION_MARKER_NAME); - final boolean currentVersionCorrupted = corruptionMarker.exists(); - boolean versionChanged = false; - for (FileBasedIndexExtension extension : extensions) { - versionChanged |= registerIndexer(extension, currentVersionCorrupted); - } - FileUtil.delete(corruptionMarker); - - String rebuildNotification = null; - if (currentVersionCorrupted) { - rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; - } - else if (versionChanged) { - rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; - } - if (rebuildNotification != null - && !ApplicationManager.getApplication().isHeadlessEnvironment() - && Registry.is("ide.showIndexRebuildMessage")) { - new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) - .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); - } - - dropUnregisteredIndices(); - - // check if rebuild was requested for any index during registration - for (ID indexId : myIndices.keySet()) { - if (ourRebuildStatus.get(indexId).compareAndSet(REQUIRES_REBUILD, OK)) { - try { - clearIndex(indexId); - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.error(e); - } - } - } - - myVfManager.addVirtualFileListener(myChangedFilesCollector); - - registerIndexableSet(new AdditionalIndexableFileSet(), null); - } - finally { - ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { - @Override - public void run() { - performShutdown(); - } - }); - //FileUtil.createIfDoesntExist(workInProgressFile); - saveRegisteredIndices(myIndices.keySet()); - myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() { - int lastModCount = 0; - @Override - public void run() { - if (lastModCount == myLocalModCount) { - flushAllIndices(lastModCount); - } - lastModCount = myLocalModCount; - } - }); - - } - } - - @Override - public void initComponent() { - } - - @Nullable - private static String calcConfigPath(final String path) { - try { - final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()); - return _path.endsWith("/")? _path : _path + "/" ; - } - catch (IOException e) { - LOG.info(e); - return null; - } - } - - private static class FileBasedIndexHolder { - private static final FileBasedIndex ourInstance = ApplicationManager.getApplication().getComponent(FileBasedIndex.class); - } - +public abstract class FileBasedIndex implements ApplicationComponent { public static FileBasedIndex getInstance() { - return FileBasedIndexHolder.ourInstance; - } - - /** - * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted - * - * @param extension - * @param isCurrentVersionCorrupted - */ - private boolean registerIndexer(@NotNull final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) throws IOException { - final ID name = extension.getName(); - final int version = extension.getVersion(); - final File versionFile = IndexInfrastructure.getVersionFile(name); - final boolean versionFileExisted = versionFile.exists(); - boolean versionChanged = false; - if (isCurrentVersionCorrupted || IndexInfrastructure.versionDiffers(versionFile, version)) { - if (!isCurrentVersionCorrupted && versionFileExisted) { - versionChanged = true; - LOG.info("Version has changed for index " + name + ". The index will be rebuilt."); - } - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); - IndexInfrastructure.rewriteVersion(versionFile, version); - } - - for (int attempt = 0; attempt < 2; attempt++) { - try { - final MapIndexStorage storage = new MapIndexStorage(IndexInfrastructure.getStorageFile(name), extension.getKeyDescriptor(), extension.getValueExternalizer(), extension.getCacheSize()); - final MemoryIndexStorage memStorage = new MemoryIndexStorage(storage); - final UpdatableIndex index = createIndex(name, extension, memStorage); - final InputFilter inputFilter = extension.getInputFilter(); - - assert inputFilter != null : "Index extension " + name + " must provide non-null input filter"; - - myIndices.put(name, new Pair, InputFilter>(index, new IndexableFilesFilter(inputFilter))); - myUnsavedDataIndexingSemaphores.put(name, new Semaphore()); - myIndexIdToVersionMap.put(name, version); - if (!extension.dependsOnFileContent()) { - myNotRequiringContentIndices.add(name); - } - else { - myRequiringContentIndices.add(name); - } - myNoLimitCheckTypes.addAll(extension.getFileTypesWithSizeLimitNotApplicable()); - break; - } - catch (IOException e) { - LOG.info(e); - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); - IndexInfrastructure.rewriteVersion(versionFile, version); - } - } - return versionChanged; - } - - private static void saveRegisteredIndices(@NotNull Collection> ids) { - final File file = getRegisteredIndicesFile(); - try { - FileUtil.createIfDoesntExist(file); - final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); - try { - os.writeInt(ids.size()); - for (ID id : ids) { - IOUtil.writeString(id.toString(), os); - } - } - finally { - os.close(); - } - } - catch (IOException ignored) { - } - } - - @NotNull - private static Set readRegisteredIndexNames() { - final Set result = new THashSet(); - try { - final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); - try { - final int size = in.readInt(); - for (int idx = 0; idx < size; idx++) { - result.add(IOUtil.readString(in)); - } - } - finally { - in.close(); - } - } - catch (IOException ignored) { - } - return result; - } - - @NotNull - private static File getRegisteredIndicesFile() { - return new File(PathManager.getIndexRoot(), "registered"); - } - - @NotNull - private UpdatableIndex createIndex(@NotNull final ID indexId, @NotNull final FileBasedIndexExtension extension, @NotNull final MemoryIndexStorage storage) throws IOException { - final MapReduceIndex index; - if (extension instanceof CustomImplementationFileBasedIndexExtension) { - final UpdatableIndex custom = ((CustomImplementationFileBasedIndexExtension)extension).createIndexImplementation(indexId, this, storage); - - assert custom != null : "Custom index implementation must not be null; index: " + indexId; - - if (!(custom instanceof MapReduceIndex)) { - return custom; - } - index = (MapReduceIndex)custom; - } - else { - index = new MapReduceIndex(indexId, extension.getIndexer(), storage); - } - - final KeyDescriptor keyDescriptor = extension.getKeyDescriptor(); - index.setInputIdToDataKeysIndex(new Factory>>() { - @Override - public PersistentHashMap> create() { - try { - return createIdToDataKeysIndex(indexId, keyDescriptor, storage); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - }); - - return index; - } - - @NotNull - private static PersistentHashMap> createIdToDataKeysIndex(@NotNull final ID indexId, - @NotNull final KeyDescriptor keyDescriptor, - @NotNull MemoryIndexStorage storage) throws IOException { - final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); - final Ref isBufferingMode = new Ref(false); - final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); - - final DataExternalizer> dataExternalizer = new DataExternalizer>() { - @Override - public void save(DataOutput out, @NotNull Collection value) throws IOException { - try { - DataInputOutputUtil.writeINT(out, value.size()); - for (K key : value) { - keyDescriptor.save(out, key); - } - } - catch (IllegalArgumentException e) { - throw new IOException("Error saving data for index " + indexId, e); - } - } - - @NotNull - @Override - public Collection read(DataInput in) throws IOException { - try { - final int size = DataInputOutputUtil.readINT(in); - final List list = new ArrayList(size); - for (int idx = 0; idx < size; idx++) { - list.add(keyDescriptor.read(in)); - } - return list; - } - catch (IllegalArgumentException e) { - throw new IOException("Error reading data for index " + indexId, e); - } - } - }; - - // Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage. - // If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage). - // Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the - // wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be - // cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects. - - final PersistentHashMap> map = new PersistentHashMap>( - indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, dataExternalizer - ) { - - @Override - protected Collection doGet(Integer integer) throws IOException { - if (isBufferingMode.get()) { - final Collection collection = tempMap.get(integer); - if (collection != null) { - return collection; - } - } - return super.doGet(integer); - } - - @Override - protected void doPut(Integer integer, @Nullable Collection ks) throws IOException { - if (isBufferingMode.get()) { - tempMap.put(integer, ks == null? Collections.emptySet() : ks); - } - else { - super.doPut(integer, ks); - } - } - - @Override - protected void doRemove(Integer integer) throws IOException { - if (isBufferingMode.get()) { - tempMap.put(integer, Collections.emptySet()); - } - else { - super.doRemove(integer); - } - } - }; - - storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { - @Override - public void bufferingStateChanged(boolean newState) { - synchronized (map) { - isBufferingMode.set(newState); - } - } - @Override - public void memoryStorageCleared() { - synchronized (map) { - tempMap.clear(); - } - } - }); - return map; - } - - @Override - @NonNls - @NotNull - public String getComponentName() { - return "FileBasedIndex"; - } - - @Override - public void disposeComponent() { - performShutdown(); - } - - private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false); - - private void performShutdown() { - if (!myShutdownPerformed.compareAndSet(false, true)) { - return; // already shut down - } - try { - if (myFlushingFuture != null) { - myFlushingFuture.cancel(false); - myFlushingFuture = null; - } - - myFileDocumentManager.saveAllDocuments(); - } - finally { - LOG.info("START INDEX SHUTDOWN"); - try { - myChangedFilesCollector.forceUpdate(null, null, null, true); - - for (ID indexId : myIndices.keySet()) { - final UpdatableIndex index = getIndex(indexId); - assert index != null; - checkRebuild(indexId, true); // if the index was scheduled for rebuild, only clean it - //LOG.info("DISPOSING " + indexId); - index.dispose(); - } - - myVfManager.removeVirtualFileListener(myChangedFilesCollector); - - //FileUtil.delete(getMarkerFile()); - } - catch (Throwable e) { - LOG.info("Problems during index shutdown", e); - throw new RuntimeException(e); - } - LOG.info("END INDEX SHUTDOWN"); - } - } - - private void flushAllIndices(final long modCount) { - if (HeavyProcessLatch.INSTANCE.isRunning()) { - return; - } - IndexingStamp.flushCache(); - for (ID indexId : new ArrayList>(myIndices.keySet())) { - if (HeavyProcessLatch.INSTANCE.isRunning() || modCount != myLocalModCount) { - return; // do not interfere with 'main' jobs - } - try { - final UpdatableIndex index = getIndex(indexId); - if (index != null) { - index.flush(); - } - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - - if (!HeavyProcessLatch.INSTANCE.isRunning() && modCount == myLocalModCount) { // do not interfere with 'main' jobs - SerializationManager.getInstance().flushNameStorage(); - } - } - - /** - * @param project it is guaranteed to return data which is up-to-date withing the project - * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist - */ - @NotNull - public Collection getAllKeys(@NotNull final ID indexId, @NotNull Project project) { - Set allKeys = new THashSet(); - processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); - return allKeys; - } - - /** - * @param project it is guaranteed to return data which is up-to-date withing the project - * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist - */ - public boolean processAllKeys(@NotNull final ID indexId, Processor processor, @Nullable Project project) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return true; - } - ensureUpToDate(indexId, project, project != null? GlobalSearchScope.allScope(project) : new EverythingGlobalScope()); - return index.processAllKeys(processor); - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - - return false; - } - - private static final ThreadLocal myUpToDateCheckState = new ThreadLocal(); - - public static void disableUpToDateCheckForCurrentThread() { - final Integer currentValue = myUpToDateCheckState.get(); - myUpToDateCheckState.set(currentValue == null? 1 : currentValue.intValue() + 1); - } - - public static void enableUpToDateCheckForCurrentThread() { - final Integer currentValue = myUpToDateCheckState.get(); - if (currentValue != null) { - final int newValue = currentValue.intValue() - 1; - if (newValue != 0) { - myUpToDateCheckState.set(newValue); - } - else { - myUpToDateCheckState.remove(); - } - } - } - - private static boolean isUpToDateCheckEnabled() { - final Integer value = myUpToDateCheckState.get(); - return value == null || value.intValue() == 0; - } - - - private final ThreadLocal myReentrancyGuard = new ThreadLocal() { - @Override - protected Boolean initialValue() { - return Boolean.FALSE; - } - }; - - /** - * DO NOT CALL DIRECTLY IN CLIENT CODE - * The method is internal to indexing engine end is called internally. The method is public due to implementation details - */ - public void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter) { - ensureUpToDate(indexId, project, filter, null); - } - - private void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, - @Nullable VirtualFile restrictedFile) { - if (!needsFileContentLoading(indexId)) { - return; //indexed eagerly in foreground while building unindexed file list - } - if (isDumb(project)) { - handleDumbMode(project); - } - - if (myReentrancyGuard.get().booleanValue()) { - //assert false : "ensureUpToDate() is not reentrant!"; - return; - } - myReentrancyGuard.set(Boolean.TRUE); - - try { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - if (isUpToDateCheckEnabled()) { - try { - checkRebuild(indexId, false); - myChangedFilesCollector.forceUpdate(project, filter, restrictedFile, false); - indexUnsavedDocuments(indexId, project, filter, restrictedFile); - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, e); - } - else { - throw e; - } - } - } - } - finally { - myReentrancyGuard.set(Boolean.FALSE); - } - } - - private static void handleDumbMode(@Nullable Project project) { - ProgressManager.checkCanceled(); // DumbModeAction.CANCEL - - if (project != null) { - final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); - if (progressIndicator instanceof BackgroundableProcessIndicator) { - final BackgroundableProcessIndicator indicator = (BackgroundableProcessIndicator)progressIndicator; - if (indicator.getDumbModeAction() == DumbModeAction.WAIT) { - assert !ApplicationManager.getApplication().isDispatchThread(); - DumbService.getInstance(project).waitForSmartMode(); - return; - } - } - } - - throw new IndexNotReadyException(); - } - - private static boolean isDumb(@Nullable Project project) { - if (project != null) { - return DumbServiceImpl.getInstance(project).isDumb(); - } - for (Project proj : ProjectManager.getInstance().getOpenProjects()) { - if (DumbServiceImpl.getInstance(proj).isDumb()) { - return true; - } - } - return false; - } - - @NotNull - public List getValues(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final List values = new SmartList(); - processValuesImpl(indexId, dataKey, true, null, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - values.add(value); - return true; - } - }, filter); - return values; - } - - @NotNull - public Collection getContainingFiles(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final Set files = new THashSet(); - processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - files.add(file); - return true; - } - }, filter); - return files; - } - - - public interface ValueProcessor { - /** - * @param value a value to process - * @param file the file the value came from - * @return false if no further processing is needed, true otherwise - */ - boolean process(VirtualFile file, V value); - } - - /** - * @return false if ValueProcessor.process() returned false; true otherwise or if ValueProcessor was not called at all - */ - public boolean processValues(@NotNull final ID indexId, @NotNull final K dataKey, @Nullable final VirtualFile inFile, - @NotNull ValueProcessor processor, @NotNull final GlobalSearchScope filter) { - return processValuesImpl(indexId, dataKey, false, inFile, processor, filter); - } - - - - - @Nullable - private R processExceptions(@NotNull final ID indexId, - @Nullable final VirtualFile restrictToFile, - @NotNull final GlobalSearchScope filter, - @NotNull ThrowableConvertor, R, StorageException> computable) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return null; - } - final Project project = filter.getProject(); - //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; - ensureUpToDate(indexId, project, filter, restrictToFile); - - try { - index.getReadLock().lock(); - return computable.convert(index); - } - finally { - index.getReadLock().unlock(); - } - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = getCauseToRebuildIndex(e); - if (cause != null) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - return null; - } - - private boolean processValuesImpl(@NotNull final ID indexId, final K dataKey, final boolean ensureValueProcessedOnce, - @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, - @NotNull final GlobalSearchScope filter) { - ThrowableConvertor, Boolean, StorageException> keyProcessor = new ThrowableConvertor, Boolean, StorageException>() { - @Override - public Boolean convert(@NotNull UpdatableIndex index) throws StorageException { - final ValueContainer container = index.getData(dataKey); - - boolean shouldContinue = true; - - if (restrictToFile != null) { - if (restrictToFile instanceof VirtualFileWithId) { - final int restrictedFileId = getFileId(restrictToFile); - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - if (container.isAssociated(value, restrictedFileId)) { - shouldContinue = processor.process(restrictToFile, value); - if (!shouldContinue) { - break; - } - } - } - } - } - else { - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - ProjectIndexableFilesFilter projectFilesSet = projectIndexableFiles(filter.getProject()); - VALUES_LOOP: for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { - final V value = valueIt.next(); - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { - final int id = inputIdsIterator.next(); - if (projectFilesSet != null && !projectFilesSet.contains(id)) continue; - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - shouldContinue = processor.process(file, value); - if (!shouldContinue) { - break VALUES_LOOP; - } - if (ensureValueProcessedOnce) { - break; // continue with the next value - } - } - } - } - } - return shouldContinue; - } - }; - final Boolean result = processExceptions(indexId, restrictToFile, filter, keyProcessor); - return result == null || result.booleanValue(); - } - - public boolean processFilesContainingAllKeys(@NotNull final ID indexId, - @NotNull final Collection dataKeys, - @NotNull final GlobalSearchScope filter, - @Nullable Condition valueChecker, - @NotNull final Processor processor) { - ProjectIndexableFilesFilter filesSet = projectIndexableFiles(filter.getProject()); - final TIntHashSet set = collectFileIdsContainingAllKeys(indexId, dataKeys, filter, valueChecker, filesSet); - return set != null && processVirtualFiles(set, filter, processor); - } - - private static final Key> ourProjectFilesSetKey = Key.create("projectFiles"); - - public static final class ProjectIndexableFilesFilter { - private static final int SHIFT = 6; - private static final int MASK = (1 << SHIFT) - 1; - private final long[] myBitMask; - private final int myModificationCount; - private final int myMinId; - private final int myMaxId; - - private ProjectIndexableFilesFilter(@NotNull TIntHashSet set, int modificationCount) { - myModificationCount = modificationCount; - final int[] minMax = new int[2]; - if (set.size() > 0) { - minMax[0] = minMax[1] = set.iterator().next(); - } - set.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - minMax[0] = Math.min(minMax[0], value); - minMax[1] = Math.max(minMax[1], value); - return true; - } - }); - myMaxId = minMax[1]; - myMinId = minMax[0]; - myBitMask = new long[((myMaxId - myMinId) >> SHIFT) + 1]; - set.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - value = value - myMinId; - myBitMask[value >> SHIFT] |= (1L << (value & MASK)); - return true; - } - }); - } - - public boolean contains(int id) { - if (id < myMinId) return false; - if (id > myMaxId) return false; - id -= myMinId; - return (myBitMask[id >> SHIFT] & (1L << (id & MASK))) != 0; - } - } - - @Nullable - public ProjectIndexableFilesFilter projectIndexableFiles(@Nullable Project project) { - if (project == null) return null; - - SoftReference reference = project.getUserData(ourProjectFilesSetKey); - ProjectIndexableFilesFilter data = reference != null ? reference.get() : null; - if (data != null && data.myModificationCount == myFilesModCount) return data; - - final TIntHashSet filesSet = new TIntHashSet(); - iterateIndexableFiles(new ContentIterator() { - @Override - public boolean processFile(@NotNull VirtualFile fileOrDir) { - filesSet.add(((VirtualFileWithId)fileOrDir).getId()); - return true; - } - }, project, ProgressManager.getInstance().getProgressIndicator()); - ProjectIndexableFilesFilter files = new ProjectIndexableFilesFilter(filesSet, myFilesModCount); - project.putUserData(ourProjectFilesSetKey, new SoftReference(files)); - return files; - } - - @Nullable - private TIntHashSet collectFileIdsContainingAllKeys(@NotNull final ID indexId, - @NotNull final Collection dataKeys, - @NotNull final GlobalSearchScope filter, - @Nullable final Condition valueChecker, - @Nullable final ProjectIndexableFilesFilter projectFilesFilter) { - final ThrowableConvertor, TIntHashSet, StorageException> convertor = - new ThrowableConvertor, TIntHashSet, StorageException>() { - @Nullable - @Override - public TIntHashSet convert(@NotNull UpdatableIndex index) throws StorageException { - TIntHashSet mainIntersection = null; - - for (K dataKey : dataKeys) { - ProgressManager.checkCanceled(); - final TIntHashSet copy = new TIntHashSet(); - final ValueContainer container = index.getData(dataKey); - - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - if (valueChecker != null && !valueChecker.value(value)) { - continue; - } - - ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); - - if (mainIntersection == null || iterator.size() < mainIntersection.size()) { - for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { - final int id = inputIdsIterator.next(); - if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || - mainIntersection != null && mainIntersection.contains(id) - ) { - copy.add(id); - } - } - } else { - mainIntersection.forEach(new TIntProcedure() { - final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); - @Override - public boolean execute(int id) { - if (predicate.contains(id)) copy.add(id); - return true; - } - }); - } - } - - mainIntersection = copy; - if (mainIntersection.isEmpty()) { - return new TIntHashSet(); - } - } - - return mainIntersection; - } - }; - - - return processExceptions(indexId, null, filter, convertor); - } - - private static boolean processVirtualFiles(@NotNull TIntHashSet ids, - @NotNull final GlobalSearchScope filter, - @NotNull final Processor processor) { - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - return ids.forEach(new TIntProcedure() { - @Override - public boolean execute(int id) { - ProgressManager.checkCanceled(); - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - return processor.process(file); - } - return true; - } - }); - } - - @Nullable - public static Throwable getCauseToRebuildIndex(@NotNull RuntimeException e) { - Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException || - cause instanceof IllegalArgumentException) return cause; - return null; - } - - public boolean getFilesWithKey(@NotNull final ID indexId, - @NotNull final Set dataKeys, - @NotNull Processor processor, - @NotNull GlobalSearchScope filter) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return true; - } - final Project project = filter.getProject(); - //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; - ensureUpToDate(indexId, project, filter); - - try { - index.getReadLock().lock(); - final List locals = new ArrayList(); - for (K dataKey : dataKeys) { - TIntHashSet local = new TIntHashSet(); - locals.add(local); - final ValueContainer container = index.getData(dataKey); - - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { - final V value = valueIt.next(); - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { - final int id = inputIdsIterator.next(); - local.add(id); - } - } - } - - if (locals.isEmpty()) { - return true; - } - - Collections.sort(locals, new Comparator() { - @Override - public int compare(TIntHashSet o1, TIntHashSet o2) { - return o1.size() - o2.size(); - } - }); - - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - TIntIterator ids = join(locals).iterator(); - ProjectIndexableFilesFilter projectIndexableFilesFilter = projectIndexableFiles(project); - while (ids.hasNext()) { - int id = ids.next(); - if (projectIndexableFilesFilter != null && !projectIndexableFilesFilter.contains(id)) continue; - //VirtualFile file = IndexInfrastructure.findFileById(fs, id); - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - if (!processor.process(file)) { - return false; - } - } - } - } - finally { - index.getReadLock().unlock(); - } - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - return true; - } - - @NotNull - private static TIntHashSet join(@NotNull List locals) { - TIntHashSet result = locals.get(0); - if (locals.size() > 1) { - TIntIterator it = result.iterator(); - - while (it.hasNext()) { - int id = it.next(); - for (int i = 1; i < locals.size(); i++) { - if (!locals.get(i).contains(id)) { - it.remove(); - break; - } - } - } - } - return result; - } - - public void scheduleRebuild(@NotNull final ID indexId, @NotNull final Throwable e) { - LOG.info(e); - requestRebuild(indexId); - try { - checkRebuild(indexId, false); - } - catch (ProcessCanceledException ignored) { - } - } - - private void checkRebuild(@NotNull final ID indexId, final boolean cleanupOnly) { - final AtomicInteger status = ourRebuildStatus.get(indexId); - if (status.get() == OK) return; - if (status.compareAndSet(REQUIRES_REBUILD, REBUILD_IN_PROGRESS)) { - cleanupProcessedFlag(); - - final Runnable rebuildRunnable = new Runnable() { - @Override - public void run() { - try { - clearIndex(indexId); - if (!cleanupOnly) { - scheduleIndexRebuild(false); - } - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.info(e); - } - finally { - status.compareAndSet(REBUILD_IN_PROGRESS, OK); - } - } - }; - - if (cleanupOnly || myIsUnitTestMode) { - rebuildRunnable.run(); - } - else { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - new Task.Modal(null, "Updating index", false) { - @Override - public void run(@NotNull final ProgressIndicator indicator) { - indicator.setIndeterminate(true); - rebuildRunnable.run(); - } - }.queue(); - } - }); - } - } - - if (status.get() == REBUILD_IN_PROGRESS) { - throw new ProcessCanceledException(); - } - } - - private void scheduleIndexRebuild(boolean forceDumbMode) { - for (Project project : ProjectManager.getInstance().getOpenProjects()) { - final Set updatersToRun = Collections.singleton(new UnindexedFilesUpdater(project, this)); - final DumbServiceImpl service = DumbServiceImpl.getInstance(project); - if (forceDumbMode) { - service.queueCacheUpdateInDumbMode(updatersToRun); - } - else { - service.queueCacheUpdate(updatersToRun); - } - } - } - - private void clearIndex(@NotNull final ID indexId) throws StorageException { - final UpdatableIndex index = getIndex(indexId); - assert index != null: "Index with key " + indexId + " not found or not registered properly"; - index.clear(); - try { - IndexInfrastructure.rewriteVersion(IndexInfrastructure.getVersionFile(indexId), myIndexIdToVersionMap.get(indexId)); - } - catch (IOException e) { - LOG.error(e); - } - } - - @NotNull - private Set getUnsavedOrTransactedDocuments() { - final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); - synchronized (myTransactionMap) { - docs.addAll(myTransactionMap.keySet()); - } - return docs; - } - - private void indexUnsavedDocuments(@NotNull ID indexId, - @Nullable Project project, - GlobalSearchScope filter, - VirtualFile restrictedFile) throws StorageException { - if (myUpToDateIndices.contains(indexId)) { - return; // no need to index unsaved docs - } - - final Set documents = getUnsavedOrTransactedDocuments(); - if (!documents.isEmpty()) { - // now index unsaved data - final StorageGuard.Holder guard = setDataBufferingEnabled(true); - try { - final Semaphore semaphore = myUnsavedDataIndexingSemaphores.get(indexId); - - assert semaphore != null : "Semaphore for unsaved data indexing was not initialized for index " + indexId; - - semaphore.down(); - boolean allDocsProcessed = true; - try { - for (Document document : documents) { - allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); - } - } - finally { - semaphore.up(); - - while (!semaphore.waitFor(500)) { // may need to wait until another thread is done with indexing - if (Thread.holdsLock(PsiLock.LOCK)) { - break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. - } - } - if (allDocsProcessed && !hasActiveTransactions()) { - myUpToDateIndices.add(indexId); // safe to set the flag here, because it will be cleared under the WriteAction - } - } - } - finally { - guard.leave(); - } - } - } - - private boolean hasActiveTransactions() { - synchronized (myTransactionMap) { - return !myTransactionMap.isEmpty(); - } - } - - private interface DocumentContent { - String getText(); - long getModificationStamp(); - } - - private static class AuthenticContent implements DocumentContent { - private final Document myDocument; - - private AuthenticContent(final Document document) { - myDocument = document; - } - - @Override - public String getText() { - return myDocument.getText(); - } - - @Override - public long getModificationStamp() { - return myDocument.getModificationStamp(); - } - } - - private static class PsiContent implements DocumentContent { - private final Document myDocument; - private final PsiFile myFile; - - private PsiContent(final Document document, final PsiFile file) { - myDocument = document; - myFile = file; - } - - @Override - public String getText() { - if (myFile.getModificationStamp() != myDocument.getModificationStamp()) { - final ASTNode node = myFile.getNode(); - assert node != null; - return node.getText(); - } - return myDocument.getText(); - } - - @Override - public long getModificationStamp() { - return myFile.getModificationStamp(); - } - } - -// returns false if doc was not indexed because the file does not fit in scope - private boolean indexUnsavedDocument(@NotNull final Document document, @NotNull final ID requestedIndexId, final Project project, - @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedFile) throws StorageException { - final VirtualFile vFile = myFileDocumentManager.getFile(document); - if (!(vFile instanceof VirtualFileWithId) || !vFile.isValid()) { - return true; - } - - if (restrictedFile != null) { - if(vFile != restrictedFile) { - return false; - } - } - else if (filter != null && !filter.accept(vFile)) { - return false; - } - - final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); - - final DocumentContent content; - if (dominantContentFile != null && dominantContentFile.getModificationStamp() != document.getModificationStamp()) { - content = new PsiContent(document, dominantContentFile); - } - else { - content = new AuthenticContent(document); - } - - final long currentDocStamp = content.getModificationStamp(); - if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp)) { - final Ref exRef = new Ref(null); - ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { - @Override - public void run() { - try { - final String contentText = content.getText(); - if (isTooLarge(vFile, contentText.length())) { - return; - } - - final FileContentImpl newFc = new FileContentImpl(vFile, contentText, vFile.getCharset()); - - if (dominantContentFile != null) { - dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, true); - newFc.putUserData(IndexingDataKeys.PSI_FILE, dominantContentFile); - } - - if (content instanceof AuthenticContent) { - newFc.putUserData(EDITOR_HIGHLIGHTER, EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)); - } - - if (getInputFilter(requestedIndexId).acceptInput(vFile)) { - newFc.putUserData(IndexingDataKeys.PROJECT, project); - final int inputId = Math.abs(getFileId(vFile)); - getIndex(requestedIndexId).update(inputId, newFc); - } - - if (dominantContentFile != null) { - dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, null); - } - } - catch (StorageException e) { - exRef.set(e); - } - } - }); - final StorageException storageException = exRef.get(); - if (storageException != null) { - throw storageException; - } - } - return true; - } - - public static final Key EDITOR_HIGHLIGHTER = new Key("Editor"); - - @Nullable - private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { - synchronized (myTransactionMap) { - PsiFile psiFile = myTransactionMap.get(document); - if (psiFile != null) return psiFile; - } - - return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); - } - - private final StorageGuard myStorageLock = new StorageGuard(); - - @NotNull - private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) { - final StorageGuard.Holder holder = myStorageLock.enter(enabled); - for (ID indexId : myIndices.keySet()) { - final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); - assert index != null; - final IndexStorage indexStorage = index.getStorage(); - ((MemoryIndexStorage)indexStorage).setBufferingEnabled(enabled); - } - return holder; - } - - private void cleanupMemoryStorage() { - myLastIndexedDocStamps.clear(); - for (ID indexId : myIndices.keySet()) { - final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); - assert index != null; - final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage(); - index.getWriteLock().lock(); - try { - memStorage.clearMemoryMap(); - } - finally { - index.getWriteLock().unlock(); - } - memStorage.fireMemoryStorageCleared(); - } - } - - private void dropUnregisteredIndices() { - final Set indicesToDrop = readRegisteredIndexNames(); - for (ID key : myIndices.keySet()) { - indicesToDrop.remove(key.toString()); - } - for (String s : indicesToDrop) { - FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); - } - } - - public static void requestRebuild(ID indexId) { - requestRebuild(indexId, new Throwable()); - } - - public static void requestRebuild(ID indexId, Throwable throwable) { - cleanupProcessedFlag(); - LOG.info("Rebuild requested for index " + indexId, throwable); - ourRebuildStatus.get(indexId).set(REQUIRES_REBUILD); - } - - private UpdatableIndex getIndex(ID indexId) { - final Pair, InputFilter> pair = myIndices.get(indexId); - - assert pair != null : "Index data is absent for index " + indexId; - - //noinspection unchecked - return (UpdatableIndex)pair.getFirst(); - } - - private InputFilter getInputFilter(ID indexId) { - final Pair, InputFilter> pair = myIndices.get(indexId); - - assert pair != null : "Index data is absent for index " + indexId; - - return pair.getSecond(); - } - - public int getNumberOfPendingInvalidations() { - return myChangedFilesCollector.getNumberOfPendingInvalidations(); - } - - @NotNull - public Collection getFilesToUpdate(final Project project) { - return ContainerUtil.findAll(myChangedFilesCollector.getAllFilesToUpdate(), new Condition() { - @Override - public boolean value(VirtualFile virtualFile) { - for (IndexableFileSet set : myIndexableSets) { - final Project proj = myIndexableSetToProjectMap.get(set); - if (proj != null && !proj.equals(project)) { - continue; // skip this set as associated with a different project - } - if (set.isInSet(virtualFile)) { - return true; - } - } - return false; - } - }); - } - - public void processRefreshedFile(@NotNull Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - myChangedFilesCollector.processFileImpl(project, fileContent, false); - } - - public void indexFileContent(@Nullable Project project, @NotNull com.intellij.ide.caches.FileContent content) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - final VirtualFile file = content.getVirtualFile(); - FileContentImpl fc = null; - - PsiFile psiFile = null; - - FileTypeManagerImpl.cacheFileType(file, file.getFileType()); - try { - for (final ID indexId : myIndices.keySet()) { - if (shouldIndexFile(file, indexId)) { - if (fc == null) { - byte[] currentBytes; - try { - currentBytes = content.getBytes(); - } - catch (IOException e) { - currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY; - } - fc = new FileContentImpl(file, currentBytes); - - psiFile = content.getUserData(IndexingDataKeys.PSI_FILE); - if (psiFile != null) { - psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true); - fc.putUserData(IndexingDataKeys.PSI_FILE, psiFile); - } - if (project == null) { - project = ProjectUtil.guessProjectForFile(file); - } - fc.putUserData(IndexingDataKeys.PROJECT, project); - } - - try { - ProgressManager.checkCanceled(); - updateSingleIndex(indexId, file, fc); - } - catch (ProcessCanceledException e) { - myChangedFilesCollector.scheduleForUpdate(file); - throw e; - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.info(e); - } - } - } - - if (psiFile != null) { - psiFile.putUserData(PsiFileImpl.BUILDING_STUB, null); - } - } finally { - FileTypeManagerImpl.cacheFileType(file, null); - } - } - - private void updateSingleIndex(final ID indexId, @NotNull final VirtualFile file, @Nullable final FileContent currentFC) - throws StorageException { - if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { - return; // the index is scheduled for rebuild, no need to update - } - myLocalModCount++; - - final StorageGuard.Holder lock = setDataBufferingEnabled(false); - - try { - final int inputId = Math.abs(getFileId(file)); - - final UpdatableIndex index = getIndex(indexId); - assert index != null; - - final Ref exRef = new Ref(null); - ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { - @Override - public void run() { - try { - index.update(inputId, currentFC); - } - catch (StorageException e) { - exRef.set(e); - } - } - }); - final StorageException storageException = exRef.get(); - if (storageException != null) { - throw storageException; - } - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - if (file.isValid()) { - if (currentFC != null) { - IndexingStamp.update(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); - } - else { - // mark the file as unindexed - IndexingStamp.update(file, indexId, -1L); - } - } - } - }); - } - finally { - lock.leave(); - } + return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } public static int getFileId(@NotNull final VirtualFile file) { @@ -1693,653 +47,68 @@ public class FileBasedIndex implements ApplicationComponent { throw new IllegalArgumentException("Virtual file doesn't support id: " + file + ", implementation class: " + file.getClass().getName()); } - private boolean needsFileContentLoading(ID indexId) { - return !myNotRequiringContentIndices.contains(indexId); + public void requestRebuild(ID indexId) { + requestRebuild(indexId, new Throwable()); } - private abstract static class InvalidationTask implements Runnable { - private final VirtualFile mySubj; - protected InvalidationTask(final VirtualFile subj) { - mySubj = subj; - } - - public VirtualFile getSubj() { - return mySubj; - } - } - - private final class ChangedFilesCollector extends VirtualFileAdapter { - private final Set myFilesToUpdate = new ConcurrentHashSet(); - private final Queue myFutureInvalidations = new ConcurrentLinkedQueue(); - - private final ManagingFS myManagingFS = ManagingFS.getInstance(); - // No need to react on movement events since files stay valid, their ids don't change and all associated attributes remain intact. - - @Override - public void fileCreated(@NotNull final VirtualFileEvent event) { - markDirty(event, false); - } - - @Override - public void fileDeleted(@NotNull final VirtualFileEvent event) { - myFilesToUpdate.remove(event.getFile()); // no need to update it anymore - } - - @Override - public void fileCopied(@NotNull final VirtualFileCopyEvent event) { - markDirty(event, false); - } - - @Override - public void beforeFileDeletion(@NotNull final VirtualFileEvent event) { - invalidateIndices(event.getFile(), false); - } - - @Override - public void beforeContentsChange(@NotNull final VirtualFileEvent event) { - invalidateIndices(event.getFile(), true); - } - - @Override - public void contentsChanged(@NotNull final VirtualFileEvent event) { - markDirty(event, true); - } - - @Override - public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { - if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { - // indexes may depend on file name - final VirtualFile file = event.getFile(); - if (!file.isDirectory()) { - // name change may lead to filetype change so the file might become not indexable - // in general case have to 'unindex' the file and index it again if needed after the name has been changed - invalidateIndices(file, false); - } - } - } - - @Override - public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) { - if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { - // indexes may depend on file name - if (!event.getFile().isDirectory()) { - markDirty(event, false); - } - } - } - - private void markDirty(@NotNull final VirtualFileEvent event, final boolean contentChange) { - final VirtualFile eventFile = event.getFile(); - cleanProcessedFlag(eventFile); - iterateIndexableFiles(eventFile, new Processor() { - @Override - public boolean process(@NotNull final VirtualFile file) { - if (!contentChange) ++myFilesModCount; - FileContent fileContent = null; - // handle 'content-less' indices separately - for (ID indexId : myNotRequiringContentIndices) { - if (getInputFilter(indexId).acceptInput(file)) { - try { - if (fileContent == null) { - fileContent = new FileContentImpl(file); - } - updateSingleIndex(indexId, file, fileContent); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - } - // For 'normal indices' schedule the file for update and stop iteration if at least one index accepts it - if (!isTooLarge(file)) { - for (ID indexId : myIndices.keySet()) { - if (needsFileContentLoading(indexId) && getInputFilter(indexId).acceptInput(file)) { - scheduleForUpdate(file); - break; // no need to iterate further, as the file is already marked - } - } - } - - return true; - } - }); - IndexingStamp.flushCache(); - } - - public void scheduleForUpdate(VirtualFile file) { - myFilesToUpdate.add(file); - } - - void invalidateIndices(@NotNull final VirtualFile file, final boolean markForReindex) { - if (isUnderConfigOrSystem(file)) { - return; - } - if (file.isDirectory()) { - if (isMock(file) || myManagingFS.wereChildrenAccessed(file)) { - final Iterable children = file instanceof NewVirtualFile - ? ((NewVirtualFile)file).iterInDbChildren() : Arrays.asList(file.getChildren()); - for (VirtualFile child : children) { - invalidateIndices(child, markForReindex); - } - } - } - else { - cleanProcessedFlag(file); - IndexingStamp.flushCache(); - final List> affectedIndices = new ArrayList>(myIndices.size()); - - for (final ID indexId : myIndices.keySet()) { - try { - if (!needsFileContentLoading(indexId)) { - if (shouldUpdateIndex(file, indexId)) { - updateSingleIndex(indexId, file, null); - } - } - else { // the index requires file content - if (shouldUpdateIndex(file, indexId)) { - affectedIndices.add(indexId); - } - } - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - - if (!affectedIndices.isEmpty()) { - if (markForReindex && !isTooLarge(file)) { - // only mark the file as unindexed, reindex will be done lazily - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - for (ID indexId : affectedIndices) { - IndexingStamp.update(file, indexId, -2L); - } - } - }); - // the file is for sure not a dir and it was previously indexed by at least one index - scheduleForUpdate(file); - } - else { - myFutureInvalidations.offer(new InvalidationTask(file) { - @Override - public void run() { - removeFileDataFromIndices(affectedIndices, file); - } - }); - } - } - if (!markForReindex) { - final boolean removedFromUpdateQueue = myFilesToUpdate.remove(file);// no need to update it anymore - if (removedFromUpdateQueue && affectedIndices.isEmpty()) { - // Currently the file is about to be deleted and previously it was scheduled for update and not processed up to now. - // Because the file was scheduled for update, at the moment of scheduling it was marked as unindexed, - // so, to be on the safe side, we have to schedule data invalidation from all content-requiring indices for this file - myFutureInvalidations.offer(new InvalidationTask(file) { - @Override - public void run() { - removeFileDataFromIndices(myRequiringContentIndices, file); - } - }); - } - } - - IndexingStamp.flushCache(); - } - } - - private void removeFileDataFromIndices(@NotNull Collection> affectedIndices, @NotNull VirtualFile file) { - Throwable unexpectedError = null; - for (ID indexId : affectedIndices) { - try { - updateSingleIndex(indexId, file, null); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - catch (ProcessCanceledException ignored) { - } - catch (Throwable e) { - LOG.info(e); - if (unexpectedError == null) { - unexpectedError = e; - } - } - } - IndexingStamp.flushCache(); - if (unexpectedError != null) { - LOG.error(unexpectedError); - } - } - - public int getNumberOfPendingInvalidations() { - return myFutureInvalidations.size(); - } - - public void ensureAllInvalidateTasksCompleted() { - final int size = getNumberOfPendingInvalidations(); - if (size == 0) { - return; - } - final ProgressIndicator current = ProgressManager.getInstance().getProgressIndicator(); - final ProgressIndicator indicator = current != null ? current : new EmptyProgressIndicator(); - indicator.setText(""); - int count = 0; - while (true) { - InvalidationTask task = myFutureInvalidations.poll(); - - if (task == null) { - break; - } - indicator.setFraction((double)count++ /size); - indicator.setText2(task.getSubj().getPresentableUrl()); - task.run(); - } - } - - private void iterateIndexableFiles(@NotNull final VirtualFile file, @NotNull final Processor processor) { - if (file.isDirectory()) { - final ContentIterator iterator = new ContentIterator() { - @Override - public boolean processFile(@NotNull final VirtualFile fileOrDir) { - if (!fileOrDir.isDirectory()) { - processor.process(fileOrDir); - } - return true; - } - }; - - for (IndexableFileSet set : myIndexableSets) { - if (set.isInSet(file)) { - set.iterateIndexableFilesIn(file, iterator); - } - } - } - else { - for (IndexableFileSet set : myIndexableSets) { - if (set.isInSet(file)) { - processor.process(file); - break; - } - } - } - } - - public Collection getAllFilesToUpdate() { - if (myFilesToUpdate.isEmpty()) { - return Collections.emptyList(); - } - return new ArrayList(myFilesToUpdate); - } - - private final Semaphore myForceUpdateSemaphore = new Semaphore(); - - private void forceUpdate(@Nullable Project project, @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedTo, - boolean onlyRemoveOutdatedData) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - for (VirtualFile file: getAllFilesToUpdate()) { - if (filter == null || filter.accept(file) || file == restrictedTo) { - try { - myForceUpdateSemaphore.down(); - // process only files that can affect result - processFileImpl(project, new com.intellij.ide.caches.FileContent(file), onlyRemoveOutdatedData); - } - finally { - myForceUpdateSemaphore.up(); - } - } - } - - // If several threads entered the method at the same time and there were files to update, - // all the threads should leave the method synchronously after all the files scheduled for update are reindexed, - // no matter which thread will do reindexing job. - // Thus we ensure that all the threads that entered the method will get the most recent data - - while (!myForceUpdateSemaphore.waitFor(500)) { // may need to wait until another thread is done with indexing - if (Thread.holdsLock(PsiLock.LOCK)) { - break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. - } - } - } - - private void processFileImpl(Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent, boolean onlyRemoveOutdatedData) { - final VirtualFile file = fileContent.getVirtualFile(); - final boolean reallyRemoved = myFilesToUpdate.remove(file); - if (reallyRemoved && file.isValid()) { - if (onlyRemoveOutdatedData) { - // on shutdown there is no need to re-index the file, just remove outdated data from indices - final List> affected = new ArrayList>(); - for (final ID indexId : myIndices.keySet()) { - if (getInputFilter(indexId).acceptInput(file)) { - affected.add(indexId); - } - } - removeFileDataFromIndices(affected, file); - } - else { - indexFileContent(project, fileContent); - } - IndexingStamp.flushCache(); - } - } - } - - private class UnindexedFilesFinder implements CollectingContentIterator { - private final List myFiles = new ArrayList(); - private final ProgressIndicator myProgressIndicator; - - private UnindexedFilesFinder() { - myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); - } - - @NotNull - @Override - public List getFiles() { - return myFiles; - } - - @Override - public boolean processFile(@NotNull final VirtualFile file) { - if (!file.isValid()) { - return true; - } - if (!file.isDirectory()) { - if (file instanceof NewVirtualFile && ((NewVirtualFile)file).getFlag(ALREADY_PROCESSED)) { - return true; - } - - if (file instanceof VirtualFileWithId) { - try { - FileTypeManagerImpl.cacheFileType(file, file.getFileType()); - - boolean oldStuff = true; - if (!isTooLarge(file)) { - for (ID indexId : myIndices.keySet()) { - try { - if (needsFileContentLoading(indexId) && shouldIndexFile(file, indexId)) { - myFiles.add(file); - oldStuff = false; - break; - } - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof IOException || cause instanceof StorageException) { - LOG.info(e); - requestRebuild(indexId); - } - else { - throw e; - } - } - } - } - FileContent fileContent = null; - for (ID indexId : myNotRequiringContentIndices) { - if (shouldIndexFile(file, indexId)) { - oldStuff = false; - try { - if (fileContent == null) { - fileContent = new FileContentImpl(file); - } - updateSingleIndex(indexId, file, fileContent); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - } - IndexingStamp.flushCache(); - - if (oldStuff && file instanceof NewVirtualFile) { - ((NewVirtualFile)file).setFlag(ALREADY_PROCESSED, true); - } - } - finally { - FileTypeManagerImpl.cacheFileType(file, null); - } - } - } - else { - if (myProgressIndicator != null) { - myProgressIndicator.setText("Scanning files to index"); - myProgressIndicator.setText2(file.getPresentableUrl()); - } - } - return true; - } - } - - private boolean shouldUpdateIndex(final VirtualFile file, final ID indexId) { - return getInputFilter(indexId).acceptInput(file) && - (isMock(file) || IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); - } - - private boolean shouldIndexFile(final VirtualFile file, final ID indexId) { - return getInputFilter(indexId).acceptInput(file) && - (isMock(file) || !IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); - } - - private boolean isUnderConfigOrSystem(@NotNull VirtualFile file) { - final String filePath = file.getPath(); - return myConfigPath != null && FileUtil.startsWith(filePath, myConfigPath) || - mySystemPath != null && FileUtil.startsWith(filePath, mySystemPath); - } - - private static boolean isMock(final VirtualFile file) { - return !(file instanceof NewVirtualFile); - } - - private boolean isTooLarge(@NotNull VirtualFile file) { - if (SingleRootFileViewProvider.isTooLarge(file)) { - final FileType type = file.getFileType(); - return !myNoLimitCheckTypes.contains(type); - } - return false; - } - - private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) { - if (SingleRootFileViewProvider.isTooLarge(file, contentSize)) { - final FileType type = file.getFileType(); - return !myNoLimitCheckTypes.contains(type); - } - return false; + @NonNls + @NotNull + public String getComponentName() { + return "FileBasedIndex"; } @NotNull - public CollectingContentIterator createContentIterator() { - ++myFilesModCount; - return new UnindexedFilesFinder(); - } + public abstract List getValues(@NotNull ID indexId, @NotNull K dataKey, @NotNull GlobalSearchScope filter); - public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { - myIndexableSets.add(set); - myIndexableSetToProjectMap.put(set, project); - } + @NotNull + public abstract Collection getContainingFiles(@NotNull ID indexId, + @NotNull K dataKey, + @NotNull GlobalSearchScope filter); - public void removeIndexableSet(@NotNull IndexableFileSet set) { - myChangedFilesCollector.forceUpdate(null, null, null, true); - myIndexableSets.remove(set); - myIndexableSetToProjectMap.remove(set); - } + public abstract boolean processValues(@NotNull ID indexId, + @NotNull K dataKey, + @Nullable VirtualFile inFile, + @NotNull FileBasedIndex.ValueProcessor processor, + @NotNull GlobalSearchScope filter); - @Nullable - private static PsiFile findLatestKnownPsiForUncomittedDocument(@NotNull Document doc, @NotNull Project project) { - return PsiDocumentManager.getInstance(project).getCachedPsiFile(doc); - } - - private static class IndexableFilesFilter implements InputFilter { - private final InputFilter myDelegate; + public abstract boolean processFilesContainingAllKeys(@NotNull ID indexId, + @NotNull Collection dataKeys, + @NotNull GlobalSearchScope filter, + @Nullable Condition valueChecker, + @NotNull Processor processor); - private IndexableFilesFilter(InputFilter delegate) { - myDelegate = delegate; - } + @NotNull + public abstract Collection getAllKeys(@NotNull ID indexId, @NotNull Project project); - @Override - public boolean acceptInput(final VirtualFile file) { - return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); - } - } + public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); - private static void cleanupProcessedFlag() { - final VirtualFile[] roots = ManagingFS.getInstance().getRoots(); - for (VirtualFile root : roots) { - cleanProcessedFlag(root); - } - } + protected abstract void ensureUpToDate(@NotNull ID indexId, + @Nullable Project project, + @Nullable GlobalSearchScope filter, + @Nullable VirtualFile restrictedFile); - private static void cleanProcessedFlag(@NotNull final VirtualFile file) { - if (!(file instanceof NewVirtualFile)) return; - - final NewVirtualFile nvf = (NewVirtualFile)file; - if (file.isDirectory()) { - for (VirtualFile child : nvf.getCachedChildren()) { - cleanProcessedFlag(child); - } - } - else { - nvf.setFlag(ALREADY_PROCESSED, false); - } - } + public abstract void requestRebuild(ID indexId, Throwable throwable); - public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { - if (project.isDisposed()) { - return; - } - final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - // iterate project content - projectFileIndex.iterateContent(processor); + public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); - if (project.isDisposed()) { - return; - } + public abstract void requestReindex(@NotNull VirtualFile file); - Set visitedRoots = new THashSet(); - for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { - //important not to depend on project here, to support per-project background reindex - // each client gives a project to FileBasedIndex - if (project.isDisposed()) { - return; - } - for (VirtualFile root : IndexableSetContributor.getRootsToIndex(provider)) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - for (VirtualFile root : IndexableSetContributor.getProjectRootsToIndex(provider, project)) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - } + public abstract void requestReindexExcluded(@NotNull VirtualFile file); - if (project.isDisposed()) { - return; - } - // iterate associated libraries - for (Module module : ModuleManager.getInstance(project).getModules()) { - if (module.isDisposed()) { - return; - } - OrderEntry[] orderEntries = ModuleRootManager.getInstance(module).getOrderEntries(); - for (OrderEntry orderEntry : orderEntries) { - if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { - if (orderEntry.isValid()) { - final VirtualFile[] libSources = orderEntry.getFiles(OrderRootType.SOURCES); - final VirtualFile[] libClasses = orderEntry.getFiles(OrderRootType.CLASSES); - for (VirtualFile[] roots : new VirtualFile[][]{libSources, libClasses}) { - for (VirtualFile root : roots) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - } - } - } - } - } - } + public abstract boolean getFilesWithKey(@NotNull ID indexId, + @NotNull Set dataKeys, + @NotNull Processor processor, + @NotNull GlobalSearchScope filter); - private static void iterateRecursively(@Nullable final VirtualFile root, @NotNull final ContentIterator processor, @Nullable ProgressIndicator indicator) { - if (root != null) { - if (indicator != null) { - indicator.checkCanceled(); - indicator.setText2(root.getPresentableUrl()); - } - - if (root.isDirectory()) { - for (VirtualFile file : root.getChildren()) { - if (file.isDirectory()) { - iterateRecursively(file, processor, indicator); - } - else { - processor.processFile(file); - } - } - } - else { - processor.processFile(root); - } - } - } - - private static class StorageGuard { - private int myHolds = 0; - - public interface Holder { - void leave(); - } - - private final Holder myTrueHolder = new Holder() { - @Override - public void leave() { - StorageGuard.this.leave(true); - } - }; - private final Holder myFalseHolder = new Holder() { - @Override - public void leave() { - StorageGuard.this.leave(false); - } - }; - - @NotNull - public synchronized Holder enter(boolean mode) { - if (mode) { - while (myHolds < 0) { - try { - wait(); - } - catch (InterruptedException ignored) { - } - } - myHolds++; - return myTrueHolder; - } - else { - while (myHolds > 0) { - try { - wait(); - } - catch (InterruptedException ignored) { - } - } - myHolds--; - return myFalseHolder; - } - } - - private synchronized void leave(boolean mode) { - myHolds += mode? -1 : 1; - if (myHolds == 0) { - notifyAll(); - } - } + public abstract boolean processAllKeys(@NotNull ID indexId, Processor processor, @Nullable Project project); + public interface ValueProcessor { + /** + * @param value a value to process + * @param file the file the value came from + * @return false if no further processing is needed, true otherwise + */ + boolean process(VirtualFile file, V value); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java new file mode 100644 index 000000000000..1cf3b2677d89 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -0,0 +1,2327 @@ +/* + * Copyright 2000-2012 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.util.indexing; + +import com.intellij.AppTopics; +import com.intellij.history.LocalHistory; +import com.intellij.ide.caches.CacheUpdater; +import com.intellij.lang.ASTNode; +import com.intellij.notification.NotificationDisplayType; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.application.ApplicationAdapter; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.impl.EditorHighlighterCache; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; +import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.*; +import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; +import com.intellij.openapi.project.*; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; +import com.intellij.openapi.vfs.newvfs.BulkFileListener; +import com.intellij.openapi.vfs.newvfs.ManagingFS; +import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.openapi.vfs.newvfs.events.VFileEvent; +import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon; +import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiDocumentTransactionListener; +import com.intellij.psi.impl.source.PsiFileImpl; +import com.intellij.psi.search.EverythingGlobalScope; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.stubs.SerializationManager; +import com.intellij.util.*; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ConcurrentHashSet; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.*; +import com.intellij.util.io.DataOutputStream; +import com.intellij.util.io.storage.HeavyProcessLatch; +import com.intellij.util.messages.MessageBus; +import com.intellij.util.messages.MessageBusConnection; +import gnu.trove.*; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.*; +import java.lang.ref.SoftReference; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Eugene Zhuravlev + * Date: Dec 20, 2007 + */ + +public class FileBasedIndexImpl extends FileBasedIndex { + private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.FileBasedIndexImpl"); + @NonNls + private static final String CORRUPTION_MARKER_NAME = "corruption.marker"; + private final Map, Pair, InputFilter>> myIndices = new THashMap, Pair, InputFilter>>(); + private final Map, Semaphore> myUnsavedDataIndexingSemaphores = new THashMap, Semaphore>(); + private final TObjectIntHashMap> myIndexIdToVersionMap = new TObjectIntHashMap>(); + private final Set> myNotRequiringContentIndices = new THashSet>(); + private final Set> myRequiringContentIndices = new THashSet>(); + private final Set myNoLimitCheckTypes = new THashSet(); + + private final PerIndexDocumentVersionMap myLastIndexedDocStamps = new PerIndexDocumentVersionMap(); + @NotNull private final ChangedFilesCollector myChangedFilesCollector; + + private final List myIndexableSets = ContainerUtil.createEmptyCOWList(); + private final Map myIndexableSetToProjectMap = new THashMap(); + + private static final int OK = 1; + private static final int REQUIRES_REBUILD = 2; + private static final int REBUILD_IN_PROGRESS = 3; + private static final Map, AtomicInteger> ourRebuildStatus = new THashMap, AtomicInteger>(); + + private final VirtualFileManagerEx myVfManager; + private final FileDocumentManager myFileDocumentManager; + private final FileTypeManager myFileTypeManager; + private final ConcurrentHashSet> myUpToDateIndices = new ConcurrentHashSet>(); + private final Map myTransactionMap = new THashMap(); + + private static final int ALREADY_PROCESSED = 0x04; + + @Nullable private final String myConfigPath; + @Nullable private final String mySystemPath; + private final boolean myIsUnitTestMode; + @Nullable private ScheduledFuture myFlushingFuture; + private volatile int myLocalModCount; + private volatile int myFilesModCount; + + @Override + public void requestReindex(@NotNull final VirtualFile file) { + myChangedFilesCollector.invalidateIndices(file, true); + } + + @Override + public void requestReindexExcluded(@NotNull final VirtualFile file) { + myChangedFilesCollector.invalidateIndices(file, false); + } + + public FileBasedIndexImpl(final VirtualFileManagerEx vfManager, + FileDocumentManager fdm, + FileTypeManager fileTypeManager, + @NotNull MessageBus bus, + SerializationManager sm + /*need this parameter to ensure component dependency*/) throws IOException { + myVfManager = vfManager; + myFileDocumentManager = fdm; + myFileTypeManager = fileTypeManager; + myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); + myConfigPath = calcConfigPath(PathManager.getConfigPath()); + mySystemPath = calcConfigPath(PathManager.getSystemPath()); + + final MessageBusConnection connection = bus.connect(); + connection.subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { + @Override + public void transactionStarted(final Document doc, final PsiFile file) { + if (file != null) { + synchronized (myTransactionMap) { + myTransactionMap.put(doc, file); + } + myUpToDateIndices.clear(); + } + } + + @Override + public void transactionCompleted(final Document doc, final PsiFile file) { + synchronized (myTransactionMap) { + myTransactionMap.remove(doc); + } + } + }); + + connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener() { + @Nullable private Map> myTypeToExtensionMap; + @Override + public void beforeFileTypesChanged(final FileTypeEvent event) { + cleanupProcessedFlag(); + myTypeToExtensionMap = new THashMap>(); + for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { + myTypeToExtensionMap.put(type, getExtensions(type)); + } + } + + @Override + public void fileTypesChanged(final FileTypeEvent event) { + final Map> oldExtensions = myTypeToExtensionMap; + myTypeToExtensionMap = null; + if (oldExtensions != null) { + final Map> newExtensions = new THashMap>(); + for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { + newExtensions.put(type, getExtensions(type)); + } + // we are interested only in extension changes or removals. + // addition of an extension is handled separately by RootsChanged event + if (!newExtensions.keySet().containsAll(oldExtensions.keySet())) { + rebuildAllIndices(); + return; + } + for (Map.Entry> entry : oldExtensions.entrySet()) { + FileType fileType = entry.getKey(); + Set strings = entry.getValue(); + if (!newExtensions.get(fileType).containsAll(strings)) { + rebuildAllIndices(); + return; + } + } + } + } + + @NotNull + private Set getExtensions(@NotNull FileType type) { + final Set set = new THashSet(); + for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { + set.add(matcher.getPresentableString()); + } + return set; + } + + private void rebuildAllIndices() { + for (ID indexId : myIndices.keySet()) { + try { + clearIndex(indexId); + } + catch (StorageException e) { + LOG.info(e); + } + } + scheduleIndexRebuild(true); + } + }); + + connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + @Override + public void before(@NotNull List events) { + for (VFileEvent event : events) { + final Object requestor = event.getRequestor(); + if (requestor instanceof FileDocumentManager || requestor instanceof PsiManager || requestor == LocalHistory.VFS_EVENT_REQUESTOR) { + cleanupMemoryStorage(); + break; + } + } + } + + @Override + public void after(@NotNull List events) { + } + }); + + connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { + @Override + public void fileContentReloaded(VirtualFile file, @NotNull Document document) { + cleanupMemoryStorage(); + } + + @Override + public void unsavedDocumentsDropped() { + cleanupMemoryStorage(); + } + }); + + ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { + @Override + public void writeActionStarted(Object action) { + myUpToDateIndices.clear(); + } + }); + + myChangedFilesCollector = new ChangedFilesCollector(); + + /* + final File workInProgressFile = getMarkerFile(); + if (workInProgressFile.exists()) { + // previous IDEA session was closed incorrectly, so drop all indices + FileUtil.delete(PathManager.getIndexRoot()); + } + */ + + try { + final FileBasedIndexExtension[] extensions = Extensions.getExtensions(FileBasedIndexExtension.EXTENSION_POINT_NAME); + for (FileBasedIndexExtension extension : extensions) { + ourRebuildStatus.put(extension.getName(), new AtomicInteger(OK)); + } + + final File corruptionMarker = new File(PathManager.getIndexRoot(), CORRUPTION_MARKER_NAME); + final boolean currentVersionCorrupted = corruptionMarker.exists(); + boolean versionChanged = false; + for (FileBasedIndexExtension extension : extensions) { + versionChanged |= registerIndexer(extension, currentVersionCorrupted); + } + FileUtil.delete(corruptionMarker); + + String rebuildNotification = null; + if (currentVersionCorrupted) { + rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; + } + else if (versionChanged) { + rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; + } + if (rebuildNotification != null + && !ApplicationManager.getApplication().isHeadlessEnvironment() + && Registry.is("ide.showIndexRebuildMessage")) { + new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) + .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); + } + + dropUnregisteredIndices(); + + // check if rebuild was requested for any index during registration + for (ID indexId : myIndices.keySet()) { + if (ourRebuildStatus.get(indexId).compareAndSet(REQUIRES_REBUILD, OK)) { + try { + clearIndex(indexId); + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.error(e); + } + } + } + + myVfManager.addVirtualFileListener(myChangedFilesCollector); + + registerIndexableSet(new AdditionalIndexableFileSet(), null); + } + finally { + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + @Override + public void run() { + performShutdown(); + } + }); + //FileUtil.createIfDoesntExist(workInProgressFile); + saveRegisteredIndices(myIndices.keySet()); + myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() { + int lastModCount = 0; + @Override + public void run() { + if (lastModCount == myLocalModCount) { + flushAllIndices(lastModCount); + } + lastModCount = myLocalModCount; + } + }); + + } + } + + @Override + public void initComponent() { + } + + @Nullable + private static String calcConfigPath(final String path) { + try { + final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()); + return _path.endsWith("/")? _path : _path + "/" ; + } + catch (IOException e) { + LOG.info(e); + return null; + } + } + + /** + * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted + * + * @param extension + * @param isCurrentVersionCorrupted + */ + private boolean registerIndexer(@NotNull final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) throws IOException { + final ID name = extension.getName(); + final int version = extension.getVersion(); + final File versionFile = IndexInfrastructure.getVersionFile(name); + final boolean versionFileExisted = versionFile.exists(); + boolean versionChanged = false; + if (isCurrentVersionCorrupted || IndexInfrastructure.versionDiffers(versionFile, version)) { + if (!isCurrentVersionCorrupted && versionFileExisted) { + versionChanged = true; + LOG.info("Version has changed for index " + name + ". The index will be rebuilt."); + } + FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + IndexInfrastructure.rewriteVersion(versionFile, version); + } + + for (int attempt = 0; attempt < 2; attempt++) { + try { + final MapIndexStorage storage = new MapIndexStorage(IndexInfrastructure.getStorageFile(name), extension.getKeyDescriptor(), extension.getValueExternalizer(), extension.getCacheSize()); + final MemoryIndexStorage memStorage = new MemoryIndexStorage(storage); + final UpdatableIndex index = createIndex(name, extension, memStorage); + final InputFilter inputFilter = extension.getInputFilter(); + + assert inputFilter != null : "Index extension " + name + " must provide non-null input filter"; + + myIndices.put(name, new Pair, InputFilter>(index, new IndexableFilesFilter(inputFilter))); + myUnsavedDataIndexingSemaphores.put(name, new Semaphore()); + myIndexIdToVersionMap.put(name, version); + if (!extension.dependsOnFileContent()) { + myNotRequiringContentIndices.add(name); + } + else { + myRequiringContentIndices.add(name); + } + myNoLimitCheckTypes.addAll(extension.getFileTypesWithSizeLimitNotApplicable()); + break; + } + catch (IOException e) { + LOG.info(e); + FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + IndexInfrastructure.rewriteVersion(versionFile, version); + } + } + return versionChanged; + } + + private static void saveRegisteredIndices(@NotNull Collection> ids) { + final File file = getRegisteredIndicesFile(); + try { + FileUtil.createIfDoesntExist(file); + final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); + try { + os.writeInt(ids.size()); + for (ID id : ids) { + IOUtil.writeString(id.toString(), os); + } + } + finally { + os.close(); + } + } + catch (IOException ignored) { + } + } + + @NotNull + private static Set readRegisteredIndexNames() { + final Set result = new THashSet(); + try { + final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); + try { + final int size = in.readInt(); + for (int idx = 0; idx < size; idx++) { + result.add(IOUtil.readString(in)); + } + } + finally { + in.close(); + } + } + catch (IOException ignored) { + } + return result; + } + + @NotNull + private static File getRegisteredIndicesFile() { + return new File(PathManager.getIndexRoot(), "registered"); + } + + @NotNull + private UpdatableIndex createIndex(@NotNull final ID indexId, @NotNull final FileBasedIndexExtension extension, @NotNull final MemoryIndexStorage storage) throws IOException { + final MapReduceIndex index; + if (extension instanceof CustomImplementationFileBasedIndexExtension) { + final UpdatableIndex custom = ((CustomImplementationFileBasedIndexExtension)extension).createIndexImplementation(indexId, this, storage); + + assert custom != null : "Custom index implementation must not be null; index: " + indexId; + + if (!(custom instanceof MapReduceIndex)) { + return custom; + } + index = (MapReduceIndex)custom; + } + else { + index = new MapReduceIndex(indexId, extension.getIndexer(), storage); + } + + final KeyDescriptor keyDescriptor = extension.getKeyDescriptor(); + index.setInputIdToDataKeysIndex(new Factory>>() { + @Override + public PersistentHashMap> create() { + try { + return createIdToDataKeysIndex(indexId, keyDescriptor, storage); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }); + + return index; + } + + @NotNull + private static PersistentHashMap> createIdToDataKeysIndex(@NotNull final ID indexId, + @NotNull final KeyDescriptor keyDescriptor, + @NotNull MemoryIndexStorage storage) throws IOException { + final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); + final Ref isBufferingMode = new Ref(false); + final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); + + final DataExternalizer> dataExternalizer = new DataExternalizer>() { + @Override + public void save(DataOutput out, @NotNull Collection value) throws IOException { + try { + DataInputOutputUtil.writeINT(out, value.size()); + for (K key : value) { + keyDescriptor.save(out, key); + } + } + catch (IllegalArgumentException e) { + throw new IOException("Error saving data for index " + indexId, e); + } + } + + @NotNull + @Override + public Collection read(DataInput in) throws IOException { + try { + final int size = DataInputOutputUtil.readINT(in); + final List list = new ArrayList(size); + for (int idx = 0; idx < size; idx++) { + list.add(keyDescriptor.read(in)); + } + return list; + } + catch (IllegalArgumentException e) { + throw new IOException("Error reading data for index " + indexId, e); + } + } + }; + + // Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage. + // If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage). + // Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the + // wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be + // cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects. + + final PersistentHashMap> map = new PersistentHashMap>( + indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, dataExternalizer + ) { + + @Override + protected Collection doGet(Integer integer) throws IOException { + if (isBufferingMode.get()) { + final Collection collection = tempMap.get(integer); + if (collection != null) { + return collection; + } + } + return super.doGet(integer); + } + + @Override + protected void doPut(Integer integer, @Nullable Collection ks) throws IOException { + if (isBufferingMode.get()) { + tempMap.put(integer, ks == null? Collections.emptySet() : ks); + } + else { + super.doPut(integer, ks); + } + } + + @Override + protected void doRemove(Integer integer) throws IOException { + if (isBufferingMode.get()) { + tempMap.put(integer, Collections.emptySet()); + } + else { + super.doRemove(integer); + } + } + }; + + storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { + @Override + public void bufferingStateChanged(boolean newState) { + synchronized (map) { + isBufferingMode.set(newState); + } + } + @Override + public void memoryStorageCleared() { + synchronized (map) { + tempMap.clear(); + } + } + }); + return map; + } + + @Override + public void disposeComponent() { + performShutdown(); + } + + private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false); + + private void performShutdown() { + if (!myShutdownPerformed.compareAndSet(false, true)) { + return; // already shut down + } + try { + if (myFlushingFuture != null) { + myFlushingFuture.cancel(false); + myFlushingFuture = null; + } + + myFileDocumentManager.saveAllDocuments(); + } + finally { + LOG.info("START INDEX SHUTDOWN"); + try { + myChangedFilesCollector.forceUpdate(null, null, null, true); + + for (ID indexId : myIndices.keySet()) { + final UpdatableIndex index = getIndex(indexId); + assert index != null; + checkRebuild(indexId, true); // if the index was scheduled for rebuild, only clean it + //LOG.info("DISPOSING " + indexId); + index.dispose(); + } + + myVfManager.removeVirtualFileListener(myChangedFilesCollector); + + //FileUtil.delete(getMarkerFile()); + } + catch (Throwable e) { + LOG.info("Problems during index shutdown", e); + throw new RuntimeException(e); + } + LOG.info("END INDEX SHUTDOWN"); + } + } + + private void flushAllIndices(final long modCount) { + if (HeavyProcessLatch.INSTANCE.isRunning()) { + return; + } + IndexingStamp.flushCache(); + for (ID indexId : new ArrayList>(myIndices.keySet())) { + if (HeavyProcessLatch.INSTANCE.isRunning() || modCount != myLocalModCount) { + return; // do not interfere with 'main' jobs + } + try { + final UpdatableIndex index = getIndex(indexId); + if (index != null) { + index.flush(); + } + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + + if (!HeavyProcessLatch.INSTANCE.isRunning() && modCount == myLocalModCount) { // do not interfere with 'main' jobs + SerializationManager.getInstance().flushNameStorage(); + } + } + + /** + * @param project it is guaranteed to return data which is up-to-date withing the project + * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist + */ + @Override + @NotNull + public Collection getAllKeys(@NotNull final ID indexId, @NotNull Project project) { + Set allKeys = new THashSet(); + processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); + return allKeys; + } + + /** + * @param project it is guaranteed to return data which is up-to-date withing the project + * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist + */ + @Override + public boolean processAllKeys(@NotNull final ID indexId, Processor processor, @Nullable Project project) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return true; + } + ensureUpToDate(indexId, project, project != null? GlobalSearchScope.allScope(project) : new EverythingGlobalScope()); + return index.processAllKeys(processor); + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + + return false; + } + + private static final ThreadLocal myUpToDateCheckState = new ThreadLocal(); + + public static void disableUpToDateCheckForCurrentThread() { + final Integer currentValue = myUpToDateCheckState.get(); + myUpToDateCheckState.set(currentValue == null? 1 : currentValue.intValue() + 1); + } + + public static void enableUpToDateCheckForCurrentThread() { + final Integer currentValue = myUpToDateCheckState.get(); + if (currentValue != null) { + final int newValue = currentValue.intValue() - 1; + if (newValue != 0) { + myUpToDateCheckState.set(newValue); + } + else { + myUpToDateCheckState.remove(); + } + } + } + + private static boolean isUpToDateCheckEnabled() { + final Integer value = myUpToDateCheckState.get(); + return value == null || value.intValue() == 0; + } + + + private final ThreadLocal myReentrancyGuard = new ThreadLocal() { + @Override + protected Boolean initialValue() { + return Boolean.FALSE; + } + }; + + /** + * DO NOT CALL DIRECTLY IN CLIENT CODE + * The method is internal to indexing engine end is called internally. The method is public due to implementation details + */ + @Override + public void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter) { + ensureUpToDate(indexId, project, filter, null); + } + + @Override + protected void ensureUpToDate(@NotNull final ID indexId, + @Nullable Project project, + @Nullable GlobalSearchScope filter, + @Nullable VirtualFile restrictedFile) { + if (!needsFileContentLoading(indexId)) { + return; //indexed eagerly in foreground while building unindexed file list + } + if (isDumb(project)) { + handleDumbMode(project); + } + + if (myReentrancyGuard.get().booleanValue()) { + //assert false : "ensureUpToDate() is not reentrant!"; + return; + } + myReentrancyGuard.set(Boolean.TRUE); + + try { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + if (isUpToDateCheckEnabled()) { + try { + checkRebuild(indexId, false); + myChangedFilesCollector.forceUpdate(project, filter, restrictedFile, false); + indexUnsavedDocuments(indexId, project, filter, restrictedFile); + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, e); + } + else { + throw e; + } + } + } + } + finally { + myReentrancyGuard.set(Boolean.FALSE); + } + } + + private static void handleDumbMode(@Nullable Project project) { + ProgressManager.checkCanceled(); // DumbModeAction.CANCEL + + if (project != null) { + final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); + if (progressIndicator instanceof BackgroundableProcessIndicator) { + final BackgroundableProcessIndicator indicator = (BackgroundableProcessIndicator)progressIndicator; + if (indicator.getDumbModeAction() == DumbModeAction.WAIT) { + assert !ApplicationManager.getApplication().isDispatchThread(); + DumbService.getInstance(project).waitForSmartMode(); + return; + } + } + } + + throw new IndexNotReadyException(); + } + + private static boolean isDumb(@Nullable Project project) { + if (project != null) { + return DumbServiceImpl.getInstance(project).isDumb(); + } + for (Project proj : ProjectManager.getInstance().getOpenProjects()) { + if (DumbServiceImpl.getInstance(proj).isDumb()) { + return true; + } + } + return false; + } + + @Override + @NotNull + public List getValues(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { + final List values = new SmartList(); + processValuesImpl(indexId, dataKey, true, null, new ValueProcessor() { + @Override + public boolean process(final VirtualFile file, final V value) { + values.add(value); + return true; + } + }, filter); + return values; + } + + @Override + @NotNull + public Collection getContainingFiles(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { + final Set files = new THashSet(); + processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { + @Override + public boolean process(final VirtualFile file, final V value) { + files.add(file); + return true; + } + }, filter); + return files; + } + + + /** + * @return false if ValueProcessor.process() returned false; true otherwise or if ValueProcessor was not called at all + */ + @Override + public boolean processValues(@NotNull final ID indexId, @NotNull final K dataKey, @Nullable final VirtualFile inFile, + @NotNull ValueProcessor processor, @NotNull final GlobalSearchScope filter) { + return processValuesImpl(indexId, dataKey, false, inFile, processor, filter); + } + + + + + @Nullable + private R processExceptions(@NotNull final ID indexId, + @Nullable final VirtualFile restrictToFile, + @NotNull final GlobalSearchScope filter, + @NotNull ThrowableConvertor, R, StorageException> computable) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return null; + } + final Project project = filter.getProject(); + //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; + ensureUpToDate(indexId, project, filter, restrictToFile); + + try { + index.getReadLock().lock(); + return computable.convert(index); + } + finally { + index.getReadLock().unlock(); + } + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = getCauseToRebuildIndex(e); + if (cause != null) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + return null; + } + + private boolean processValuesImpl(@NotNull final ID indexId, final K dataKey, final boolean ensureValueProcessedOnce, + @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, + @NotNull final GlobalSearchScope filter) { + ThrowableConvertor, Boolean, StorageException> keyProcessor = new ThrowableConvertor, Boolean, StorageException>() { + @Override + public Boolean convert(@NotNull UpdatableIndex index) throws StorageException { + final ValueContainer container = index.getData(dataKey); + + boolean shouldContinue = true; + + if (restrictToFile != null) { + if (restrictToFile instanceof VirtualFileWithId) { + final int restrictedFileId = getFileId(restrictToFile); + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + final V value = valueIt.next(); + if (container.isAssociated(value, restrictedFileId)) { + shouldContinue = processor.process(restrictToFile, value); + if (!shouldContinue) { + break; + } + } + } + } + } + else { + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + ProjectIndexableFilesFilter projectFilesSet = projectIndexableFiles(filter.getProject()); + VALUES_LOOP: for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { + final V value = valueIt.next(); + for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { + final int id = inputIdsIterator.next(); + if (projectFilesSet != null && !projectFilesSet.contains(id)) continue; + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + shouldContinue = processor.process(file, value); + if (!shouldContinue) { + break VALUES_LOOP; + } + if (ensureValueProcessedOnce) { + break; // continue with the next value + } + } + } + } + } + return shouldContinue; + } + }; + final Boolean result = processExceptions(indexId, restrictToFile, filter, keyProcessor); + return result == null || result.booleanValue(); + } + + @Override + public boolean processFilesContainingAllKeys(@NotNull final ID indexId, + @NotNull final Collection dataKeys, + @NotNull final GlobalSearchScope filter, + @Nullable Condition valueChecker, + @NotNull final Processor processor) { + ProjectIndexableFilesFilter filesSet = projectIndexableFiles(filter.getProject()); + final TIntHashSet set = collectFileIdsContainingAllKeys(indexId, dataKeys, filter, valueChecker, filesSet); + return set != null && processVirtualFiles(set, filter, processor); + } + + private static final Key> ourProjectFilesSetKey = Key.create("projectFiles"); + + public static final class ProjectIndexableFilesFilter { + private static final int SHIFT = 6; + private static final int MASK = (1 << SHIFT) - 1; + private final long[] myBitMask; + private final int myModificationCount; + private final int myMinId; + private final int myMaxId; + + private ProjectIndexableFilesFilter(@NotNull TIntHashSet set, int modificationCount) { + myModificationCount = modificationCount; + final int[] minMax = new int[2]; + if (set.size() > 0) { + minMax[0] = minMax[1] = set.iterator().next(); + } + set.forEach(new TIntProcedure() { + @Override + public boolean execute(int value) { + minMax[0] = Math.min(minMax[0], value); + minMax[1] = Math.max(minMax[1], value); + return true; + } + }); + myMaxId = minMax[1]; + myMinId = minMax[0]; + myBitMask = new long[((myMaxId - myMinId) >> SHIFT) + 1]; + set.forEach(new TIntProcedure() { + @Override + public boolean execute(int value) { + value = value - myMinId; + myBitMask[value >> SHIFT] |= (1L << (value & MASK)); + return true; + } + }); + } + + public boolean contains(int id) { + if (id < myMinId) return false; + if (id > myMaxId) return false; + id -= myMinId; + return (myBitMask[id >> SHIFT] & (1L << (id & MASK))) != 0; + } + } + + @Nullable + public ProjectIndexableFilesFilter projectIndexableFiles(@Nullable Project project) { + if (project == null) return null; + + SoftReference reference = project.getUserData(ourProjectFilesSetKey); + ProjectIndexableFilesFilter data = reference != null ? reference.get() : null; + if (data != null && data.myModificationCount == myFilesModCount) return data; + + final TIntHashSet filesSet = new TIntHashSet(); + iterateIndexableFiles(new ContentIterator() { + @Override + public boolean processFile(@NotNull VirtualFile fileOrDir) { + filesSet.add(((VirtualFileWithId)fileOrDir).getId()); + return true; + } + }, project, ProgressManager.getInstance().getProgressIndicator()); + ProjectIndexableFilesFilter files = new ProjectIndexableFilesFilter(filesSet, myFilesModCount); + project.putUserData(ourProjectFilesSetKey, new SoftReference(files)); + return files; + } + + @Nullable + private TIntHashSet collectFileIdsContainingAllKeys(@NotNull final ID indexId, + @NotNull final Collection dataKeys, + @NotNull final GlobalSearchScope filter, + @Nullable final Condition valueChecker, + @Nullable final ProjectIndexableFilesFilter projectFilesFilter) { + final ThrowableConvertor, TIntHashSet, StorageException> convertor = + new ThrowableConvertor, TIntHashSet, StorageException>() { + @Nullable + @Override + public TIntHashSet convert(@NotNull UpdatableIndex index) throws StorageException { + TIntHashSet mainIntersection = null; + + for (K dataKey : dataKeys) { + ProgressManager.checkCanceled(); + final TIntHashSet copy = new TIntHashSet(); + final ValueContainer container = index.getData(dataKey); + + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + final V value = valueIt.next(); + if (valueChecker != null && !valueChecker.value(value)) { + continue; + } + + ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); + + if (mainIntersection == null || iterator.size() < mainIntersection.size()) { + for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { + final int id = inputIdsIterator.next(); + if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || + mainIntersection != null && mainIntersection.contains(id) + ) { + copy.add(id); + } + } + } else { + mainIntersection.forEach(new TIntProcedure() { + final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); + @Override + public boolean execute(int id) { + if (predicate.contains(id)) copy.add(id); + return true; + } + }); + } + } + + mainIntersection = copy; + if (mainIntersection.isEmpty()) { + return new TIntHashSet(); + } + } + + return mainIntersection; + } + }; + + + return processExceptions(indexId, null, filter, convertor); + } + + private static boolean processVirtualFiles(@NotNull TIntHashSet ids, + @NotNull final GlobalSearchScope filter, + @NotNull final Processor processor) { + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + return ids.forEach(new TIntProcedure() { + @Override + public boolean execute(int id) { + ProgressManager.checkCanceled(); + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + return processor.process(file); + } + return true; + } + }); + } + + @Nullable + public static Throwable getCauseToRebuildIndex(@NotNull RuntimeException e) { + Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException || + cause instanceof IllegalArgumentException) return cause; + return null; + } + + @Override + public boolean getFilesWithKey(@NotNull final ID indexId, + @NotNull final Set dataKeys, + @NotNull Processor processor, + @NotNull GlobalSearchScope filter) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return true; + } + final Project project = filter.getProject(); + //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; + ensureUpToDate(indexId, project, filter); + + try { + index.getReadLock().lock(); + final List locals = new ArrayList(); + for (K dataKey : dataKeys) { + TIntHashSet local = new TIntHashSet(); + locals.add(local); + final ValueContainer container = index.getData(dataKey); + + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { + final V value = valueIt.next(); + for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { + final int id = inputIdsIterator.next(); + local.add(id); + } + } + } + + if (locals.isEmpty()) { + return true; + } + + Collections.sort(locals, new Comparator() { + @Override + public int compare(TIntHashSet o1, TIntHashSet o2) { + return o1.size() - o2.size(); + } + }); + + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + TIntIterator ids = join(locals).iterator(); + ProjectIndexableFilesFilter projectIndexableFilesFilter = projectIndexableFiles(project); + while (ids.hasNext()) { + int id = ids.next(); + if (projectIndexableFilesFilter != null && !projectIndexableFilesFilter.contains(id)) continue; + //VirtualFile file = IndexInfrastructure.findFileById(fs, id); + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + if (!processor.process(file)) { + return false; + } + } + } + } + finally { + index.getReadLock().unlock(); + } + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + return true; + } + + @NotNull + private static TIntHashSet join(@NotNull List locals) { + TIntHashSet result = locals.get(0); + if (locals.size() > 1) { + TIntIterator it = result.iterator(); + + while (it.hasNext()) { + int id = it.next(); + for (int i = 1; i < locals.size(); i++) { + if (!locals.get(i).contains(id)) { + it.remove(); + break; + } + } + } + } + return result; + } + + @Override + public void scheduleRebuild(@NotNull final ID indexId, @NotNull final Throwable e) { + LOG.info(e); + requestRebuild(indexId); + try { + checkRebuild(indexId, false); + } + catch (ProcessCanceledException ignored) { + } + } + + private void checkRebuild(@NotNull final ID indexId, final boolean cleanupOnly) { + final AtomicInteger status = ourRebuildStatus.get(indexId); + if (status.get() == OK) return; + if (status.compareAndSet(REQUIRES_REBUILD, REBUILD_IN_PROGRESS)) { + cleanupProcessedFlag(); + + final Runnable rebuildRunnable = new Runnable() { + @Override + public void run() { + try { + clearIndex(indexId); + if (!cleanupOnly) { + scheduleIndexRebuild(false); + } + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.info(e); + } + finally { + status.compareAndSet(REBUILD_IN_PROGRESS, OK); + } + } + }; + + if (cleanupOnly || myIsUnitTestMode) { + rebuildRunnable.run(); + } + else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new Task.Modal(null, "Updating index", false) { + @Override + public void run(@NotNull final ProgressIndicator indicator) { + indicator.setIndeterminate(true); + rebuildRunnable.run(); + } + }.queue(); + } + }); + } + } + + if (status.get() == REBUILD_IN_PROGRESS) { + throw new ProcessCanceledException(); + } + } + + private void scheduleIndexRebuild(boolean forceDumbMode) { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + final Set updatersToRun = Collections.singleton(new UnindexedFilesUpdater(project, this)); + final DumbServiceImpl service = DumbServiceImpl.getInstance(project); + if (forceDumbMode) { + service.queueCacheUpdateInDumbMode(updatersToRun); + } + else { + service.queueCacheUpdate(updatersToRun); + } + } + } + + private void clearIndex(@NotNull final ID indexId) throws StorageException { + final UpdatableIndex index = getIndex(indexId); + assert index != null: "Index with key " + indexId + " not found or not registered properly"; + index.clear(); + try { + IndexInfrastructure.rewriteVersion(IndexInfrastructure.getVersionFile(indexId), myIndexIdToVersionMap.get(indexId)); + } + catch (IOException e) { + LOG.error(e); + } + } + + @NotNull + private Set getUnsavedOrTransactedDocuments() { + final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); + synchronized (myTransactionMap) { + docs.addAll(myTransactionMap.keySet()); + } + return docs; + } + + private void indexUnsavedDocuments(@NotNull ID indexId, + @Nullable Project project, + GlobalSearchScope filter, + VirtualFile restrictedFile) throws StorageException { + if (myUpToDateIndices.contains(indexId)) { + return; // no need to index unsaved docs + } + + final Set documents = getUnsavedOrTransactedDocuments(); + if (!documents.isEmpty()) { + // now index unsaved data + final StorageGuard.Holder guard = setDataBufferingEnabled(true); + try { + final Semaphore semaphore = myUnsavedDataIndexingSemaphores.get(indexId); + + assert semaphore != null : "Semaphore for unsaved data indexing was not initialized for index " + indexId; + + semaphore.down(); + boolean allDocsProcessed = true; + try { + for (Document document : documents) { + allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); + } + } + finally { + semaphore.up(); + + while (!semaphore.waitFor(500)) { // may need to wait until another thread is done with indexing + if (Thread.holdsLock(PsiLock.LOCK)) { + break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. + } + } + if (allDocsProcessed && !hasActiveTransactions()) { + myUpToDateIndices.add(indexId); // safe to set the flag here, because it will be cleared under the WriteAction + } + } + } + finally { + guard.leave(); + } + } + } + + private boolean hasActiveTransactions() { + synchronized (myTransactionMap) { + return !myTransactionMap.isEmpty(); + } + } + + private interface DocumentContent { + String getText(); + long getModificationStamp(); + } + + private static class AuthenticContent implements DocumentContent { + private final Document myDocument; + + private AuthenticContent(final Document document) { + myDocument = document; + } + + @Override + public String getText() { + return myDocument.getText(); + } + + @Override + public long getModificationStamp() { + return myDocument.getModificationStamp(); + } + } + + private static class PsiContent implements DocumentContent { + private final Document myDocument; + private final PsiFile myFile; + + private PsiContent(final Document document, final PsiFile file) { + myDocument = document; + myFile = file; + } + + @Override + public String getText() { + if (myFile.getModificationStamp() != myDocument.getModificationStamp()) { + final ASTNode node = myFile.getNode(); + assert node != null; + return node.getText(); + } + return myDocument.getText(); + } + + @Override + public long getModificationStamp() { + return myFile.getModificationStamp(); + } + } + +// returns false if doc was not indexed because the file does not fit in scope + private boolean indexUnsavedDocument(@NotNull final Document document, @NotNull final ID requestedIndexId, final Project project, + @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedFile) throws StorageException { + final VirtualFile vFile = myFileDocumentManager.getFile(document); + if (!(vFile instanceof VirtualFileWithId) || !vFile.isValid()) { + return true; + } + + if (restrictedFile != null) { + if(vFile != restrictedFile) { + return false; + } + } + else if (filter != null && !filter.accept(vFile)) { + return false; + } + + final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); + + final DocumentContent content; + if (dominantContentFile != null && dominantContentFile.getModificationStamp() != document.getModificationStamp()) { + content = new PsiContent(document, dominantContentFile); + } + else { + content = new AuthenticContent(document); + } + + final long currentDocStamp = content.getModificationStamp(); + if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp)) { + final Ref exRef = new Ref(null); + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + @Override + public void run() { + try { + final String contentText = content.getText(); + if (isTooLarge(vFile, contentText.length())) { + return; + } + + final FileContentImpl newFc = new FileContentImpl(vFile, contentText, vFile.getCharset()); + + if (dominantContentFile != null) { + dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, true); + newFc.putUserData(IndexingDataKeys.PSI_FILE, dominantContentFile); + } + + if (content instanceof AuthenticContent) { + newFc.putUserData(EDITOR_HIGHLIGHTER, EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)); + } + + if (getInputFilter(requestedIndexId).acceptInput(vFile)) { + newFc.putUserData(IndexingDataKeys.PROJECT, project); + final int inputId = Math.abs(getFileId(vFile)); + getIndex(requestedIndexId).update(inputId, newFc); + } + + if (dominantContentFile != null) { + dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, null); + } + } + catch (StorageException e) { + exRef.set(e); + } + } + }); + final StorageException storageException = exRef.get(); + if (storageException != null) { + throw storageException; + } + } + return true; + } + + public static final Key EDITOR_HIGHLIGHTER = new Key("Editor"); + + @Nullable + private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { + synchronized (myTransactionMap) { + PsiFile psiFile = myTransactionMap.get(document); + if (psiFile != null) return psiFile; + } + + return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); + } + + private final StorageGuard myStorageLock = new StorageGuard(); + + @NotNull + private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) { + final StorageGuard.Holder holder = myStorageLock.enter(enabled); + for (ID indexId : myIndices.keySet()) { + final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); + assert index != null; + final IndexStorage indexStorage = index.getStorage(); + ((MemoryIndexStorage)indexStorage).setBufferingEnabled(enabled); + } + return holder; + } + + private void cleanupMemoryStorage() { + myLastIndexedDocStamps.clear(); + for (ID indexId : myIndices.keySet()) { + final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); + assert index != null; + final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage(); + index.getWriteLock().lock(); + try { + memStorage.clearMemoryMap(); + } + finally { + index.getWriteLock().unlock(); + } + memStorage.fireMemoryStorageCleared(); + } + } + + private void dropUnregisteredIndices() { + final Set indicesToDrop = readRegisteredIndexNames(); + for (ID key : myIndices.keySet()) { + indicesToDrop.remove(key.toString()); + } + for (String s : indicesToDrop) { + FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); + } + } + + @Override + public void requestRebuild(ID indexId, Throwable throwable) { + cleanupProcessedFlag(); + LOG.info("Rebuild requested for index " + indexId, throwable); + ourRebuildStatus.get(indexId).set(REQUIRES_REBUILD); + } + + private UpdatableIndex getIndex(ID indexId) { + final Pair, InputFilter> pair = myIndices.get(indexId); + + assert pair != null : "Index data is absent for index " + indexId; + + //noinspection unchecked + return (UpdatableIndex)pair.getFirst(); + } + + private InputFilter getInputFilter(ID indexId) { + final Pair, InputFilter> pair = myIndices.get(indexId); + + assert pair != null : "Index data is absent for index " + indexId; + + return pair.getSecond(); + } + + public int getNumberOfPendingInvalidations() { + return myChangedFilesCollector.getNumberOfPendingInvalidations(); + } + + @NotNull + public Collection getFilesToUpdate(final Project project) { + return ContainerUtil.findAll(myChangedFilesCollector.getAllFilesToUpdate(), new Condition() { + @Override + public boolean value(VirtualFile virtualFile) { + for (IndexableFileSet set : myIndexableSets) { + final Project proj = myIndexableSetToProjectMap.get(set); + if (proj != null && !proj.equals(project)) { + continue; // skip this set as associated with a different project + } + if (set.isInSet(virtualFile)) { + return true; + } + } + return false; + } + }); + } + + public void processRefreshedFile(@NotNull Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + myChangedFilesCollector.processFileImpl(project, fileContent, false); + } + + public void indexFileContent(@Nullable Project project, @NotNull com.intellij.ide.caches.FileContent content) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + final VirtualFile file = content.getVirtualFile(); + FileContentImpl fc = null; + + PsiFile psiFile = null; + + FileTypeManagerImpl.cacheFileType(file, file.getFileType()); + try { + for (final ID indexId : myIndices.keySet()) { + if (shouldIndexFile(file, indexId)) { + if (fc == null) { + byte[] currentBytes; + try { + currentBytes = content.getBytes(); + } + catch (IOException e) { + currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY; + } + fc = new FileContentImpl(file, currentBytes); + + psiFile = content.getUserData(IndexingDataKeys.PSI_FILE); + if (psiFile != null) { + psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true); + fc.putUserData(IndexingDataKeys.PSI_FILE, psiFile); + } + if (project == null) { + project = ProjectUtil.guessProjectForFile(file); + } + fc.putUserData(IndexingDataKeys.PROJECT, project); + } + + try { + ProgressManager.checkCanceled(); + updateSingleIndex(indexId, file, fc); + } + catch (ProcessCanceledException e) { + myChangedFilesCollector.scheduleForUpdate(file); + throw e; + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.info(e); + } + } + } + + if (psiFile != null) { + psiFile.putUserData(PsiFileImpl.BUILDING_STUB, null); + } + } finally { + FileTypeManagerImpl.cacheFileType(file, null); + } + } + + private void updateSingleIndex(final ID indexId, @NotNull final VirtualFile file, @Nullable final FileContent currentFC) + throws StorageException { + if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { + return; // the index is scheduled for rebuild, no need to update + } + myLocalModCount++; + + final StorageGuard.Holder lock = setDataBufferingEnabled(false); + + try { + final int inputId = Math.abs(getFileId(file)); + + final UpdatableIndex index = getIndex(indexId); + assert index != null; + + final Ref exRef = new Ref(null); + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + @Override + public void run() { + try { + index.update(inputId, currentFC); + } + catch (StorageException e) { + exRef.set(e); + } + } + }); + final StorageException storageException = exRef.get(); + if (storageException != null) { + throw storageException; + } + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (file.isValid()) { + if (currentFC != null) { + IndexingStamp.update(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); + } + else { + // mark the file as unindexed + IndexingStamp.update(file, indexId, -1L); + } + } + } + }); + } + finally { + lock.leave(); + } + } + + private boolean needsFileContentLoading(ID indexId) { + return !myNotRequiringContentIndices.contains(indexId); + } + + private abstract static class InvalidationTask implements Runnable { + private final VirtualFile mySubj; + + protected InvalidationTask(final VirtualFile subj) { + mySubj = subj; + } + + public VirtualFile getSubj() { + return mySubj; + } + } + + private final class ChangedFilesCollector extends VirtualFileAdapter { + private final Set myFilesToUpdate = new ConcurrentHashSet(); + private final Queue myFutureInvalidations = new ConcurrentLinkedQueue(); + + private final ManagingFS myManagingFS = ManagingFS.getInstance(); + // No need to react on movement events since files stay valid, their ids don't change and all associated attributes remain intact. + + @Override + public void fileCreated(@NotNull final VirtualFileEvent event) { + markDirty(event, false); + } + + @Override + public void fileDeleted(@NotNull final VirtualFileEvent event) { + myFilesToUpdate.remove(event.getFile()); // no need to update it anymore + } + + @Override + public void fileCopied(@NotNull final VirtualFileCopyEvent event) { + markDirty(event, false); + } + + @Override + public void beforeFileDeletion(@NotNull final VirtualFileEvent event) { + invalidateIndices(event.getFile(), false); + } + + @Override + public void beforeContentsChange(@NotNull final VirtualFileEvent event) { + invalidateIndices(event.getFile(), true); + } + + @Override + public void contentsChanged(@NotNull final VirtualFileEvent event) { + markDirty(event, true); + } + + @Override + public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { + if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { + // indexes may depend on file name + final VirtualFile file = event.getFile(); + if (!file.isDirectory()) { + // name change may lead to filetype change so the file might become not indexable + // in general case have to 'unindex' the file and index it again if needed after the name has been changed + invalidateIndices(file, false); + } + } + } + + @Override + public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) { + if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { + // indexes may depend on file name + if (!event.getFile().isDirectory()) { + markDirty(event, false); + } + } + } + + private void markDirty(@NotNull final VirtualFileEvent event, final boolean contentChange) { + final VirtualFile eventFile = event.getFile(); + cleanProcessedFlag(eventFile); + iterateIndexableFiles(eventFile, new Processor() { + @Override + public boolean process(@NotNull final VirtualFile file) { + if (!contentChange) ++myFilesModCount; + FileContent fileContent = null; + // handle 'content-less' indices separately + for (ID indexId : myNotRequiringContentIndices) { + if (getInputFilter(indexId).acceptInput(file)) { + try { + if (fileContent == null) { + fileContent = new FileContentImpl(file); + } + updateSingleIndex(indexId, file, fileContent); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + } + // For 'normal indices' schedule the file for update and stop iteration if at least one index accepts it + if (!isTooLarge(file)) { + for (ID indexId : myIndices.keySet()) { + if (needsFileContentLoading(indexId) && getInputFilter(indexId).acceptInput(file)) { + scheduleForUpdate(file); + break; // no need to iterate further, as the file is already marked + } + } + } + + return true; + } + }); + IndexingStamp.flushCache(); + } + + public void scheduleForUpdate(VirtualFile file) { + myFilesToUpdate.add(file); + } + + void invalidateIndices(@NotNull final VirtualFile file, final boolean markForReindex) { + if (isUnderConfigOrSystem(file)) { + return; + } + if (file.isDirectory()) { + if (isMock(file) || myManagingFS.wereChildrenAccessed(file)) { + final Iterable children = file instanceof NewVirtualFile + ? ((NewVirtualFile)file).iterInDbChildren() : Arrays.asList(file.getChildren()); + for (VirtualFile child : children) { + invalidateIndices(child, markForReindex); + } + } + } + else { + cleanProcessedFlag(file); + IndexingStamp.flushCache(); + final List> affectedIndices = new ArrayList>(myIndices.size()); + + for (final ID indexId : myIndices.keySet()) { + try { + if (!needsFileContentLoading(indexId)) { + if (shouldUpdateIndex(file, indexId)) { + updateSingleIndex(indexId, file, null); + } + } + else { // the index requires file content + if (shouldUpdateIndex(file, indexId)) { + affectedIndices.add(indexId); + } + } + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + + if (!affectedIndices.isEmpty()) { + if (markForReindex && !isTooLarge(file)) { + // only mark the file as unindexed, reindex will be done lazily + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + for (ID indexId : affectedIndices) { + IndexingStamp.update(file, indexId, -2L); + } + } + }); + // the file is for sure not a dir and it was previously indexed by at least one index + scheduleForUpdate(file); + } + else { + myFutureInvalidations.offer(new InvalidationTask(file) { + @Override + public void run() { + removeFileDataFromIndices(affectedIndices, file); + } + }); + } + } + if (!markForReindex) { + final boolean removedFromUpdateQueue = myFilesToUpdate.remove(file);// no need to update it anymore + if (removedFromUpdateQueue && affectedIndices.isEmpty()) { + // Currently the file is about to be deleted and previously it was scheduled for update and not processed up to now. + // Because the file was scheduled for update, at the moment of scheduling it was marked as unindexed, + // so, to be on the safe side, we have to schedule data invalidation from all content-requiring indices for this file + myFutureInvalidations.offer(new InvalidationTask(file) { + @Override + public void run() { + removeFileDataFromIndices(myRequiringContentIndices, file); + } + }); + } + } + + IndexingStamp.flushCache(); + } + } + + private void removeFileDataFromIndices(@NotNull Collection> affectedIndices, @NotNull VirtualFile file) { + Throwable unexpectedError = null; + for (ID indexId : affectedIndices) { + try { + updateSingleIndex(indexId, file, null); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + catch (ProcessCanceledException ignored) { + } + catch (Throwable e) { + LOG.info(e); + if (unexpectedError == null) { + unexpectedError = e; + } + } + } + IndexingStamp.flushCache(); + if (unexpectedError != null) { + LOG.error(unexpectedError); + } + } + + public int getNumberOfPendingInvalidations() { + return myFutureInvalidations.size(); + } + + public void ensureAllInvalidateTasksCompleted() { + final int size = getNumberOfPendingInvalidations(); + if (size == 0) { + return; + } + final ProgressIndicator current = ProgressManager.getInstance().getProgressIndicator(); + final ProgressIndicator indicator = current != null ? current : new EmptyProgressIndicator(); + indicator.setText(""); + int count = 0; + while (true) { + InvalidationTask task = myFutureInvalidations.poll(); + + if (task == null) { + break; + } + indicator.setFraction((double)count++ /size); + indicator.setText2(task.getSubj().getPresentableUrl()); + task.run(); + } + } + + private void iterateIndexableFiles(@NotNull final VirtualFile file, @NotNull final Processor processor) { + if (file.isDirectory()) { + final ContentIterator iterator = new ContentIterator() { + @Override + public boolean processFile(@NotNull final VirtualFile fileOrDir) { + if (!fileOrDir.isDirectory()) { + processor.process(fileOrDir); + } + return true; + } + }; + + for (IndexableFileSet set : myIndexableSets) { + if (set.isInSet(file)) { + set.iterateIndexableFilesIn(file, iterator); + } + } + } + else { + for (IndexableFileSet set : myIndexableSets) { + if (set.isInSet(file)) { + processor.process(file); + break; + } + } + } + } + + public Collection getAllFilesToUpdate() { + if (myFilesToUpdate.isEmpty()) { + return Collections.emptyList(); + } + return new ArrayList(myFilesToUpdate); + } + + private final Semaphore myForceUpdateSemaphore = new Semaphore(); + + private void forceUpdate(@Nullable Project project, @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedTo, + boolean onlyRemoveOutdatedData) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + for (VirtualFile file: getAllFilesToUpdate()) { + if (filter == null || filter.accept(file) || file == restrictedTo) { + try { + myForceUpdateSemaphore.down(); + // process only files that can affect result + processFileImpl(project, new com.intellij.ide.caches.FileContent(file), onlyRemoveOutdatedData); + } + finally { + myForceUpdateSemaphore.up(); + } + } + } + + // If several threads entered the method at the same time and there were files to update, + // all the threads should leave the method synchronously after all the files scheduled for update are reindexed, + // no matter which thread will do reindexing job. + // Thus we ensure that all the threads that entered the method will get the most recent data + + while (!myForceUpdateSemaphore.waitFor(500)) { // may need to wait until another thread is done with indexing + if (Thread.holdsLock(PsiLock.LOCK)) { + break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. + } + } + } + + private void processFileImpl(Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent, boolean onlyRemoveOutdatedData) { + final VirtualFile file = fileContent.getVirtualFile(); + final boolean reallyRemoved = myFilesToUpdate.remove(file); + if (reallyRemoved && file.isValid()) { + if (onlyRemoveOutdatedData) { + // on shutdown there is no need to re-index the file, just remove outdated data from indices + final List> affected = new ArrayList>(); + for (final ID indexId : myIndices.keySet()) { + if (getInputFilter(indexId).acceptInput(file)) { + affected.add(indexId); + } + } + removeFileDataFromIndices(affected, file); + } + else { + indexFileContent(project, fileContent); + } + IndexingStamp.flushCache(); + } + } + } + + private class UnindexedFilesFinder implements CollectingContentIterator { + private final List myFiles = new ArrayList(); + private final ProgressIndicator myProgressIndicator; + + private UnindexedFilesFinder() { + myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); + } + + @NotNull + @Override + public List getFiles() { + return myFiles; + } + + @Override + public boolean processFile(@NotNull final VirtualFile file) { + if (!file.isValid()) { + return true; + } + if (!file.isDirectory()) { + if (file instanceof NewVirtualFile && ((NewVirtualFile)file).getFlag(ALREADY_PROCESSED)) { + return true; + } + + if (file instanceof VirtualFileWithId) { + try { + FileTypeManagerImpl.cacheFileType(file, file.getFileType()); + + boolean oldStuff = true; + if (!isTooLarge(file)) { + for (ID indexId : myIndices.keySet()) { + try { + if (needsFileContentLoading(indexId) && shouldIndexFile(file, indexId)) { + myFiles.add(file); + oldStuff = false; + break; + } + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof IOException || cause instanceof StorageException) { + LOG.info(e); + requestRebuild(indexId); + } + else { + throw e; + } + } + } + } + FileContent fileContent = null; + for (ID indexId : myNotRequiringContentIndices) { + if (shouldIndexFile(file, indexId)) { + oldStuff = false; + try { + if (fileContent == null) { + fileContent = new FileContentImpl(file); + } + updateSingleIndex(indexId, file, fileContent); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + } + IndexingStamp.flushCache(); + + if (oldStuff && file instanceof NewVirtualFile) { + ((NewVirtualFile)file).setFlag(ALREADY_PROCESSED, true); + } + } + finally { + FileTypeManagerImpl.cacheFileType(file, null); + } + } + } + else { + if (myProgressIndicator != null) { + myProgressIndicator.setText("Scanning files to index"); + myProgressIndicator.setText2(file.getPresentableUrl()); + } + } + return true; + } + } + + private boolean shouldUpdateIndex(final VirtualFile file, final ID indexId) { + return getInputFilter(indexId).acceptInput(file) && + (isMock(file) || IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); + } + + private boolean shouldIndexFile(final VirtualFile file, final ID indexId) { + return getInputFilter(indexId).acceptInput(file) && + (isMock(file) || !IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); + } + + private boolean isUnderConfigOrSystem(@NotNull VirtualFile file) { + final String filePath = file.getPath(); + return myConfigPath != null && FileUtil.startsWith(filePath, myConfigPath) || + mySystemPath != null && FileUtil.startsWith(filePath, mySystemPath); + } + + private static boolean isMock(final VirtualFile file) { + return !(file instanceof NewVirtualFile); + } + + private boolean isTooLarge(@NotNull VirtualFile file) { + if (SingleRootFileViewProvider.isTooLarge(file)) { + final FileType type = file.getFileType(); + return !myNoLimitCheckTypes.contains(type); + } + return false; + } + + private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) { + if (SingleRootFileViewProvider.isTooLarge(file, contentSize)) { + final FileType type = file.getFileType(); + return !myNoLimitCheckTypes.contains(type); + } + return false; + } + + @NotNull + public CollectingContentIterator createContentIterator() { + ++myFilesModCount; + return new UnindexedFilesFinder(); + } + + public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { + myIndexableSets.add(set); + myIndexableSetToProjectMap.put(set, project); + } + + public void removeIndexableSet(@NotNull IndexableFileSet set) { + myChangedFilesCollector.forceUpdate(null, null, null, true); + myIndexableSets.remove(set); + myIndexableSetToProjectMap.remove(set); + } + + @Nullable + private static PsiFile findLatestKnownPsiForUncomittedDocument(@NotNull Document doc, @NotNull Project project) { + return PsiDocumentManager.getInstance(project).getCachedPsiFile(doc); + } + + private static class IndexableFilesFilter implements InputFilter { + private final InputFilter myDelegate; + + private IndexableFilesFilter(InputFilter delegate) { + myDelegate = delegate; + } + + @Override + public boolean acceptInput(final VirtualFile file) { + return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); + } + } + + private static void cleanupProcessedFlag() { + final VirtualFile[] roots = ManagingFS.getInstance().getRoots(); + for (VirtualFile root : roots) { + cleanProcessedFlag(root); + } + } + + private static void cleanProcessedFlag(@NotNull final VirtualFile file) { + if (!(file instanceof NewVirtualFile)) return; + + final NewVirtualFile nvf = (NewVirtualFile)file; + if (file.isDirectory()) { + for (VirtualFile child : nvf.getCachedChildren()) { + cleanProcessedFlag(child); + } + } + else { + nvf.setFlag(ALREADY_PROCESSED, false); + } + } + + public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { + if (project.isDisposed()) { + return; + } + final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + // iterate project content + projectFileIndex.iterateContent(processor); + + if (project.isDisposed()) { + return; + } + + Set visitedRoots = new THashSet(); + for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { + //important not to depend on project here, to support per-project background reindex + // each client gives a project to FileBasedIndex + if (project.isDisposed()) { + return; + } + for (VirtualFile root : IndexableSetContributor.getRootsToIndex(provider)) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + for (VirtualFile root : IndexableSetContributor.getProjectRootsToIndex(provider, project)) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + } + + if (project.isDisposed()) { + return; + } + // iterate associated libraries + for (Module module : ModuleManager.getInstance(project).getModules()) { + if (module.isDisposed()) { + return; + } + OrderEntry[] orderEntries = ModuleRootManager.getInstance(module).getOrderEntries(); + for (OrderEntry orderEntry : orderEntries) { + if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { + if (orderEntry.isValid()) { + final VirtualFile[] libSources = orderEntry.getFiles(OrderRootType.SOURCES); + final VirtualFile[] libClasses = orderEntry.getFiles(OrderRootType.CLASSES); + for (VirtualFile[] roots : new VirtualFile[][]{libSources, libClasses}) { + for (VirtualFile root : roots) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + } + } + } + } + } + } + + private static void iterateRecursively(@Nullable final VirtualFile root, @NotNull final ContentIterator processor, @Nullable ProgressIndicator indicator) { + if (root != null) { + if (indicator != null) { + indicator.checkCanceled(); + indicator.setText2(root.getPresentableUrl()); + } + + if (root.isDirectory()) { + for (VirtualFile file : root.getChildren()) { + if (file.isDirectory()) { + iterateRecursively(file, processor, indicator); + } + else { + processor.processFile(file); + } + } + } + else { + processor.processFile(root); + } + } + } + + private static class StorageGuard { + private int myHolds = 0; + + public interface Holder { + void leave(); + } + + private final Holder myTrueHolder = new Holder() { + @Override + public void leave() { + StorageGuard.this.leave(true); + } + }; + private final Holder myFalseHolder = new Holder() { + @Override + public void leave() { + StorageGuard.this.leave(false); + } + }; + + @NotNull + public synchronized Holder enter(boolean mode) { + if (mode) { + while (myHolds < 0) { + try { + wait(); + } + catch (InterruptedException ignored) { + } + } + myHolds++; + return myTrueHolder; + } + else { + while (myHolds > 0) { + try { + wait(); + } + catch (InterruptedException ignored) { + } + } + myHolds--; + return myFalseHolder; + } + } + + private synchronized void leave(boolean mode) { + myHolds += mode? -1 : 1; + if (myHolds == 0) { + notifyAll(); + } + } + + } +} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java index 7e1994218251..13fee5b720ab 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java @@ -42,12 +42,12 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; public class FileBasedIndexProjectHandler extends AbstractProjectComponent implements IndexableFileSet { - private final FileBasedIndex myIndex; + private final FileBasedIndexImpl myIndex; private final ProjectRootManagerEx myRootManager; private final FileTypeManager myFileTypeManager; private final ProjectFileExclusionManagerImpl myExclusionManager; - public FileBasedIndexProjectHandler(final FileBasedIndex index, final Project project, final ProjectRootManagerEx rootManager, FileTypeManager ftManager, final ProjectManager projectManager) { + public FileBasedIndexProjectHandler(final FileBasedIndexImpl index, final Project project, final ProjectRootManagerEx rootManager, FileTypeManager ftManager, final ProjectManager projectManager) { super(project); myIndex = index; myRootManager = rootManager; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index d8ea84dc00b0..efb1445da0be 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -33,11 +33,11 @@ import java.util.List; */ public class UnindexedFilesUpdater implements CacheUpdater { private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.UnindexedFilesUpdater"); - private final FileBasedIndex myIndex; + private final FileBasedIndexImpl myIndex; private final Project myProject; private long myStarted; - public UnindexedFilesUpdater(final Project project, FileBasedIndex index) { + public UnindexedFilesUpdater(final Project project, FileBasedIndexImpl index) { myIndex = index; myProject = project; } @@ -51,7 +51,7 @@ public class UnindexedFilesUpdater implements CacheUpdater { public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { CollectingContentIterator finder = myIndex.createContentIterator(); long l = System.currentTimeMillis(); - FileBasedIndex.iterateIndexableFiles(finder, myProject, indicator); + FileBasedIndexImpl.iterateIndexableFiles(finder, myProject, indicator); LOG.info("Indexable files iterated in " + (System.currentTimeMillis() - l) + " ms"); List files = finder.getFiles(); LOG.info("Unindexed files update started: " + files.size() + " files to update"); diff --git a/platform/platform-resources/src/componentSets/Lang.xml b/platform/platform-resources/src/componentSets/Lang.xml index f4ce41d26018..54e0cc2a543c 100644 --- a/platform/platform-resources/src/componentSets/Lang.xml +++ b/platform/platform-resources/src/componentSets/Lang.xml @@ -12,7 +12,8 @@ - com.intellij.util.indexing.FileBasedIndex + com.intellij.util.indexing.FileBasedIndex + com.intellij.util.indexing.FileBasedIndexImpl com.intellij.psi.stubs.StubIndex diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index a8ba4077789d..a7e2d39a9746 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -93,6 +93,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.LocalTimeCounter; import com.intellij.util.containers.CollectionFactory; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import com.intellij.util.indexing.IndexableFileSet; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.UIUtil; @@ -234,7 +235,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da throw new RuntimeException(e); } - FileBasedIndex.getInstance().registerIndexableSet(new IndexableFileSet() { + ((FileBasedIndexImpl)FileBasedIndex.getInstance()).registerIndexableSet(new IndexableFileSet() { @Override public boolean isInSet(@NotNull final VirtualFile file) { return ourSourceRoot != null && file.getFileSystem() == ourSourceRoot.getFileSystem() && ourProject.isOpen(); From ae8871187fd45e7bd6a1948daee89880ad41359f Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:02:03 +0200 Subject: [PATCH 02/67] Extra changes --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++++ .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 3 ++- .../src/com/intellij/util/indexing/UnindexedFilesUpdater.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index c2f3ad423b19..3ef57cafca3a 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -17,7 +17,9 @@ package com.intellij.util.indexing; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; @@ -35,6 +37,8 @@ import java.util.Set; * Author: dmitrylomov */ public abstract class FileBasedIndex implements ApplicationComponent { + public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); + public static FileBasedIndex getInstance() { return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 1cf3b2677d89..29e82dd6d2a6 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2189,7 +2189,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { + @Override + public void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { if (project.isDisposed()) { return; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index efb1445da0be..a0e42f63198d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -51,7 +51,7 @@ public class UnindexedFilesUpdater implements CacheUpdater { public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { CollectingContentIterator finder = myIndex.createContentIterator(); long l = System.currentTimeMillis(); - FileBasedIndexImpl.iterateIndexableFiles(finder, myProject, indicator); + FileBasedIndex.getInstance().iterateIndexableFiles(finder, myProject, indicator); LOG.info("Indexable files iterated in " + (System.currentTimeMillis() - l) + " ms"); List files = finder.getFiles(); LOG.info("Unindexed files update started: " + files.size() + " files to update"); From 192e954227661e34a3ac305c5c3a861a896a685f Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:32:20 +0200 Subject: [PATCH 03/67] Extra methods --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++++ .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 3ef57cafca3a..f2dad634cf9f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -39,6 +39,10 @@ import java.util.Set; public abstract class FileBasedIndex implements ApplicationComponent { public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); + public abstract void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project); + + public abstract void removeIndexableSet(@NotNull IndexableFileSet set); + public static FileBasedIndex getInstance() { return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 29e82dd6d2a6..b6043d4bef02 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2139,11 +2139,13 @@ public class FileBasedIndexImpl extends FileBasedIndex { return new UnindexedFilesFinder(); } + @Override public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { myIndexableSets.add(set); myIndexableSetToProjectMap.put(set, project); } + @Override public void removeIndexableSet(@NotNull IndexableFileSet set) { myChangedFilesCollector.forceUpdate(null, null, null, true); myIndexableSets.remove(set); From 34eead6c82f04b8d00ae06ea6a2976449a48f022 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 12:07:10 +0200 Subject: [PATCH 04/67] More fixed --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 5 ----- .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 1 - 2 files changed, 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index f2dad634cf9f..0c7c23ce6f62 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -91,11 +91,6 @@ public abstract class FileBasedIndex implements ApplicationComponent { public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); - protected abstract void ensureUpToDate(@NotNull ID indexId, - @Nullable Project project, - @Nullable GlobalSearchScope filter, - @Nullable VirtualFile restrictedFile); - public abstract void requestRebuild(ID indexId, Throwable throwable); public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index b6043d4bef02..a5f15bf670d1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -737,7 +737,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { ensureUpToDate(indexId, project, filter, null); } - @Override protected void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, From fcdf45c29d8e68006820df39a62caa96e8bd617b Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Tue, 8 May 2012 18:26:13 +0200 Subject: [PATCH 05/67] FileBasedIndex --- .../psi/impl/cache/impl/IdCacheTest.java | 6 +- .../intellij/psi/search/UpdateCacheTest.java | 5 +- .../intellij/find/impl/FindInProjectUtil.java | 3 +- .../impl/cache/impl/id/IdTableBuilding.java | 2 +- .../psi/impl/cache/impl/todo/TodoIndex.java | 2 +- .../com/intellij/psi/stubs/StubIndexImpl.java | 12 +- .../intellij/psi/stubs/StubUpdatingIndex.java | 2 +- .../util/indexing/FileBasedIndex.java | 2341 +---------------- .../util/indexing/FileBasedIndexImpl.java | 2327 ++++++++++++++++ .../FileBasedIndexProjectHandler.java | 4 +- .../util/indexing/UnindexedFilesUpdater.java | 6 +- .../src/componentSets/Lang.xml | 3 +- .../testFramework/LightPlatformTestCase.java | 3 +- 13 files changed, 2407 insertions(+), 2309 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java index 5ec392f58c23..eaf7ae618ffe 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java @@ -21,6 +21,7 @@ import com.intellij.psi.search.UsageSearchContext; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import java.io.File; import java.util.Arrays; @@ -35,9 +36,8 @@ public class IdCacheTest extends CodeInsightTestCase{ protected void setUp() throws Exception { super.setUp(); - final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance(); - fileBasedIndex.requestRebuild(IdIndex.NAME); - fileBasedIndex.requestRebuild(TodoIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(IdIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(TodoIndex.NAME); String root = JavaTestUtil.getJavaTestDataPath()+ "/psi/impl/cache/"; diff --git a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java index cd2cf6890ac3..be90964eafae 100644 --- a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java @@ -44,6 +44,7 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import org.jetbrains.annotations.NonNls; import java.io.File; @@ -55,8 +56,8 @@ public class UpdateCacheTest extends PsiTestCase{ protected void setUp() throws Exception { super.setUp(); - FileBasedIndex.requestRebuild(IdIndex.NAME); - FileBasedIndex.requestRebuild(TodoIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(IdIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(TodoIndex.NAME); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index a9c2eb118461..e5601ebb1b87 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -502,8 +502,7 @@ public class FindInProjectUtil { if (!keys.isEmpty()) { fast = true; List hits = new ArrayList(); - FileBasedIndex.getInstance() - .getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); + FileBasedIndex.getInstance().getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); for (VirtualFile hit : hits) { resultFiles.add(pm.findFile(hit)); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java index 8e09281d2675..bb8dc7f3104f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java @@ -322,7 +322,7 @@ public class IdTableBuilding { final OccurrenceConsumer occurrenceConsumer = new OccurrenceConsumer(null, true); EditorHighlighter highlighter; - final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndex.EDITOR_HIGHLIGHTER); + final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndexImpl.EDITOR_HIGHLIGHTER); if (editorHighlighter != null && checkCanUseCachedEditorHighlighter(chars, editorHighlighter)) { highlighter = editorHighlighter; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index 594436346a7d..e4c91b7904da 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -54,7 +54,7 @@ public class TodoIndex extends FileBasedIndexExtension messageBus.connect().subscribe(IndexPatternProvider.INDEX_PATTERNS_CHANGED, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - FileBasedIndex.requestRebuild(NAME); + FileBasedIndex.getInstance().requestRebuild(NAME); } }); } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java index d11e89e0f5a7..05a5e6d08e00 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java @@ -200,7 +200,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe @NotNull final Project project, @Nullable final GlobalSearchScope scope, @NotNull final Processor processor) { - final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance(); + final FileBasedIndexImpl fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance(); fileBasedIndex.ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, scope); final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); @@ -211,11 +211,11 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe try { try { // disable up-to-date check to avoid locks on attempt to acquire index write lock while holding at the same time the readLock for this index - FileBasedIndex.disableUpToDateCheckForCurrentThread(); + FileBasedIndexImpl.disableUpToDateCheckForCurrentThread(); index.getReadLock().lock(); final ValueContainer container = index.getData(key); - final FileBasedIndex.ProjectIndexableFilesFilter projectFilesFilter = fileBasedIndex.projectIndexableFiles(project); + final FileBasedIndexImpl.ProjectIndexableFilesFilter projectFilesFilter = fileBasedIndex.projectIndexableFiles(project); return container.forEach(new ValueContainer.ContainerAction() { @Override @@ -320,14 +320,14 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe } finally { index.getReadLock().unlock(); - FileBasedIndex.enableUpToDateCheckForCurrentThread(); + FileBasedIndexImpl.enableUpToDateCheckForCurrentThread(); } } catch (StorageException e) { forceRebuild(e); } catch (RuntimeException e) { - final Throwable cause = FileBasedIndex.getCauseToRebuildIndex(e); + final Throwable cause = FileBasedIndexImpl.getCauseToRebuildIndex(e); if (cause != null) { forceRebuild(cause); } @@ -354,7 +354,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe } private static void requestRebuild() { - FileBasedIndex.requestRebuild(StubUpdatingIndex.INDEX_ID); + FileBasedIndex.getInstance().requestRebuild(StubUpdatingIndex.INDEX_ID); } @Override diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 40fa9d8ac2cd..428f29dd556e 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -232,7 +232,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi } catch (StorageException e) { LOG.info(e); - FileBasedIndex.requestRebuild(INDEX_ID); + FileBasedIndex.getInstance().requestRebuild(INDEX_ID); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 6e8bcf2a307b..c2f3ad423b19 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -13,1676 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.indexing; -import com.intellij.AppTopics; -import com.intellij.history.LocalHistory; -import com.intellij.ide.caches.CacheUpdater; -import com.intellij.lang.ASTNode; -import com.intellij.notification.NotificationDisplayType; -import com.intellij.notification.NotificationGroup; -import com.intellij.notification.NotificationType; -import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ApplicationComponent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.impl.EditorHighlighterCache; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; -import com.intellij.openapi.fileTypes.*; -import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.*; -import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; -import com.intellij.openapi.project.*; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.vfs.*; -import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; -import com.intellij.openapi.vfs.newvfs.BulkFileListener; -import com.intellij.openapi.vfs.newvfs.ManagingFS; -import com.intellij.openapi.vfs.newvfs.NewVirtualFile; -import com.intellij.openapi.vfs.newvfs.events.VFileEvent; -import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon; -import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiDocumentTransactionListener; -import com.intellij.psi.impl.source.PsiFileImpl; -import com.intellij.psi.search.EverythingGlobalScope; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.stubs.SerializationManager; -import com.intellij.util.*; -import com.intellij.util.concurrency.Semaphore; -import com.intellij.util.containers.ConcurrentHashSet; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.io.*; -import com.intellij.util.io.DataOutputStream; -import com.intellij.util.io.storage.HeavyProcessLatch; -import com.intellij.util.messages.MessageBus; -import com.intellij.util.messages.MessageBusConnection; -import gnu.trove.*; +import com.intellij.util.Processor; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.io.*; -import java.lang.ref.SoftReference; -import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Collection; +import java.util.List; +import java.util.Set; /** - * @author Eugene Zhuravlev - * Date: Dec 20, 2007 + * Author: dmitrylomov */ - -public class FileBasedIndex implements ApplicationComponent { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.FileBasedIndex"); - @NonNls - private static final String CORRUPTION_MARKER_NAME = "corruption.marker"; - private final Map, Pair, InputFilter>> myIndices = new THashMap, Pair, InputFilter>>(); - private final Map, Semaphore> myUnsavedDataIndexingSemaphores = new THashMap, Semaphore>(); - private final TObjectIntHashMap> myIndexIdToVersionMap = new TObjectIntHashMap>(); - private final Set> myNotRequiringContentIndices = new THashSet>(); - private final Set> myRequiringContentIndices = new THashSet>(); - private final Set myNoLimitCheckTypes = new THashSet(); - - private final PerIndexDocumentVersionMap myLastIndexedDocStamps = new PerIndexDocumentVersionMap(); - @NotNull private final ChangedFilesCollector myChangedFilesCollector; - - private final List myIndexableSets = ContainerUtil.createEmptyCOWList(); - private final Map myIndexableSetToProjectMap = new THashMap(); - - private static final int OK = 1; - private static final int REQUIRES_REBUILD = 2; - private static final int REBUILD_IN_PROGRESS = 3; - private static final Map, AtomicInteger> ourRebuildStatus = new THashMap, AtomicInteger>(); - - private final VirtualFileManagerEx myVfManager; - private final FileDocumentManager myFileDocumentManager; - private final FileTypeManager myFileTypeManager; - private final ConcurrentHashSet> myUpToDateIndices = new ConcurrentHashSet>(); - private final Map myTransactionMap = new THashMap(); - - private static final int ALREADY_PROCESSED = 0x04; - - @Nullable private final String myConfigPath; - @Nullable private final String mySystemPath; - private final boolean myIsUnitTestMode; - @Nullable private ScheduledFuture myFlushingFuture; - private volatile int myLocalModCount; - private volatile int myFilesModCount; - - public void requestReindex(@NotNull final VirtualFile file) { - myChangedFilesCollector.invalidateIndices(file, true); - } - - public void requestReindexExcluded(@NotNull final VirtualFile file) { - myChangedFilesCollector.invalidateIndices(file, false); - } - - public FileBasedIndex(final VirtualFileManagerEx vfManager, FileDocumentManager fdm, - FileTypeManager fileTypeManager, @NotNull MessageBus bus, SerializationManager sm /*need this parameter to ensure component dependency*/) throws IOException { - myVfManager = vfManager; - myFileDocumentManager = fdm; - myFileTypeManager = fileTypeManager; - myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); - myConfigPath = calcConfigPath(PathManager.getConfigPath()); - mySystemPath = calcConfigPath(PathManager.getSystemPath()); - - final MessageBusConnection connection = bus.connect(); - connection.subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { - @Override - public void transactionStarted(final Document doc, final PsiFile file) { - if (file != null) { - synchronized (myTransactionMap) { - myTransactionMap.put(doc, file); - } - myUpToDateIndices.clear(); - } - } - - @Override - public void transactionCompleted(final Document doc, final PsiFile file) { - synchronized (myTransactionMap) { - myTransactionMap.remove(doc); - } - } - }); - - connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener() { - @Nullable private Map> myTypeToExtensionMap; - @Override - public void beforeFileTypesChanged(final FileTypeEvent event) { - cleanupProcessedFlag(); - myTypeToExtensionMap = new THashMap>(); - for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { - myTypeToExtensionMap.put(type, getExtensions(type)); - } - } - - @Override - public void fileTypesChanged(final FileTypeEvent event) { - final Map> oldExtensions = myTypeToExtensionMap; - myTypeToExtensionMap = null; - if (oldExtensions != null) { - final Map> newExtensions = new THashMap>(); - for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { - newExtensions.put(type, getExtensions(type)); - } - // we are interested only in extension changes or removals. - // addition of an extension is handled separately by RootsChanged event - if (!newExtensions.keySet().containsAll(oldExtensions.keySet())) { - rebuildAllIndices(); - return; - } - for (Map.Entry> entry : oldExtensions.entrySet()) { - FileType fileType = entry.getKey(); - Set strings = entry.getValue(); - if (!newExtensions.get(fileType).containsAll(strings)) { - rebuildAllIndices(); - return; - } - } - } - } - - @NotNull - private Set getExtensions(@NotNull FileType type) { - final Set set = new THashSet(); - for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { - set.add(matcher.getPresentableString()); - } - return set; - } - - private void rebuildAllIndices() { - for (ID indexId : myIndices.keySet()) { - try { - clearIndex(indexId); - } - catch (StorageException e) { - LOG.info(e); - } - } - scheduleIndexRebuild(true); - } - }); - - connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { - @Override - public void before(@NotNull List events) { - for (VFileEvent event : events) { - final Object requestor = event.getRequestor(); - if (requestor instanceof FileDocumentManager || requestor instanceof PsiManager || requestor == LocalHistory.VFS_EVENT_REQUESTOR) { - cleanupMemoryStorage(); - break; - } - } - } - - @Override - public void after(@NotNull List events) { - } - }); - - connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { - @Override - public void fileContentReloaded(VirtualFile file, @NotNull Document document) { - cleanupMemoryStorage(); - } - - @Override - public void unsavedDocumentsDropped() { - cleanupMemoryStorage(); - } - }); - - ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { - @Override - public void writeActionStarted(Object action) { - myUpToDateIndices.clear(); - } - }); - - myChangedFilesCollector = new ChangedFilesCollector(); - - /* - final File workInProgressFile = getMarkerFile(); - if (workInProgressFile.exists()) { - // previous IDEA session was closed incorrectly, so drop all indices - FileUtil.delete(PathManager.getIndexRoot()); - } - */ - - try { - final FileBasedIndexExtension[] extensions = Extensions.getExtensions(FileBasedIndexExtension.EXTENSION_POINT_NAME); - for (FileBasedIndexExtension extension : extensions) { - ourRebuildStatus.put(extension.getName(), new AtomicInteger(OK)); - } - - final File corruptionMarker = new File(PathManager.getIndexRoot(), CORRUPTION_MARKER_NAME); - final boolean currentVersionCorrupted = corruptionMarker.exists(); - boolean versionChanged = false; - for (FileBasedIndexExtension extension : extensions) { - versionChanged |= registerIndexer(extension, currentVersionCorrupted); - } - FileUtil.delete(corruptionMarker); - - String rebuildNotification = null; - if (currentVersionCorrupted) { - rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; - } - else if (versionChanged) { - rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; - } - if (rebuildNotification != null - && !ApplicationManager.getApplication().isHeadlessEnvironment() - && Registry.is("ide.showIndexRebuildMessage")) { - new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) - .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); - } - - dropUnregisteredIndices(); - - // check if rebuild was requested for any index during registration - for (ID indexId : myIndices.keySet()) { - if (ourRebuildStatus.get(indexId).compareAndSet(REQUIRES_REBUILD, OK)) { - try { - clearIndex(indexId); - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.error(e); - } - } - } - - myVfManager.addVirtualFileListener(myChangedFilesCollector); - - registerIndexableSet(new AdditionalIndexableFileSet(), null); - } - finally { - ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { - @Override - public void run() { - performShutdown(); - } - }); - //FileUtil.createIfDoesntExist(workInProgressFile); - saveRegisteredIndices(myIndices.keySet()); - myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() { - int lastModCount = 0; - @Override - public void run() { - if (lastModCount == myLocalModCount) { - flushAllIndices(lastModCount); - } - lastModCount = myLocalModCount; - } - }); - - } - } - - @Override - public void initComponent() { - } - - @Nullable - private static String calcConfigPath(final String path) { - try { - final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()); - return _path.endsWith("/")? _path : _path + "/" ; - } - catch (IOException e) { - LOG.info(e); - return null; - } - } - - private static class FileBasedIndexHolder { - private static final FileBasedIndex ourInstance = ApplicationManager.getApplication().getComponent(FileBasedIndex.class); - } - +public abstract class FileBasedIndex implements ApplicationComponent { public static FileBasedIndex getInstance() { - return FileBasedIndexHolder.ourInstance; - } - - /** - * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted - * - * @param extension - * @param isCurrentVersionCorrupted - */ - private boolean registerIndexer(@NotNull final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) throws IOException { - final ID name = extension.getName(); - final int version = extension.getVersion(); - final File versionFile = IndexInfrastructure.getVersionFile(name); - final boolean versionFileExisted = versionFile.exists(); - boolean versionChanged = false; - if (isCurrentVersionCorrupted || IndexInfrastructure.versionDiffers(versionFile, version)) { - if (!isCurrentVersionCorrupted && versionFileExisted) { - versionChanged = true; - LOG.info("Version has changed for index " + name + ". The index will be rebuilt."); - } - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); - IndexInfrastructure.rewriteVersion(versionFile, version); - } - - for (int attempt = 0; attempt < 2; attempt++) { - try { - final MapIndexStorage storage = new MapIndexStorage(IndexInfrastructure.getStorageFile(name), extension.getKeyDescriptor(), extension.getValueExternalizer(), extension.getCacheSize()); - final MemoryIndexStorage memStorage = new MemoryIndexStorage(storage); - final UpdatableIndex index = createIndex(name, extension, memStorage); - final InputFilter inputFilter = extension.getInputFilter(); - - assert inputFilter != null : "Index extension " + name + " must provide non-null input filter"; - - myIndices.put(name, new Pair, InputFilter>(index, new IndexableFilesFilter(inputFilter))); - myUnsavedDataIndexingSemaphores.put(name, new Semaphore()); - myIndexIdToVersionMap.put(name, version); - if (!extension.dependsOnFileContent()) { - myNotRequiringContentIndices.add(name); - } - else { - myRequiringContentIndices.add(name); - } - myNoLimitCheckTypes.addAll(extension.getFileTypesWithSizeLimitNotApplicable()); - break; - } - catch (IOException e) { - LOG.info(e); - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); - IndexInfrastructure.rewriteVersion(versionFile, version); - } - } - return versionChanged; - } - - private static void saveRegisteredIndices(@NotNull Collection> ids) { - final File file = getRegisteredIndicesFile(); - try { - FileUtil.createIfDoesntExist(file); - final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); - try { - os.writeInt(ids.size()); - for (ID id : ids) { - IOUtil.writeString(id.toString(), os); - } - } - finally { - os.close(); - } - } - catch (IOException ignored) { - } - } - - @NotNull - private static Set readRegisteredIndexNames() { - final Set result = new THashSet(); - try { - final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); - try { - final int size = in.readInt(); - for (int idx = 0; idx < size; idx++) { - result.add(IOUtil.readString(in)); - } - } - finally { - in.close(); - } - } - catch (IOException ignored) { - } - return result; - } - - @NotNull - private static File getRegisteredIndicesFile() { - return new File(PathManager.getIndexRoot(), "registered"); - } - - @NotNull - private UpdatableIndex createIndex(@NotNull final ID indexId, @NotNull final FileBasedIndexExtension extension, @NotNull final MemoryIndexStorage storage) throws IOException { - final MapReduceIndex index; - if (extension instanceof CustomImplementationFileBasedIndexExtension) { - final UpdatableIndex custom = ((CustomImplementationFileBasedIndexExtension)extension).createIndexImplementation(indexId, this, storage); - - assert custom != null : "Custom index implementation must not be null; index: " + indexId; - - if (!(custom instanceof MapReduceIndex)) { - return custom; - } - index = (MapReduceIndex)custom; - } - else { - index = new MapReduceIndex(indexId, extension.getIndexer(), storage); - } - - final KeyDescriptor keyDescriptor = extension.getKeyDescriptor(); - index.setInputIdToDataKeysIndex(new Factory>>() { - @Override - public PersistentHashMap> create() { - try { - return createIdToDataKeysIndex(indexId, keyDescriptor, storage); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - }); - - return index; - } - - @NotNull - private static PersistentHashMap> createIdToDataKeysIndex(@NotNull final ID indexId, - @NotNull final KeyDescriptor keyDescriptor, - @NotNull MemoryIndexStorage storage) throws IOException { - final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); - final Ref isBufferingMode = new Ref(false); - final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); - - final DataExternalizer> dataExternalizer = new DataExternalizer>() { - @Override - public void save(DataOutput out, @NotNull Collection value) throws IOException { - try { - DataInputOutputUtil.writeINT(out, value.size()); - for (K key : value) { - keyDescriptor.save(out, key); - } - } - catch (IllegalArgumentException e) { - throw new IOException("Error saving data for index " + indexId, e); - } - } - - @NotNull - @Override - public Collection read(DataInput in) throws IOException { - try { - final int size = DataInputOutputUtil.readINT(in); - final List list = new ArrayList(size); - for (int idx = 0; idx < size; idx++) { - list.add(keyDescriptor.read(in)); - } - return list; - } - catch (IllegalArgumentException e) { - throw new IOException("Error reading data for index " + indexId, e); - } - } - }; - - // Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage. - // If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage). - // Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the - // wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be - // cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects. - - final PersistentHashMap> map = new PersistentHashMap>( - indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, dataExternalizer - ) { - - @Override - protected Collection doGet(Integer integer) throws IOException { - if (isBufferingMode.get()) { - final Collection collection = tempMap.get(integer); - if (collection != null) { - return collection; - } - } - return super.doGet(integer); - } - - @Override - protected void doPut(Integer integer, @Nullable Collection ks) throws IOException { - if (isBufferingMode.get()) { - tempMap.put(integer, ks == null? Collections.emptySet() : ks); - } - else { - super.doPut(integer, ks); - } - } - - @Override - protected void doRemove(Integer integer) throws IOException { - if (isBufferingMode.get()) { - tempMap.put(integer, Collections.emptySet()); - } - else { - super.doRemove(integer); - } - } - }; - - storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { - @Override - public void bufferingStateChanged(boolean newState) { - synchronized (map) { - isBufferingMode.set(newState); - } - } - @Override - public void memoryStorageCleared() { - synchronized (map) { - tempMap.clear(); - } - } - }); - return map; - } - - @Override - @NonNls - @NotNull - public String getComponentName() { - return "FileBasedIndex"; - } - - @Override - public void disposeComponent() { - performShutdown(); - } - - private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false); - - private void performShutdown() { - if (!myShutdownPerformed.compareAndSet(false, true)) { - return; // already shut down - } - try { - if (myFlushingFuture != null) { - myFlushingFuture.cancel(false); - myFlushingFuture = null; - } - - myFileDocumentManager.saveAllDocuments(); - } - finally { - LOG.info("START INDEX SHUTDOWN"); - try { - myChangedFilesCollector.forceUpdate(null, null, null, true); - - for (ID indexId : myIndices.keySet()) { - final UpdatableIndex index = getIndex(indexId); - assert index != null; - checkRebuild(indexId, true); // if the index was scheduled for rebuild, only clean it - //LOG.info("DISPOSING " + indexId); - index.dispose(); - } - - myVfManager.removeVirtualFileListener(myChangedFilesCollector); - - //FileUtil.delete(getMarkerFile()); - } - catch (Throwable e) { - LOG.info("Problems during index shutdown", e); - throw new RuntimeException(e); - } - LOG.info("END INDEX SHUTDOWN"); - } - } - - private void flushAllIndices(final long modCount) { - if (HeavyProcessLatch.INSTANCE.isRunning()) { - return; - } - IndexingStamp.flushCache(); - for (ID indexId : new ArrayList>(myIndices.keySet())) { - if (HeavyProcessLatch.INSTANCE.isRunning() || modCount != myLocalModCount) { - return; // do not interfere with 'main' jobs - } - try { - final UpdatableIndex index = getIndex(indexId); - if (index != null) { - index.flush(); - } - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - - if (!HeavyProcessLatch.INSTANCE.isRunning() && modCount == myLocalModCount) { // do not interfere with 'main' jobs - SerializationManager.getInstance().flushNameStorage(); - } - } - - /** - * @param project it is guaranteed to return data which is up-to-date withing the project - * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist - */ - @NotNull - public Collection getAllKeys(@NotNull final ID indexId, @NotNull Project project) { - Set allKeys = new THashSet(); - processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); - return allKeys; - } - - /** - * @param project it is guaranteed to return data which is up-to-date withing the project - * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist - */ - public boolean processAllKeys(@NotNull final ID indexId, Processor processor, @Nullable Project project) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return true; - } - ensureUpToDate(indexId, project, project != null? GlobalSearchScope.allScope(project) : new EverythingGlobalScope()); - return index.processAllKeys(processor); - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - - return false; - } - - private static final ThreadLocal myUpToDateCheckState = new ThreadLocal(); - - public static void disableUpToDateCheckForCurrentThread() { - final Integer currentValue = myUpToDateCheckState.get(); - myUpToDateCheckState.set(currentValue == null? 1 : currentValue.intValue() + 1); - } - - public static void enableUpToDateCheckForCurrentThread() { - final Integer currentValue = myUpToDateCheckState.get(); - if (currentValue != null) { - final int newValue = currentValue.intValue() - 1; - if (newValue != 0) { - myUpToDateCheckState.set(newValue); - } - else { - myUpToDateCheckState.remove(); - } - } - } - - private static boolean isUpToDateCheckEnabled() { - final Integer value = myUpToDateCheckState.get(); - return value == null || value.intValue() == 0; - } - - - private final ThreadLocal myReentrancyGuard = new ThreadLocal() { - @Override - protected Boolean initialValue() { - return Boolean.FALSE; - } - }; - - /** - * DO NOT CALL DIRECTLY IN CLIENT CODE - * The method is internal to indexing engine end is called internally. The method is public due to implementation details - */ - public void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter) { - ensureUpToDate(indexId, project, filter, null); - } - - private void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, - @Nullable VirtualFile restrictedFile) { - if (!needsFileContentLoading(indexId)) { - return; //indexed eagerly in foreground while building unindexed file list - } - if (isDumb(project)) { - handleDumbMode(project); - } - - if (myReentrancyGuard.get().booleanValue()) { - //assert false : "ensureUpToDate() is not reentrant!"; - return; - } - myReentrancyGuard.set(Boolean.TRUE); - - try { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - if (isUpToDateCheckEnabled()) { - try { - checkRebuild(indexId, false); - myChangedFilesCollector.forceUpdate(project, filter, restrictedFile, false); - indexUnsavedDocuments(indexId, project, filter, restrictedFile); - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, e); - } - else { - throw e; - } - } - } - } - finally { - myReentrancyGuard.set(Boolean.FALSE); - } - } - - private static void handleDumbMode(@Nullable Project project) { - ProgressManager.checkCanceled(); // DumbModeAction.CANCEL - - if (project != null) { - final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); - if (progressIndicator instanceof BackgroundableProcessIndicator) { - final BackgroundableProcessIndicator indicator = (BackgroundableProcessIndicator)progressIndicator; - if (indicator.getDumbModeAction() == DumbModeAction.WAIT) { - assert !ApplicationManager.getApplication().isDispatchThread(); - DumbService.getInstance(project).waitForSmartMode(); - return; - } - } - } - - throw new IndexNotReadyException(); - } - - private static boolean isDumb(@Nullable Project project) { - if (project != null) { - return DumbServiceImpl.getInstance(project).isDumb(); - } - for (Project proj : ProjectManager.getInstance().getOpenProjects()) { - if (DumbServiceImpl.getInstance(proj).isDumb()) { - return true; - } - } - return false; - } - - @NotNull - public List getValues(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final List values = new SmartList(); - processValuesImpl(indexId, dataKey, true, null, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - values.add(value); - return true; - } - }, filter); - return values; - } - - @NotNull - public Collection getContainingFiles(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final Set files = new THashSet(); - processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - files.add(file); - return true; - } - }, filter); - return files; - } - - - public interface ValueProcessor { - /** - * @param value a value to process - * @param file the file the value came from - * @return false if no further processing is needed, true otherwise - */ - boolean process(VirtualFile file, V value); - } - - /** - * @return false if ValueProcessor.process() returned false; true otherwise or if ValueProcessor was not called at all - */ - public boolean processValues(@NotNull final ID indexId, @NotNull final K dataKey, @Nullable final VirtualFile inFile, - @NotNull ValueProcessor processor, @NotNull final GlobalSearchScope filter) { - return processValuesImpl(indexId, dataKey, false, inFile, processor, filter); - } - - - - - @Nullable - private R processExceptions(@NotNull final ID indexId, - @Nullable final VirtualFile restrictToFile, - @NotNull final GlobalSearchScope filter, - @NotNull ThrowableConvertor, R, StorageException> computable) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return null; - } - final Project project = filter.getProject(); - //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; - ensureUpToDate(indexId, project, filter, restrictToFile); - - try { - index.getReadLock().lock(); - return computable.convert(index); - } - finally { - index.getReadLock().unlock(); - } - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = getCauseToRebuildIndex(e); - if (cause != null) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - return null; - } - - private boolean processValuesImpl(@NotNull final ID indexId, final K dataKey, final boolean ensureValueProcessedOnce, - @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, - @NotNull final GlobalSearchScope filter) { - ThrowableConvertor, Boolean, StorageException> keyProcessor = new ThrowableConvertor, Boolean, StorageException>() { - @Override - public Boolean convert(@NotNull UpdatableIndex index) throws StorageException { - final ValueContainer container = index.getData(dataKey); - - boolean shouldContinue = true; - - if (restrictToFile != null) { - if (restrictToFile instanceof VirtualFileWithId) { - final int restrictedFileId = getFileId(restrictToFile); - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - if (container.isAssociated(value, restrictedFileId)) { - shouldContinue = processor.process(restrictToFile, value); - if (!shouldContinue) { - break; - } - } - } - } - } - else { - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - ProjectIndexableFilesFilter projectFilesSet = projectIndexableFiles(filter.getProject()); - VALUES_LOOP: for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { - final V value = valueIt.next(); - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { - final int id = inputIdsIterator.next(); - if (projectFilesSet != null && !projectFilesSet.contains(id)) continue; - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - shouldContinue = processor.process(file, value); - if (!shouldContinue) { - break VALUES_LOOP; - } - if (ensureValueProcessedOnce) { - break; // continue with the next value - } - } - } - } - } - return shouldContinue; - } - }; - final Boolean result = processExceptions(indexId, restrictToFile, filter, keyProcessor); - return result == null || result.booleanValue(); - } - - public boolean processFilesContainingAllKeys(@NotNull final ID indexId, - @NotNull final Collection dataKeys, - @NotNull final GlobalSearchScope filter, - @Nullable Condition valueChecker, - @NotNull final Processor processor) { - ProjectIndexableFilesFilter filesSet = projectIndexableFiles(filter.getProject()); - final TIntHashSet set = collectFileIdsContainingAllKeys(indexId, dataKeys, filter, valueChecker, filesSet); - return set != null && processVirtualFiles(set, filter, processor); - } - - private static final Key> ourProjectFilesSetKey = Key.create("projectFiles"); - - public static final class ProjectIndexableFilesFilter { - private static final int SHIFT = 6; - private static final int MASK = (1 << SHIFT) - 1; - private final long[] myBitMask; - private final int myModificationCount; - private final int myMinId; - private final int myMaxId; - - private ProjectIndexableFilesFilter(@NotNull TIntHashSet set, int modificationCount) { - myModificationCount = modificationCount; - final int[] minMax = new int[2]; - if (set.size() > 0) { - minMax[0] = minMax[1] = set.iterator().next(); - } - set.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - minMax[0] = Math.min(minMax[0], value); - minMax[1] = Math.max(minMax[1], value); - return true; - } - }); - myMaxId = minMax[1]; - myMinId = minMax[0]; - myBitMask = new long[((myMaxId - myMinId) >> SHIFT) + 1]; - set.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - value = value - myMinId; - myBitMask[value >> SHIFT] |= (1L << (value & MASK)); - return true; - } - }); - } - - public boolean contains(int id) { - if (id < myMinId) return false; - if (id > myMaxId) return false; - id -= myMinId; - return (myBitMask[id >> SHIFT] & (1L << (id & MASK))) != 0; - } - } - - @Nullable - public ProjectIndexableFilesFilter projectIndexableFiles(@Nullable Project project) { - if (project == null) return null; - - SoftReference reference = project.getUserData(ourProjectFilesSetKey); - ProjectIndexableFilesFilter data = reference != null ? reference.get() : null; - if (data != null && data.myModificationCount == myFilesModCount) return data; - - final TIntHashSet filesSet = new TIntHashSet(); - iterateIndexableFiles(new ContentIterator() { - @Override - public boolean processFile(@NotNull VirtualFile fileOrDir) { - filesSet.add(((VirtualFileWithId)fileOrDir).getId()); - return true; - } - }, project, ProgressManager.getInstance().getProgressIndicator()); - ProjectIndexableFilesFilter files = new ProjectIndexableFilesFilter(filesSet, myFilesModCount); - project.putUserData(ourProjectFilesSetKey, new SoftReference(files)); - return files; - } - - @Nullable - private TIntHashSet collectFileIdsContainingAllKeys(@NotNull final ID indexId, - @NotNull final Collection dataKeys, - @NotNull final GlobalSearchScope filter, - @Nullable final Condition valueChecker, - @Nullable final ProjectIndexableFilesFilter projectFilesFilter) { - final ThrowableConvertor, TIntHashSet, StorageException> convertor = - new ThrowableConvertor, TIntHashSet, StorageException>() { - @Nullable - @Override - public TIntHashSet convert(@NotNull UpdatableIndex index) throws StorageException { - TIntHashSet mainIntersection = null; - - for (K dataKey : dataKeys) { - ProgressManager.checkCanceled(); - final TIntHashSet copy = new TIntHashSet(); - final ValueContainer container = index.getData(dataKey); - - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - if (valueChecker != null && !valueChecker.value(value)) { - continue; - } - - ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); - - if (mainIntersection == null || iterator.size() < mainIntersection.size()) { - for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { - final int id = inputIdsIterator.next(); - if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || - mainIntersection != null && mainIntersection.contains(id) - ) { - copy.add(id); - } - } - } else { - mainIntersection.forEach(new TIntProcedure() { - final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); - @Override - public boolean execute(int id) { - if (predicate.contains(id)) copy.add(id); - return true; - } - }); - } - } - - mainIntersection = copy; - if (mainIntersection.isEmpty()) { - return new TIntHashSet(); - } - } - - return mainIntersection; - } - }; - - - return processExceptions(indexId, null, filter, convertor); - } - - private static boolean processVirtualFiles(@NotNull TIntHashSet ids, - @NotNull final GlobalSearchScope filter, - @NotNull final Processor processor) { - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - return ids.forEach(new TIntProcedure() { - @Override - public boolean execute(int id) { - ProgressManager.checkCanceled(); - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - return processor.process(file); - } - return true; - } - }); - } - - @Nullable - public static Throwable getCauseToRebuildIndex(@NotNull RuntimeException e) { - Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException || - cause instanceof IllegalArgumentException) return cause; - return null; - } - - public boolean getFilesWithKey(@NotNull final ID indexId, - @NotNull final Set dataKeys, - @NotNull Processor processor, - @NotNull GlobalSearchScope filter) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return true; - } - final Project project = filter.getProject(); - //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; - ensureUpToDate(indexId, project, filter); - - try { - index.getReadLock().lock(); - final List locals = new ArrayList(); - for (K dataKey : dataKeys) { - TIntHashSet local = new TIntHashSet(); - locals.add(local); - final ValueContainer container = index.getData(dataKey); - - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { - final V value = valueIt.next(); - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { - final int id = inputIdsIterator.next(); - local.add(id); - } - } - } - - if (locals.isEmpty()) { - return true; - } - - Collections.sort(locals, new Comparator() { - @Override - public int compare(TIntHashSet o1, TIntHashSet o2) { - return o1.size() - o2.size(); - } - }); - - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - TIntIterator ids = join(locals).iterator(); - ProjectIndexableFilesFilter projectIndexableFilesFilter = projectIndexableFiles(project); - while (ids.hasNext()) { - int id = ids.next(); - if (projectIndexableFilesFilter != null && !projectIndexableFilesFilter.contains(id)) continue; - //VirtualFile file = IndexInfrastructure.findFileById(fs, id); - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - if (!processor.process(file)) { - return false; - } - } - } - } - finally { - index.getReadLock().unlock(); - } - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - return true; - } - - @NotNull - private static TIntHashSet join(@NotNull List locals) { - TIntHashSet result = locals.get(0); - if (locals.size() > 1) { - TIntIterator it = result.iterator(); - - while (it.hasNext()) { - int id = it.next(); - for (int i = 1; i < locals.size(); i++) { - if (!locals.get(i).contains(id)) { - it.remove(); - break; - } - } - } - } - return result; - } - - public void scheduleRebuild(@NotNull final ID indexId, @NotNull final Throwable e) { - LOG.info(e); - requestRebuild(indexId); - try { - checkRebuild(indexId, false); - } - catch (ProcessCanceledException ignored) { - } - } - - private void checkRebuild(@NotNull final ID indexId, final boolean cleanupOnly) { - final AtomicInteger status = ourRebuildStatus.get(indexId); - if (status.get() == OK) return; - if (status.compareAndSet(REQUIRES_REBUILD, REBUILD_IN_PROGRESS)) { - cleanupProcessedFlag(); - - final Runnable rebuildRunnable = new Runnable() { - @Override - public void run() { - try { - clearIndex(indexId); - if (!cleanupOnly) { - scheduleIndexRebuild(false); - } - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.info(e); - } - finally { - status.compareAndSet(REBUILD_IN_PROGRESS, OK); - } - } - }; - - if (cleanupOnly || myIsUnitTestMode) { - rebuildRunnable.run(); - } - else { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - new Task.Modal(null, "Updating index", false) { - @Override - public void run(@NotNull final ProgressIndicator indicator) { - indicator.setIndeterminate(true); - rebuildRunnable.run(); - } - }.queue(); - } - }); - } - } - - if (status.get() == REBUILD_IN_PROGRESS) { - throw new ProcessCanceledException(); - } - } - - private void scheduleIndexRebuild(boolean forceDumbMode) { - for (Project project : ProjectManager.getInstance().getOpenProjects()) { - final Set updatersToRun = Collections.singleton(new UnindexedFilesUpdater(project, this)); - final DumbServiceImpl service = DumbServiceImpl.getInstance(project); - if (forceDumbMode) { - service.queueCacheUpdateInDumbMode(updatersToRun); - } - else { - service.queueCacheUpdate(updatersToRun); - } - } - } - - private void clearIndex(@NotNull final ID indexId) throws StorageException { - final UpdatableIndex index = getIndex(indexId); - assert index != null: "Index with key " + indexId + " not found or not registered properly"; - index.clear(); - try { - IndexInfrastructure.rewriteVersion(IndexInfrastructure.getVersionFile(indexId), myIndexIdToVersionMap.get(indexId)); - } - catch (IOException e) { - LOG.error(e); - } - } - - @NotNull - private Set getUnsavedOrTransactedDocuments() { - final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); - synchronized (myTransactionMap) { - docs.addAll(myTransactionMap.keySet()); - } - return docs; - } - - private void indexUnsavedDocuments(@NotNull ID indexId, - @Nullable Project project, - GlobalSearchScope filter, - VirtualFile restrictedFile) throws StorageException { - if (myUpToDateIndices.contains(indexId)) { - return; // no need to index unsaved docs - } - - final Set documents = getUnsavedOrTransactedDocuments(); - if (!documents.isEmpty()) { - // now index unsaved data - final StorageGuard.Holder guard = setDataBufferingEnabled(true); - try { - final Semaphore semaphore = myUnsavedDataIndexingSemaphores.get(indexId); - - assert semaphore != null : "Semaphore for unsaved data indexing was not initialized for index " + indexId; - - semaphore.down(); - boolean allDocsProcessed = true; - try { - for (Document document : documents) { - allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); - } - } - finally { - semaphore.up(); - - while (!semaphore.waitFor(500)) { // may need to wait until another thread is done with indexing - if (Thread.holdsLock(PsiLock.LOCK)) { - break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. - } - } - if (allDocsProcessed && !hasActiveTransactions()) { - myUpToDateIndices.add(indexId); // safe to set the flag here, because it will be cleared under the WriteAction - } - } - } - finally { - guard.leave(); - } - } - } - - private boolean hasActiveTransactions() { - synchronized (myTransactionMap) { - return !myTransactionMap.isEmpty(); - } - } - - private interface DocumentContent { - String getText(); - long getModificationStamp(); - } - - private static class AuthenticContent implements DocumentContent { - private final Document myDocument; - - private AuthenticContent(final Document document) { - myDocument = document; - } - - @Override - public String getText() { - return myDocument.getText(); - } - - @Override - public long getModificationStamp() { - return myDocument.getModificationStamp(); - } - } - - private static class PsiContent implements DocumentContent { - private final Document myDocument; - private final PsiFile myFile; - - private PsiContent(final Document document, final PsiFile file) { - myDocument = document; - myFile = file; - } - - @Override - public String getText() { - if (myFile.getModificationStamp() != myDocument.getModificationStamp()) { - final ASTNode node = myFile.getNode(); - assert node != null; - return node.getText(); - } - return myDocument.getText(); - } - - @Override - public long getModificationStamp() { - return myFile.getModificationStamp(); - } - } - -// returns false if doc was not indexed because the file does not fit in scope - private boolean indexUnsavedDocument(@NotNull final Document document, @NotNull final ID requestedIndexId, final Project project, - @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedFile) throws StorageException { - final VirtualFile vFile = myFileDocumentManager.getFile(document); - if (!(vFile instanceof VirtualFileWithId) || !vFile.isValid()) { - return true; - } - - if (restrictedFile != null) { - if(vFile != restrictedFile) { - return false; - } - } - else if (filter != null && !filter.accept(vFile)) { - return false; - } - - final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); - - final DocumentContent content; - if (dominantContentFile != null && dominantContentFile.getModificationStamp() != document.getModificationStamp()) { - content = new PsiContent(document, dominantContentFile); - } - else { - content = new AuthenticContent(document); - } - - final long currentDocStamp = content.getModificationStamp(); - if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp)) { - final Ref exRef = new Ref(null); - ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { - @Override - public void run() { - try { - final String contentText = content.getText(); - if (isTooLarge(vFile, contentText.length())) { - return; - } - - final FileContentImpl newFc = new FileContentImpl(vFile, contentText, vFile.getCharset()); - - if (dominantContentFile != null) { - dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, true); - newFc.putUserData(IndexingDataKeys.PSI_FILE, dominantContentFile); - } - - if (content instanceof AuthenticContent) { - newFc.putUserData(EDITOR_HIGHLIGHTER, EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)); - } - - if (getInputFilter(requestedIndexId).acceptInput(vFile)) { - newFc.putUserData(IndexingDataKeys.PROJECT, project); - final int inputId = Math.abs(getFileId(vFile)); - getIndex(requestedIndexId).update(inputId, newFc); - } - - if (dominantContentFile != null) { - dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, null); - } - } - catch (StorageException e) { - exRef.set(e); - } - } - }); - final StorageException storageException = exRef.get(); - if (storageException != null) { - throw storageException; - } - } - return true; - } - - public static final Key EDITOR_HIGHLIGHTER = new Key("Editor"); - - @Nullable - private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { - synchronized (myTransactionMap) { - PsiFile psiFile = myTransactionMap.get(document); - if (psiFile != null) return psiFile; - } - - return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); - } - - private final StorageGuard myStorageLock = new StorageGuard(); - - @NotNull - private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) { - final StorageGuard.Holder holder = myStorageLock.enter(enabled); - for (ID indexId : myIndices.keySet()) { - final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); - assert index != null; - final IndexStorage indexStorage = index.getStorage(); - ((MemoryIndexStorage)indexStorage).setBufferingEnabled(enabled); - } - return holder; - } - - private void cleanupMemoryStorage() { - myLastIndexedDocStamps.clear(); - for (ID indexId : myIndices.keySet()) { - final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); - assert index != null; - final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage(); - index.getWriteLock().lock(); - try { - memStorage.clearMemoryMap(); - } - finally { - index.getWriteLock().unlock(); - } - memStorage.fireMemoryStorageCleared(); - } - } - - private void dropUnregisteredIndices() { - final Set indicesToDrop = readRegisteredIndexNames(); - for (ID key : myIndices.keySet()) { - indicesToDrop.remove(key.toString()); - } - for (String s : indicesToDrop) { - FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); - } - } - - public static void requestRebuild(ID indexId) { - requestRebuild(indexId, new Throwable()); - } - - public static void requestRebuild(ID indexId, Throwable throwable) { - cleanupProcessedFlag(); - LOG.info("Rebuild requested for index " + indexId, throwable); - ourRebuildStatus.get(indexId).set(REQUIRES_REBUILD); - } - - private UpdatableIndex getIndex(ID indexId) { - final Pair, InputFilter> pair = myIndices.get(indexId); - - assert pair != null : "Index data is absent for index " + indexId; - - //noinspection unchecked - return (UpdatableIndex)pair.getFirst(); - } - - private InputFilter getInputFilter(ID indexId) { - final Pair, InputFilter> pair = myIndices.get(indexId); - - assert pair != null : "Index data is absent for index " + indexId; - - return pair.getSecond(); - } - - public int getNumberOfPendingInvalidations() { - return myChangedFilesCollector.getNumberOfPendingInvalidations(); - } - - @NotNull - public Collection getFilesToUpdate(final Project project) { - return ContainerUtil.findAll(myChangedFilesCollector.getAllFilesToUpdate(), new Condition() { - @Override - public boolean value(VirtualFile virtualFile) { - for (IndexableFileSet set : myIndexableSets) { - final Project proj = myIndexableSetToProjectMap.get(set); - if (proj != null && !proj.equals(project)) { - continue; // skip this set as associated with a different project - } - if (set.isInSet(virtualFile)) { - return true; - } - } - return false; - } - }); - } - - public void processRefreshedFile(@NotNull Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - myChangedFilesCollector.processFileImpl(project, fileContent, false); - } - - public void indexFileContent(@Nullable Project project, @NotNull com.intellij.ide.caches.FileContent content) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - final VirtualFile file = content.getVirtualFile(); - FileContentImpl fc = null; - - PsiFile psiFile = null; - - FileTypeManagerImpl.cacheFileType(file, file.getFileType()); - try { - for (final ID indexId : myIndices.keySet()) { - if (shouldIndexFile(file, indexId)) { - if (fc == null) { - byte[] currentBytes; - try { - currentBytes = content.getBytes(); - } - catch (IOException e) { - currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY; - } - fc = new FileContentImpl(file, currentBytes); - - psiFile = content.getUserData(IndexingDataKeys.PSI_FILE); - if (psiFile != null) { - psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true); - fc.putUserData(IndexingDataKeys.PSI_FILE, psiFile); - } - if (project == null) { - project = ProjectUtil.guessProjectForFile(file); - } - fc.putUserData(IndexingDataKeys.PROJECT, project); - } - - try { - ProgressManager.checkCanceled(); - updateSingleIndex(indexId, file, fc); - } - catch (ProcessCanceledException e) { - myChangedFilesCollector.scheduleForUpdate(file); - throw e; - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.info(e); - } - } - } - - if (psiFile != null) { - psiFile.putUserData(PsiFileImpl.BUILDING_STUB, null); - } - } finally { - FileTypeManagerImpl.cacheFileType(file, null); - } - } - - private void updateSingleIndex(final ID indexId, @NotNull final VirtualFile file, @Nullable final FileContent currentFC) - throws StorageException { - if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { - return; // the index is scheduled for rebuild, no need to update - } - myLocalModCount++; - - final StorageGuard.Holder lock = setDataBufferingEnabled(false); - - try { - final int inputId = Math.abs(getFileId(file)); - - final UpdatableIndex index = getIndex(indexId); - assert index != null; - - final Ref exRef = new Ref(null); - ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { - @Override - public void run() { - try { - index.update(inputId, currentFC); - } - catch (StorageException e) { - exRef.set(e); - } - } - }); - final StorageException storageException = exRef.get(); - if (storageException != null) { - throw storageException; - } - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - if (file.isValid()) { - if (currentFC != null) { - IndexingStamp.update(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); - } - else { - // mark the file as unindexed - IndexingStamp.update(file, indexId, -1L); - } - } - } - }); - } - finally { - lock.leave(); - } + return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } public static int getFileId(@NotNull final VirtualFile file) { @@ -1693,653 +47,68 @@ public class FileBasedIndex implements ApplicationComponent { throw new IllegalArgumentException("Virtual file doesn't support id: " + file + ", implementation class: " + file.getClass().getName()); } - private boolean needsFileContentLoading(ID indexId) { - return !myNotRequiringContentIndices.contains(indexId); + public void requestRebuild(ID indexId) { + requestRebuild(indexId, new Throwable()); } - private abstract static class InvalidationTask implements Runnable { - private final VirtualFile mySubj; - protected InvalidationTask(final VirtualFile subj) { - mySubj = subj; - } - - public VirtualFile getSubj() { - return mySubj; - } - } - - private final class ChangedFilesCollector extends VirtualFileAdapter { - private final Set myFilesToUpdate = new ConcurrentHashSet(); - private final Queue myFutureInvalidations = new ConcurrentLinkedQueue(); - - private final ManagingFS myManagingFS = ManagingFS.getInstance(); - // No need to react on movement events since files stay valid, their ids don't change and all associated attributes remain intact. - - @Override - public void fileCreated(@NotNull final VirtualFileEvent event) { - markDirty(event, false); - } - - @Override - public void fileDeleted(@NotNull final VirtualFileEvent event) { - myFilesToUpdate.remove(event.getFile()); // no need to update it anymore - } - - @Override - public void fileCopied(@NotNull final VirtualFileCopyEvent event) { - markDirty(event, false); - } - - @Override - public void beforeFileDeletion(@NotNull final VirtualFileEvent event) { - invalidateIndices(event.getFile(), false); - } - - @Override - public void beforeContentsChange(@NotNull final VirtualFileEvent event) { - invalidateIndices(event.getFile(), true); - } - - @Override - public void contentsChanged(@NotNull final VirtualFileEvent event) { - markDirty(event, true); - } - - @Override - public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { - if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { - // indexes may depend on file name - final VirtualFile file = event.getFile(); - if (!file.isDirectory()) { - // name change may lead to filetype change so the file might become not indexable - // in general case have to 'unindex' the file and index it again if needed after the name has been changed - invalidateIndices(file, false); - } - } - } - - @Override - public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) { - if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { - // indexes may depend on file name - if (!event.getFile().isDirectory()) { - markDirty(event, false); - } - } - } - - private void markDirty(@NotNull final VirtualFileEvent event, final boolean contentChange) { - final VirtualFile eventFile = event.getFile(); - cleanProcessedFlag(eventFile); - iterateIndexableFiles(eventFile, new Processor() { - @Override - public boolean process(@NotNull final VirtualFile file) { - if (!contentChange) ++myFilesModCount; - FileContent fileContent = null; - // handle 'content-less' indices separately - for (ID indexId : myNotRequiringContentIndices) { - if (getInputFilter(indexId).acceptInput(file)) { - try { - if (fileContent == null) { - fileContent = new FileContentImpl(file); - } - updateSingleIndex(indexId, file, fileContent); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - } - // For 'normal indices' schedule the file for update and stop iteration if at least one index accepts it - if (!isTooLarge(file)) { - for (ID indexId : myIndices.keySet()) { - if (needsFileContentLoading(indexId) && getInputFilter(indexId).acceptInput(file)) { - scheduleForUpdate(file); - break; // no need to iterate further, as the file is already marked - } - } - } - - return true; - } - }); - IndexingStamp.flushCache(); - } - - public void scheduleForUpdate(VirtualFile file) { - myFilesToUpdate.add(file); - } - - void invalidateIndices(@NotNull final VirtualFile file, final boolean markForReindex) { - if (isUnderConfigOrSystem(file)) { - return; - } - if (file.isDirectory()) { - if (isMock(file) || myManagingFS.wereChildrenAccessed(file)) { - final Iterable children = file instanceof NewVirtualFile - ? ((NewVirtualFile)file).iterInDbChildren() : Arrays.asList(file.getChildren()); - for (VirtualFile child : children) { - invalidateIndices(child, markForReindex); - } - } - } - else { - cleanProcessedFlag(file); - IndexingStamp.flushCache(); - final List> affectedIndices = new ArrayList>(myIndices.size()); - - for (final ID indexId : myIndices.keySet()) { - try { - if (!needsFileContentLoading(indexId)) { - if (shouldUpdateIndex(file, indexId)) { - updateSingleIndex(indexId, file, null); - } - } - else { // the index requires file content - if (shouldUpdateIndex(file, indexId)) { - affectedIndices.add(indexId); - } - } - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - - if (!affectedIndices.isEmpty()) { - if (markForReindex && !isTooLarge(file)) { - // only mark the file as unindexed, reindex will be done lazily - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - for (ID indexId : affectedIndices) { - IndexingStamp.update(file, indexId, -2L); - } - } - }); - // the file is for sure not a dir and it was previously indexed by at least one index - scheduleForUpdate(file); - } - else { - myFutureInvalidations.offer(new InvalidationTask(file) { - @Override - public void run() { - removeFileDataFromIndices(affectedIndices, file); - } - }); - } - } - if (!markForReindex) { - final boolean removedFromUpdateQueue = myFilesToUpdate.remove(file);// no need to update it anymore - if (removedFromUpdateQueue && affectedIndices.isEmpty()) { - // Currently the file is about to be deleted and previously it was scheduled for update and not processed up to now. - // Because the file was scheduled for update, at the moment of scheduling it was marked as unindexed, - // so, to be on the safe side, we have to schedule data invalidation from all content-requiring indices for this file - myFutureInvalidations.offer(new InvalidationTask(file) { - @Override - public void run() { - removeFileDataFromIndices(myRequiringContentIndices, file); - } - }); - } - } - - IndexingStamp.flushCache(); - } - } - - private void removeFileDataFromIndices(@NotNull Collection> affectedIndices, @NotNull VirtualFile file) { - Throwable unexpectedError = null; - for (ID indexId : affectedIndices) { - try { - updateSingleIndex(indexId, file, null); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - catch (ProcessCanceledException ignored) { - } - catch (Throwable e) { - LOG.info(e); - if (unexpectedError == null) { - unexpectedError = e; - } - } - } - IndexingStamp.flushCache(); - if (unexpectedError != null) { - LOG.error(unexpectedError); - } - } - - public int getNumberOfPendingInvalidations() { - return myFutureInvalidations.size(); - } - - public void ensureAllInvalidateTasksCompleted() { - final int size = getNumberOfPendingInvalidations(); - if (size == 0) { - return; - } - final ProgressIndicator current = ProgressManager.getInstance().getProgressIndicator(); - final ProgressIndicator indicator = current != null ? current : new EmptyProgressIndicator(); - indicator.setText(""); - int count = 0; - while (true) { - InvalidationTask task = myFutureInvalidations.poll(); - - if (task == null) { - break; - } - indicator.setFraction((double)count++ /size); - indicator.setText2(task.getSubj().getPresentableUrl()); - task.run(); - } - } - - private void iterateIndexableFiles(@NotNull final VirtualFile file, @NotNull final Processor processor) { - if (file.isDirectory()) { - final ContentIterator iterator = new ContentIterator() { - @Override - public boolean processFile(@NotNull final VirtualFile fileOrDir) { - if (!fileOrDir.isDirectory()) { - processor.process(fileOrDir); - } - return true; - } - }; - - for (IndexableFileSet set : myIndexableSets) { - if (set.isInSet(file)) { - set.iterateIndexableFilesIn(file, iterator); - } - } - } - else { - for (IndexableFileSet set : myIndexableSets) { - if (set.isInSet(file)) { - processor.process(file); - break; - } - } - } - } - - public Collection getAllFilesToUpdate() { - if (myFilesToUpdate.isEmpty()) { - return Collections.emptyList(); - } - return new ArrayList(myFilesToUpdate); - } - - private final Semaphore myForceUpdateSemaphore = new Semaphore(); - - private void forceUpdate(@Nullable Project project, @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedTo, - boolean onlyRemoveOutdatedData) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - for (VirtualFile file: getAllFilesToUpdate()) { - if (filter == null || filter.accept(file) || file == restrictedTo) { - try { - myForceUpdateSemaphore.down(); - // process only files that can affect result - processFileImpl(project, new com.intellij.ide.caches.FileContent(file), onlyRemoveOutdatedData); - } - finally { - myForceUpdateSemaphore.up(); - } - } - } - - // If several threads entered the method at the same time and there were files to update, - // all the threads should leave the method synchronously after all the files scheduled for update are reindexed, - // no matter which thread will do reindexing job. - // Thus we ensure that all the threads that entered the method will get the most recent data - - while (!myForceUpdateSemaphore.waitFor(500)) { // may need to wait until another thread is done with indexing - if (Thread.holdsLock(PsiLock.LOCK)) { - break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. - } - } - } - - private void processFileImpl(Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent, boolean onlyRemoveOutdatedData) { - final VirtualFile file = fileContent.getVirtualFile(); - final boolean reallyRemoved = myFilesToUpdate.remove(file); - if (reallyRemoved && file.isValid()) { - if (onlyRemoveOutdatedData) { - // on shutdown there is no need to re-index the file, just remove outdated data from indices - final List> affected = new ArrayList>(); - for (final ID indexId : myIndices.keySet()) { - if (getInputFilter(indexId).acceptInput(file)) { - affected.add(indexId); - } - } - removeFileDataFromIndices(affected, file); - } - else { - indexFileContent(project, fileContent); - } - IndexingStamp.flushCache(); - } - } - } - - private class UnindexedFilesFinder implements CollectingContentIterator { - private final List myFiles = new ArrayList(); - private final ProgressIndicator myProgressIndicator; - - private UnindexedFilesFinder() { - myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); - } - - @NotNull - @Override - public List getFiles() { - return myFiles; - } - - @Override - public boolean processFile(@NotNull final VirtualFile file) { - if (!file.isValid()) { - return true; - } - if (!file.isDirectory()) { - if (file instanceof NewVirtualFile && ((NewVirtualFile)file).getFlag(ALREADY_PROCESSED)) { - return true; - } - - if (file instanceof VirtualFileWithId) { - try { - FileTypeManagerImpl.cacheFileType(file, file.getFileType()); - - boolean oldStuff = true; - if (!isTooLarge(file)) { - for (ID indexId : myIndices.keySet()) { - try { - if (needsFileContentLoading(indexId) && shouldIndexFile(file, indexId)) { - myFiles.add(file); - oldStuff = false; - break; - } - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof IOException || cause instanceof StorageException) { - LOG.info(e); - requestRebuild(indexId); - } - else { - throw e; - } - } - } - } - FileContent fileContent = null; - for (ID indexId : myNotRequiringContentIndices) { - if (shouldIndexFile(file, indexId)) { - oldStuff = false; - try { - if (fileContent == null) { - fileContent = new FileContentImpl(file); - } - updateSingleIndex(indexId, file, fileContent); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - } - IndexingStamp.flushCache(); - - if (oldStuff && file instanceof NewVirtualFile) { - ((NewVirtualFile)file).setFlag(ALREADY_PROCESSED, true); - } - } - finally { - FileTypeManagerImpl.cacheFileType(file, null); - } - } - } - else { - if (myProgressIndicator != null) { - myProgressIndicator.setText("Scanning files to index"); - myProgressIndicator.setText2(file.getPresentableUrl()); - } - } - return true; - } - } - - private boolean shouldUpdateIndex(final VirtualFile file, final ID indexId) { - return getInputFilter(indexId).acceptInput(file) && - (isMock(file) || IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); - } - - private boolean shouldIndexFile(final VirtualFile file, final ID indexId) { - return getInputFilter(indexId).acceptInput(file) && - (isMock(file) || !IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); - } - - private boolean isUnderConfigOrSystem(@NotNull VirtualFile file) { - final String filePath = file.getPath(); - return myConfigPath != null && FileUtil.startsWith(filePath, myConfigPath) || - mySystemPath != null && FileUtil.startsWith(filePath, mySystemPath); - } - - private static boolean isMock(final VirtualFile file) { - return !(file instanceof NewVirtualFile); - } - - private boolean isTooLarge(@NotNull VirtualFile file) { - if (SingleRootFileViewProvider.isTooLarge(file)) { - final FileType type = file.getFileType(); - return !myNoLimitCheckTypes.contains(type); - } - return false; - } - - private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) { - if (SingleRootFileViewProvider.isTooLarge(file, contentSize)) { - final FileType type = file.getFileType(); - return !myNoLimitCheckTypes.contains(type); - } - return false; + @NonNls + @NotNull + public String getComponentName() { + return "FileBasedIndex"; } @NotNull - public CollectingContentIterator createContentIterator() { - ++myFilesModCount; - return new UnindexedFilesFinder(); - } + public abstract List getValues(@NotNull ID indexId, @NotNull K dataKey, @NotNull GlobalSearchScope filter); - public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { - myIndexableSets.add(set); - myIndexableSetToProjectMap.put(set, project); - } + @NotNull + public abstract Collection getContainingFiles(@NotNull ID indexId, + @NotNull K dataKey, + @NotNull GlobalSearchScope filter); - public void removeIndexableSet(@NotNull IndexableFileSet set) { - myChangedFilesCollector.forceUpdate(null, null, null, true); - myIndexableSets.remove(set); - myIndexableSetToProjectMap.remove(set); - } + public abstract boolean processValues(@NotNull ID indexId, + @NotNull K dataKey, + @Nullable VirtualFile inFile, + @NotNull FileBasedIndex.ValueProcessor processor, + @NotNull GlobalSearchScope filter); - @Nullable - private static PsiFile findLatestKnownPsiForUncomittedDocument(@NotNull Document doc, @NotNull Project project) { - return PsiDocumentManager.getInstance(project).getCachedPsiFile(doc); - } - - private static class IndexableFilesFilter implements InputFilter { - private final InputFilter myDelegate; + public abstract boolean processFilesContainingAllKeys(@NotNull ID indexId, + @NotNull Collection dataKeys, + @NotNull GlobalSearchScope filter, + @Nullable Condition valueChecker, + @NotNull Processor processor); - private IndexableFilesFilter(InputFilter delegate) { - myDelegate = delegate; - } + @NotNull + public abstract Collection getAllKeys(@NotNull ID indexId, @NotNull Project project); - @Override - public boolean acceptInput(final VirtualFile file) { - return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); - } - } + public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); - private static void cleanupProcessedFlag() { - final VirtualFile[] roots = ManagingFS.getInstance().getRoots(); - for (VirtualFile root : roots) { - cleanProcessedFlag(root); - } - } + protected abstract void ensureUpToDate(@NotNull ID indexId, + @Nullable Project project, + @Nullable GlobalSearchScope filter, + @Nullable VirtualFile restrictedFile); - private static void cleanProcessedFlag(@NotNull final VirtualFile file) { - if (!(file instanceof NewVirtualFile)) return; - - final NewVirtualFile nvf = (NewVirtualFile)file; - if (file.isDirectory()) { - for (VirtualFile child : nvf.getCachedChildren()) { - cleanProcessedFlag(child); - } - } - else { - nvf.setFlag(ALREADY_PROCESSED, false); - } - } + public abstract void requestRebuild(ID indexId, Throwable throwable); - public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { - if (project.isDisposed()) { - return; - } - final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - // iterate project content - projectFileIndex.iterateContent(processor); + public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); - if (project.isDisposed()) { - return; - } + public abstract void requestReindex(@NotNull VirtualFile file); - Set visitedRoots = new THashSet(); - for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { - //important not to depend on project here, to support per-project background reindex - // each client gives a project to FileBasedIndex - if (project.isDisposed()) { - return; - } - for (VirtualFile root : IndexableSetContributor.getRootsToIndex(provider)) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - for (VirtualFile root : IndexableSetContributor.getProjectRootsToIndex(provider, project)) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - } + public abstract void requestReindexExcluded(@NotNull VirtualFile file); - if (project.isDisposed()) { - return; - } - // iterate associated libraries - for (Module module : ModuleManager.getInstance(project).getModules()) { - if (module.isDisposed()) { - return; - } - OrderEntry[] orderEntries = ModuleRootManager.getInstance(module).getOrderEntries(); - for (OrderEntry orderEntry : orderEntries) { - if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { - if (orderEntry.isValid()) { - final VirtualFile[] libSources = orderEntry.getFiles(OrderRootType.SOURCES); - final VirtualFile[] libClasses = orderEntry.getFiles(OrderRootType.CLASSES); - for (VirtualFile[] roots : new VirtualFile[][]{libSources, libClasses}) { - for (VirtualFile root : roots) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - } - } - } - } - } - } + public abstract boolean getFilesWithKey(@NotNull ID indexId, + @NotNull Set dataKeys, + @NotNull Processor processor, + @NotNull GlobalSearchScope filter); - private static void iterateRecursively(@Nullable final VirtualFile root, @NotNull final ContentIterator processor, @Nullable ProgressIndicator indicator) { - if (root != null) { - if (indicator != null) { - indicator.checkCanceled(); - indicator.setText2(root.getPresentableUrl()); - } - - if (root.isDirectory()) { - for (VirtualFile file : root.getChildren()) { - if (file.isDirectory()) { - iterateRecursively(file, processor, indicator); - } - else { - processor.processFile(file); - } - } - } - else { - processor.processFile(root); - } - } - } - - private static class StorageGuard { - private int myHolds = 0; - - public interface Holder { - void leave(); - } - - private final Holder myTrueHolder = new Holder() { - @Override - public void leave() { - StorageGuard.this.leave(true); - } - }; - private final Holder myFalseHolder = new Holder() { - @Override - public void leave() { - StorageGuard.this.leave(false); - } - }; - - @NotNull - public synchronized Holder enter(boolean mode) { - if (mode) { - while (myHolds < 0) { - try { - wait(); - } - catch (InterruptedException ignored) { - } - } - myHolds++; - return myTrueHolder; - } - else { - while (myHolds > 0) { - try { - wait(); - } - catch (InterruptedException ignored) { - } - } - myHolds--; - return myFalseHolder; - } - } - - private synchronized void leave(boolean mode) { - myHolds += mode? -1 : 1; - if (myHolds == 0) { - notifyAll(); - } - } + public abstract boolean processAllKeys(@NotNull ID indexId, Processor processor, @Nullable Project project); + public interface ValueProcessor { + /** + * @param value a value to process + * @param file the file the value came from + * @return false if no further processing is needed, true otherwise + */ + boolean process(VirtualFile file, V value); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java new file mode 100644 index 000000000000..1cf3b2677d89 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -0,0 +1,2327 @@ +/* + * Copyright 2000-2012 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.util.indexing; + +import com.intellij.AppTopics; +import com.intellij.history.LocalHistory; +import com.intellij.ide.caches.CacheUpdater; +import com.intellij.lang.ASTNode; +import com.intellij.notification.NotificationDisplayType; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.application.ApplicationAdapter; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.impl.EditorHighlighterCache; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; +import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.*; +import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; +import com.intellij.openapi.project.*; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; +import com.intellij.openapi.vfs.newvfs.BulkFileListener; +import com.intellij.openapi.vfs.newvfs.ManagingFS; +import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.openapi.vfs.newvfs.events.VFileEvent; +import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon; +import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiDocumentTransactionListener; +import com.intellij.psi.impl.source.PsiFileImpl; +import com.intellij.psi.search.EverythingGlobalScope; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.stubs.SerializationManager; +import com.intellij.util.*; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ConcurrentHashSet; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.*; +import com.intellij.util.io.DataOutputStream; +import com.intellij.util.io.storage.HeavyProcessLatch; +import com.intellij.util.messages.MessageBus; +import com.intellij.util.messages.MessageBusConnection; +import gnu.trove.*; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.*; +import java.lang.ref.SoftReference; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Eugene Zhuravlev + * Date: Dec 20, 2007 + */ + +public class FileBasedIndexImpl extends FileBasedIndex { + private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.FileBasedIndexImpl"); + @NonNls + private static final String CORRUPTION_MARKER_NAME = "corruption.marker"; + private final Map, Pair, InputFilter>> myIndices = new THashMap, Pair, InputFilter>>(); + private final Map, Semaphore> myUnsavedDataIndexingSemaphores = new THashMap, Semaphore>(); + private final TObjectIntHashMap> myIndexIdToVersionMap = new TObjectIntHashMap>(); + private final Set> myNotRequiringContentIndices = new THashSet>(); + private final Set> myRequiringContentIndices = new THashSet>(); + private final Set myNoLimitCheckTypes = new THashSet(); + + private final PerIndexDocumentVersionMap myLastIndexedDocStamps = new PerIndexDocumentVersionMap(); + @NotNull private final ChangedFilesCollector myChangedFilesCollector; + + private final List myIndexableSets = ContainerUtil.createEmptyCOWList(); + private final Map myIndexableSetToProjectMap = new THashMap(); + + private static final int OK = 1; + private static final int REQUIRES_REBUILD = 2; + private static final int REBUILD_IN_PROGRESS = 3; + private static final Map, AtomicInteger> ourRebuildStatus = new THashMap, AtomicInteger>(); + + private final VirtualFileManagerEx myVfManager; + private final FileDocumentManager myFileDocumentManager; + private final FileTypeManager myFileTypeManager; + private final ConcurrentHashSet> myUpToDateIndices = new ConcurrentHashSet>(); + private final Map myTransactionMap = new THashMap(); + + private static final int ALREADY_PROCESSED = 0x04; + + @Nullable private final String myConfigPath; + @Nullable private final String mySystemPath; + private final boolean myIsUnitTestMode; + @Nullable private ScheduledFuture myFlushingFuture; + private volatile int myLocalModCount; + private volatile int myFilesModCount; + + @Override + public void requestReindex(@NotNull final VirtualFile file) { + myChangedFilesCollector.invalidateIndices(file, true); + } + + @Override + public void requestReindexExcluded(@NotNull final VirtualFile file) { + myChangedFilesCollector.invalidateIndices(file, false); + } + + public FileBasedIndexImpl(final VirtualFileManagerEx vfManager, + FileDocumentManager fdm, + FileTypeManager fileTypeManager, + @NotNull MessageBus bus, + SerializationManager sm + /*need this parameter to ensure component dependency*/) throws IOException { + myVfManager = vfManager; + myFileDocumentManager = fdm; + myFileTypeManager = fileTypeManager; + myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); + myConfigPath = calcConfigPath(PathManager.getConfigPath()); + mySystemPath = calcConfigPath(PathManager.getSystemPath()); + + final MessageBusConnection connection = bus.connect(); + connection.subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { + @Override + public void transactionStarted(final Document doc, final PsiFile file) { + if (file != null) { + synchronized (myTransactionMap) { + myTransactionMap.put(doc, file); + } + myUpToDateIndices.clear(); + } + } + + @Override + public void transactionCompleted(final Document doc, final PsiFile file) { + synchronized (myTransactionMap) { + myTransactionMap.remove(doc); + } + } + }); + + connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener() { + @Nullable private Map> myTypeToExtensionMap; + @Override + public void beforeFileTypesChanged(final FileTypeEvent event) { + cleanupProcessedFlag(); + myTypeToExtensionMap = new THashMap>(); + for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { + myTypeToExtensionMap.put(type, getExtensions(type)); + } + } + + @Override + public void fileTypesChanged(final FileTypeEvent event) { + final Map> oldExtensions = myTypeToExtensionMap; + myTypeToExtensionMap = null; + if (oldExtensions != null) { + final Map> newExtensions = new THashMap>(); + for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { + newExtensions.put(type, getExtensions(type)); + } + // we are interested only in extension changes or removals. + // addition of an extension is handled separately by RootsChanged event + if (!newExtensions.keySet().containsAll(oldExtensions.keySet())) { + rebuildAllIndices(); + return; + } + for (Map.Entry> entry : oldExtensions.entrySet()) { + FileType fileType = entry.getKey(); + Set strings = entry.getValue(); + if (!newExtensions.get(fileType).containsAll(strings)) { + rebuildAllIndices(); + return; + } + } + } + } + + @NotNull + private Set getExtensions(@NotNull FileType type) { + final Set set = new THashSet(); + for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { + set.add(matcher.getPresentableString()); + } + return set; + } + + private void rebuildAllIndices() { + for (ID indexId : myIndices.keySet()) { + try { + clearIndex(indexId); + } + catch (StorageException e) { + LOG.info(e); + } + } + scheduleIndexRebuild(true); + } + }); + + connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + @Override + public void before(@NotNull List events) { + for (VFileEvent event : events) { + final Object requestor = event.getRequestor(); + if (requestor instanceof FileDocumentManager || requestor instanceof PsiManager || requestor == LocalHistory.VFS_EVENT_REQUESTOR) { + cleanupMemoryStorage(); + break; + } + } + } + + @Override + public void after(@NotNull List events) { + } + }); + + connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { + @Override + public void fileContentReloaded(VirtualFile file, @NotNull Document document) { + cleanupMemoryStorage(); + } + + @Override + public void unsavedDocumentsDropped() { + cleanupMemoryStorage(); + } + }); + + ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { + @Override + public void writeActionStarted(Object action) { + myUpToDateIndices.clear(); + } + }); + + myChangedFilesCollector = new ChangedFilesCollector(); + + /* + final File workInProgressFile = getMarkerFile(); + if (workInProgressFile.exists()) { + // previous IDEA session was closed incorrectly, so drop all indices + FileUtil.delete(PathManager.getIndexRoot()); + } + */ + + try { + final FileBasedIndexExtension[] extensions = Extensions.getExtensions(FileBasedIndexExtension.EXTENSION_POINT_NAME); + for (FileBasedIndexExtension extension : extensions) { + ourRebuildStatus.put(extension.getName(), new AtomicInteger(OK)); + } + + final File corruptionMarker = new File(PathManager.getIndexRoot(), CORRUPTION_MARKER_NAME); + final boolean currentVersionCorrupted = corruptionMarker.exists(); + boolean versionChanged = false; + for (FileBasedIndexExtension extension : extensions) { + versionChanged |= registerIndexer(extension, currentVersionCorrupted); + } + FileUtil.delete(corruptionMarker); + + String rebuildNotification = null; + if (currentVersionCorrupted) { + rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; + } + else if (versionChanged) { + rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; + } + if (rebuildNotification != null + && !ApplicationManager.getApplication().isHeadlessEnvironment() + && Registry.is("ide.showIndexRebuildMessage")) { + new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) + .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); + } + + dropUnregisteredIndices(); + + // check if rebuild was requested for any index during registration + for (ID indexId : myIndices.keySet()) { + if (ourRebuildStatus.get(indexId).compareAndSet(REQUIRES_REBUILD, OK)) { + try { + clearIndex(indexId); + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.error(e); + } + } + } + + myVfManager.addVirtualFileListener(myChangedFilesCollector); + + registerIndexableSet(new AdditionalIndexableFileSet(), null); + } + finally { + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + @Override + public void run() { + performShutdown(); + } + }); + //FileUtil.createIfDoesntExist(workInProgressFile); + saveRegisteredIndices(myIndices.keySet()); + myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() { + int lastModCount = 0; + @Override + public void run() { + if (lastModCount == myLocalModCount) { + flushAllIndices(lastModCount); + } + lastModCount = myLocalModCount; + } + }); + + } + } + + @Override + public void initComponent() { + } + + @Nullable + private static String calcConfigPath(final String path) { + try { + final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()); + return _path.endsWith("/")? _path : _path + "/" ; + } + catch (IOException e) { + LOG.info(e); + return null; + } + } + + /** + * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted + * + * @param extension + * @param isCurrentVersionCorrupted + */ + private boolean registerIndexer(@NotNull final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) throws IOException { + final ID name = extension.getName(); + final int version = extension.getVersion(); + final File versionFile = IndexInfrastructure.getVersionFile(name); + final boolean versionFileExisted = versionFile.exists(); + boolean versionChanged = false; + if (isCurrentVersionCorrupted || IndexInfrastructure.versionDiffers(versionFile, version)) { + if (!isCurrentVersionCorrupted && versionFileExisted) { + versionChanged = true; + LOG.info("Version has changed for index " + name + ". The index will be rebuilt."); + } + FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + IndexInfrastructure.rewriteVersion(versionFile, version); + } + + for (int attempt = 0; attempt < 2; attempt++) { + try { + final MapIndexStorage storage = new MapIndexStorage(IndexInfrastructure.getStorageFile(name), extension.getKeyDescriptor(), extension.getValueExternalizer(), extension.getCacheSize()); + final MemoryIndexStorage memStorage = new MemoryIndexStorage(storage); + final UpdatableIndex index = createIndex(name, extension, memStorage); + final InputFilter inputFilter = extension.getInputFilter(); + + assert inputFilter != null : "Index extension " + name + " must provide non-null input filter"; + + myIndices.put(name, new Pair, InputFilter>(index, new IndexableFilesFilter(inputFilter))); + myUnsavedDataIndexingSemaphores.put(name, new Semaphore()); + myIndexIdToVersionMap.put(name, version); + if (!extension.dependsOnFileContent()) { + myNotRequiringContentIndices.add(name); + } + else { + myRequiringContentIndices.add(name); + } + myNoLimitCheckTypes.addAll(extension.getFileTypesWithSizeLimitNotApplicable()); + break; + } + catch (IOException e) { + LOG.info(e); + FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + IndexInfrastructure.rewriteVersion(versionFile, version); + } + } + return versionChanged; + } + + private static void saveRegisteredIndices(@NotNull Collection> ids) { + final File file = getRegisteredIndicesFile(); + try { + FileUtil.createIfDoesntExist(file); + final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); + try { + os.writeInt(ids.size()); + for (ID id : ids) { + IOUtil.writeString(id.toString(), os); + } + } + finally { + os.close(); + } + } + catch (IOException ignored) { + } + } + + @NotNull + private static Set readRegisteredIndexNames() { + final Set result = new THashSet(); + try { + final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); + try { + final int size = in.readInt(); + for (int idx = 0; idx < size; idx++) { + result.add(IOUtil.readString(in)); + } + } + finally { + in.close(); + } + } + catch (IOException ignored) { + } + return result; + } + + @NotNull + private static File getRegisteredIndicesFile() { + return new File(PathManager.getIndexRoot(), "registered"); + } + + @NotNull + private UpdatableIndex createIndex(@NotNull final ID indexId, @NotNull final FileBasedIndexExtension extension, @NotNull final MemoryIndexStorage storage) throws IOException { + final MapReduceIndex index; + if (extension instanceof CustomImplementationFileBasedIndexExtension) { + final UpdatableIndex custom = ((CustomImplementationFileBasedIndexExtension)extension).createIndexImplementation(indexId, this, storage); + + assert custom != null : "Custom index implementation must not be null; index: " + indexId; + + if (!(custom instanceof MapReduceIndex)) { + return custom; + } + index = (MapReduceIndex)custom; + } + else { + index = new MapReduceIndex(indexId, extension.getIndexer(), storage); + } + + final KeyDescriptor keyDescriptor = extension.getKeyDescriptor(); + index.setInputIdToDataKeysIndex(new Factory>>() { + @Override + public PersistentHashMap> create() { + try { + return createIdToDataKeysIndex(indexId, keyDescriptor, storage); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }); + + return index; + } + + @NotNull + private static PersistentHashMap> createIdToDataKeysIndex(@NotNull final ID indexId, + @NotNull final KeyDescriptor keyDescriptor, + @NotNull MemoryIndexStorage storage) throws IOException { + final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); + final Ref isBufferingMode = new Ref(false); + final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); + + final DataExternalizer> dataExternalizer = new DataExternalizer>() { + @Override + public void save(DataOutput out, @NotNull Collection value) throws IOException { + try { + DataInputOutputUtil.writeINT(out, value.size()); + for (K key : value) { + keyDescriptor.save(out, key); + } + } + catch (IllegalArgumentException e) { + throw new IOException("Error saving data for index " + indexId, e); + } + } + + @NotNull + @Override + public Collection read(DataInput in) throws IOException { + try { + final int size = DataInputOutputUtil.readINT(in); + final List list = new ArrayList(size); + for (int idx = 0; idx < size; idx++) { + list.add(keyDescriptor.read(in)); + } + return list; + } + catch (IllegalArgumentException e) { + throw new IOException("Error reading data for index " + indexId, e); + } + } + }; + + // Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage. + // If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage). + // Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the + // wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be + // cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects. + + final PersistentHashMap> map = new PersistentHashMap>( + indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, dataExternalizer + ) { + + @Override + protected Collection doGet(Integer integer) throws IOException { + if (isBufferingMode.get()) { + final Collection collection = tempMap.get(integer); + if (collection != null) { + return collection; + } + } + return super.doGet(integer); + } + + @Override + protected void doPut(Integer integer, @Nullable Collection ks) throws IOException { + if (isBufferingMode.get()) { + tempMap.put(integer, ks == null? Collections.emptySet() : ks); + } + else { + super.doPut(integer, ks); + } + } + + @Override + protected void doRemove(Integer integer) throws IOException { + if (isBufferingMode.get()) { + tempMap.put(integer, Collections.emptySet()); + } + else { + super.doRemove(integer); + } + } + }; + + storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { + @Override + public void bufferingStateChanged(boolean newState) { + synchronized (map) { + isBufferingMode.set(newState); + } + } + @Override + public void memoryStorageCleared() { + synchronized (map) { + tempMap.clear(); + } + } + }); + return map; + } + + @Override + public void disposeComponent() { + performShutdown(); + } + + private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false); + + private void performShutdown() { + if (!myShutdownPerformed.compareAndSet(false, true)) { + return; // already shut down + } + try { + if (myFlushingFuture != null) { + myFlushingFuture.cancel(false); + myFlushingFuture = null; + } + + myFileDocumentManager.saveAllDocuments(); + } + finally { + LOG.info("START INDEX SHUTDOWN"); + try { + myChangedFilesCollector.forceUpdate(null, null, null, true); + + for (ID indexId : myIndices.keySet()) { + final UpdatableIndex index = getIndex(indexId); + assert index != null; + checkRebuild(indexId, true); // if the index was scheduled for rebuild, only clean it + //LOG.info("DISPOSING " + indexId); + index.dispose(); + } + + myVfManager.removeVirtualFileListener(myChangedFilesCollector); + + //FileUtil.delete(getMarkerFile()); + } + catch (Throwable e) { + LOG.info("Problems during index shutdown", e); + throw new RuntimeException(e); + } + LOG.info("END INDEX SHUTDOWN"); + } + } + + private void flushAllIndices(final long modCount) { + if (HeavyProcessLatch.INSTANCE.isRunning()) { + return; + } + IndexingStamp.flushCache(); + for (ID indexId : new ArrayList>(myIndices.keySet())) { + if (HeavyProcessLatch.INSTANCE.isRunning() || modCount != myLocalModCount) { + return; // do not interfere with 'main' jobs + } + try { + final UpdatableIndex index = getIndex(indexId); + if (index != null) { + index.flush(); + } + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + + if (!HeavyProcessLatch.INSTANCE.isRunning() && modCount == myLocalModCount) { // do not interfere with 'main' jobs + SerializationManager.getInstance().flushNameStorage(); + } + } + + /** + * @param project it is guaranteed to return data which is up-to-date withing the project + * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist + */ + @Override + @NotNull + public Collection getAllKeys(@NotNull final ID indexId, @NotNull Project project) { + Set allKeys = new THashSet(); + processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); + return allKeys; + } + + /** + * @param project it is guaranteed to return data which is up-to-date withing the project + * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist + */ + @Override + public boolean processAllKeys(@NotNull final ID indexId, Processor processor, @Nullable Project project) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return true; + } + ensureUpToDate(indexId, project, project != null? GlobalSearchScope.allScope(project) : new EverythingGlobalScope()); + return index.processAllKeys(processor); + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + + return false; + } + + private static final ThreadLocal myUpToDateCheckState = new ThreadLocal(); + + public static void disableUpToDateCheckForCurrentThread() { + final Integer currentValue = myUpToDateCheckState.get(); + myUpToDateCheckState.set(currentValue == null? 1 : currentValue.intValue() + 1); + } + + public static void enableUpToDateCheckForCurrentThread() { + final Integer currentValue = myUpToDateCheckState.get(); + if (currentValue != null) { + final int newValue = currentValue.intValue() - 1; + if (newValue != 0) { + myUpToDateCheckState.set(newValue); + } + else { + myUpToDateCheckState.remove(); + } + } + } + + private static boolean isUpToDateCheckEnabled() { + final Integer value = myUpToDateCheckState.get(); + return value == null || value.intValue() == 0; + } + + + private final ThreadLocal myReentrancyGuard = new ThreadLocal() { + @Override + protected Boolean initialValue() { + return Boolean.FALSE; + } + }; + + /** + * DO NOT CALL DIRECTLY IN CLIENT CODE + * The method is internal to indexing engine end is called internally. The method is public due to implementation details + */ + @Override + public void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter) { + ensureUpToDate(indexId, project, filter, null); + } + + @Override + protected void ensureUpToDate(@NotNull final ID indexId, + @Nullable Project project, + @Nullable GlobalSearchScope filter, + @Nullable VirtualFile restrictedFile) { + if (!needsFileContentLoading(indexId)) { + return; //indexed eagerly in foreground while building unindexed file list + } + if (isDumb(project)) { + handleDumbMode(project); + } + + if (myReentrancyGuard.get().booleanValue()) { + //assert false : "ensureUpToDate() is not reentrant!"; + return; + } + myReentrancyGuard.set(Boolean.TRUE); + + try { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + if (isUpToDateCheckEnabled()) { + try { + checkRebuild(indexId, false); + myChangedFilesCollector.forceUpdate(project, filter, restrictedFile, false); + indexUnsavedDocuments(indexId, project, filter, restrictedFile); + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, e); + } + else { + throw e; + } + } + } + } + finally { + myReentrancyGuard.set(Boolean.FALSE); + } + } + + private static void handleDumbMode(@Nullable Project project) { + ProgressManager.checkCanceled(); // DumbModeAction.CANCEL + + if (project != null) { + final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); + if (progressIndicator instanceof BackgroundableProcessIndicator) { + final BackgroundableProcessIndicator indicator = (BackgroundableProcessIndicator)progressIndicator; + if (indicator.getDumbModeAction() == DumbModeAction.WAIT) { + assert !ApplicationManager.getApplication().isDispatchThread(); + DumbService.getInstance(project).waitForSmartMode(); + return; + } + } + } + + throw new IndexNotReadyException(); + } + + private static boolean isDumb(@Nullable Project project) { + if (project != null) { + return DumbServiceImpl.getInstance(project).isDumb(); + } + for (Project proj : ProjectManager.getInstance().getOpenProjects()) { + if (DumbServiceImpl.getInstance(proj).isDumb()) { + return true; + } + } + return false; + } + + @Override + @NotNull + public List getValues(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { + final List values = new SmartList(); + processValuesImpl(indexId, dataKey, true, null, new ValueProcessor() { + @Override + public boolean process(final VirtualFile file, final V value) { + values.add(value); + return true; + } + }, filter); + return values; + } + + @Override + @NotNull + public Collection getContainingFiles(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { + final Set files = new THashSet(); + processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { + @Override + public boolean process(final VirtualFile file, final V value) { + files.add(file); + return true; + } + }, filter); + return files; + } + + + /** + * @return false if ValueProcessor.process() returned false; true otherwise or if ValueProcessor was not called at all + */ + @Override + public boolean processValues(@NotNull final ID indexId, @NotNull final K dataKey, @Nullable final VirtualFile inFile, + @NotNull ValueProcessor processor, @NotNull final GlobalSearchScope filter) { + return processValuesImpl(indexId, dataKey, false, inFile, processor, filter); + } + + + + + @Nullable + private R processExceptions(@NotNull final ID indexId, + @Nullable final VirtualFile restrictToFile, + @NotNull final GlobalSearchScope filter, + @NotNull ThrowableConvertor, R, StorageException> computable) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return null; + } + final Project project = filter.getProject(); + //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; + ensureUpToDate(indexId, project, filter, restrictToFile); + + try { + index.getReadLock().lock(); + return computable.convert(index); + } + finally { + index.getReadLock().unlock(); + } + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = getCauseToRebuildIndex(e); + if (cause != null) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + return null; + } + + private boolean processValuesImpl(@NotNull final ID indexId, final K dataKey, final boolean ensureValueProcessedOnce, + @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, + @NotNull final GlobalSearchScope filter) { + ThrowableConvertor, Boolean, StorageException> keyProcessor = new ThrowableConvertor, Boolean, StorageException>() { + @Override + public Boolean convert(@NotNull UpdatableIndex index) throws StorageException { + final ValueContainer container = index.getData(dataKey); + + boolean shouldContinue = true; + + if (restrictToFile != null) { + if (restrictToFile instanceof VirtualFileWithId) { + final int restrictedFileId = getFileId(restrictToFile); + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + final V value = valueIt.next(); + if (container.isAssociated(value, restrictedFileId)) { + shouldContinue = processor.process(restrictToFile, value); + if (!shouldContinue) { + break; + } + } + } + } + } + else { + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + ProjectIndexableFilesFilter projectFilesSet = projectIndexableFiles(filter.getProject()); + VALUES_LOOP: for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { + final V value = valueIt.next(); + for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { + final int id = inputIdsIterator.next(); + if (projectFilesSet != null && !projectFilesSet.contains(id)) continue; + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + shouldContinue = processor.process(file, value); + if (!shouldContinue) { + break VALUES_LOOP; + } + if (ensureValueProcessedOnce) { + break; // continue with the next value + } + } + } + } + } + return shouldContinue; + } + }; + final Boolean result = processExceptions(indexId, restrictToFile, filter, keyProcessor); + return result == null || result.booleanValue(); + } + + @Override + public boolean processFilesContainingAllKeys(@NotNull final ID indexId, + @NotNull final Collection dataKeys, + @NotNull final GlobalSearchScope filter, + @Nullable Condition valueChecker, + @NotNull final Processor processor) { + ProjectIndexableFilesFilter filesSet = projectIndexableFiles(filter.getProject()); + final TIntHashSet set = collectFileIdsContainingAllKeys(indexId, dataKeys, filter, valueChecker, filesSet); + return set != null && processVirtualFiles(set, filter, processor); + } + + private static final Key> ourProjectFilesSetKey = Key.create("projectFiles"); + + public static final class ProjectIndexableFilesFilter { + private static final int SHIFT = 6; + private static final int MASK = (1 << SHIFT) - 1; + private final long[] myBitMask; + private final int myModificationCount; + private final int myMinId; + private final int myMaxId; + + private ProjectIndexableFilesFilter(@NotNull TIntHashSet set, int modificationCount) { + myModificationCount = modificationCount; + final int[] minMax = new int[2]; + if (set.size() > 0) { + minMax[0] = minMax[1] = set.iterator().next(); + } + set.forEach(new TIntProcedure() { + @Override + public boolean execute(int value) { + minMax[0] = Math.min(minMax[0], value); + minMax[1] = Math.max(minMax[1], value); + return true; + } + }); + myMaxId = minMax[1]; + myMinId = minMax[0]; + myBitMask = new long[((myMaxId - myMinId) >> SHIFT) + 1]; + set.forEach(new TIntProcedure() { + @Override + public boolean execute(int value) { + value = value - myMinId; + myBitMask[value >> SHIFT] |= (1L << (value & MASK)); + return true; + } + }); + } + + public boolean contains(int id) { + if (id < myMinId) return false; + if (id > myMaxId) return false; + id -= myMinId; + return (myBitMask[id >> SHIFT] & (1L << (id & MASK))) != 0; + } + } + + @Nullable + public ProjectIndexableFilesFilter projectIndexableFiles(@Nullable Project project) { + if (project == null) return null; + + SoftReference reference = project.getUserData(ourProjectFilesSetKey); + ProjectIndexableFilesFilter data = reference != null ? reference.get() : null; + if (data != null && data.myModificationCount == myFilesModCount) return data; + + final TIntHashSet filesSet = new TIntHashSet(); + iterateIndexableFiles(new ContentIterator() { + @Override + public boolean processFile(@NotNull VirtualFile fileOrDir) { + filesSet.add(((VirtualFileWithId)fileOrDir).getId()); + return true; + } + }, project, ProgressManager.getInstance().getProgressIndicator()); + ProjectIndexableFilesFilter files = new ProjectIndexableFilesFilter(filesSet, myFilesModCount); + project.putUserData(ourProjectFilesSetKey, new SoftReference(files)); + return files; + } + + @Nullable + private TIntHashSet collectFileIdsContainingAllKeys(@NotNull final ID indexId, + @NotNull final Collection dataKeys, + @NotNull final GlobalSearchScope filter, + @Nullable final Condition valueChecker, + @Nullable final ProjectIndexableFilesFilter projectFilesFilter) { + final ThrowableConvertor, TIntHashSet, StorageException> convertor = + new ThrowableConvertor, TIntHashSet, StorageException>() { + @Nullable + @Override + public TIntHashSet convert(@NotNull UpdatableIndex index) throws StorageException { + TIntHashSet mainIntersection = null; + + for (K dataKey : dataKeys) { + ProgressManager.checkCanceled(); + final TIntHashSet copy = new TIntHashSet(); + final ValueContainer container = index.getData(dataKey); + + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + final V value = valueIt.next(); + if (valueChecker != null && !valueChecker.value(value)) { + continue; + } + + ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); + + if (mainIntersection == null || iterator.size() < mainIntersection.size()) { + for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { + final int id = inputIdsIterator.next(); + if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || + mainIntersection != null && mainIntersection.contains(id) + ) { + copy.add(id); + } + } + } else { + mainIntersection.forEach(new TIntProcedure() { + final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); + @Override + public boolean execute(int id) { + if (predicate.contains(id)) copy.add(id); + return true; + } + }); + } + } + + mainIntersection = copy; + if (mainIntersection.isEmpty()) { + return new TIntHashSet(); + } + } + + return mainIntersection; + } + }; + + + return processExceptions(indexId, null, filter, convertor); + } + + private static boolean processVirtualFiles(@NotNull TIntHashSet ids, + @NotNull final GlobalSearchScope filter, + @NotNull final Processor processor) { + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + return ids.forEach(new TIntProcedure() { + @Override + public boolean execute(int id) { + ProgressManager.checkCanceled(); + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + return processor.process(file); + } + return true; + } + }); + } + + @Nullable + public static Throwable getCauseToRebuildIndex(@NotNull RuntimeException e) { + Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException || + cause instanceof IllegalArgumentException) return cause; + return null; + } + + @Override + public boolean getFilesWithKey(@NotNull final ID indexId, + @NotNull final Set dataKeys, + @NotNull Processor processor, + @NotNull GlobalSearchScope filter) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return true; + } + final Project project = filter.getProject(); + //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; + ensureUpToDate(indexId, project, filter); + + try { + index.getReadLock().lock(); + final List locals = new ArrayList(); + for (K dataKey : dataKeys) { + TIntHashSet local = new TIntHashSet(); + locals.add(local); + final ValueContainer container = index.getData(dataKey); + + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { + final V value = valueIt.next(); + for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { + final int id = inputIdsIterator.next(); + local.add(id); + } + } + } + + if (locals.isEmpty()) { + return true; + } + + Collections.sort(locals, new Comparator() { + @Override + public int compare(TIntHashSet o1, TIntHashSet o2) { + return o1.size() - o2.size(); + } + }); + + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + TIntIterator ids = join(locals).iterator(); + ProjectIndexableFilesFilter projectIndexableFilesFilter = projectIndexableFiles(project); + while (ids.hasNext()) { + int id = ids.next(); + if (projectIndexableFilesFilter != null && !projectIndexableFilesFilter.contains(id)) continue; + //VirtualFile file = IndexInfrastructure.findFileById(fs, id); + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + if (!processor.process(file)) { + return false; + } + } + } + } + finally { + index.getReadLock().unlock(); + } + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + return true; + } + + @NotNull + private static TIntHashSet join(@NotNull List locals) { + TIntHashSet result = locals.get(0); + if (locals.size() > 1) { + TIntIterator it = result.iterator(); + + while (it.hasNext()) { + int id = it.next(); + for (int i = 1; i < locals.size(); i++) { + if (!locals.get(i).contains(id)) { + it.remove(); + break; + } + } + } + } + return result; + } + + @Override + public void scheduleRebuild(@NotNull final ID indexId, @NotNull final Throwable e) { + LOG.info(e); + requestRebuild(indexId); + try { + checkRebuild(indexId, false); + } + catch (ProcessCanceledException ignored) { + } + } + + private void checkRebuild(@NotNull final ID indexId, final boolean cleanupOnly) { + final AtomicInteger status = ourRebuildStatus.get(indexId); + if (status.get() == OK) return; + if (status.compareAndSet(REQUIRES_REBUILD, REBUILD_IN_PROGRESS)) { + cleanupProcessedFlag(); + + final Runnable rebuildRunnable = new Runnable() { + @Override + public void run() { + try { + clearIndex(indexId); + if (!cleanupOnly) { + scheduleIndexRebuild(false); + } + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.info(e); + } + finally { + status.compareAndSet(REBUILD_IN_PROGRESS, OK); + } + } + }; + + if (cleanupOnly || myIsUnitTestMode) { + rebuildRunnable.run(); + } + else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new Task.Modal(null, "Updating index", false) { + @Override + public void run(@NotNull final ProgressIndicator indicator) { + indicator.setIndeterminate(true); + rebuildRunnable.run(); + } + }.queue(); + } + }); + } + } + + if (status.get() == REBUILD_IN_PROGRESS) { + throw new ProcessCanceledException(); + } + } + + private void scheduleIndexRebuild(boolean forceDumbMode) { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + final Set updatersToRun = Collections.singleton(new UnindexedFilesUpdater(project, this)); + final DumbServiceImpl service = DumbServiceImpl.getInstance(project); + if (forceDumbMode) { + service.queueCacheUpdateInDumbMode(updatersToRun); + } + else { + service.queueCacheUpdate(updatersToRun); + } + } + } + + private void clearIndex(@NotNull final ID indexId) throws StorageException { + final UpdatableIndex index = getIndex(indexId); + assert index != null: "Index with key " + indexId + " not found or not registered properly"; + index.clear(); + try { + IndexInfrastructure.rewriteVersion(IndexInfrastructure.getVersionFile(indexId), myIndexIdToVersionMap.get(indexId)); + } + catch (IOException e) { + LOG.error(e); + } + } + + @NotNull + private Set getUnsavedOrTransactedDocuments() { + final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); + synchronized (myTransactionMap) { + docs.addAll(myTransactionMap.keySet()); + } + return docs; + } + + private void indexUnsavedDocuments(@NotNull ID indexId, + @Nullable Project project, + GlobalSearchScope filter, + VirtualFile restrictedFile) throws StorageException { + if (myUpToDateIndices.contains(indexId)) { + return; // no need to index unsaved docs + } + + final Set documents = getUnsavedOrTransactedDocuments(); + if (!documents.isEmpty()) { + // now index unsaved data + final StorageGuard.Holder guard = setDataBufferingEnabled(true); + try { + final Semaphore semaphore = myUnsavedDataIndexingSemaphores.get(indexId); + + assert semaphore != null : "Semaphore for unsaved data indexing was not initialized for index " + indexId; + + semaphore.down(); + boolean allDocsProcessed = true; + try { + for (Document document : documents) { + allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); + } + } + finally { + semaphore.up(); + + while (!semaphore.waitFor(500)) { // may need to wait until another thread is done with indexing + if (Thread.holdsLock(PsiLock.LOCK)) { + break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. + } + } + if (allDocsProcessed && !hasActiveTransactions()) { + myUpToDateIndices.add(indexId); // safe to set the flag here, because it will be cleared under the WriteAction + } + } + } + finally { + guard.leave(); + } + } + } + + private boolean hasActiveTransactions() { + synchronized (myTransactionMap) { + return !myTransactionMap.isEmpty(); + } + } + + private interface DocumentContent { + String getText(); + long getModificationStamp(); + } + + private static class AuthenticContent implements DocumentContent { + private final Document myDocument; + + private AuthenticContent(final Document document) { + myDocument = document; + } + + @Override + public String getText() { + return myDocument.getText(); + } + + @Override + public long getModificationStamp() { + return myDocument.getModificationStamp(); + } + } + + private static class PsiContent implements DocumentContent { + private final Document myDocument; + private final PsiFile myFile; + + private PsiContent(final Document document, final PsiFile file) { + myDocument = document; + myFile = file; + } + + @Override + public String getText() { + if (myFile.getModificationStamp() != myDocument.getModificationStamp()) { + final ASTNode node = myFile.getNode(); + assert node != null; + return node.getText(); + } + return myDocument.getText(); + } + + @Override + public long getModificationStamp() { + return myFile.getModificationStamp(); + } + } + +// returns false if doc was not indexed because the file does not fit in scope + private boolean indexUnsavedDocument(@NotNull final Document document, @NotNull final ID requestedIndexId, final Project project, + @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedFile) throws StorageException { + final VirtualFile vFile = myFileDocumentManager.getFile(document); + if (!(vFile instanceof VirtualFileWithId) || !vFile.isValid()) { + return true; + } + + if (restrictedFile != null) { + if(vFile != restrictedFile) { + return false; + } + } + else if (filter != null && !filter.accept(vFile)) { + return false; + } + + final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); + + final DocumentContent content; + if (dominantContentFile != null && dominantContentFile.getModificationStamp() != document.getModificationStamp()) { + content = new PsiContent(document, dominantContentFile); + } + else { + content = new AuthenticContent(document); + } + + final long currentDocStamp = content.getModificationStamp(); + if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp)) { + final Ref exRef = new Ref(null); + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + @Override + public void run() { + try { + final String contentText = content.getText(); + if (isTooLarge(vFile, contentText.length())) { + return; + } + + final FileContentImpl newFc = new FileContentImpl(vFile, contentText, vFile.getCharset()); + + if (dominantContentFile != null) { + dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, true); + newFc.putUserData(IndexingDataKeys.PSI_FILE, dominantContentFile); + } + + if (content instanceof AuthenticContent) { + newFc.putUserData(EDITOR_HIGHLIGHTER, EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)); + } + + if (getInputFilter(requestedIndexId).acceptInput(vFile)) { + newFc.putUserData(IndexingDataKeys.PROJECT, project); + final int inputId = Math.abs(getFileId(vFile)); + getIndex(requestedIndexId).update(inputId, newFc); + } + + if (dominantContentFile != null) { + dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, null); + } + } + catch (StorageException e) { + exRef.set(e); + } + } + }); + final StorageException storageException = exRef.get(); + if (storageException != null) { + throw storageException; + } + } + return true; + } + + public static final Key EDITOR_HIGHLIGHTER = new Key("Editor"); + + @Nullable + private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { + synchronized (myTransactionMap) { + PsiFile psiFile = myTransactionMap.get(document); + if (psiFile != null) return psiFile; + } + + return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); + } + + private final StorageGuard myStorageLock = new StorageGuard(); + + @NotNull + private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) { + final StorageGuard.Holder holder = myStorageLock.enter(enabled); + for (ID indexId : myIndices.keySet()) { + final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); + assert index != null; + final IndexStorage indexStorage = index.getStorage(); + ((MemoryIndexStorage)indexStorage).setBufferingEnabled(enabled); + } + return holder; + } + + private void cleanupMemoryStorage() { + myLastIndexedDocStamps.clear(); + for (ID indexId : myIndices.keySet()) { + final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); + assert index != null; + final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage(); + index.getWriteLock().lock(); + try { + memStorage.clearMemoryMap(); + } + finally { + index.getWriteLock().unlock(); + } + memStorage.fireMemoryStorageCleared(); + } + } + + private void dropUnregisteredIndices() { + final Set indicesToDrop = readRegisteredIndexNames(); + for (ID key : myIndices.keySet()) { + indicesToDrop.remove(key.toString()); + } + for (String s : indicesToDrop) { + FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); + } + } + + @Override + public void requestRebuild(ID indexId, Throwable throwable) { + cleanupProcessedFlag(); + LOG.info("Rebuild requested for index " + indexId, throwable); + ourRebuildStatus.get(indexId).set(REQUIRES_REBUILD); + } + + private UpdatableIndex getIndex(ID indexId) { + final Pair, InputFilter> pair = myIndices.get(indexId); + + assert pair != null : "Index data is absent for index " + indexId; + + //noinspection unchecked + return (UpdatableIndex)pair.getFirst(); + } + + private InputFilter getInputFilter(ID indexId) { + final Pair, InputFilter> pair = myIndices.get(indexId); + + assert pair != null : "Index data is absent for index " + indexId; + + return pair.getSecond(); + } + + public int getNumberOfPendingInvalidations() { + return myChangedFilesCollector.getNumberOfPendingInvalidations(); + } + + @NotNull + public Collection getFilesToUpdate(final Project project) { + return ContainerUtil.findAll(myChangedFilesCollector.getAllFilesToUpdate(), new Condition() { + @Override + public boolean value(VirtualFile virtualFile) { + for (IndexableFileSet set : myIndexableSets) { + final Project proj = myIndexableSetToProjectMap.get(set); + if (proj != null && !proj.equals(project)) { + continue; // skip this set as associated with a different project + } + if (set.isInSet(virtualFile)) { + return true; + } + } + return false; + } + }); + } + + public void processRefreshedFile(@NotNull Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + myChangedFilesCollector.processFileImpl(project, fileContent, false); + } + + public void indexFileContent(@Nullable Project project, @NotNull com.intellij.ide.caches.FileContent content) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + final VirtualFile file = content.getVirtualFile(); + FileContentImpl fc = null; + + PsiFile psiFile = null; + + FileTypeManagerImpl.cacheFileType(file, file.getFileType()); + try { + for (final ID indexId : myIndices.keySet()) { + if (shouldIndexFile(file, indexId)) { + if (fc == null) { + byte[] currentBytes; + try { + currentBytes = content.getBytes(); + } + catch (IOException e) { + currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY; + } + fc = new FileContentImpl(file, currentBytes); + + psiFile = content.getUserData(IndexingDataKeys.PSI_FILE); + if (psiFile != null) { + psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true); + fc.putUserData(IndexingDataKeys.PSI_FILE, psiFile); + } + if (project == null) { + project = ProjectUtil.guessProjectForFile(file); + } + fc.putUserData(IndexingDataKeys.PROJECT, project); + } + + try { + ProgressManager.checkCanceled(); + updateSingleIndex(indexId, file, fc); + } + catch (ProcessCanceledException e) { + myChangedFilesCollector.scheduleForUpdate(file); + throw e; + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.info(e); + } + } + } + + if (psiFile != null) { + psiFile.putUserData(PsiFileImpl.BUILDING_STUB, null); + } + } finally { + FileTypeManagerImpl.cacheFileType(file, null); + } + } + + private void updateSingleIndex(final ID indexId, @NotNull final VirtualFile file, @Nullable final FileContent currentFC) + throws StorageException { + if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { + return; // the index is scheduled for rebuild, no need to update + } + myLocalModCount++; + + final StorageGuard.Holder lock = setDataBufferingEnabled(false); + + try { + final int inputId = Math.abs(getFileId(file)); + + final UpdatableIndex index = getIndex(indexId); + assert index != null; + + final Ref exRef = new Ref(null); + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + @Override + public void run() { + try { + index.update(inputId, currentFC); + } + catch (StorageException e) { + exRef.set(e); + } + } + }); + final StorageException storageException = exRef.get(); + if (storageException != null) { + throw storageException; + } + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (file.isValid()) { + if (currentFC != null) { + IndexingStamp.update(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); + } + else { + // mark the file as unindexed + IndexingStamp.update(file, indexId, -1L); + } + } + } + }); + } + finally { + lock.leave(); + } + } + + private boolean needsFileContentLoading(ID indexId) { + return !myNotRequiringContentIndices.contains(indexId); + } + + private abstract static class InvalidationTask implements Runnable { + private final VirtualFile mySubj; + + protected InvalidationTask(final VirtualFile subj) { + mySubj = subj; + } + + public VirtualFile getSubj() { + return mySubj; + } + } + + private final class ChangedFilesCollector extends VirtualFileAdapter { + private final Set myFilesToUpdate = new ConcurrentHashSet(); + private final Queue myFutureInvalidations = new ConcurrentLinkedQueue(); + + private final ManagingFS myManagingFS = ManagingFS.getInstance(); + // No need to react on movement events since files stay valid, their ids don't change and all associated attributes remain intact. + + @Override + public void fileCreated(@NotNull final VirtualFileEvent event) { + markDirty(event, false); + } + + @Override + public void fileDeleted(@NotNull final VirtualFileEvent event) { + myFilesToUpdate.remove(event.getFile()); // no need to update it anymore + } + + @Override + public void fileCopied(@NotNull final VirtualFileCopyEvent event) { + markDirty(event, false); + } + + @Override + public void beforeFileDeletion(@NotNull final VirtualFileEvent event) { + invalidateIndices(event.getFile(), false); + } + + @Override + public void beforeContentsChange(@NotNull final VirtualFileEvent event) { + invalidateIndices(event.getFile(), true); + } + + @Override + public void contentsChanged(@NotNull final VirtualFileEvent event) { + markDirty(event, true); + } + + @Override + public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { + if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { + // indexes may depend on file name + final VirtualFile file = event.getFile(); + if (!file.isDirectory()) { + // name change may lead to filetype change so the file might become not indexable + // in general case have to 'unindex' the file and index it again if needed after the name has been changed + invalidateIndices(file, false); + } + } + } + + @Override + public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) { + if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { + // indexes may depend on file name + if (!event.getFile().isDirectory()) { + markDirty(event, false); + } + } + } + + private void markDirty(@NotNull final VirtualFileEvent event, final boolean contentChange) { + final VirtualFile eventFile = event.getFile(); + cleanProcessedFlag(eventFile); + iterateIndexableFiles(eventFile, new Processor() { + @Override + public boolean process(@NotNull final VirtualFile file) { + if (!contentChange) ++myFilesModCount; + FileContent fileContent = null; + // handle 'content-less' indices separately + for (ID indexId : myNotRequiringContentIndices) { + if (getInputFilter(indexId).acceptInput(file)) { + try { + if (fileContent == null) { + fileContent = new FileContentImpl(file); + } + updateSingleIndex(indexId, file, fileContent); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + } + // For 'normal indices' schedule the file for update and stop iteration if at least one index accepts it + if (!isTooLarge(file)) { + for (ID indexId : myIndices.keySet()) { + if (needsFileContentLoading(indexId) && getInputFilter(indexId).acceptInput(file)) { + scheduleForUpdate(file); + break; // no need to iterate further, as the file is already marked + } + } + } + + return true; + } + }); + IndexingStamp.flushCache(); + } + + public void scheduleForUpdate(VirtualFile file) { + myFilesToUpdate.add(file); + } + + void invalidateIndices(@NotNull final VirtualFile file, final boolean markForReindex) { + if (isUnderConfigOrSystem(file)) { + return; + } + if (file.isDirectory()) { + if (isMock(file) || myManagingFS.wereChildrenAccessed(file)) { + final Iterable children = file instanceof NewVirtualFile + ? ((NewVirtualFile)file).iterInDbChildren() : Arrays.asList(file.getChildren()); + for (VirtualFile child : children) { + invalidateIndices(child, markForReindex); + } + } + } + else { + cleanProcessedFlag(file); + IndexingStamp.flushCache(); + final List> affectedIndices = new ArrayList>(myIndices.size()); + + for (final ID indexId : myIndices.keySet()) { + try { + if (!needsFileContentLoading(indexId)) { + if (shouldUpdateIndex(file, indexId)) { + updateSingleIndex(indexId, file, null); + } + } + else { // the index requires file content + if (shouldUpdateIndex(file, indexId)) { + affectedIndices.add(indexId); + } + } + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + + if (!affectedIndices.isEmpty()) { + if (markForReindex && !isTooLarge(file)) { + // only mark the file as unindexed, reindex will be done lazily + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + for (ID indexId : affectedIndices) { + IndexingStamp.update(file, indexId, -2L); + } + } + }); + // the file is for sure not a dir and it was previously indexed by at least one index + scheduleForUpdate(file); + } + else { + myFutureInvalidations.offer(new InvalidationTask(file) { + @Override + public void run() { + removeFileDataFromIndices(affectedIndices, file); + } + }); + } + } + if (!markForReindex) { + final boolean removedFromUpdateQueue = myFilesToUpdate.remove(file);// no need to update it anymore + if (removedFromUpdateQueue && affectedIndices.isEmpty()) { + // Currently the file is about to be deleted and previously it was scheduled for update and not processed up to now. + // Because the file was scheduled for update, at the moment of scheduling it was marked as unindexed, + // so, to be on the safe side, we have to schedule data invalidation from all content-requiring indices for this file + myFutureInvalidations.offer(new InvalidationTask(file) { + @Override + public void run() { + removeFileDataFromIndices(myRequiringContentIndices, file); + } + }); + } + } + + IndexingStamp.flushCache(); + } + } + + private void removeFileDataFromIndices(@NotNull Collection> affectedIndices, @NotNull VirtualFile file) { + Throwable unexpectedError = null; + for (ID indexId : affectedIndices) { + try { + updateSingleIndex(indexId, file, null); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + catch (ProcessCanceledException ignored) { + } + catch (Throwable e) { + LOG.info(e); + if (unexpectedError == null) { + unexpectedError = e; + } + } + } + IndexingStamp.flushCache(); + if (unexpectedError != null) { + LOG.error(unexpectedError); + } + } + + public int getNumberOfPendingInvalidations() { + return myFutureInvalidations.size(); + } + + public void ensureAllInvalidateTasksCompleted() { + final int size = getNumberOfPendingInvalidations(); + if (size == 0) { + return; + } + final ProgressIndicator current = ProgressManager.getInstance().getProgressIndicator(); + final ProgressIndicator indicator = current != null ? current : new EmptyProgressIndicator(); + indicator.setText(""); + int count = 0; + while (true) { + InvalidationTask task = myFutureInvalidations.poll(); + + if (task == null) { + break; + } + indicator.setFraction((double)count++ /size); + indicator.setText2(task.getSubj().getPresentableUrl()); + task.run(); + } + } + + private void iterateIndexableFiles(@NotNull final VirtualFile file, @NotNull final Processor processor) { + if (file.isDirectory()) { + final ContentIterator iterator = new ContentIterator() { + @Override + public boolean processFile(@NotNull final VirtualFile fileOrDir) { + if (!fileOrDir.isDirectory()) { + processor.process(fileOrDir); + } + return true; + } + }; + + for (IndexableFileSet set : myIndexableSets) { + if (set.isInSet(file)) { + set.iterateIndexableFilesIn(file, iterator); + } + } + } + else { + for (IndexableFileSet set : myIndexableSets) { + if (set.isInSet(file)) { + processor.process(file); + break; + } + } + } + } + + public Collection getAllFilesToUpdate() { + if (myFilesToUpdate.isEmpty()) { + return Collections.emptyList(); + } + return new ArrayList(myFilesToUpdate); + } + + private final Semaphore myForceUpdateSemaphore = new Semaphore(); + + private void forceUpdate(@Nullable Project project, @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedTo, + boolean onlyRemoveOutdatedData) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + for (VirtualFile file: getAllFilesToUpdate()) { + if (filter == null || filter.accept(file) || file == restrictedTo) { + try { + myForceUpdateSemaphore.down(); + // process only files that can affect result + processFileImpl(project, new com.intellij.ide.caches.FileContent(file), onlyRemoveOutdatedData); + } + finally { + myForceUpdateSemaphore.up(); + } + } + } + + // If several threads entered the method at the same time and there were files to update, + // all the threads should leave the method synchronously after all the files scheduled for update are reindexed, + // no matter which thread will do reindexing job. + // Thus we ensure that all the threads that entered the method will get the most recent data + + while (!myForceUpdateSemaphore.waitFor(500)) { // may need to wait until another thread is done with indexing + if (Thread.holdsLock(PsiLock.LOCK)) { + break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. + } + } + } + + private void processFileImpl(Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent, boolean onlyRemoveOutdatedData) { + final VirtualFile file = fileContent.getVirtualFile(); + final boolean reallyRemoved = myFilesToUpdate.remove(file); + if (reallyRemoved && file.isValid()) { + if (onlyRemoveOutdatedData) { + // on shutdown there is no need to re-index the file, just remove outdated data from indices + final List> affected = new ArrayList>(); + for (final ID indexId : myIndices.keySet()) { + if (getInputFilter(indexId).acceptInput(file)) { + affected.add(indexId); + } + } + removeFileDataFromIndices(affected, file); + } + else { + indexFileContent(project, fileContent); + } + IndexingStamp.flushCache(); + } + } + } + + private class UnindexedFilesFinder implements CollectingContentIterator { + private final List myFiles = new ArrayList(); + private final ProgressIndicator myProgressIndicator; + + private UnindexedFilesFinder() { + myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); + } + + @NotNull + @Override + public List getFiles() { + return myFiles; + } + + @Override + public boolean processFile(@NotNull final VirtualFile file) { + if (!file.isValid()) { + return true; + } + if (!file.isDirectory()) { + if (file instanceof NewVirtualFile && ((NewVirtualFile)file).getFlag(ALREADY_PROCESSED)) { + return true; + } + + if (file instanceof VirtualFileWithId) { + try { + FileTypeManagerImpl.cacheFileType(file, file.getFileType()); + + boolean oldStuff = true; + if (!isTooLarge(file)) { + for (ID indexId : myIndices.keySet()) { + try { + if (needsFileContentLoading(indexId) && shouldIndexFile(file, indexId)) { + myFiles.add(file); + oldStuff = false; + break; + } + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof IOException || cause instanceof StorageException) { + LOG.info(e); + requestRebuild(indexId); + } + else { + throw e; + } + } + } + } + FileContent fileContent = null; + for (ID indexId : myNotRequiringContentIndices) { + if (shouldIndexFile(file, indexId)) { + oldStuff = false; + try { + if (fileContent == null) { + fileContent = new FileContentImpl(file); + } + updateSingleIndex(indexId, file, fileContent); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + } + IndexingStamp.flushCache(); + + if (oldStuff && file instanceof NewVirtualFile) { + ((NewVirtualFile)file).setFlag(ALREADY_PROCESSED, true); + } + } + finally { + FileTypeManagerImpl.cacheFileType(file, null); + } + } + } + else { + if (myProgressIndicator != null) { + myProgressIndicator.setText("Scanning files to index"); + myProgressIndicator.setText2(file.getPresentableUrl()); + } + } + return true; + } + } + + private boolean shouldUpdateIndex(final VirtualFile file, final ID indexId) { + return getInputFilter(indexId).acceptInput(file) && + (isMock(file) || IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); + } + + private boolean shouldIndexFile(final VirtualFile file, final ID indexId) { + return getInputFilter(indexId).acceptInput(file) && + (isMock(file) || !IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); + } + + private boolean isUnderConfigOrSystem(@NotNull VirtualFile file) { + final String filePath = file.getPath(); + return myConfigPath != null && FileUtil.startsWith(filePath, myConfigPath) || + mySystemPath != null && FileUtil.startsWith(filePath, mySystemPath); + } + + private static boolean isMock(final VirtualFile file) { + return !(file instanceof NewVirtualFile); + } + + private boolean isTooLarge(@NotNull VirtualFile file) { + if (SingleRootFileViewProvider.isTooLarge(file)) { + final FileType type = file.getFileType(); + return !myNoLimitCheckTypes.contains(type); + } + return false; + } + + private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) { + if (SingleRootFileViewProvider.isTooLarge(file, contentSize)) { + final FileType type = file.getFileType(); + return !myNoLimitCheckTypes.contains(type); + } + return false; + } + + @NotNull + public CollectingContentIterator createContentIterator() { + ++myFilesModCount; + return new UnindexedFilesFinder(); + } + + public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { + myIndexableSets.add(set); + myIndexableSetToProjectMap.put(set, project); + } + + public void removeIndexableSet(@NotNull IndexableFileSet set) { + myChangedFilesCollector.forceUpdate(null, null, null, true); + myIndexableSets.remove(set); + myIndexableSetToProjectMap.remove(set); + } + + @Nullable + private static PsiFile findLatestKnownPsiForUncomittedDocument(@NotNull Document doc, @NotNull Project project) { + return PsiDocumentManager.getInstance(project).getCachedPsiFile(doc); + } + + private static class IndexableFilesFilter implements InputFilter { + private final InputFilter myDelegate; + + private IndexableFilesFilter(InputFilter delegate) { + myDelegate = delegate; + } + + @Override + public boolean acceptInput(final VirtualFile file) { + return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); + } + } + + private static void cleanupProcessedFlag() { + final VirtualFile[] roots = ManagingFS.getInstance().getRoots(); + for (VirtualFile root : roots) { + cleanProcessedFlag(root); + } + } + + private static void cleanProcessedFlag(@NotNull final VirtualFile file) { + if (!(file instanceof NewVirtualFile)) return; + + final NewVirtualFile nvf = (NewVirtualFile)file; + if (file.isDirectory()) { + for (VirtualFile child : nvf.getCachedChildren()) { + cleanProcessedFlag(child); + } + } + else { + nvf.setFlag(ALREADY_PROCESSED, false); + } + } + + public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { + if (project.isDisposed()) { + return; + } + final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + // iterate project content + projectFileIndex.iterateContent(processor); + + if (project.isDisposed()) { + return; + } + + Set visitedRoots = new THashSet(); + for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { + //important not to depend on project here, to support per-project background reindex + // each client gives a project to FileBasedIndex + if (project.isDisposed()) { + return; + } + for (VirtualFile root : IndexableSetContributor.getRootsToIndex(provider)) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + for (VirtualFile root : IndexableSetContributor.getProjectRootsToIndex(provider, project)) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + } + + if (project.isDisposed()) { + return; + } + // iterate associated libraries + for (Module module : ModuleManager.getInstance(project).getModules()) { + if (module.isDisposed()) { + return; + } + OrderEntry[] orderEntries = ModuleRootManager.getInstance(module).getOrderEntries(); + for (OrderEntry orderEntry : orderEntries) { + if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { + if (orderEntry.isValid()) { + final VirtualFile[] libSources = orderEntry.getFiles(OrderRootType.SOURCES); + final VirtualFile[] libClasses = orderEntry.getFiles(OrderRootType.CLASSES); + for (VirtualFile[] roots : new VirtualFile[][]{libSources, libClasses}) { + for (VirtualFile root : roots) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + } + } + } + } + } + } + + private static void iterateRecursively(@Nullable final VirtualFile root, @NotNull final ContentIterator processor, @Nullable ProgressIndicator indicator) { + if (root != null) { + if (indicator != null) { + indicator.checkCanceled(); + indicator.setText2(root.getPresentableUrl()); + } + + if (root.isDirectory()) { + for (VirtualFile file : root.getChildren()) { + if (file.isDirectory()) { + iterateRecursively(file, processor, indicator); + } + else { + processor.processFile(file); + } + } + } + else { + processor.processFile(root); + } + } + } + + private static class StorageGuard { + private int myHolds = 0; + + public interface Holder { + void leave(); + } + + private final Holder myTrueHolder = new Holder() { + @Override + public void leave() { + StorageGuard.this.leave(true); + } + }; + private final Holder myFalseHolder = new Holder() { + @Override + public void leave() { + StorageGuard.this.leave(false); + } + }; + + @NotNull + public synchronized Holder enter(boolean mode) { + if (mode) { + while (myHolds < 0) { + try { + wait(); + } + catch (InterruptedException ignored) { + } + } + myHolds++; + return myTrueHolder; + } + else { + while (myHolds > 0) { + try { + wait(); + } + catch (InterruptedException ignored) { + } + } + myHolds--; + return myFalseHolder; + } + } + + private synchronized void leave(boolean mode) { + myHolds += mode? -1 : 1; + if (myHolds == 0) { + notifyAll(); + } + } + + } +} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java index 7e1994218251..13fee5b720ab 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java @@ -42,12 +42,12 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; public class FileBasedIndexProjectHandler extends AbstractProjectComponent implements IndexableFileSet { - private final FileBasedIndex myIndex; + private final FileBasedIndexImpl myIndex; private final ProjectRootManagerEx myRootManager; private final FileTypeManager myFileTypeManager; private final ProjectFileExclusionManagerImpl myExclusionManager; - public FileBasedIndexProjectHandler(final FileBasedIndex index, final Project project, final ProjectRootManagerEx rootManager, FileTypeManager ftManager, final ProjectManager projectManager) { + public FileBasedIndexProjectHandler(final FileBasedIndexImpl index, final Project project, final ProjectRootManagerEx rootManager, FileTypeManager ftManager, final ProjectManager projectManager) { super(project); myIndex = index; myRootManager = rootManager; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index d8ea84dc00b0..efb1445da0be 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -33,11 +33,11 @@ import java.util.List; */ public class UnindexedFilesUpdater implements CacheUpdater { private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.UnindexedFilesUpdater"); - private final FileBasedIndex myIndex; + private final FileBasedIndexImpl myIndex; private final Project myProject; private long myStarted; - public UnindexedFilesUpdater(final Project project, FileBasedIndex index) { + public UnindexedFilesUpdater(final Project project, FileBasedIndexImpl index) { myIndex = index; myProject = project; } @@ -51,7 +51,7 @@ public class UnindexedFilesUpdater implements CacheUpdater { public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { CollectingContentIterator finder = myIndex.createContentIterator(); long l = System.currentTimeMillis(); - FileBasedIndex.iterateIndexableFiles(finder, myProject, indicator); + FileBasedIndexImpl.iterateIndexableFiles(finder, myProject, indicator); LOG.info("Indexable files iterated in " + (System.currentTimeMillis() - l) + " ms"); List files = finder.getFiles(); LOG.info("Unindexed files update started: " + files.size() + " files to update"); diff --git a/platform/platform-resources/src/componentSets/Lang.xml b/platform/platform-resources/src/componentSets/Lang.xml index f4ce41d26018..54e0cc2a543c 100644 --- a/platform/platform-resources/src/componentSets/Lang.xml +++ b/platform/platform-resources/src/componentSets/Lang.xml @@ -12,7 +12,8 @@ - com.intellij.util.indexing.FileBasedIndex + com.intellij.util.indexing.FileBasedIndex + com.intellij.util.indexing.FileBasedIndexImpl com.intellij.psi.stubs.StubIndex diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index a8ba4077789d..a7e2d39a9746 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -93,6 +93,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.LocalTimeCounter; import com.intellij.util.containers.CollectionFactory; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import com.intellij.util.indexing.IndexableFileSet; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.UIUtil; @@ -234,7 +235,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da throw new RuntimeException(e); } - FileBasedIndex.getInstance().registerIndexableSet(new IndexableFileSet() { + ((FileBasedIndexImpl)FileBasedIndex.getInstance()).registerIndexableSet(new IndexableFileSet() { @Override public boolean isInSet(@NotNull final VirtualFile file) { return ourSourceRoot != null && file.getFileSystem() == ourSourceRoot.getFileSystem() && ourProject.isOpen(); From 379ac23a9fec8d1b692458e03164e74eac2ffec5 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:02:03 +0200 Subject: [PATCH 06/67] Extra changes --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++++ .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 3 ++- .../src/com/intellij/util/indexing/UnindexedFilesUpdater.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index c2f3ad423b19..3ef57cafca3a 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -17,7 +17,9 @@ package com.intellij.util.indexing; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; @@ -35,6 +37,8 @@ import java.util.Set; * Author: dmitrylomov */ public abstract class FileBasedIndex implements ApplicationComponent { + public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); + public static FileBasedIndex getInstance() { return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 1cf3b2677d89..29e82dd6d2a6 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2189,7 +2189,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { + @Override + public void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { if (project.isDisposed()) { return; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index efb1445da0be..a0e42f63198d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -51,7 +51,7 @@ public class UnindexedFilesUpdater implements CacheUpdater { public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { CollectingContentIterator finder = myIndex.createContentIterator(); long l = System.currentTimeMillis(); - FileBasedIndexImpl.iterateIndexableFiles(finder, myProject, indicator); + FileBasedIndex.getInstance().iterateIndexableFiles(finder, myProject, indicator); LOG.info("Indexable files iterated in " + (System.currentTimeMillis() - l) + " ms"); List files = finder.getFiles(); LOG.info("Unindexed files update started: " + files.size() + " files to update"); From 1c1a4f8c55c3904af7e19eb139f64303692abf17 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:32:20 +0200 Subject: [PATCH 07/67] Extra methods --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++++ .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 3ef57cafca3a..f2dad634cf9f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -39,6 +39,10 @@ import java.util.Set; public abstract class FileBasedIndex implements ApplicationComponent { public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); + public abstract void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project); + + public abstract void removeIndexableSet(@NotNull IndexableFileSet set); + public static FileBasedIndex getInstance() { return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 29e82dd6d2a6..b6043d4bef02 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2139,11 +2139,13 @@ public class FileBasedIndexImpl extends FileBasedIndex { return new UnindexedFilesFinder(); } + @Override public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { myIndexableSets.add(set); myIndexableSetToProjectMap.put(set, project); } + @Override public void removeIndexableSet(@NotNull IndexableFileSet set) { myChangedFilesCollector.forceUpdate(null, null, null, true); myIndexableSets.remove(set); From c031b8e01ed71df6119b4036cf12e8d39e3b86be Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 12:07:10 +0200 Subject: [PATCH 08/67] More fixed --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 5 ----- .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 1 - 2 files changed, 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index f2dad634cf9f..0c7c23ce6f62 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -91,11 +91,6 @@ public abstract class FileBasedIndex implements ApplicationComponent { public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); - protected abstract void ensureUpToDate(@NotNull ID indexId, - @Nullable Project project, - @Nullable GlobalSearchScope filter, - @Nullable VirtualFile restrictedFile); - public abstract void requestRebuild(ID indexId, Throwable throwable); public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index b6043d4bef02..a5f15bf670d1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -737,7 +737,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { ensureUpToDate(indexId, project, filter, null); } - @Override protected void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, From f3b1e7b9b1c21e16d191f993edcca2c296f5e7b7 Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Wed, 9 May 2012 13:35:15 +0200 Subject: [PATCH 09/67] +CoreJavaCodeStyleManager --- .../com/intellij/core/CoreJavaCodeStyleManager.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java new file mode 100644 index 000000000000..c5632dfdcf6f --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -0,0 +1,11 @@ +package com.intellij.core; + +/** + * Created with IntelliJ IDEA. + * User: pasynkov + * Date: 09.05.12 + * Time: 13:22 + * To change this template use File | Settings | File Templates. + */ +public class CoreJavaCodeStyleManager { +} From 691b78015913c3b95eff5d71a4af65bcaa1f9d8f Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 13:36:53 +0200 Subject: [PATCH 10/67] FileBasedIndex moved to indexing-impl --- .../src/com/intellij/openapi/roots/ContentIterator.java | 0 .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++-- .../src/com/intellij/util/indexing/IndexableFileSet.java | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename platform/{platform-api => core-api}/src/com/intellij/openapi/roots/ContentIterator.java (100%) rename platform/{lang-impl => indexing-api}/src/com/intellij/util/indexing/FileBasedIndex.java (97%) rename platform/{lang-impl => indexing-api}/src/com/intellij/util/indexing/IndexableFileSet.java (100%) diff --git a/platform/platform-api/src/com/intellij/openapi/roots/ContentIterator.java b/platform/core-api/src/com/intellij/openapi/roots/ContentIterator.java similarity index 100% rename from platform/platform-api/src/com/intellij/openapi/roots/ContentIterator.java rename to platform/core-api/src/com/intellij/openapi/roots/ContentIterator.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java similarity index 97% rename from platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java rename to platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java index 0c7c23ce6f62..afcb32543471 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java @@ -16,7 +16,7 @@ package com.intellij.util.indexing; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.components.BaseComponent; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentIterator; @@ -36,7 +36,7 @@ import java.util.Set; /** * Author: dmitrylomov */ -public abstract class FileBasedIndex implements ApplicationComponent { +public abstract class FileBasedIndex implements BaseComponent { public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); public abstract void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexableFileSet.java b/platform/indexing-api/src/com/intellij/util/indexing/IndexableFileSet.java similarity index 100% rename from platform/lang-impl/src/com/intellij/util/indexing/IndexableFileSet.java rename to platform/indexing-api/src/com/intellij/util/indexing/IndexableFileSet.java From 710b0663bb823210780a333121292753e8ad894f Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 13:37:05 +0200 Subject: [PATCH 11/67] FileBasedIndex moved to indexing-impl --- .../src/com/intellij/compiler/impl/CompilerContentIterator.java | 1 - .../testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java | 1 - .../testSrc/com/intellij/psi/search/UpdateCacheTest.java | 1 - .../src/com/intellij/testFramework/LightPlatformTestCase.java | 1 - 4 files changed, 4 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java index 74bba4091d7b..c7634804a18d 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java @@ -19,7 +19,6 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.FileIndex; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import java.util.Collection; diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java index eaf7ae618ffe..bb43aac5a141 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java @@ -21,7 +21,6 @@ import com.intellij.psi.search.UsageSearchContext; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.FileBasedIndexImpl; import java.io.File; import java.util.Arrays; diff --git a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java index be90964eafae..9ed5627cc09b 100644 --- a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java @@ -44,7 +44,6 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.FileBasedIndexImpl; import org.jetbrains.annotations.NonNls; import java.io.File; diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index a7e2d39a9746..2078af288a71 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -56,7 +56,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.project.ModuleAdapter; -import com.intellij.openapi.project.ModuleListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ex.ProjectEx; From 9a4ae3a5b1f86cc9882061628df6b5a1228ed39e Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Wed, 9 May 2012 13:40:34 +0200 Subject: [PATCH 12/67] +CoreJavaCodeStyleManager --- .../core/CoreJavaCodeStyleManager.java | 134 ++++++++++++++++-- .../intellij/core/JavaCoreEnvironment.java | 2 + 2 files changed, 128 insertions(+), 8 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java index c5632dfdcf6f..7f651a21df0e 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -1,11 +1,129 @@ +/* + * Copyright 2000-2012 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.core; -/** - * Created with IntelliJ IDEA. - * User: pasynkov - * Date: 09.05.12 - * Time: 13:22 - * To change this template use File | Settings | File Templates. - */ -public class CoreJavaCodeStyleManager { +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.util.IncorrectOperationException; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { + @Override + public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { + return false; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element, + @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) + throws IncorrectOperationException { + return null; + } + + @NotNull + @Override + public String getPrefixByVariableKind(VariableKind variableKind) { + return ""; + } + + @NotNull + @Override + public String getSuffixByVariableKind(VariableKind variableKind) { + return ""; + } + + @Override + public int findEntryIndex(@NotNull PsiImportStatementBase statement) { + return 0; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { + return null; + } + + @Override + public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException { + } + + @Override + public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { + } + + @Override + public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { + return null; + } + + @Override + public VariableKind getVariableKind(@NotNull PsiVariable variable) { + return null; + } + + @Override + public SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, + @Nullable String propertyName, + @Nullable PsiExpression expr, + @Nullable PsiType type, + boolean correctKeywords) { + return null; + } + + @Override + public String variableNameToPropertyName(@NonNls String name, VariableKind variableKind) { + return null; + } + + @Override + public String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind) { + return null; + } + + @Override + public String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward) { + return null; + } + + @NotNull + @Override + public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward) { + return SuggestedNameInfo.NULL_INFO; + } + + @Override + public PsiElement qualifyClassReferences(@NotNull PsiElement element) { + return null; + } + + @Override + public void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException { + } + + @Override + public Collection findRedundantImports(PsiJavaFile file) { + return null; + } } diff --git a/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java b/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java index 46aa4080730f..16cdc8d46e90 100644 --- a/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java +++ b/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java @@ -30,6 +30,7 @@ import com.intellij.openapi.roots.PackageIndex; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.augment.PsiAugmentProvider; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade; import com.intellij.psi.impl.EmptySubstitutorImpl; import com.intellij.psi.impl.JavaPsiFacadeImpl; @@ -79,6 +80,7 @@ public class JavaCoreEnvironment extends CoreEnvironment { myProject.registerService(PackageIndex.class, myFileManager); myProject.registerService(JavaResolveCache.class, new JavaResolveCache(null)); myProject.registerService(JavaCodeStyleSettingsFacade.class, new CoreJavaCodeStyleSettingsFacade()); + myProject.registerService(JavaCodeStyleManager.class, new CoreJavaCodeStyleManager()); JavaPsiFacadeImpl javaPsiFacade = new JavaPsiFacadeImpl(myProject, myPsiManager, myFileManager, null); myProject.registerService(CoreJavaFileManager.class, myFileManager); From ea7598920afc9f38aa1a94671fd4ac590fe1616e Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Wed, 9 May 2012 14:58:39 +0200 Subject: [PATCH 13/67] Better stub CoreJavaCodeStyleManager --- .../codeStyle/JavaCodeStyleManagerImpl.java | 2100 ++++++++--------- .../psi/codeStyle/JavaCodeStyleManager.java | 407 ++-- .../core/CoreJavaCodeStyleManager.java | 9 +- 3 files changed, 1254 insertions(+), 1262 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java index ed7ec70859e1..76ac3ac6a49b 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java @@ -1,1061 +1,1039 @@ -/* - * Copyright 2000-2011 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. - */ - -/* - * @author max - */ -package com.intellij.psi.impl.source.codeStyle; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.util.text.StringUtilRt; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.*; -import com.intellij.psi.impl.CheckUtil; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; -import com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatement; -import com.intellij.psi.impl.source.tree.TreeElement; -import com.intellij.psi.statistics.JavaStatisticsManager; -import com.intellij.psi.util.*; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashSet; -import gnu.trove.TObjectHashingStrategy; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.beans.Introspector; -import java.util.*; - -public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl"); - - @NonNls private static final String IMPL_TYPNAME_SUFFIX = "Impl"; - @NonNls private static final String GET_PREFIX = "get"; - @NonNls private static final String IS_PREFIX = "is"; - @NonNls private static final String FIND_PREFIX = "find"; - @NonNls private static final String CREATE_PREFIX = "create"; - @NonNls private static final String WITH_PREFIX = "with"; - @NonNls private static final String SET_PREFIX = "set"; - - private final Project myProject; - - public JavaCodeStyleManagerImpl(final Project project) { - myProject = project; - } - - @Override - public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { - return shortenClassReferences(element, 0); - } - - @Override - public PsiElement shortenClassReferences(@NotNull PsiElement element, int flags) throws IncorrectOperationException { - CheckUtil.checkWritable(element); - if (!SourceTreeToPsiMap.hasTreeElement(element)) return element; - - return SourceTreeToPsiMap.treeElementToPsi( - new ReferenceAdjuster(myProject).process((TreeElement)element.getNode(), (flags & DO_NOT_ADD_IMPORTS) == 0, - (flags & UNCOMPLETE_CODE) != 0)); - } - - @Override - public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) - throws IncorrectOperationException { - CheckUtil.checkWritable(element); - if (SourceTreeToPsiMap.hasTreeElement(element)) { - new ReferenceAdjuster(myProject).processRange((TreeElement)element.getNode(), startOffset, endOffset); - } - } - - @Override - public PsiElement qualifyClassReferences(@NotNull PsiElement element) { - return SourceTreeToPsiMap.treeElementToPsi(new ReferenceAdjuster(true, true).process((TreeElement)element.getNode(), false, false)); - } - - @Override - public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { - CheckUtil.checkWritable(file); - if (file instanceof PsiJavaFile) { - PsiImportList newList = prepareOptimizeImportsResult((PsiJavaFile)file); - if (newList != null) { - final PsiImportList importList = ((PsiJavaFile)file).getImportList(); - if (importList != null) { - importList.replace(newList); - } - } - } - } - - @Override - public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { - return new ImportHelper(getSettings()).prepareOptimizeImportsResult(file); - } - - @Override - public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { - return new ImportHelper(getSettings()).addImport(file, refClass); - } - - @Override - public void removeRedundantImports(@NotNull final PsiJavaFile file) throws IncorrectOperationException { - final Collection redundants = findRedundantImports(file); - if (redundants == null) return; - - for (final PsiImportStatementBase importStatement : redundants) { - final PsiJavaCodeReferenceElement ref = importStatement.getImportReference(); - //Do not remove non-resolving refs - if (ref == null || ref.resolve() == null) { - continue; - } - - importStatement.delete(); - } - } - - @Override - @Nullable - public Collection findRedundantImports(final PsiJavaFile file) { - final PsiImportList importList = file.getImportList(); - if (importList == null) return null; - final PsiImportStatementBase[] imports = importList.getAllImportStatements(); - if( imports.length == 0 ) return null; - - Set allImports = new THashSet(Arrays.asList(imports)); - final Collection redundants; - if (JspPsiUtil.isInJspFile(file)) { - // remove only duplicate imports - redundants = new THashSet(TObjectHashingStrategy.IDENTITY); - ContainerUtil.addAll(redundants, imports); - redundants.removeAll(allImports); - for (PsiImportStatementBase importStatement : imports) { - if (importStatement instanceof JspxImportStatement && ((JspxImportStatement)importStatement).isForeignFileImport()) { - redundants.remove(importStatement); - } - } - } - else { - redundants = allImports; - final List roots = file.getViewProvider().getAllFiles(); - for (PsiElement root : roots) { - root.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - if (!reference.isQualified()) { - final JavaResolveResult resolveResult = reference.advancedResolve(false); - if (!inTheSamePackage(file, resolveResult.getElement())) { - final PsiElement resolveScope = resolveResult.getCurrentFileResolveScope(); - if (resolveScope instanceof PsiImportStatementBase) { - final PsiImportStatementBase importStatementBase = (PsiImportStatementBase)resolveScope; - redundants.remove(importStatementBase); - } - } - } - super.visitReferenceElement(reference); - } - - private boolean inTheSamePackage(PsiJavaFile file, PsiElement element) { - if (element instanceof PsiClass && ((PsiClass)element).getContainingClass() == null) { - final PsiFile containingFile = element.getContainingFile(); - if (containingFile instanceof PsiJavaFile) { - return Comparing.strEqual(file.getPackageName(), ((PsiJavaFile)containingFile).getPackageName()); - } - } - return false; - } - }); - } - } - return redundants; - } - - @Override - public int findEntryIndex(@NotNull PsiImportStatementBase statement) { - return new ImportHelper(getSettings()).findEntryIndex(statement); - } - - @Override - public VariableKind getVariableKind(@NotNull PsiVariable variable) { - if (variable instanceof PsiField) { - if (variable.hasModifierProperty(PsiModifier.STATIC)) { - if (variable.hasModifierProperty(PsiModifier.FINAL)) { - return VariableKind.STATIC_FINAL_FIELD; - } - return VariableKind.STATIC_FIELD; - } - return VariableKind.FIELD; - } - else { - if (variable instanceof PsiParameter) { - if (((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { - return VariableKind.LOCAL_VARIABLE; - } - return VariableKind.PARAMETER; - } - return VariableKind.LOCAL_VARIABLE; - } - } - - @Override - public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, - @Nullable final String propertyName, - @Nullable final PsiExpression expr, - @Nullable PsiType type, - final boolean correctKeywords) { - LinkedHashSet names = new LinkedHashSet(); - - if (expr != null && type == null) { - type = expr.getType(); - } - - if (propertyName != null) { - String[] namesByName = getSuggestionsByName(propertyName, kind, false, correctKeywords); - sortVariableNameSuggestions(namesByName, kind, propertyName, null); - ContainerUtil.addAll(names, namesByName); - } - - final NamesByExprInfo namesByExpr; - if (expr != null) { - namesByExpr = suggestVariableNameByExpression(expr, kind, correctKeywords); - if (namesByExpr.propertyName != null) { - sortVariableNameSuggestions(namesByExpr.names, kind, namesByExpr.propertyName, null); - } - ContainerUtil.addAll(names, namesByExpr.names); - } - else { - namesByExpr = null; - } - - if (type != null) { - String[] namesByType = suggestVariableNameByType(type, kind, correctKeywords); - sortVariableNameSuggestions(namesByType, kind, null, type); - ContainerUtil.addAll(names, namesByType); - } - - final String _propertyName; - if (propertyName != null) { - _propertyName = propertyName; - } - else { - _propertyName = namesByExpr != null ? namesByExpr.propertyName : null; - } - - addNamesFromStatistics(names, kind, _propertyName, type); - - String[] namesArray = ArrayUtil.toStringArray(names); - sortVariableNameSuggestions(namesArray, kind, _propertyName, type); - - final PsiType _type = type; - return new SuggestedNameInfo(namesArray) { - @Override - public void nameChoosen(String name) { - if (_propertyName != null || _type != null && _type.isValid()) { - JavaStatisticsManager.incVariableNameUseCount(name, kind, _propertyName, _type); - } - } - }; - } - - private static void addNamesFromStatistics(Set names, VariableKind variableKind, @Nullable String propertyName, @Nullable PsiType type) { - String[] allNames = JavaStatisticsManager.getAllVariableNamesUsed(variableKind, propertyName, type); - - int maxFrequency = 0; - for (String name : allNames) { - int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); - maxFrequency = Math.max(maxFrequency, count); - } - - int frequencyLimit = Math.max(5, maxFrequency / 2); - - for (String name : allNames) { - if( names.contains( name ) ) - { - continue; - } - int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); - if (LOG.isDebugEnabled()) { - LOG.debug("new name:" + name + " count:" + count); - LOG.debug("frequencyLimit:" + frequencyLimit); - } - if (count >= frequencyLimit) { - names.add(name); - } - } - - if (propertyName != null && type != null) { - addNamesFromStatistics(names, variableKind, propertyName, null); - addNamesFromStatistics(names, variableKind, null, type); - } - } - - private String[] suggestVariableNameByType(PsiType type, final VariableKind variableKind, boolean correctKeywords) { - String longTypeName = getLongTypeName(type); - CodeStyleSettings.TypeToNameMap map = getMapByVariableKind(variableKind); - if (map != null && longTypeName != null) { - if (type.equals(PsiType.NULL)) { - longTypeName = CommonClassNames.JAVA_LANG_OBJECT; - } - String name = map.nameByType(longTypeName); - if (name != null && isIdentifier(name)) { - return new String[]{name}; - } - } - - Collection suggestions = new LinkedHashSet(); - - suggestNamesForCollectionInheritors(type, variableKind, suggestions, correctKeywords); - suggestNamesFromGenericParameters(type, variableKind, suggestions, correctKeywords); - - String typeName = normalizeTypeName(getTypeName(type)); - if (typeName != null) { - ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, type instanceof PsiArrayType, correctKeywords)); - } - - return ArrayUtil.toStringArray(suggestions); - } - - private void suggestNamesFromGenericParameters(final PsiType type, - final VariableKind variableKind, - final Collection suggestions, boolean correctKeywords) { - if (!(type instanceof PsiClassType)) { - return; - } - StringBuilder fullNameBuilder = new StringBuilder(); - final PsiType[] parameters = ((PsiClassType)type).getParameters(); - for (PsiType parameter : parameters) { - if (parameter instanceof PsiClassType) { - final String typeName = normalizeTypeName(getTypeName(parameter)); - if (typeName != null) { - fullNameBuilder.append(typeName); - } - } - } - String baseName = normalizeTypeName(getTypeName(type)); - if (baseName != null) { - fullNameBuilder.append(baseName); - ContainerUtil.addAll(suggestions, getSuggestionsByName(fullNameBuilder.toString(), variableKind, false, correctKeywords)); - } - } - - private void suggestNamesForCollectionInheritors(final PsiType type, - final VariableKind variableKind, - Collection suggestions, boolean correctKeywords) { - PsiType componentType = PsiUtil.extractIterableTypeParameter(type, false); - if( componentType == null ) { - return; - } - String typeName = normalizeTypeName(getTypeName(componentType)); - if (typeName != null) { - ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, true, correctKeywords)); - } - } - - @Nullable - private static String normalizeTypeName(String typeName) { - if( typeName == null ) - { - return null; - } - if (typeName.endsWith(IMPL_TYPNAME_SUFFIX) && typeName.length() > IMPL_TYPNAME_SUFFIX.length()) { - return typeName.substring(0, typeName.length() - IMPL_TYPNAME_SUFFIX.length()); - } - return typeName; - } - - @Nullable - private static String getTypeName(PsiType type) { - type = type.getDeepComponentType(); - if (type instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)type; - final String className = classType.getClassName(); - if (className != null) { - return className; - } - else { - final PsiClass aClass = classType.resolve(); - if (aClass instanceof PsiAnonymousClass) { - return ((PsiAnonymousClass)aClass).getBaseClassType().getClassName(); - } - else { - return null; - } - } - } - else { - if (type instanceof PsiPrimitiveType) { - return type.getPresentableText(); - } - else { - if (type instanceof PsiWildcardType) { - return getTypeName(((PsiWildcardType)type).getExtendsBound()); - } - else { - if (type instanceof PsiIntersectionType) { - return getTypeName(((PsiIntersectionType)type).getRepresentative()); - } - else { - if (type instanceof PsiCapturedWildcardType) { - return getTypeName(((PsiCapturedWildcardType)type).getWildcard()); - } - else { - if (type instanceof PsiDisjunctionType) { - return getTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); - } - else { - LOG.error("Unknown type:" + type); - return null; - } - } - } - } - } - } - } - - @Nullable - private static String getLongTypeName(PsiType type) { - if (type instanceof PsiClassType) { - PsiClass aClass = ((PsiClassType)type).resolve(); - if( aClass == null ) - { - return null; - } - if (aClass instanceof PsiAnonymousClass) { - PsiClass baseClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve(); - if( baseClass == null ) - { - return null; - } - return baseClass.getQualifiedName(); - } - return aClass.getQualifiedName(); - } - else { - if (type instanceof PsiArrayType) { - return getLongTypeName(((PsiArrayType)type).getComponentType()) + "[]"; - } - else { - if (type instanceof PsiPrimitiveType) { - return type.getPresentableText(); - } - else { - if (type instanceof PsiWildcardType) { - final PsiType bound = ((PsiWildcardType)type).getBound(); - if (bound != null) { - return getLongTypeName(bound); - } - else { - return "java.lang.Object"; - } - } - else { - if (type instanceof PsiCapturedWildcardType) { - final PsiType bound = ((PsiCapturedWildcardType)type).getWildcard().getBound(); - if (bound != null) { - return getLongTypeName(bound); - } - else { - return "java.lang.Object"; - } - } - else { - if (type instanceof PsiIntersectionType) { - return getLongTypeName(((PsiIntersectionType)type).getRepresentative()); - } - else { - if (type instanceof PsiDisjunctionType) { - return getLongTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); - } - else { - LOG.error("Unknown type:" + type); - return null; - } - } - } - } - } - } - } - } - - private static class NamesByExprInfo { - final String[] names; - final String propertyName; - - public NamesByExprInfo(String propertyName, String... names) { - this.names = names; - this.propertyName = propertyName; - } - } - - private NamesByExprInfo suggestVariableNameByExpression(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { - final NamesByExprInfo names1 = suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords); - final NamesByExprInfo names2 = suggestVariableNameByExpressionPlace(expr, variableKind, correctKeywords); - - PsiType type = expr.getType(); - final String[] names3; - if (type != null) { - names3 = suggestVariableNameByType(type, variableKind, correctKeywords); - } - else { - names3 = null; - } - - final LinkedHashSet names = new LinkedHashSet(); - final String[] fromLiterals = suggestVariableNameFromLiterals(expr, variableKind, correctKeywords); - if (fromLiterals != null) { - ContainerUtil.addAll(names, fromLiterals); - } - ContainerUtil.addAll(names, names1.names); - ContainerUtil.addAll(names, names2.names); - if (names3 != null) { - ContainerUtil.addAll(names, names3); - } - - String[] namesArray = ArrayUtil.toStringArray(names); - String propertyName = names1.propertyName != null ? names1.propertyName : names2.propertyName; - return new NamesByExprInfo(propertyName, namesArray); - } - - @Nullable - private String[] suggestVariableNameFromLiterals(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { - final PsiElement[] literals = PsiTreeUtil.collectElements(expr, new PsiElementFilter() { - @Override - public boolean isAccepted(PsiElement element) { - if (isStringPsiLiteral(element) && StringUtil.isJavaIdentifier(StringUtil.unquoteString(element.getText()))) { - final PsiElement exprList = element.getParent(); - if (exprList instanceof PsiExpressionList) { - final PsiElement call = exprList.getParent(); - if (call instanceof PsiNewExpression) { - return true; - } else if (call instanceof PsiMethodCallExpression) { - //TODO: exclude or not getA().getB("name").getC(); or getA(getB("name").getC()); It works fine for now in the most cases - return true; - } - } - } - return false; - } - }); - - if (literals.length == 1) { - final String text = StringUtil.unquoteString(literals[0].getText()); - return getSuggestionsByName(text, variableKind, expr.getType() instanceof PsiArrayType, correctKeywords); - } - return null; - } - - private NamesByExprInfo suggestVariableNameByExpressionOnly(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { - if (expr instanceof PsiMethodCallExpression) { - PsiReferenceExpression methodExpr = ((PsiMethodCallExpression)expr).getMethodExpression(); - String methodName = methodExpr.getReferenceName(); - if (methodName != null) { - String[] words = NameUtil.nameToWords(methodName); - if (words.length > 0) { - final String firstWord = words[0]; - if (GET_PREFIX.equals(firstWord) - || IS_PREFIX.equals(firstWord) - || FIND_PREFIX.equals(firstWord) - || CREATE_PREFIX.equals(firstWord)) { - if (words.length > 1) { - final String propertyName = methodName.substring(firstWord.length()); - String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); - final PsiExpression qualifierExpression = methodExpr.getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() instanceof PsiVariable) { - names = ArrayUtil.append(names, StringUtil.sanitizeJavaIdentifier(changeIfNotIdentifier(qualifierExpression.getText() + StringUtil.capitalize(propertyName)))); - } - return new NamesByExprInfo(propertyName, names); - } - } - else if (words.length == 1) { - return new NamesByExprInfo(methodName, getSuggestionsByName(methodName, variableKind, false, correctKeywords)); - } - } - } - } - else if (expr instanceof PsiReferenceExpression) { - String propertyName = ((PsiReferenceExpression)expr).getReferenceName(); - PsiElement refElement = ((PsiReferenceExpression)expr).resolve(); - if (refElement instanceof PsiVariable) { - VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); - propertyName = variableNameToPropertyName(propertyName, refVariableKind); - } - if (refElement != null && propertyName != null) { - String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); - return new NamesByExprInfo(propertyName, names); - } - } - else if (expr instanceof PsiArrayAccessExpression) { - PsiExpression arrayExpr = ((PsiArrayAccessExpression)expr).getArrayExpression(); - if (arrayExpr instanceof PsiReferenceExpression) { - String arrayName = ((PsiReferenceExpression)arrayExpr).getReferenceName(); - PsiElement refElement = ((PsiReferenceExpression)arrayExpr).resolve(); - if (refElement instanceof PsiVariable) { - VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); - arrayName = variableNameToPropertyName(arrayName, refVariableKind); - } - - if (arrayName != null) { - String name = StringUtil.unpluralize(arrayName); - if (name != null) { - String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); - return new NamesByExprInfo(name, names); - } - } - } - } - else if (expr instanceof PsiLiteralExpression && variableKind == VariableKind.STATIC_FINAL_FIELD) { - final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expr; - final Object value = literalExpression.getValue(); - if (value instanceof String) { - final String stringValue = (String)value; - String[] names = getSuggestionsByValue(stringValue); - if (names.length > 0) { - return new NamesByExprInfo(null, constantValueToConstantName(names)); - } - } - } else if (expr instanceof PsiParenthesizedExpression) { - return suggestVariableNameByExpressionOnly(((PsiParenthesizedExpression)expr).getExpression(), variableKind, correctKeywords); - } else if (expr instanceof PsiTypeCastExpression) { - return suggestVariableNameByExpressionOnly(((PsiTypeCastExpression)expr).getOperand(), variableKind, correctKeywords); - } else if (expr instanceof PsiLiteralExpression) { - final String text = StringUtil.stripQuotesAroundValue(expr.getText()); - if (isIdentifier(text)) { - return new NamesByExprInfo(text, getSuggestionsByName(text, variableKind, false, correctKeywords)); - } - } - - return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); - } - - private static String constantValueToConstantName(final String[] names) { - final StringBuilder result = new StringBuilder(); - for (int i = 0; i < names.length; i++) { - if (i > 0) result.append("_"); - result.append(names[i]); - } - return result.toString(); - } - - private static String[] getSuggestionsByValue(final String stringValue) { - List result = new ArrayList(); - StringBuffer currentWord = new StringBuffer(); - - boolean prevIsUpperCase = false; - - for (int i = 0; i < stringValue.length(); i++) { - final char c = stringValue.charAt(i); - if (Character.isUpperCase(c)) { - if (currentWord.length() > 0 && !prevIsUpperCase) { - result.add(currentWord.toString()); - currentWord = new StringBuffer(); - } - currentWord.append(c); - } else if (Character.isLowerCase(c)) { - currentWord.append(Character.toUpperCase(c)); - } else if (Character.isJavaIdentifierPart(c) && c != '_') { - if (Character.isJavaIdentifierStart(c) || currentWord.length() > 0 || !result.isEmpty()) { - currentWord.append(c); - } - } else { - if (currentWord.length() > 0) { - result.add(currentWord.toString()); - currentWord = new StringBuffer(); - } - } - - prevIsUpperCase = Character.isUpperCase(c); - } - - if (currentWord.length() > 0) { - result.add(currentWord.toString()); - } - return ArrayUtil.toStringArray(result); - } - - private NamesByExprInfo suggestVariableNameByExpressionPlace(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { - if (expr.getParent() instanceof PsiExpressionList) { - PsiExpressionList list = (PsiExpressionList)expr.getParent(); - PsiElement listParent = list.getParent(); - PsiSubstitutor subst = PsiSubstitutor.EMPTY; - PsiMethod method = null; - if (listParent instanceof PsiMethodCallExpression) { - final JavaResolveResult resolveResult = ((PsiMethodCallExpression)listParent).getMethodExpression().advancedResolve(false); - method = (PsiMethod)resolveResult.getElement(); - subst = resolveResult.getSubstitutor(); - } - else { - if (listParent instanceof PsiAnonymousClass) { - listParent = listParent.getParent(); - } - if (listParent instanceof PsiNewExpression) { - method = ((PsiNewExpression)listParent).resolveConstructor(); - } - } - - if (method != null) { - final PsiElement navElement = method.getNavigationElement(); - if (navElement instanceof PsiMethod) { - method = (PsiMethod)navElement; - } - PsiExpression[] expressions = list.getExpressions(); - int index = -1; - for (int i = 0; i < expressions.length; i++) { - if (expressions[i] == expr) { - index = i; - break; - } - } - PsiParameter[] parms = method.getParameterList().getParameters(); - if (index < parms.length) { - String name = parms[index].getName(); - if (name != null && TypeConversionUtil.areTypesAssignmentCompatible(subst.substitute(parms[index].getType()), expr)) { - name = variableNameToPropertyName(name, VariableKind.PARAMETER); - String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); - if (expressions.length == 1) { - final String methodName = method.getName(); - String[] words = NameUtil.nameToWords(methodName); - if (words.length > 0) { - final String firstWord = words[0]; - if (SET_PREFIX.equals(firstWord)) { - final String propertyName = methodName.substring(firstWord.length()); - final String[] setterNames = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); - names = ArrayUtil.mergeArrays(names, setterNames); - } - } - } - return new NamesByExprInfo(name, names); - } - } - } - } - else if (expr.getParent() instanceof PsiAssignmentExpression && variableKind == VariableKind.PARAMETER) { - final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expr.getParent(); - if (expr == assignmentExpression.getRExpression()) { - final PsiExpression leftExpression = assignmentExpression.getLExpression(); - if (leftExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression) leftExpression).getQualifier() == null) { - String name = leftExpression.getText(); - if (name != null) { - final PsiElement resolve = ((PsiReferenceExpression)leftExpression).resolve(); - if (resolve instanceof PsiVariable) { - name = variableNameToPropertyName(name, getVariableKind((PsiVariable)resolve)); - } - String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); - return new NamesByExprInfo(name, names); - } - } - } - } - - return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); - } - - @Override - public String variableNameToPropertyName(String name, VariableKind variableKind) { - if (variableKind == VariableKind.STATIC_FINAL_FIELD) { - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < name.length(); i++) { - char c = name.charAt(i); - if (c != '_') { - if( Character.isLowerCase( c ) ) - { - return variableNameToPropertyNameInner( name, variableKind ); - } - - buffer.append(Character.toLowerCase(c)); - continue; - } - i++; - if (i < name.length()) { - c = name.charAt(i); - buffer.append(c); - } - } - return buffer.toString(); - } - - return variableNameToPropertyNameInner(name, variableKind); - } - - private String variableNameToPropertyNameInner(String name, VariableKind variableKind) { - String prefix = getPrefixByVariableKind(variableKind); - String suffix = getSuffixByVariableKind(variableKind); - boolean doDecapitalize = false; - - if (name.startsWith(prefix) && name.length() > prefix.length()) { - name = name.substring(prefix.length()); - doDecapitalize = true; - } - - if (name.endsWith(suffix) && name.length() > suffix.length()) { - name = name.substring(0, name.length() - suffix.length()); - doDecapitalize = true; - } - - if (name.startsWith(IS_PREFIX) && name.length() > IS_PREFIX.length() && Character.isUpperCase(name.charAt(IS_PREFIX.length()))) { - name = name.substring(IS_PREFIX.length()); - doDecapitalize = true; - } - - if (doDecapitalize) { - name = Introspector.decapitalize(name); - } - - return name; - } - - @Override - public String propertyNameToVariableName(String propertyName, VariableKind variableKind) { - if (variableKind == VariableKind.STATIC_FINAL_FIELD) { - String[] words = NameUtil.nameToWords(propertyName); - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < words.length; i++) { - String word = words[i]; - if (i > 0) { - buffer.append("_"); - } - buffer.append(StringUtilRt.toUpperCase(word)); - } - return buffer.toString(); - } - - String prefix = getPrefixByVariableKind(variableKind); - String name = propertyName; - if (name.length() > 0 && prefix.length() > 0 && !StringUtil.endsWithChar(prefix, '_')) { - name = Character.toUpperCase(name.charAt(0)) + name.substring(1); - } - name = prefix + name + getSuffixByVariableKind(variableKind); - name = changeIfNotIdentifier(name); - return name; - } - - private String[] getSuggestionsByName(String name, VariableKind variableKind, boolean isArray, boolean correctKeywords) { - boolean upperCaseStyle = variableKind == VariableKind.STATIC_FINAL_FIELD; - boolean preferLongerNames = getSettings().PREFER_LONGER_NAMES; - String prefix = getPrefixByVariableKind(variableKind); - String suffix = getSuffixByVariableKind(variableKind); - - List answer = new ArrayList(); - for (String suggestion : NameUtil.getSuggestionsByName(name, prefix, suffix, upperCaseStyle, preferLongerNames, isArray)) { - answer.add(correctKeywords ? changeIfNotIdentifier(suggestion) : suggestion); - } - - return ArrayUtil.toStringArray(answer); - } - - @Override - public String suggestUniqueVariableName(String baseName, PsiElement place, boolean lookForward) { - int index = 0; - PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); - NextName: - while (true) { - String name = baseName; - if (index > 0) { - name += index; - } - index++; - if (PsiUtil.isVariableNameUnique(name, place)) { - if (lookForward) { - final String name1 = name; - PsiElement run = scope; - while (run != null) { - class CancelException extends RuntimeException { - } - try { - run.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitAnonymousClass(final PsiAnonymousClass aClass) { - } - - @Override public void visitVariable(PsiVariable variable) { - if (name1.equals(variable.getName())) { - throw new CancelException(); - } - } - }); - } - catch (CancelException e) { - continue NextName; - } - run = run.getNextSibling(); - if (scope instanceof PsiMethod) {//do not check next member for param name conflict - break; - } - } - - } - return name; - } - } - } - - @Override - @NotNull - public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean ignorePlaceName, - boolean lookForward) { - final String[] names = baseNameInfo.names; - final LinkedHashSet uniqueNames = new LinkedHashSet(names.length); - for (String name : names) { - if (ignorePlaceName && place instanceof PsiNamedElement) { - final String placeName = ((PsiNamedElement)place).getName(); - if (Comparing.strEqual(placeName, name)) { - uniqueNames.add(name); - continue; - } - } - uniqueNames.add(suggestUniqueVariableName(name, place, lookForward)); - } - - return new SuggestedNameInfo(ArrayUtil.toStringArray(uniqueNames)) { - @Override - public void nameChoosen(String name) { - baseNameInfo.nameChoosen(name); - } - }; - } - - private static void sortVariableNameSuggestions(String[] names, - final VariableKind variableKind, - @Nullable final String propertyName, - @Nullable final PsiType type) { - if( names.length <= 1 ) { - return; - } - - if (LOG.isDebugEnabled()) { - LOG.debug("sorting names:" + variableKind); - if (propertyName != null) { - LOG.debug("propertyName:" + propertyName); - } - if (type != null) { - LOG.debug("type:" + type); - } - for (String name : names) { - int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); - LOG.debug(name + " : " + count); - } - } - - Comparator comparator = new Comparator() { - @Override - public int compare(String s1, String s2) { - int count1 = JavaStatisticsManager.getVariableNameUseCount(s1, variableKind, propertyName, type); - int count2 = JavaStatisticsManager.getVariableNameUseCount(s2, variableKind, propertyName, type); - return count2 - count1; - } - }; - Arrays.sort(names, comparator); - } - - @Override - @NotNull - public String getPrefixByVariableKind(VariableKind variableKind) { - String prefix = ""; - switch (variableKind) { - case FIELD: - prefix = getSettings().FIELD_NAME_PREFIX; - break; - case STATIC_FIELD: - prefix = getSettings().STATIC_FIELD_NAME_PREFIX; - break; - case PARAMETER: - prefix = getSettings().PARAMETER_NAME_PREFIX; - break; - case LOCAL_VARIABLE: - prefix = getSettings().LOCAL_VARIABLE_NAME_PREFIX; - break; - case STATIC_FINAL_FIELD: - prefix = ""; - break; - default: - LOG.assertTrue(false); - break; - } - if (prefix == null) { - prefix = ""; - } - return prefix; - } - - @Override - @NotNull - public String getSuffixByVariableKind(VariableKind variableKind) { - String suffix = ""; - switch (variableKind) { - case FIELD: - suffix = getSettings().FIELD_NAME_SUFFIX; - break; - case STATIC_FIELD: - suffix = getSettings().STATIC_FIELD_NAME_SUFFIX; - break; - case PARAMETER: - suffix = getSettings().PARAMETER_NAME_SUFFIX; - break; - case LOCAL_VARIABLE: - suffix = getSettings().LOCAL_VARIABLE_NAME_SUFFIX; - break; - case STATIC_FINAL_FIELD: - suffix = ""; - break; - default: - LOG.assertTrue(false); - break; - } - if (suffix == null) { - suffix = ""; - } - return suffix; - } - - @Nullable - private CodeStyleSettings.TypeToNameMap getMapByVariableKind(VariableKind variableKind) { - if (variableKind == VariableKind.FIELD) return getSettings().FIELD_TYPE_TO_NAME; - if (variableKind == VariableKind.STATIC_FIELD) return getSettings().STATIC_FIELD_TYPE_TO_NAME; - if (variableKind == VariableKind.PARAMETER) return getSettings().PARAMETER_TYPE_TO_NAME; - if (variableKind == VariableKind.LOCAL_VARIABLE) return getSettings().LOCAL_VARIABLE_TYPE_TO_NAME; - return null; - } - - @NonNls - private String changeIfNotIdentifier(String name) { - if (!isIdentifier(name)) { - return StringUtil.fixVariableNameDerivedFromPropertyName(name); - } - return name; - } - - private boolean isIdentifier(String name) { - return JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(name, LanguageLevel.HIGHEST); - } - - private CodeStyleSettings getSettings() { - return CodeStyleSettingsManager.getSettings(myProject); - } - - public static boolean isStringPsiLiteral(PsiElement element) { - if (element instanceof PsiLiteralExpression) { - final String text = element.getText(); - return text.length() > 1 && StringUtil.isQuotedString(text); - } - return false; - } -} +/* + * Copyright 2000-2011 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. + */ + +/* + * @author max + */ +package com.intellij.psi.impl.source.codeStyle; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.util.text.StringUtilRt; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.*; +import com.intellij.psi.impl.CheckUtil; +import com.intellij.psi.impl.source.SourceTreeToPsiMap; +import com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatement; +import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.statistics.JavaStatisticsManager; +import com.intellij.psi.util.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.beans.Introspector; +import java.util.*; + +public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl"); + + @NonNls private static final String IMPL_TYPNAME_SUFFIX = "Impl"; + @NonNls private static final String GET_PREFIX = "get"; + @NonNls private static final String IS_PREFIX = "is"; + @NonNls private static final String FIND_PREFIX = "find"; + @NonNls private static final String CREATE_PREFIX = "create"; + @NonNls private static final String WITH_PREFIX = "with"; + @NonNls private static final String SET_PREFIX = "set"; + + private final Project myProject; + + public JavaCodeStyleManagerImpl(final Project project) { + myProject = project; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { + return shortenClassReferences(element, 0); + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element, int flags) throws IncorrectOperationException { + CheckUtil.checkWritable(element); + if (!SourceTreeToPsiMap.hasTreeElement(element)) return element; + + return SourceTreeToPsiMap.treeElementToPsi( + new ReferenceAdjuster(myProject).process((TreeElement)element.getNode(), (flags & DO_NOT_ADD_IMPORTS) == 0, + (flags & UNCOMPLETE_CODE) != 0)); + } + + @Override + public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) + throws IncorrectOperationException { + CheckUtil.checkWritable(element); + if (SourceTreeToPsiMap.hasTreeElement(element)) { + new ReferenceAdjuster(myProject).processRange((TreeElement)element.getNode(), startOffset, endOffset); + } + } + + @Override + public PsiElement qualifyClassReferences(@NotNull PsiElement element) { + return SourceTreeToPsiMap.treeElementToPsi(new ReferenceAdjuster(true, true).process((TreeElement)element.getNode(), false, false)); + } + + @Override + public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { + CheckUtil.checkWritable(file); + if (file instanceof PsiJavaFile) { + PsiImportList newList = prepareOptimizeImportsResult((PsiJavaFile)file); + if (newList != null) { + final PsiImportList importList = ((PsiJavaFile)file).getImportList(); + if (importList != null) { + importList.replace(newList); + } + } + } + } + + @Override + public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { + return new ImportHelper(getSettings()).prepareOptimizeImportsResult(file); + } + + @Override + public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { + return new ImportHelper(getSettings()).addImport(file, refClass); + } + + @Override + public void removeRedundantImports(@NotNull final PsiJavaFile file) throws IncorrectOperationException { + final Collection redundants = findRedundantImports(file); + if (redundants == null) return; + + for (final PsiImportStatementBase importStatement : redundants) { + final PsiJavaCodeReferenceElement ref = importStatement.getImportReference(); + //Do not remove non-resolving refs + if (ref == null || ref.resolve() == null) { + continue; + } + + importStatement.delete(); + } + } + + @Override + @Nullable + public Collection findRedundantImports(final PsiJavaFile file) { + final PsiImportList importList = file.getImportList(); + if (importList == null) return null; + final PsiImportStatementBase[] imports = importList.getAllImportStatements(); + if( imports.length == 0 ) return null; + + Set allImports = new THashSet(Arrays.asList(imports)); + final Collection redundants; + if (JspPsiUtil.isInJspFile(file)) { + // remove only duplicate imports + redundants = new THashSet(TObjectHashingStrategy.IDENTITY); + ContainerUtil.addAll(redundants, imports); + redundants.removeAll(allImports); + for (PsiImportStatementBase importStatement : imports) { + if (importStatement instanceof JspxImportStatement && ((JspxImportStatement)importStatement).isForeignFileImport()) { + redundants.remove(importStatement); + } + } + } + else { + redundants = allImports; + final List roots = file.getViewProvider().getAllFiles(); + for (PsiElement root : roots) { + root.accept(new JavaRecursiveElementWalkingVisitor() { + @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + if (!reference.isQualified()) { + final JavaResolveResult resolveResult = reference.advancedResolve(false); + if (!inTheSamePackage(file, resolveResult.getElement())) { + final PsiElement resolveScope = resolveResult.getCurrentFileResolveScope(); + if (resolveScope instanceof PsiImportStatementBase) { + final PsiImportStatementBase importStatementBase = (PsiImportStatementBase)resolveScope; + redundants.remove(importStatementBase); + } + } + } + super.visitReferenceElement(reference); + } + + private boolean inTheSamePackage(PsiJavaFile file, PsiElement element) { + if (element instanceof PsiClass && ((PsiClass)element).getContainingClass() == null) { + final PsiFile containingFile = element.getContainingFile(); + if (containingFile instanceof PsiJavaFile) { + return Comparing.strEqual(file.getPackageName(), ((PsiJavaFile)containingFile).getPackageName()); + } + } + return false; + } + }); + } + } + return redundants; + } + + @Override + public int findEntryIndex(@NotNull PsiImportStatementBase statement) { + return new ImportHelper(getSettings()).findEntryIndex(statement); + } + + @Override + public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, + @Nullable final String propertyName, + @Nullable final PsiExpression expr, + @Nullable PsiType type, + final boolean correctKeywords) { + LinkedHashSet names = new LinkedHashSet(); + + if (expr != null && type == null) { + type = expr.getType(); + } + + if (propertyName != null) { + String[] namesByName = getSuggestionsByName(propertyName, kind, false, correctKeywords); + sortVariableNameSuggestions(namesByName, kind, propertyName, null); + ContainerUtil.addAll(names, namesByName); + } + + final NamesByExprInfo namesByExpr; + if (expr != null) { + namesByExpr = suggestVariableNameByExpression(expr, kind, correctKeywords); + if (namesByExpr.propertyName != null) { + sortVariableNameSuggestions(namesByExpr.names, kind, namesByExpr.propertyName, null); + } + ContainerUtil.addAll(names, namesByExpr.names); + } + else { + namesByExpr = null; + } + + if (type != null) { + String[] namesByType = suggestVariableNameByType(type, kind, correctKeywords); + sortVariableNameSuggestions(namesByType, kind, null, type); + ContainerUtil.addAll(names, namesByType); + } + + final String _propertyName; + if (propertyName != null) { + _propertyName = propertyName; + } + else { + _propertyName = namesByExpr != null ? namesByExpr.propertyName : null; + } + + addNamesFromStatistics(names, kind, _propertyName, type); + + String[] namesArray = ArrayUtil.toStringArray(names); + sortVariableNameSuggestions(namesArray, kind, _propertyName, type); + + final PsiType _type = type; + return new SuggestedNameInfo(namesArray) { + @Override + public void nameChoosen(String name) { + if (_propertyName != null || _type != null && _type.isValid()) { + JavaStatisticsManager.incVariableNameUseCount(name, kind, _propertyName, _type); + } + } + }; + } + + private static void addNamesFromStatistics(Set names, VariableKind variableKind, @Nullable String propertyName, @Nullable PsiType type) { + String[] allNames = JavaStatisticsManager.getAllVariableNamesUsed(variableKind, propertyName, type); + + int maxFrequency = 0; + for (String name : allNames) { + int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); + maxFrequency = Math.max(maxFrequency, count); + } + + int frequencyLimit = Math.max(5, maxFrequency / 2); + + for (String name : allNames) { + if( names.contains( name ) ) + { + continue; + } + int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); + if (LOG.isDebugEnabled()) { + LOG.debug("new name:" + name + " count:" + count); + LOG.debug("frequencyLimit:" + frequencyLimit); + } + if (count >= frequencyLimit) { + names.add(name); + } + } + + if (propertyName != null && type != null) { + addNamesFromStatistics(names, variableKind, propertyName, null); + addNamesFromStatistics(names, variableKind, null, type); + } + } + + private String[] suggestVariableNameByType(PsiType type, final VariableKind variableKind, boolean correctKeywords) { + String longTypeName = getLongTypeName(type); + CodeStyleSettings.TypeToNameMap map = getMapByVariableKind(variableKind); + if (map != null && longTypeName != null) { + if (type.equals(PsiType.NULL)) { + longTypeName = CommonClassNames.JAVA_LANG_OBJECT; + } + String name = map.nameByType(longTypeName); + if (name != null && isIdentifier(name)) { + return new String[]{name}; + } + } + + Collection suggestions = new LinkedHashSet(); + + suggestNamesForCollectionInheritors(type, variableKind, suggestions, correctKeywords); + suggestNamesFromGenericParameters(type, variableKind, suggestions, correctKeywords); + + String typeName = normalizeTypeName(getTypeName(type)); + if (typeName != null) { + ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, type instanceof PsiArrayType, correctKeywords)); + } + + return ArrayUtil.toStringArray(suggestions); + } + + private void suggestNamesFromGenericParameters(final PsiType type, + final VariableKind variableKind, + final Collection suggestions, boolean correctKeywords) { + if (!(type instanceof PsiClassType)) { + return; + } + StringBuilder fullNameBuilder = new StringBuilder(); + final PsiType[] parameters = ((PsiClassType)type).getParameters(); + for (PsiType parameter : parameters) { + if (parameter instanceof PsiClassType) { + final String typeName = normalizeTypeName(getTypeName(parameter)); + if (typeName != null) { + fullNameBuilder.append(typeName); + } + } + } + String baseName = normalizeTypeName(getTypeName(type)); + if (baseName != null) { + fullNameBuilder.append(baseName); + ContainerUtil.addAll(suggestions, getSuggestionsByName(fullNameBuilder.toString(), variableKind, false, correctKeywords)); + } + } + + private void suggestNamesForCollectionInheritors(final PsiType type, + final VariableKind variableKind, + Collection suggestions, boolean correctKeywords) { + PsiType componentType = PsiUtil.extractIterableTypeParameter(type, false); + if( componentType == null ) { + return; + } + String typeName = normalizeTypeName(getTypeName(componentType)); + if (typeName != null) { + ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, true, correctKeywords)); + } + } + + @Nullable + private static String normalizeTypeName(String typeName) { + if( typeName == null ) + { + return null; + } + if (typeName.endsWith(IMPL_TYPNAME_SUFFIX) && typeName.length() > IMPL_TYPNAME_SUFFIX.length()) { + return typeName.substring(0, typeName.length() - IMPL_TYPNAME_SUFFIX.length()); + } + return typeName; + } + + @Nullable + private static String getTypeName(PsiType type) { + type = type.getDeepComponentType(); + if (type instanceof PsiClassType) { + final PsiClassType classType = (PsiClassType)type; + final String className = classType.getClassName(); + if (className != null) { + return className; + } + else { + final PsiClass aClass = classType.resolve(); + if (aClass instanceof PsiAnonymousClass) { + return ((PsiAnonymousClass)aClass).getBaseClassType().getClassName(); + } + else { + return null; + } + } + } + else { + if (type instanceof PsiPrimitiveType) { + return type.getPresentableText(); + } + else { + if (type instanceof PsiWildcardType) { + return getTypeName(((PsiWildcardType)type).getExtendsBound()); + } + else { + if (type instanceof PsiIntersectionType) { + return getTypeName(((PsiIntersectionType)type).getRepresentative()); + } + else { + if (type instanceof PsiCapturedWildcardType) { + return getTypeName(((PsiCapturedWildcardType)type).getWildcard()); + } + else { + if (type instanceof PsiDisjunctionType) { + return getTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); + } + else { + LOG.error("Unknown type:" + type); + return null; + } + } + } + } + } + } + } + + @Nullable + private static String getLongTypeName(PsiType type) { + if (type instanceof PsiClassType) { + PsiClass aClass = ((PsiClassType)type).resolve(); + if( aClass == null ) + { + return null; + } + if (aClass instanceof PsiAnonymousClass) { + PsiClass baseClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve(); + if( baseClass == null ) + { + return null; + } + return baseClass.getQualifiedName(); + } + return aClass.getQualifiedName(); + } + else { + if (type instanceof PsiArrayType) { + return getLongTypeName(((PsiArrayType)type).getComponentType()) + "[]"; + } + else { + if (type instanceof PsiPrimitiveType) { + return type.getPresentableText(); + } + else { + if (type instanceof PsiWildcardType) { + final PsiType bound = ((PsiWildcardType)type).getBound(); + if (bound != null) { + return getLongTypeName(bound); + } + else { + return "java.lang.Object"; + } + } + else { + if (type instanceof PsiCapturedWildcardType) { + final PsiType bound = ((PsiCapturedWildcardType)type).getWildcard().getBound(); + if (bound != null) { + return getLongTypeName(bound); + } + else { + return "java.lang.Object"; + } + } + else { + if (type instanceof PsiIntersectionType) { + return getLongTypeName(((PsiIntersectionType)type).getRepresentative()); + } + else { + if (type instanceof PsiDisjunctionType) { + return getLongTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); + } + else { + LOG.error("Unknown type:" + type); + return null; + } + } + } + } + } + } + } + } + + private static class NamesByExprInfo { + final String[] names; + final String propertyName; + + public NamesByExprInfo(String propertyName, String... names) { + this.names = names; + this.propertyName = propertyName; + } + } + + private NamesByExprInfo suggestVariableNameByExpression(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { + final NamesByExprInfo names1 = suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords); + final NamesByExprInfo names2 = suggestVariableNameByExpressionPlace(expr, variableKind, correctKeywords); + + PsiType type = expr.getType(); + final String[] names3; + if (type != null) { + names3 = suggestVariableNameByType(type, variableKind, correctKeywords); + } + else { + names3 = null; + } + + final LinkedHashSet names = new LinkedHashSet(); + final String[] fromLiterals = suggestVariableNameFromLiterals(expr, variableKind, correctKeywords); + if (fromLiterals != null) { + ContainerUtil.addAll(names, fromLiterals); + } + ContainerUtil.addAll(names, names1.names); + ContainerUtil.addAll(names, names2.names); + if (names3 != null) { + ContainerUtil.addAll(names, names3); + } + + String[] namesArray = ArrayUtil.toStringArray(names); + String propertyName = names1.propertyName != null ? names1.propertyName : names2.propertyName; + return new NamesByExprInfo(propertyName, namesArray); + } + + @Nullable + private String[] suggestVariableNameFromLiterals(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { + final PsiElement[] literals = PsiTreeUtil.collectElements(expr, new PsiElementFilter() { + @Override + public boolean isAccepted(PsiElement element) { + if (isStringPsiLiteral(element) && StringUtil.isJavaIdentifier(StringUtil.unquoteString(element.getText()))) { + final PsiElement exprList = element.getParent(); + if (exprList instanceof PsiExpressionList) { + final PsiElement call = exprList.getParent(); + if (call instanceof PsiNewExpression) { + return true; + } else if (call instanceof PsiMethodCallExpression) { + //TODO: exclude or not getA().getB("name").getC(); or getA(getB("name").getC()); It works fine for now in the most cases + return true; + } + } + } + return false; + } + }); + + if (literals.length == 1) { + final String text = StringUtil.unquoteString(literals[0].getText()); + return getSuggestionsByName(text, variableKind, expr.getType() instanceof PsiArrayType, correctKeywords); + } + return null; + } + + private NamesByExprInfo suggestVariableNameByExpressionOnly(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { + if (expr instanceof PsiMethodCallExpression) { + PsiReferenceExpression methodExpr = ((PsiMethodCallExpression)expr).getMethodExpression(); + String methodName = methodExpr.getReferenceName(); + if (methodName != null) { + String[] words = NameUtil.nameToWords(methodName); + if (words.length > 0) { + final String firstWord = words[0]; + if (GET_PREFIX.equals(firstWord) + || IS_PREFIX.equals(firstWord) + || FIND_PREFIX.equals(firstWord) + || CREATE_PREFIX.equals(firstWord)) { + if (words.length > 1) { + final String propertyName = methodName.substring(firstWord.length()); + String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); + final PsiExpression qualifierExpression = methodExpr.getQualifierExpression(); + if (qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() instanceof PsiVariable) { + names = ArrayUtil.append(names, StringUtil.sanitizeJavaIdentifier(changeIfNotIdentifier(qualifierExpression.getText() + StringUtil.capitalize(propertyName)))); + } + return new NamesByExprInfo(propertyName, names); + } + } + else if (words.length == 1) { + return new NamesByExprInfo(methodName, getSuggestionsByName(methodName, variableKind, false, correctKeywords)); + } + } + } + } + else if (expr instanceof PsiReferenceExpression) { + String propertyName = ((PsiReferenceExpression)expr).getReferenceName(); + PsiElement refElement = ((PsiReferenceExpression)expr).resolve(); + if (refElement instanceof PsiVariable) { + VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); + propertyName = variableNameToPropertyName(propertyName, refVariableKind); + } + if (refElement != null && propertyName != null) { + String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); + return new NamesByExprInfo(propertyName, names); + } + } + else if (expr instanceof PsiArrayAccessExpression) { + PsiExpression arrayExpr = ((PsiArrayAccessExpression)expr).getArrayExpression(); + if (arrayExpr instanceof PsiReferenceExpression) { + String arrayName = ((PsiReferenceExpression)arrayExpr).getReferenceName(); + PsiElement refElement = ((PsiReferenceExpression)arrayExpr).resolve(); + if (refElement instanceof PsiVariable) { + VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); + arrayName = variableNameToPropertyName(arrayName, refVariableKind); + } + + if (arrayName != null) { + String name = StringUtil.unpluralize(arrayName); + if (name != null) { + String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); + return new NamesByExprInfo(name, names); + } + } + } + } + else if (expr instanceof PsiLiteralExpression && variableKind == VariableKind.STATIC_FINAL_FIELD) { + final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expr; + final Object value = literalExpression.getValue(); + if (value instanceof String) { + final String stringValue = (String)value; + String[] names = getSuggestionsByValue(stringValue); + if (names.length > 0) { + return new NamesByExprInfo(null, constantValueToConstantName(names)); + } + } + } else if (expr instanceof PsiParenthesizedExpression) { + return suggestVariableNameByExpressionOnly(((PsiParenthesizedExpression)expr).getExpression(), variableKind, correctKeywords); + } else if (expr instanceof PsiTypeCastExpression) { + return suggestVariableNameByExpressionOnly(((PsiTypeCastExpression)expr).getOperand(), variableKind, correctKeywords); + } else if (expr instanceof PsiLiteralExpression) { + final String text = StringUtil.stripQuotesAroundValue(expr.getText()); + if (isIdentifier(text)) { + return new NamesByExprInfo(text, getSuggestionsByName(text, variableKind, false, correctKeywords)); + } + } + + return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); + } + + private static String constantValueToConstantName(final String[] names) { + final StringBuilder result = new StringBuilder(); + for (int i = 0; i < names.length; i++) { + if (i > 0) result.append("_"); + result.append(names[i]); + } + return result.toString(); + } + + private static String[] getSuggestionsByValue(final String stringValue) { + List result = new ArrayList(); + StringBuffer currentWord = new StringBuffer(); + + boolean prevIsUpperCase = false; + + for (int i = 0; i < stringValue.length(); i++) { + final char c = stringValue.charAt(i); + if (Character.isUpperCase(c)) { + if (currentWord.length() > 0 && !prevIsUpperCase) { + result.add(currentWord.toString()); + currentWord = new StringBuffer(); + } + currentWord.append(c); + } else if (Character.isLowerCase(c)) { + currentWord.append(Character.toUpperCase(c)); + } else if (Character.isJavaIdentifierPart(c) && c != '_') { + if (Character.isJavaIdentifierStart(c) || currentWord.length() > 0 || !result.isEmpty()) { + currentWord.append(c); + } + } else { + if (currentWord.length() > 0) { + result.add(currentWord.toString()); + currentWord = new StringBuffer(); + } + } + + prevIsUpperCase = Character.isUpperCase(c); + } + + if (currentWord.length() > 0) { + result.add(currentWord.toString()); + } + return ArrayUtil.toStringArray(result); + } + + private NamesByExprInfo suggestVariableNameByExpressionPlace(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { + if (expr.getParent() instanceof PsiExpressionList) { + PsiExpressionList list = (PsiExpressionList)expr.getParent(); + PsiElement listParent = list.getParent(); + PsiSubstitutor subst = PsiSubstitutor.EMPTY; + PsiMethod method = null; + if (listParent instanceof PsiMethodCallExpression) { + final JavaResolveResult resolveResult = ((PsiMethodCallExpression)listParent).getMethodExpression().advancedResolve(false); + method = (PsiMethod)resolveResult.getElement(); + subst = resolveResult.getSubstitutor(); + } + else { + if (listParent instanceof PsiAnonymousClass) { + listParent = listParent.getParent(); + } + if (listParent instanceof PsiNewExpression) { + method = ((PsiNewExpression)listParent).resolveConstructor(); + } + } + + if (method != null) { + final PsiElement navElement = method.getNavigationElement(); + if (navElement instanceof PsiMethod) { + method = (PsiMethod)navElement; + } + PsiExpression[] expressions = list.getExpressions(); + int index = -1; + for (int i = 0; i < expressions.length; i++) { + if (expressions[i] == expr) { + index = i; + break; + } + } + PsiParameter[] parms = method.getParameterList().getParameters(); + if (index < parms.length) { + String name = parms[index].getName(); + if (name != null && TypeConversionUtil.areTypesAssignmentCompatible(subst.substitute(parms[index].getType()), expr)) { + name = variableNameToPropertyName(name, VariableKind.PARAMETER); + String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); + if (expressions.length == 1) { + final String methodName = method.getName(); + String[] words = NameUtil.nameToWords(methodName); + if (words.length > 0) { + final String firstWord = words[0]; + if (SET_PREFIX.equals(firstWord)) { + final String propertyName = methodName.substring(firstWord.length()); + final String[] setterNames = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); + names = ArrayUtil.mergeArrays(names, setterNames); + } + } + } + return new NamesByExprInfo(name, names); + } + } + } + } + else if (expr.getParent() instanceof PsiAssignmentExpression && variableKind == VariableKind.PARAMETER) { + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expr.getParent(); + if (expr == assignmentExpression.getRExpression()) { + final PsiExpression leftExpression = assignmentExpression.getLExpression(); + if (leftExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression) leftExpression).getQualifier() == null) { + String name = leftExpression.getText(); + if (name != null) { + final PsiElement resolve = ((PsiReferenceExpression)leftExpression).resolve(); + if (resolve instanceof PsiVariable) { + name = variableNameToPropertyName(name, getVariableKind((PsiVariable)resolve)); + } + String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); + return new NamesByExprInfo(name, names); + } + } + } + } + + return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); + } + + @Override + public String variableNameToPropertyName(String name, VariableKind variableKind) { + if (variableKind == VariableKind.STATIC_FINAL_FIELD) { + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c != '_') { + if( Character.isLowerCase( c ) ) + { + return variableNameToPropertyNameInner( name, variableKind ); + } + + buffer.append(Character.toLowerCase(c)); + continue; + } + i++; + if (i < name.length()) { + c = name.charAt(i); + buffer.append(c); + } + } + return buffer.toString(); + } + + return variableNameToPropertyNameInner(name, variableKind); + } + + private String variableNameToPropertyNameInner(String name, VariableKind variableKind) { + String prefix = getPrefixByVariableKind(variableKind); + String suffix = getSuffixByVariableKind(variableKind); + boolean doDecapitalize = false; + + if (name.startsWith(prefix) && name.length() > prefix.length()) { + name = name.substring(prefix.length()); + doDecapitalize = true; + } + + if (name.endsWith(suffix) && name.length() > suffix.length()) { + name = name.substring(0, name.length() - suffix.length()); + doDecapitalize = true; + } + + if (name.startsWith(IS_PREFIX) && name.length() > IS_PREFIX.length() && Character.isUpperCase(name.charAt(IS_PREFIX.length()))) { + name = name.substring(IS_PREFIX.length()); + doDecapitalize = true; + } + + if (doDecapitalize) { + name = Introspector.decapitalize(name); + } + + return name; + } + + @Override + public String propertyNameToVariableName(String propertyName, VariableKind variableKind) { + if (variableKind == VariableKind.STATIC_FINAL_FIELD) { + String[] words = NameUtil.nameToWords(propertyName); + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < words.length; i++) { + String word = words[i]; + if (i > 0) { + buffer.append("_"); + } + buffer.append(StringUtilRt.toUpperCase(word)); + } + return buffer.toString(); + } + + String prefix = getPrefixByVariableKind(variableKind); + String name = propertyName; + if (name.length() > 0 && prefix.length() > 0 && !StringUtil.endsWithChar(prefix, '_')) { + name = Character.toUpperCase(name.charAt(0)) + name.substring(1); + } + name = prefix + name + getSuffixByVariableKind(variableKind); + name = changeIfNotIdentifier(name); + return name; + } + + private String[] getSuggestionsByName(String name, VariableKind variableKind, boolean isArray, boolean correctKeywords) { + boolean upperCaseStyle = variableKind == VariableKind.STATIC_FINAL_FIELD; + boolean preferLongerNames = getSettings().PREFER_LONGER_NAMES; + String prefix = getPrefixByVariableKind(variableKind); + String suffix = getSuffixByVariableKind(variableKind); + + List answer = new ArrayList(); + for (String suggestion : NameUtil.getSuggestionsByName(name, prefix, suffix, upperCaseStyle, preferLongerNames, isArray)) { + answer.add(correctKeywords ? changeIfNotIdentifier(suggestion) : suggestion); + } + + return ArrayUtil.toStringArray(answer); + } + + @Override + public String suggestUniqueVariableName(String baseName, PsiElement place, boolean lookForward) { + int index = 0; + PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); + NextName: + while (true) { + String name = baseName; + if (index > 0) { + name += index; + } + index++; + if (PsiUtil.isVariableNameUnique(name, place)) { + if (lookForward) { + final String name1 = name; + PsiElement run = scope; + while (run != null) { + class CancelException extends RuntimeException { + } + try { + run.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitAnonymousClass(final PsiAnonymousClass aClass) { + } + + @Override public void visitVariable(PsiVariable variable) { + if (name1.equals(variable.getName())) { + throw new CancelException(); + } + } + }); + } + catch (CancelException e) { + continue NextName; + } + run = run.getNextSibling(); + if (scope instanceof PsiMethod) {//do not check next member for param name conflict + break; + } + } + + } + return name; + } + } + } + + @Override + @NotNull + public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward) { + final String[] names = baseNameInfo.names; + final LinkedHashSet uniqueNames = new LinkedHashSet(names.length); + for (String name : names) { + if (ignorePlaceName && place instanceof PsiNamedElement) { + final String placeName = ((PsiNamedElement)place).getName(); + if (Comparing.strEqual(placeName, name)) { + uniqueNames.add(name); + continue; + } + } + uniqueNames.add(suggestUniqueVariableName(name, place, lookForward)); + } + + return new SuggestedNameInfo(ArrayUtil.toStringArray(uniqueNames)) { + @Override + public void nameChoosen(String name) { + baseNameInfo.nameChoosen(name); + } + }; + } + + private static void sortVariableNameSuggestions(String[] names, + final VariableKind variableKind, + @Nullable final String propertyName, + @Nullable final PsiType type) { + if( names.length <= 1 ) { + return; + } + + if (LOG.isDebugEnabled()) { + LOG.debug("sorting names:" + variableKind); + if (propertyName != null) { + LOG.debug("propertyName:" + propertyName); + } + if (type != null) { + LOG.debug("type:" + type); + } + for (String name : names) { + int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); + LOG.debug(name + " : " + count); + } + } + + Comparator comparator = new Comparator() { + @Override + public int compare(String s1, String s2) { + int count1 = JavaStatisticsManager.getVariableNameUseCount(s1, variableKind, propertyName, type); + int count2 = JavaStatisticsManager.getVariableNameUseCount(s2, variableKind, propertyName, type); + return count2 - count1; + } + }; + Arrays.sort(names, comparator); + } + + @Override + @NotNull + public String getPrefixByVariableKind(VariableKind variableKind) { + String prefix = ""; + switch (variableKind) { + case FIELD: + prefix = getSettings().FIELD_NAME_PREFIX; + break; + case STATIC_FIELD: + prefix = getSettings().STATIC_FIELD_NAME_PREFIX; + break; + case PARAMETER: + prefix = getSettings().PARAMETER_NAME_PREFIX; + break; + case LOCAL_VARIABLE: + prefix = getSettings().LOCAL_VARIABLE_NAME_PREFIX; + break; + case STATIC_FINAL_FIELD: + prefix = ""; + break; + default: + LOG.assertTrue(false); + break; + } + if (prefix == null) { + prefix = ""; + } + return prefix; + } + + @Override + @NotNull + public String getSuffixByVariableKind(VariableKind variableKind) { + String suffix = ""; + switch (variableKind) { + case FIELD: + suffix = getSettings().FIELD_NAME_SUFFIX; + break; + case STATIC_FIELD: + suffix = getSettings().STATIC_FIELD_NAME_SUFFIX; + break; + case PARAMETER: + suffix = getSettings().PARAMETER_NAME_SUFFIX; + break; + case LOCAL_VARIABLE: + suffix = getSettings().LOCAL_VARIABLE_NAME_SUFFIX; + break; + case STATIC_FINAL_FIELD: + suffix = ""; + break; + default: + LOG.assertTrue(false); + break; + } + if (suffix == null) { + suffix = ""; + } + return suffix; + } + + @Nullable + private CodeStyleSettings.TypeToNameMap getMapByVariableKind(VariableKind variableKind) { + if (variableKind == VariableKind.FIELD) return getSettings().FIELD_TYPE_TO_NAME; + if (variableKind == VariableKind.STATIC_FIELD) return getSettings().STATIC_FIELD_TYPE_TO_NAME; + if (variableKind == VariableKind.PARAMETER) return getSettings().PARAMETER_TYPE_TO_NAME; + if (variableKind == VariableKind.LOCAL_VARIABLE) return getSettings().LOCAL_VARIABLE_TYPE_TO_NAME; + return null; + } + + @NonNls + private String changeIfNotIdentifier(String name) { + if (!isIdentifier(name)) { + return StringUtil.fixVariableNameDerivedFromPropertyName(name); + } + return name; + } + + private boolean isIdentifier(String name) { + return JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(name, LanguageLevel.HIGHEST); + } + + private CodeStyleSettings getSettings() { + return CodeStyleSettingsManager.getSettings(myProject); + } + + public static boolean isStringPsiLiteral(PsiElement element) { + if (element instanceof PsiLiteralExpression) { + final String text = element.getText(); + return text.length() > 1 && StringUtil.isQuotedString(text); + } + return false; + } +} diff --git a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java index 5bc23c8e1cf1..9f24c2a5085c 100644 --- a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java +++ b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java @@ -1,194 +1,213 @@ -/* - * Copyright 2000-2011 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. - */ - -/* - * @author max - */ -package com.intellij.psi.codeStyle; - -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; -import org.intellij.lang.annotations.MagicConstant; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; - -public abstract class JavaCodeStyleManager { - public static JavaCodeStyleManager getInstance(Project project) { - return ServiceManager.getService(project, JavaCodeStyleManager.class); - } - - public static final int DO_NOT_ADD_IMPORTS = 0x1000; - public static final int UNCOMPLETE_CODE = 0x2000; - - public abstract boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass); - public abstract PsiElement shortenClassReferences(@NotNull PsiElement element, @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) throws IncorrectOperationException; - - @NotNull public abstract String getPrefixByVariableKind(VariableKind variableKind); - @NotNull public abstract String getSuffixByVariableKind(VariableKind variableKind); - - public abstract int findEntryIndex(@NotNull PsiImportStatementBase statement); - - /** - * Replaces fully-qualified class names in the contents of the specified element with - * non-qualified names and adds import statements as necessary. - * - * @param element the element to shorten references in. - * @return the element in the PSI tree after the shorten references operation corresponding - * to the original element. - * @throws com.intellij.util.IncorrectOperationException if the file to shorten references in is read-only. - */ - public abstract PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException; - - /** - * Replaces fully-qualified class names in a part of contents of the specified element with - * non-qualified names and adds import statements as necessary. - * - * @param element the element to shorten references in. - * @param startOffset the start offset in the element of the part where class references are - * shortened. - * @param endOffset the end offset in the element of the part where class references are - * shortened. - * @throws IncorrectOperationException if the file to shorten references in is read-only. - */ - public abstract void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException; - - /** - * Optimizes imports in the specified Java or JSP file. - * - * @param file the file to optimize the imports in. - * @throws IncorrectOperationException if the file is read-only. - */ - public abstract void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException; - - /** - * Calculates the import list that would be substituted in the specified Java or JSP - * file if an Optimize Imports operation was performed on it. - * - * @param file the file to calculate the import list for. - * @return the calculated import list. - */ - public abstract PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file); - - /** - * Returns the kind of the specified variable (local, parameter, field, static field or static - * final field). - * - * @param variable the variable to get the kind for. - * @return the variable kind. - */ - public abstract VariableKind getVariableKind(@NotNull PsiVariable variable); - - public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, - @Nullable final String propertyName, - @Nullable final PsiExpression expr, - @Nullable PsiType type) { - return suggestVariableName(kind, propertyName, expr, type, true); - } - - - public abstract SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, - @Nullable String propertyName, - @Nullable PsiExpression expr, - @Nullable PsiType type, - boolean correctKeywords); - /** - * Generates a stripped-down name (with no code style defined prefixes or suffixes, usable as - * a property name) from the specified name of a variable of the specified kind. - * - * @param name the name of the variable. - * @param variableKind the kind of the variable. - * @return the stripped-down name. - */ - public abstract String variableNameToPropertyName(@NonNls String name, VariableKind variableKind); - - /** - * Appends code style defined prefixes and/or suffixes for the specified variable kind - * to the specified variable name. - * - * @param propertyName the base name of the variable. - * @param variableKind the kind of the variable. - * @return the variable name. - */ - public abstract String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind); - - /** - * Suggests a unique name for the variable used at the specified location. - * - * @param baseName the base name for the variable. - * @param place the location where the variable will be used. - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward - * @return the generated unique name, - */ - public abstract String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward); - - /** - * Suggests a unique name for the variable used at the specified location. - * - * @param baseNameInfo the base name info for the variable. - * @param place the location where the variable will be used. - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward - * @return the generated unique name - */ - @NotNull - public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean lookForward) { - return suggestUniqueVariableName(baseNameInfo, place, false, lookForward); - } - - /** - * Suggests a unique name for the variable used at the specified location. - * - * - * @param baseNameInfo the base name info for the variable. - * @param place the location where the variable will be used. - * @param ignorePlaceName if true and place is PsiNamedElement, place.getName() would be still treated as unique name - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward @return the generated unique name, - * @return the generated unique name - */ - @NotNull public abstract SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean ignorePlaceName, - boolean lookForward); - - /** - * Replaces all references to Java classes in the contents of the specified element, - * except for references to classes in the same package or in implicitly imported packages, - * with full-qualified references. - * - * @param element the element to replace the references in. - * @return the element in the PSI tree after the qualify operation corresponding to the - * original element. - */ - public abstract PsiElement qualifyClassReferences(@NotNull PsiElement element); - - /** - * Removes unused import statements from the specified Java file. - * - * @param file the file to remove the import statements from. - * @throws IncorrectOperationException if the operation fails for some reason (for example, - * the file is read-only). - */ - public abstract void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException; - - @Nullable - public abstract Collection findRedundantImports(PsiJavaFile file); -} +/* + * Copyright 2000-2011 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. + */ + +/* + * @author max + */ +package com.intellij.psi.codeStyle; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public abstract class JavaCodeStyleManager { + public static JavaCodeStyleManager getInstance(Project project) { + return ServiceManager.getService(project, JavaCodeStyleManager.class); + } + + public static final int DO_NOT_ADD_IMPORTS = 0x1000; + public static final int UNCOMPLETE_CODE = 0x2000; + + public abstract boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass); + public abstract PsiElement shortenClassReferences(@NotNull PsiElement element, @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) throws IncorrectOperationException; + + @NotNull public abstract String getPrefixByVariableKind(VariableKind variableKind); + @NotNull public abstract String getSuffixByVariableKind(VariableKind variableKind); + + public abstract int findEntryIndex(@NotNull PsiImportStatementBase statement); + + /** + * Replaces fully-qualified class names in the contents of the specified element with + * non-qualified names and adds import statements as necessary. + * + * @param element the element to shorten references in. + * @return the element in the PSI tree after the shorten references operation corresponding + * to the original element. + * @throws com.intellij.util.IncorrectOperationException if the file to shorten references in is read-only. + */ + public abstract PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException; + + /** + * Replaces fully-qualified class names in a part of contents of the specified element with + * non-qualified names and adds import statements as necessary. + * + * @param element the element to shorten references in. + * @param startOffset the start offset in the element of the part where class references are + * shortened. + * @param endOffset the end offset in the element of the part where class references are + * shortened. + * @throws IncorrectOperationException if the file to shorten references in is read-only. + */ + public abstract void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException; + + /** + * Optimizes imports in the specified Java or JSP file. + * + * @param file the file to optimize the imports in. + * @throws IncorrectOperationException if the file is read-only. + */ + public abstract void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException; + + /** + * Calculates the import list that would be substituted in the specified Java or JSP + * file if an Optimize Imports operation was performed on it. + * + * @param file the file to calculate the import list for. + * @return the calculated import list. + */ + public abstract PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file); + + /** + * Returns the kind of the specified variable (local, parameter, field, static field or static + * final field). + * + * @param variable the variable to get the kind for. + * @return the variable kind. + */ + public VariableKind getVariableKind(@NotNull PsiVariable variable){ + if (variable instanceof PsiField) { + if (variable.hasModifierProperty(PsiModifier.STATIC)) { + if (variable.hasModifierProperty(PsiModifier.FINAL)) { + return VariableKind.STATIC_FINAL_FIELD; + } + return VariableKind.STATIC_FIELD; + } + return VariableKind.FIELD; + } + else { + if (variable instanceof PsiParameter) { + if (((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { + return VariableKind.LOCAL_VARIABLE; + } + return VariableKind.PARAMETER; + } + return VariableKind.LOCAL_VARIABLE; + } + } + + public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, + @Nullable final String propertyName, + @Nullable final PsiExpression expr, + @Nullable PsiType type) { + return suggestVariableName(kind, propertyName, expr, type, true); + } + + + public abstract SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, + @Nullable String propertyName, + @Nullable PsiExpression expr, + @Nullable PsiType type, + boolean correctKeywords); + /** + * Generates a stripped-down name (with no code style defined prefixes or suffixes, usable as + * a property name) from the specified name of a variable of the specified kind. + * + * @param name the name of the variable. + * @param variableKind the kind of the variable. + * @return the stripped-down name. + */ + public abstract String variableNameToPropertyName(@NonNls String name, VariableKind variableKind); + + /** + * Appends code style defined prefixes and/or suffixes for the specified variable kind + * to the specified variable name. + * + * @param propertyName the base name of the variable. + * @param variableKind the kind of the variable. + * @return the variable name. + */ + public abstract String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind); + + /** + * Suggests a unique name for the variable used at the specified location. + * + * @param baseName the base name for the variable. + * @param place the location where the variable will be used. + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward + * @return the generated unique name, + */ + public abstract String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward); + + /** + * Suggests a unique name for the variable used at the specified location. + * + * @param baseNameInfo the base name info for the variable. + * @param place the location where the variable will be used. + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward + * @return the generated unique name + */ + @NotNull + public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean lookForward) { + return suggestUniqueVariableName(baseNameInfo, place, false, lookForward); + } + + /** + * Suggests a unique name for the variable used at the specified location. + * + * + * @param baseNameInfo the base name info for the variable. + * @param place the location where the variable will be used. + * @param ignorePlaceName if true and place is PsiNamedElement, place.getName() would be still treated as unique name + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward @return the generated unique name, + * @return the generated unique name + */ + @NotNull public abstract SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward); + + /** + * Replaces all references to Java classes in the contents of the specified element, + * except for references to classes in the same package or in implicitly imported packages, + * with full-qualified references. + * + * @param element the element to replace the references in. + * @return the element in the PSI tree after the qualify operation corresponding to the + * original element. + */ + public abstract PsiElement qualifyClassReferences(@NotNull PsiElement element); + + /** + * Removes unused import statements from the specified Java file. + * + * @param file the file to remove the import statements from. + * @throws IncorrectOperationException if the operation fails for some reason (for example, + * the file is read-only). + */ + public abstract void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException; + + @Nullable + public abstract Collection findRedundantImports(PsiJavaFile file); +} diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java index 7f651a21df0e..4e9f5e68a6f8 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -75,18 +75,13 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { return null; } - @Override - public VariableKind getVariableKind(@NotNull PsiVariable variable) { - return null; - } - @Override public SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, @Nullable String propertyName, @Nullable PsiExpression expr, @Nullable PsiType type, boolean correctKeywords) { - return null; + return SuggestedNameInfo.NULL_INFO; } @Override @@ -115,7 +110,7 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { @Override public PsiElement qualifyClassReferences(@NotNull PsiElement element) { - return null; + return element; } @Override From d4a80cc3ce6b5ca9395e34c824d3ce749956544b Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Thu, 10 May 2012 10:07:19 +0200 Subject: [PATCH 14/67] Move EmptyProgressIndicator to core --- .../openapi/progress/EmptyProgressIndicator.java | 9 --------- .../intellij/util/graph/KShortestPathsFinderTest.java | 1 - .../com/intellij/util/continuation/GeneralRunner.java | 5 ----- .../org/jetbrains/idea/maven/MavenImportingTestCase.java | 1 - 4 files changed, 16 deletions(-) rename platform/{platform-api => core-api}/src/com/intellij/openapi/progress/EmptyProgressIndicator.java (94%) diff --git a/platform/platform-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java b/platform/core-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java similarity index 94% rename from platform/platform-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java rename to platform/core-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java index b367ea3c9aa7..1e745be27edb 100644 --- a/platform/platform-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java +++ b/platform/core-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java @@ -95,15 +95,6 @@ public class EmptyProgressIndicator implements ProgressIndicator { return false; } - - public void finish(final Task task) { - myFinished = true; - } - - public boolean isFinished(final Task task) { - return myFinished; - } - public void setIndeterminate(boolean indeterminate) { } diff --git a/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java b/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java index daf7f42780af..9763626760d3 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java @@ -18,7 +18,6 @@ package com.intellij.util.graph; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.util.text.StringUtil; import com.intellij.testFramework.UsefulTestCase; -import com.intellij.util.graph.impl.KShortestPathsFinder; import java.util.*; diff --git a/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java b/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java index 3a3e1e7bbe3b..6cd97ac1e322 100644 --- a/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java +++ b/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java @@ -15,11 +15,7 @@ */ package com.intellij.util.continuation; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; -import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.CalledInAny; import com.intellij.openapi.vcs.CalledInAwt; @@ -28,7 +24,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; /** * @author irengrig diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java index 13b1770f6776..793cb5c86874 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java @@ -34,7 +34,6 @@ import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TestDialog; import com.intellij.openapi.util.AsyncResult; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtil; From 54ca1712341803506c9b7443c7cd6103e4e5c495 Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Thu, 10 May 2012 10:09:18 +0200 Subject: [PATCH 15/67] Instantiate ProgressIndicatorProvider.ourInstance in CoreEnvironment --- .../com/intellij/core/CoreEnvironment.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java index 60949a95f064..3d683f9bd677 100644 --- a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java +++ b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java @@ -29,6 +29,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.ExtensionsArea; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.progress.*; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; @@ -148,6 +149,26 @@ public class CoreEnvironment { myProject.registerService(PsiDirectoryFactory.class, new PsiDirectoryFactoryImpl(myPsiManager)); myProject.registerService(ProjectScopeBuilder.class, new CoreProjectScopeBuilder(myProject, myFileIndexFacade)); myProject.registerService(DumbService.class, new MockDumbService(myProject)); + + ProgressIndicatorProvider.ourInstance = new ProgressIndicatorProvider() { + @Override + public ProgressIndicator getProgressIndicator() { + return new EmptyProgressIndicator(); + } + + @Override + protected void doCheckCanceled() throws ProcessCanceledException { + } + + @Override + public NonCancelableSection startNonCancelableSection() { + return new NonCancelableSection() { + @Override + public void done() { + } + }; + } + }; } public Project getProject() { From 67bf2bb4c75f7b8a30d3ea87fa151d30c44df4c5 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Tue, 8 May 2012 18:26:13 +0200 Subject: [PATCH 16/67] FileBasedIndex --- .../psi/impl/cache/impl/IdCacheTest.java | 6 +- .../intellij/psi/search/UpdateCacheTest.java | 5 +- .../intellij/find/impl/FindInProjectUtil.java | 3 +- .../impl/cache/impl/id/IdTableBuilding.java | 2 +- .../psi/impl/cache/impl/todo/TodoIndex.java | 2 +- .../com/intellij/psi/stubs/StubIndexImpl.java | 12 +- .../intellij/psi/stubs/StubUpdatingIndex.java | 2 +- .../util/indexing/FileBasedIndex.java | 2341 +---------------- .../util/indexing/FileBasedIndexImpl.java | 2327 ++++++++++++++++ .../FileBasedIndexProjectHandler.java | 4 +- .../util/indexing/UnindexedFilesUpdater.java | 6 +- .../src/componentSets/Lang.xml | 3 +- .../testFramework/LightPlatformTestCase.java | 3 +- 13 files changed, 2407 insertions(+), 2309 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java index 5ec392f58c23..eaf7ae618ffe 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java @@ -21,6 +21,7 @@ import com.intellij.psi.search.UsageSearchContext; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import java.io.File; import java.util.Arrays; @@ -35,9 +36,8 @@ public class IdCacheTest extends CodeInsightTestCase{ protected void setUp() throws Exception { super.setUp(); - final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance(); - fileBasedIndex.requestRebuild(IdIndex.NAME); - fileBasedIndex.requestRebuild(TodoIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(IdIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(TodoIndex.NAME); String root = JavaTestUtil.getJavaTestDataPath()+ "/psi/impl/cache/"; diff --git a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java index cd2cf6890ac3..be90964eafae 100644 --- a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java @@ -44,6 +44,7 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import org.jetbrains.annotations.NonNls; import java.io.File; @@ -55,8 +56,8 @@ public class UpdateCacheTest extends PsiTestCase{ protected void setUp() throws Exception { super.setUp(); - FileBasedIndex.requestRebuild(IdIndex.NAME); - FileBasedIndex.requestRebuild(TodoIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(IdIndex.NAME); + FileBasedIndex.getInstance().requestRebuild(TodoIndex.NAME); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index a9c2eb118461..e5601ebb1b87 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -502,8 +502,7 @@ public class FindInProjectUtil { if (!keys.isEmpty()) { fast = true; List hits = new ArrayList(); - FileBasedIndex.getInstance() - .getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); + FileBasedIndex.getInstance().getFilesWithKey(TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor(hits), scope); for (VirtualFile hit : hits) { resultFiles.add(pm.findFile(hit)); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java index 8e09281d2675..bb8dc7f3104f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java @@ -322,7 +322,7 @@ public class IdTableBuilding { final OccurrenceConsumer occurrenceConsumer = new OccurrenceConsumer(null, true); EditorHighlighter highlighter; - final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndex.EDITOR_HIGHLIGHTER); + final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndexImpl.EDITOR_HIGHLIGHTER); if (editorHighlighter != null && checkCanUseCachedEditorHighlighter(chars, editorHighlighter)) { highlighter = editorHighlighter; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index 594436346a7d..e4c91b7904da 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -54,7 +54,7 @@ public class TodoIndex extends FileBasedIndexExtension messageBus.connect().subscribe(IndexPatternProvider.INDEX_PATTERNS_CHANGED, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - FileBasedIndex.requestRebuild(NAME); + FileBasedIndex.getInstance().requestRebuild(NAME); } }); } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java index d11e89e0f5a7..05a5e6d08e00 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java @@ -200,7 +200,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe @NotNull final Project project, @Nullable final GlobalSearchScope scope, @NotNull final Processor processor) { - final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance(); + final FileBasedIndexImpl fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance(); fileBasedIndex.ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, scope); final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); @@ -211,11 +211,11 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe try { try { // disable up-to-date check to avoid locks on attempt to acquire index write lock while holding at the same time the readLock for this index - FileBasedIndex.disableUpToDateCheckForCurrentThread(); + FileBasedIndexImpl.disableUpToDateCheckForCurrentThread(); index.getReadLock().lock(); final ValueContainer container = index.getData(key); - final FileBasedIndex.ProjectIndexableFilesFilter projectFilesFilter = fileBasedIndex.projectIndexableFiles(project); + final FileBasedIndexImpl.ProjectIndexableFilesFilter projectFilesFilter = fileBasedIndex.projectIndexableFiles(project); return container.forEach(new ValueContainer.ContainerAction() { @Override @@ -320,14 +320,14 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe } finally { index.getReadLock().unlock(); - FileBasedIndex.enableUpToDateCheckForCurrentThread(); + FileBasedIndexImpl.enableUpToDateCheckForCurrentThread(); } } catch (StorageException e) { forceRebuild(e); } catch (RuntimeException e) { - final Throwable cause = FileBasedIndex.getCauseToRebuildIndex(e); + final Throwable cause = FileBasedIndexImpl.getCauseToRebuildIndex(e); if (cause != null) { forceRebuild(cause); } @@ -354,7 +354,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe } private static void requestRebuild() { - FileBasedIndex.requestRebuild(StubUpdatingIndex.INDEX_ID); + FileBasedIndex.getInstance().requestRebuild(StubUpdatingIndex.INDEX_ID); } @Override diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 40fa9d8ac2cd..428f29dd556e 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -232,7 +232,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi } catch (StorageException e) { LOG.info(e); - FileBasedIndex.requestRebuild(INDEX_ID); + FileBasedIndex.getInstance().requestRebuild(INDEX_ID); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 6e8bcf2a307b..c2f3ad423b19 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -13,1676 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.indexing; -import com.intellij.AppTopics; -import com.intellij.history.LocalHistory; -import com.intellij.ide.caches.CacheUpdater; -import com.intellij.lang.ASTNode; -import com.intellij.notification.NotificationDisplayType; -import com.intellij.notification.NotificationGroup; -import com.intellij.notification.NotificationType; -import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ApplicationComponent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.impl.EditorHighlighterCache; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; -import com.intellij.openapi.fileTypes.*; -import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.*; -import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; -import com.intellij.openapi.project.*; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.vfs.*; -import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; -import com.intellij.openapi.vfs.newvfs.BulkFileListener; -import com.intellij.openapi.vfs.newvfs.ManagingFS; -import com.intellij.openapi.vfs.newvfs.NewVirtualFile; -import com.intellij.openapi.vfs.newvfs.events.VFileEvent; -import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon; -import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiDocumentTransactionListener; -import com.intellij.psi.impl.source.PsiFileImpl; -import com.intellij.psi.search.EverythingGlobalScope; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.stubs.SerializationManager; -import com.intellij.util.*; -import com.intellij.util.concurrency.Semaphore; -import com.intellij.util.containers.ConcurrentHashSet; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.io.*; -import com.intellij.util.io.DataOutputStream; -import com.intellij.util.io.storage.HeavyProcessLatch; -import com.intellij.util.messages.MessageBus; -import com.intellij.util.messages.MessageBusConnection; -import gnu.trove.*; +import com.intellij.util.Processor; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.io.*; -import java.lang.ref.SoftReference; -import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Collection; +import java.util.List; +import java.util.Set; /** - * @author Eugene Zhuravlev - * Date: Dec 20, 2007 + * Author: dmitrylomov */ - -public class FileBasedIndex implements ApplicationComponent { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.FileBasedIndex"); - @NonNls - private static final String CORRUPTION_MARKER_NAME = "corruption.marker"; - private final Map, Pair, InputFilter>> myIndices = new THashMap, Pair, InputFilter>>(); - private final Map, Semaphore> myUnsavedDataIndexingSemaphores = new THashMap, Semaphore>(); - private final TObjectIntHashMap> myIndexIdToVersionMap = new TObjectIntHashMap>(); - private final Set> myNotRequiringContentIndices = new THashSet>(); - private final Set> myRequiringContentIndices = new THashSet>(); - private final Set myNoLimitCheckTypes = new THashSet(); - - private final PerIndexDocumentVersionMap myLastIndexedDocStamps = new PerIndexDocumentVersionMap(); - @NotNull private final ChangedFilesCollector myChangedFilesCollector; - - private final List myIndexableSets = ContainerUtil.createEmptyCOWList(); - private final Map myIndexableSetToProjectMap = new THashMap(); - - private static final int OK = 1; - private static final int REQUIRES_REBUILD = 2; - private static final int REBUILD_IN_PROGRESS = 3; - private static final Map, AtomicInteger> ourRebuildStatus = new THashMap, AtomicInteger>(); - - private final VirtualFileManagerEx myVfManager; - private final FileDocumentManager myFileDocumentManager; - private final FileTypeManager myFileTypeManager; - private final ConcurrentHashSet> myUpToDateIndices = new ConcurrentHashSet>(); - private final Map myTransactionMap = new THashMap(); - - private static final int ALREADY_PROCESSED = 0x04; - - @Nullable private final String myConfigPath; - @Nullable private final String mySystemPath; - private final boolean myIsUnitTestMode; - @Nullable private ScheduledFuture myFlushingFuture; - private volatile int myLocalModCount; - private volatile int myFilesModCount; - - public void requestReindex(@NotNull final VirtualFile file) { - myChangedFilesCollector.invalidateIndices(file, true); - } - - public void requestReindexExcluded(@NotNull final VirtualFile file) { - myChangedFilesCollector.invalidateIndices(file, false); - } - - public FileBasedIndex(final VirtualFileManagerEx vfManager, FileDocumentManager fdm, - FileTypeManager fileTypeManager, @NotNull MessageBus bus, SerializationManager sm /*need this parameter to ensure component dependency*/) throws IOException { - myVfManager = vfManager; - myFileDocumentManager = fdm; - myFileTypeManager = fileTypeManager; - myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); - myConfigPath = calcConfigPath(PathManager.getConfigPath()); - mySystemPath = calcConfigPath(PathManager.getSystemPath()); - - final MessageBusConnection connection = bus.connect(); - connection.subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { - @Override - public void transactionStarted(final Document doc, final PsiFile file) { - if (file != null) { - synchronized (myTransactionMap) { - myTransactionMap.put(doc, file); - } - myUpToDateIndices.clear(); - } - } - - @Override - public void transactionCompleted(final Document doc, final PsiFile file) { - synchronized (myTransactionMap) { - myTransactionMap.remove(doc); - } - } - }); - - connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener() { - @Nullable private Map> myTypeToExtensionMap; - @Override - public void beforeFileTypesChanged(final FileTypeEvent event) { - cleanupProcessedFlag(); - myTypeToExtensionMap = new THashMap>(); - for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { - myTypeToExtensionMap.put(type, getExtensions(type)); - } - } - - @Override - public void fileTypesChanged(final FileTypeEvent event) { - final Map> oldExtensions = myTypeToExtensionMap; - myTypeToExtensionMap = null; - if (oldExtensions != null) { - final Map> newExtensions = new THashMap>(); - for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { - newExtensions.put(type, getExtensions(type)); - } - // we are interested only in extension changes or removals. - // addition of an extension is handled separately by RootsChanged event - if (!newExtensions.keySet().containsAll(oldExtensions.keySet())) { - rebuildAllIndices(); - return; - } - for (Map.Entry> entry : oldExtensions.entrySet()) { - FileType fileType = entry.getKey(); - Set strings = entry.getValue(); - if (!newExtensions.get(fileType).containsAll(strings)) { - rebuildAllIndices(); - return; - } - } - } - } - - @NotNull - private Set getExtensions(@NotNull FileType type) { - final Set set = new THashSet(); - for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { - set.add(matcher.getPresentableString()); - } - return set; - } - - private void rebuildAllIndices() { - for (ID indexId : myIndices.keySet()) { - try { - clearIndex(indexId); - } - catch (StorageException e) { - LOG.info(e); - } - } - scheduleIndexRebuild(true); - } - }); - - connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { - @Override - public void before(@NotNull List events) { - for (VFileEvent event : events) { - final Object requestor = event.getRequestor(); - if (requestor instanceof FileDocumentManager || requestor instanceof PsiManager || requestor == LocalHistory.VFS_EVENT_REQUESTOR) { - cleanupMemoryStorage(); - break; - } - } - } - - @Override - public void after(@NotNull List events) { - } - }); - - connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { - @Override - public void fileContentReloaded(VirtualFile file, @NotNull Document document) { - cleanupMemoryStorage(); - } - - @Override - public void unsavedDocumentsDropped() { - cleanupMemoryStorage(); - } - }); - - ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { - @Override - public void writeActionStarted(Object action) { - myUpToDateIndices.clear(); - } - }); - - myChangedFilesCollector = new ChangedFilesCollector(); - - /* - final File workInProgressFile = getMarkerFile(); - if (workInProgressFile.exists()) { - // previous IDEA session was closed incorrectly, so drop all indices - FileUtil.delete(PathManager.getIndexRoot()); - } - */ - - try { - final FileBasedIndexExtension[] extensions = Extensions.getExtensions(FileBasedIndexExtension.EXTENSION_POINT_NAME); - for (FileBasedIndexExtension extension : extensions) { - ourRebuildStatus.put(extension.getName(), new AtomicInteger(OK)); - } - - final File corruptionMarker = new File(PathManager.getIndexRoot(), CORRUPTION_MARKER_NAME); - final boolean currentVersionCorrupted = corruptionMarker.exists(); - boolean versionChanged = false; - for (FileBasedIndexExtension extension : extensions) { - versionChanged |= registerIndexer(extension, currentVersionCorrupted); - } - FileUtil.delete(corruptionMarker); - - String rebuildNotification = null; - if (currentVersionCorrupted) { - rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; - } - else if (versionChanged) { - rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; - } - if (rebuildNotification != null - && !ApplicationManager.getApplication().isHeadlessEnvironment() - && Registry.is("ide.showIndexRebuildMessage")) { - new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) - .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); - } - - dropUnregisteredIndices(); - - // check if rebuild was requested for any index during registration - for (ID indexId : myIndices.keySet()) { - if (ourRebuildStatus.get(indexId).compareAndSet(REQUIRES_REBUILD, OK)) { - try { - clearIndex(indexId); - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.error(e); - } - } - } - - myVfManager.addVirtualFileListener(myChangedFilesCollector); - - registerIndexableSet(new AdditionalIndexableFileSet(), null); - } - finally { - ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { - @Override - public void run() { - performShutdown(); - } - }); - //FileUtil.createIfDoesntExist(workInProgressFile); - saveRegisteredIndices(myIndices.keySet()); - myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() { - int lastModCount = 0; - @Override - public void run() { - if (lastModCount == myLocalModCount) { - flushAllIndices(lastModCount); - } - lastModCount = myLocalModCount; - } - }); - - } - } - - @Override - public void initComponent() { - } - - @Nullable - private static String calcConfigPath(final String path) { - try { - final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()); - return _path.endsWith("/")? _path : _path + "/" ; - } - catch (IOException e) { - LOG.info(e); - return null; - } - } - - private static class FileBasedIndexHolder { - private static final FileBasedIndex ourInstance = ApplicationManager.getApplication().getComponent(FileBasedIndex.class); - } - +public abstract class FileBasedIndex implements ApplicationComponent { public static FileBasedIndex getInstance() { - return FileBasedIndexHolder.ourInstance; - } - - /** - * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted - * - * @param extension - * @param isCurrentVersionCorrupted - */ - private boolean registerIndexer(@NotNull final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) throws IOException { - final ID name = extension.getName(); - final int version = extension.getVersion(); - final File versionFile = IndexInfrastructure.getVersionFile(name); - final boolean versionFileExisted = versionFile.exists(); - boolean versionChanged = false; - if (isCurrentVersionCorrupted || IndexInfrastructure.versionDiffers(versionFile, version)) { - if (!isCurrentVersionCorrupted && versionFileExisted) { - versionChanged = true; - LOG.info("Version has changed for index " + name + ". The index will be rebuilt."); - } - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); - IndexInfrastructure.rewriteVersion(versionFile, version); - } - - for (int attempt = 0; attempt < 2; attempt++) { - try { - final MapIndexStorage storage = new MapIndexStorage(IndexInfrastructure.getStorageFile(name), extension.getKeyDescriptor(), extension.getValueExternalizer(), extension.getCacheSize()); - final MemoryIndexStorage memStorage = new MemoryIndexStorage(storage); - final UpdatableIndex index = createIndex(name, extension, memStorage); - final InputFilter inputFilter = extension.getInputFilter(); - - assert inputFilter != null : "Index extension " + name + " must provide non-null input filter"; - - myIndices.put(name, new Pair, InputFilter>(index, new IndexableFilesFilter(inputFilter))); - myUnsavedDataIndexingSemaphores.put(name, new Semaphore()); - myIndexIdToVersionMap.put(name, version); - if (!extension.dependsOnFileContent()) { - myNotRequiringContentIndices.add(name); - } - else { - myRequiringContentIndices.add(name); - } - myNoLimitCheckTypes.addAll(extension.getFileTypesWithSizeLimitNotApplicable()); - break; - } - catch (IOException e) { - LOG.info(e); - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); - IndexInfrastructure.rewriteVersion(versionFile, version); - } - } - return versionChanged; - } - - private static void saveRegisteredIndices(@NotNull Collection> ids) { - final File file = getRegisteredIndicesFile(); - try { - FileUtil.createIfDoesntExist(file); - final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); - try { - os.writeInt(ids.size()); - for (ID id : ids) { - IOUtil.writeString(id.toString(), os); - } - } - finally { - os.close(); - } - } - catch (IOException ignored) { - } - } - - @NotNull - private static Set readRegisteredIndexNames() { - final Set result = new THashSet(); - try { - final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); - try { - final int size = in.readInt(); - for (int idx = 0; idx < size; idx++) { - result.add(IOUtil.readString(in)); - } - } - finally { - in.close(); - } - } - catch (IOException ignored) { - } - return result; - } - - @NotNull - private static File getRegisteredIndicesFile() { - return new File(PathManager.getIndexRoot(), "registered"); - } - - @NotNull - private UpdatableIndex createIndex(@NotNull final ID indexId, @NotNull final FileBasedIndexExtension extension, @NotNull final MemoryIndexStorage storage) throws IOException { - final MapReduceIndex index; - if (extension instanceof CustomImplementationFileBasedIndexExtension) { - final UpdatableIndex custom = ((CustomImplementationFileBasedIndexExtension)extension).createIndexImplementation(indexId, this, storage); - - assert custom != null : "Custom index implementation must not be null; index: " + indexId; - - if (!(custom instanceof MapReduceIndex)) { - return custom; - } - index = (MapReduceIndex)custom; - } - else { - index = new MapReduceIndex(indexId, extension.getIndexer(), storage); - } - - final KeyDescriptor keyDescriptor = extension.getKeyDescriptor(); - index.setInputIdToDataKeysIndex(new Factory>>() { - @Override - public PersistentHashMap> create() { - try { - return createIdToDataKeysIndex(indexId, keyDescriptor, storage); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - }); - - return index; - } - - @NotNull - private static PersistentHashMap> createIdToDataKeysIndex(@NotNull final ID indexId, - @NotNull final KeyDescriptor keyDescriptor, - @NotNull MemoryIndexStorage storage) throws IOException { - final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); - final Ref isBufferingMode = new Ref(false); - final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); - - final DataExternalizer> dataExternalizer = new DataExternalizer>() { - @Override - public void save(DataOutput out, @NotNull Collection value) throws IOException { - try { - DataInputOutputUtil.writeINT(out, value.size()); - for (K key : value) { - keyDescriptor.save(out, key); - } - } - catch (IllegalArgumentException e) { - throw new IOException("Error saving data for index " + indexId, e); - } - } - - @NotNull - @Override - public Collection read(DataInput in) throws IOException { - try { - final int size = DataInputOutputUtil.readINT(in); - final List list = new ArrayList(size); - for (int idx = 0; idx < size; idx++) { - list.add(keyDescriptor.read(in)); - } - return list; - } - catch (IllegalArgumentException e) { - throw new IOException("Error reading data for index " + indexId, e); - } - } - }; - - // Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage. - // If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage). - // Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the - // wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be - // cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects. - - final PersistentHashMap> map = new PersistentHashMap>( - indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, dataExternalizer - ) { - - @Override - protected Collection doGet(Integer integer) throws IOException { - if (isBufferingMode.get()) { - final Collection collection = tempMap.get(integer); - if (collection != null) { - return collection; - } - } - return super.doGet(integer); - } - - @Override - protected void doPut(Integer integer, @Nullable Collection ks) throws IOException { - if (isBufferingMode.get()) { - tempMap.put(integer, ks == null? Collections.emptySet() : ks); - } - else { - super.doPut(integer, ks); - } - } - - @Override - protected void doRemove(Integer integer) throws IOException { - if (isBufferingMode.get()) { - tempMap.put(integer, Collections.emptySet()); - } - else { - super.doRemove(integer); - } - } - }; - - storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { - @Override - public void bufferingStateChanged(boolean newState) { - synchronized (map) { - isBufferingMode.set(newState); - } - } - @Override - public void memoryStorageCleared() { - synchronized (map) { - tempMap.clear(); - } - } - }); - return map; - } - - @Override - @NonNls - @NotNull - public String getComponentName() { - return "FileBasedIndex"; - } - - @Override - public void disposeComponent() { - performShutdown(); - } - - private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false); - - private void performShutdown() { - if (!myShutdownPerformed.compareAndSet(false, true)) { - return; // already shut down - } - try { - if (myFlushingFuture != null) { - myFlushingFuture.cancel(false); - myFlushingFuture = null; - } - - myFileDocumentManager.saveAllDocuments(); - } - finally { - LOG.info("START INDEX SHUTDOWN"); - try { - myChangedFilesCollector.forceUpdate(null, null, null, true); - - for (ID indexId : myIndices.keySet()) { - final UpdatableIndex index = getIndex(indexId); - assert index != null; - checkRebuild(indexId, true); // if the index was scheduled for rebuild, only clean it - //LOG.info("DISPOSING " + indexId); - index.dispose(); - } - - myVfManager.removeVirtualFileListener(myChangedFilesCollector); - - //FileUtil.delete(getMarkerFile()); - } - catch (Throwable e) { - LOG.info("Problems during index shutdown", e); - throw new RuntimeException(e); - } - LOG.info("END INDEX SHUTDOWN"); - } - } - - private void flushAllIndices(final long modCount) { - if (HeavyProcessLatch.INSTANCE.isRunning()) { - return; - } - IndexingStamp.flushCache(); - for (ID indexId : new ArrayList>(myIndices.keySet())) { - if (HeavyProcessLatch.INSTANCE.isRunning() || modCount != myLocalModCount) { - return; // do not interfere with 'main' jobs - } - try { - final UpdatableIndex index = getIndex(indexId); - if (index != null) { - index.flush(); - } - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - - if (!HeavyProcessLatch.INSTANCE.isRunning() && modCount == myLocalModCount) { // do not interfere with 'main' jobs - SerializationManager.getInstance().flushNameStorage(); - } - } - - /** - * @param project it is guaranteed to return data which is up-to-date withing the project - * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist - */ - @NotNull - public Collection getAllKeys(@NotNull final ID indexId, @NotNull Project project) { - Set allKeys = new THashSet(); - processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); - return allKeys; - } - - /** - * @param project it is guaranteed to return data which is up-to-date withing the project - * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist - */ - public boolean processAllKeys(@NotNull final ID indexId, Processor processor, @Nullable Project project) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return true; - } - ensureUpToDate(indexId, project, project != null? GlobalSearchScope.allScope(project) : new EverythingGlobalScope()); - return index.processAllKeys(processor); - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - - return false; - } - - private static final ThreadLocal myUpToDateCheckState = new ThreadLocal(); - - public static void disableUpToDateCheckForCurrentThread() { - final Integer currentValue = myUpToDateCheckState.get(); - myUpToDateCheckState.set(currentValue == null? 1 : currentValue.intValue() + 1); - } - - public static void enableUpToDateCheckForCurrentThread() { - final Integer currentValue = myUpToDateCheckState.get(); - if (currentValue != null) { - final int newValue = currentValue.intValue() - 1; - if (newValue != 0) { - myUpToDateCheckState.set(newValue); - } - else { - myUpToDateCheckState.remove(); - } - } - } - - private static boolean isUpToDateCheckEnabled() { - final Integer value = myUpToDateCheckState.get(); - return value == null || value.intValue() == 0; - } - - - private final ThreadLocal myReentrancyGuard = new ThreadLocal() { - @Override - protected Boolean initialValue() { - return Boolean.FALSE; - } - }; - - /** - * DO NOT CALL DIRECTLY IN CLIENT CODE - * The method is internal to indexing engine end is called internally. The method is public due to implementation details - */ - public void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter) { - ensureUpToDate(indexId, project, filter, null); - } - - private void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, - @Nullable VirtualFile restrictedFile) { - if (!needsFileContentLoading(indexId)) { - return; //indexed eagerly in foreground while building unindexed file list - } - if (isDumb(project)) { - handleDumbMode(project); - } - - if (myReentrancyGuard.get().booleanValue()) { - //assert false : "ensureUpToDate() is not reentrant!"; - return; - } - myReentrancyGuard.set(Boolean.TRUE); - - try { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - if (isUpToDateCheckEnabled()) { - try { - checkRebuild(indexId, false); - myChangedFilesCollector.forceUpdate(project, filter, restrictedFile, false); - indexUnsavedDocuments(indexId, project, filter, restrictedFile); - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, e); - } - else { - throw e; - } - } - } - } - finally { - myReentrancyGuard.set(Boolean.FALSE); - } - } - - private static void handleDumbMode(@Nullable Project project) { - ProgressManager.checkCanceled(); // DumbModeAction.CANCEL - - if (project != null) { - final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); - if (progressIndicator instanceof BackgroundableProcessIndicator) { - final BackgroundableProcessIndicator indicator = (BackgroundableProcessIndicator)progressIndicator; - if (indicator.getDumbModeAction() == DumbModeAction.WAIT) { - assert !ApplicationManager.getApplication().isDispatchThread(); - DumbService.getInstance(project).waitForSmartMode(); - return; - } - } - } - - throw new IndexNotReadyException(); - } - - private static boolean isDumb(@Nullable Project project) { - if (project != null) { - return DumbServiceImpl.getInstance(project).isDumb(); - } - for (Project proj : ProjectManager.getInstance().getOpenProjects()) { - if (DumbServiceImpl.getInstance(proj).isDumb()) { - return true; - } - } - return false; - } - - @NotNull - public List getValues(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final List values = new SmartList(); - processValuesImpl(indexId, dataKey, true, null, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - values.add(value); - return true; - } - }, filter); - return values; - } - - @NotNull - public Collection getContainingFiles(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { - final Set files = new THashSet(); - processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - files.add(file); - return true; - } - }, filter); - return files; - } - - - public interface ValueProcessor { - /** - * @param value a value to process - * @param file the file the value came from - * @return false if no further processing is needed, true otherwise - */ - boolean process(VirtualFile file, V value); - } - - /** - * @return false if ValueProcessor.process() returned false; true otherwise or if ValueProcessor was not called at all - */ - public boolean processValues(@NotNull final ID indexId, @NotNull final K dataKey, @Nullable final VirtualFile inFile, - @NotNull ValueProcessor processor, @NotNull final GlobalSearchScope filter) { - return processValuesImpl(indexId, dataKey, false, inFile, processor, filter); - } - - - - - @Nullable - private R processExceptions(@NotNull final ID indexId, - @Nullable final VirtualFile restrictToFile, - @NotNull final GlobalSearchScope filter, - @NotNull ThrowableConvertor, R, StorageException> computable) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return null; - } - final Project project = filter.getProject(); - //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; - ensureUpToDate(indexId, project, filter, restrictToFile); - - try { - index.getReadLock().lock(); - return computable.convert(index); - } - finally { - index.getReadLock().unlock(); - } - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = getCauseToRebuildIndex(e); - if (cause != null) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - return null; - } - - private boolean processValuesImpl(@NotNull final ID indexId, final K dataKey, final boolean ensureValueProcessedOnce, - @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, - @NotNull final GlobalSearchScope filter) { - ThrowableConvertor, Boolean, StorageException> keyProcessor = new ThrowableConvertor, Boolean, StorageException>() { - @Override - public Boolean convert(@NotNull UpdatableIndex index) throws StorageException { - final ValueContainer container = index.getData(dataKey); - - boolean shouldContinue = true; - - if (restrictToFile != null) { - if (restrictToFile instanceof VirtualFileWithId) { - final int restrictedFileId = getFileId(restrictToFile); - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - if (container.isAssociated(value, restrictedFileId)) { - shouldContinue = processor.process(restrictToFile, value); - if (!shouldContinue) { - break; - } - } - } - } - } - else { - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - ProjectIndexableFilesFilter projectFilesSet = projectIndexableFiles(filter.getProject()); - VALUES_LOOP: for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { - final V value = valueIt.next(); - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { - final int id = inputIdsIterator.next(); - if (projectFilesSet != null && !projectFilesSet.contains(id)) continue; - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - shouldContinue = processor.process(file, value); - if (!shouldContinue) { - break VALUES_LOOP; - } - if (ensureValueProcessedOnce) { - break; // continue with the next value - } - } - } - } - } - return shouldContinue; - } - }; - final Boolean result = processExceptions(indexId, restrictToFile, filter, keyProcessor); - return result == null || result.booleanValue(); - } - - public boolean processFilesContainingAllKeys(@NotNull final ID indexId, - @NotNull final Collection dataKeys, - @NotNull final GlobalSearchScope filter, - @Nullable Condition valueChecker, - @NotNull final Processor processor) { - ProjectIndexableFilesFilter filesSet = projectIndexableFiles(filter.getProject()); - final TIntHashSet set = collectFileIdsContainingAllKeys(indexId, dataKeys, filter, valueChecker, filesSet); - return set != null && processVirtualFiles(set, filter, processor); - } - - private static final Key> ourProjectFilesSetKey = Key.create("projectFiles"); - - public static final class ProjectIndexableFilesFilter { - private static final int SHIFT = 6; - private static final int MASK = (1 << SHIFT) - 1; - private final long[] myBitMask; - private final int myModificationCount; - private final int myMinId; - private final int myMaxId; - - private ProjectIndexableFilesFilter(@NotNull TIntHashSet set, int modificationCount) { - myModificationCount = modificationCount; - final int[] minMax = new int[2]; - if (set.size() > 0) { - minMax[0] = minMax[1] = set.iterator().next(); - } - set.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - minMax[0] = Math.min(minMax[0], value); - minMax[1] = Math.max(minMax[1], value); - return true; - } - }); - myMaxId = minMax[1]; - myMinId = minMax[0]; - myBitMask = new long[((myMaxId - myMinId) >> SHIFT) + 1]; - set.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - value = value - myMinId; - myBitMask[value >> SHIFT] |= (1L << (value & MASK)); - return true; - } - }); - } - - public boolean contains(int id) { - if (id < myMinId) return false; - if (id > myMaxId) return false; - id -= myMinId; - return (myBitMask[id >> SHIFT] & (1L << (id & MASK))) != 0; - } - } - - @Nullable - public ProjectIndexableFilesFilter projectIndexableFiles(@Nullable Project project) { - if (project == null) return null; - - SoftReference reference = project.getUserData(ourProjectFilesSetKey); - ProjectIndexableFilesFilter data = reference != null ? reference.get() : null; - if (data != null && data.myModificationCount == myFilesModCount) return data; - - final TIntHashSet filesSet = new TIntHashSet(); - iterateIndexableFiles(new ContentIterator() { - @Override - public boolean processFile(@NotNull VirtualFile fileOrDir) { - filesSet.add(((VirtualFileWithId)fileOrDir).getId()); - return true; - } - }, project, ProgressManager.getInstance().getProgressIndicator()); - ProjectIndexableFilesFilter files = new ProjectIndexableFilesFilter(filesSet, myFilesModCount); - project.putUserData(ourProjectFilesSetKey, new SoftReference(files)); - return files; - } - - @Nullable - private TIntHashSet collectFileIdsContainingAllKeys(@NotNull final ID indexId, - @NotNull final Collection dataKeys, - @NotNull final GlobalSearchScope filter, - @Nullable final Condition valueChecker, - @Nullable final ProjectIndexableFilesFilter projectFilesFilter) { - final ThrowableConvertor, TIntHashSet, StorageException> convertor = - new ThrowableConvertor, TIntHashSet, StorageException>() { - @Nullable - @Override - public TIntHashSet convert(@NotNull UpdatableIndex index) throws StorageException { - TIntHashSet mainIntersection = null; - - for (K dataKey : dataKeys) { - ProgressManager.checkCanceled(); - final TIntHashSet copy = new TIntHashSet(); - final ValueContainer container = index.getData(dataKey); - - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - if (valueChecker != null && !valueChecker.value(value)) { - continue; - } - - ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); - - if (mainIntersection == null || iterator.size() < mainIntersection.size()) { - for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { - final int id = inputIdsIterator.next(); - if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || - mainIntersection != null && mainIntersection.contains(id) - ) { - copy.add(id); - } - } - } else { - mainIntersection.forEach(new TIntProcedure() { - final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); - @Override - public boolean execute(int id) { - if (predicate.contains(id)) copy.add(id); - return true; - } - }); - } - } - - mainIntersection = copy; - if (mainIntersection.isEmpty()) { - return new TIntHashSet(); - } - } - - return mainIntersection; - } - }; - - - return processExceptions(indexId, null, filter, convertor); - } - - private static boolean processVirtualFiles(@NotNull TIntHashSet ids, - @NotNull final GlobalSearchScope filter, - @NotNull final Processor processor) { - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - return ids.forEach(new TIntProcedure() { - @Override - public boolean execute(int id) { - ProgressManager.checkCanceled(); - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - return processor.process(file); - } - return true; - } - }); - } - - @Nullable - public static Throwable getCauseToRebuildIndex(@NotNull RuntimeException e) { - Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException || - cause instanceof IllegalArgumentException) return cause; - return null; - } - - public boolean getFilesWithKey(@NotNull final ID indexId, - @NotNull final Set dataKeys, - @NotNull Processor processor, - @NotNull GlobalSearchScope filter) { - try { - final UpdatableIndex index = getIndex(indexId); - if (index == null) { - return true; - } - final Project project = filter.getProject(); - //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; - ensureUpToDate(indexId, project, filter); - - try { - index.getReadLock().lock(); - final List locals = new ArrayList(); - for (K dataKey : dataKeys) { - TIntHashSet local = new TIntHashSet(); - locals.add(local); - final ValueContainer container = index.getData(dataKey); - - for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { - final V value = valueIt.next(); - for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { - final int id = inputIdsIterator.next(); - local.add(id); - } - } - } - - if (locals.isEmpty()) { - return true; - } - - Collections.sort(locals, new Comparator() { - @Override - public int compare(TIntHashSet o1, TIntHashSet o2) { - return o1.size() - o2.size(); - } - }); - - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - TIntIterator ids = join(locals).iterator(); - ProjectIndexableFilesFilter projectIndexableFilesFilter = projectIndexableFiles(project); - while (ids.hasNext()) { - int id = ids.next(); - if (projectIndexableFilesFilter != null && !projectIndexableFilesFilter.contains(id)) continue; - //VirtualFile file = IndexInfrastructure.findFileById(fs, id); - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && filter.accept(file)) { - if (!processor.process(file)) { - return false; - } - } - } - } - finally { - index.getReadLock().unlock(); - } - } - catch (StorageException e) { - scheduleRebuild(indexId, e); - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof StorageException || cause instanceof IOException) { - scheduleRebuild(indexId, cause); - } - else { - throw e; - } - } - return true; - } - - @NotNull - private static TIntHashSet join(@NotNull List locals) { - TIntHashSet result = locals.get(0); - if (locals.size() > 1) { - TIntIterator it = result.iterator(); - - while (it.hasNext()) { - int id = it.next(); - for (int i = 1; i < locals.size(); i++) { - if (!locals.get(i).contains(id)) { - it.remove(); - break; - } - } - } - } - return result; - } - - public void scheduleRebuild(@NotNull final ID indexId, @NotNull final Throwable e) { - LOG.info(e); - requestRebuild(indexId); - try { - checkRebuild(indexId, false); - } - catch (ProcessCanceledException ignored) { - } - } - - private void checkRebuild(@NotNull final ID indexId, final boolean cleanupOnly) { - final AtomicInteger status = ourRebuildStatus.get(indexId); - if (status.get() == OK) return; - if (status.compareAndSet(REQUIRES_REBUILD, REBUILD_IN_PROGRESS)) { - cleanupProcessedFlag(); - - final Runnable rebuildRunnable = new Runnable() { - @Override - public void run() { - try { - clearIndex(indexId); - if (!cleanupOnly) { - scheduleIndexRebuild(false); - } - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.info(e); - } - finally { - status.compareAndSet(REBUILD_IN_PROGRESS, OK); - } - } - }; - - if (cleanupOnly || myIsUnitTestMode) { - rebuildRunnable.run(); - } - else { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - new Task.Modal(null, "Updating index", false) { - @Override - public void run(@NotNull final ProgressIndicator indicator) { - indicator.setIndeterminate(true); - rebuildRunnable.run(); - } - }.queue(); - } - }); - } - } - - if (status.get() == REBUILD_IN_PROGRESS) { - throw new ProcessCanceledException(); - } - } - - private void scheduleIndexRebuild(boolean forceDumbMode) { - for (Project project : ProjectManager.getInstance().getOpenProjects()) { - final Set updatersToRun = Collections.singleton(new UnindexedFilesUpdater(project, this)); - final DumbServiceImpl service = DumbServiceImpl.getInstance(project); - if (forceDumbMode) { - service.queueCacheUpdateInDumbMode(updatersToRun); - } - else { - service.queueCacheUpdate(updatersToRun); - } - } - } - - private void clearIndex(@NotNull final ID indexId) throws StorageException { - final UpdatableIndex index = getIndex(indexId); - assert index != null: "Index with key " + indexId + " not found or not registered properly"; - index.clear(); - try { - IndexInfrastructure.rewriteVersion(IndexInfrastructure.getVersionFile(indexId), myIndexIdToVersionMap.get(indexId)); - } - catch (IOException e) { - LOG.error(e); - } - } - - @NotNull - private Set getUnsavedOrTransactedDocuments() { - final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); - synchronized (myTransactionMap) { - docs.addAll(myTransactionMap.keySet()); - } - return docs; - } - - private void indexUnsavedDocuments(@NotNull ID indexId, - @Nullable Project project, - GlobalSearchScope filter, - VirtualFile restrictedFile) throws StorageException { - if (myUpToDateIndices.contains(indexId)) { - return; // no need to index unsaved docs - } - - final Set documents = getUnsavedOrTransactedDocuments(); - if (!documents.isEmpty()) { - // now index unsaved data - final StorageGuard.Holder guard = setDataBufferingEnabled(true); - try { - final Semaphore semaphore = myUnsavedDataIndexingSemaphores.get(indexId); - - assert semaphore != null : "Semaphore for unsaved data indexing was not initialized for index " + indexId; - - semaphore.down(); - boolean allDocsProcessed = true; - try { - for (Document document : documents) { - allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); - } - } - finally { - semaphore.up(); - - while (!semaphore.waitFor(500)) { // may need to wait until another thread is done with indexing - if (Thread.holdsLock(PsiLock.LOCK)) { - break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. - } - } - if (allDocsProcessed && !hasActiveTransactions()) { - myUpToDateIndices.add(indexId); // safe to set the flag here, because it will be cleared under the WriteAction - } - } - } - finally { - guard.leave(); - } - } - } - - private boolean hasActiveTransactions() { - synchronized (myTransactionMap) { - return !myTransactionMap.isEmpty(); - } - } - - private interface DocumentContent { - String getText(); - long getModificationStamp(); - } - - private static class AuthenticContent implements DocumentContent { - private final Document myDocument; - - private AuthenticContent(final Document document) { - myDocument = document; - } - - @Override - public String getText() { - return myDocument.getText(); - } - - @Override - public long getModificationStamp() { - return myDocument.getModificationStamp(); - } - } - - private static class PsiContent implements DocumentContent { - private final Document myDocument; - private final PsiFile myFile; - - private PsiContent(final Document document, final PsiFile file) { - myDocument = document; - myFile = file; - } - - @Override - public String getText() { - if (myFile.getModificationStamp() != myDocument.getModificationStamp()) { - final ASTNode node = myFile.getNode(); - assert node != null; - return node.getText(); - } - return myDocument.getText(); - } - - @Override - public long getModificationStamp() { - return myFile.getModificationStamp(); - } - } - -// returns false if doc was not indexed because the file does not fit in scope - private boolean indexUnsavedDocument(@NotNull final Document document, @NotNull final ID requestedIndexId, final Project project, - @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedFile) throws StorageException { - final VirtualFile vFile = myFileDocumentManager.getFile(document); - if (!(vFile instanceof VirtualFileWithId) || !vFile.isValid()) { - return true; - } - - if (restrictedFile != null) { - if(vFile != restrictedFile) { - return false; - } - } - else if (filter != null && !filter.accept(vFile)) { - return false; - } - - final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); - - final DocumentContent content; - if (dominantContentFile != null && dominantContentFile.getModificationStamp() != document.getModificationStamp()) { - content = new PsiContent(document, dominantContentFile); - } - else { - content = new AuthenticContent(document); - } - - final long currentDocStamp = content.getModificationStamp(); - if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp)) { - final Ref exRef = new Ref(null); - ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { - @Override - public void run() { - try { - final String contentText = content.getText(); - if (isTooLarge(vFile, contentText.length())) { - return; - } - - final FileContentImpl newFc = new FileContentImpl(vFile, contentText, vFile.getCharset()); - - if (dominantContentFile != null) { - dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, true); - newFc.putUserData(IndexingDataKeys.PSI_FILE, dominantContentFile); - } - - if (content instanceof AuthenticContent) { - newFc.putUserData(EDITOR_HIGHLIGHTER, EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)); - } - - if (getInputFilter(requestedIndexId).acceptInput(vFile)) { - newFc.putUserData(IndexingDataKeys.PROJECT, project); - final int inputId = Math.abs(getFileId(vFile)); - getIndex(requestedIndexId).update(inputId, newFc); - } - - if (dominantContentFile != null) { - dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, null); - } - } - catch (StorageException e) { - exRef.set(e); - } - } - }); - final StorageException storageException = exRef.get(); - if (storageException != null) { - throw storageException; - } - } - return true; - } - - public static final Key EDITOR_HIGHLIGHTER = new Key("Editor"); - - @Nullable - private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { - synchronized (myTransactionMap) { - PsiFile psiFile = myTransactionMap.get(document); - if (psiFile != null) return psiFile; - } - - return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); - } - - private final StorageGuard myStorageLock = new StorageGuard(); - - @NotNull - private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) { - final StorageGuard.Holder holder = myStorageLock.enter(enabled); - for (ID indexId : myIndices.keySet()) { - final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); - assert index != null; - final IndexStorage indexStorage = index.getStorage(); - ((MemoryIndexStorage)indexStorage).setBufferingEnabled(enabled); - } - return holder; - } - - private void cleanupMemoryStorage() { - myLastIndexedDocStamps.clear(); - for (ID indexId : myIndices.keySet()) { - final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); - assert index != null; - final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage(); - index.getWriteLock().lock(); - try { - memStorage.clearMemoryMap(); - } - finally { - index.getWriteLock().unlock(); - } - memStorage.fireMemoryStorageCleared(); - } - } - - private void dropUnregisteredIndices() { - final Set indicesToDrop = readRegisteredIndexNames(); - for (ID key : myIndices.keySet()) { - indicesToDrop.remove(key.toString()); - } - for (String s : indicesToDrop) { - FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); - } - } - - public static void requestRebuild(ID indexId) { - requestRebuild(indexId, new Throwable()); - } - - public static void requestRebuild(ID indexId, Throwable throwable) { - cleanupProcessedFlag(); - LOG.info("Rebuild requested for index " + indexId, throwable); - ourRebuildStatus.get(indexId).set(REQUIRES_REBUILD); - } - - private UpdatableIndex getIndex(ID indexId) { - final Pair, InputFilter> pair = myIndices.get(indexId); - - assert pair != null : "Index data is absent for index " + indexId; - - //noinspection unchecked - return (UpdatableIndex)pair.getFirst(); - } - - private InputFilter getInputFilter(ID indexId) { - final Pair, InputFilter> pair = myIndices.get(indexId); - - assert pair != null : "Index data is absent for index " + indexId; - - return pair.getSecond(); - } - - public int getNumberOfPendingInvalidations() { - return myChangedFilesCollector.getNumberOfPendingInvalidations(); - } - - @NotNull - public Collection getFilesToUpdate(final Project project) { - return ContainerUtil.findAll(myChangedFilesCollector.getAllFilesToUpdate(), new Condition() { - @Override - public boolean value(VirtualFile virtualFile) { - for (IndexableFileSet set : myIndexableSets) { - final Project proj = myIndexableSetToProjectMap.get(set); - if (proj != null && !proj.equals(project)) { - continue; // skip this set as associated with a different project - } - if (set.isInSet(virtualFile)) { - return true; - } - } - return false; - } - }); - } - - public void processRefreshedFile(@NotNull Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - myChangedFilesCollector.processFileImpl(project, fileContent, false); - } - - public void indexFileContent(@Nullable Project project, @NotNull com.intellij.ide.caches.FileContent content) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - final VirtualFile file = content.getVirtualFile(); - FileContentImpl fc = null; - - PsiFile psiFile = null; - - FileTypeManagerImpl.cacheFileType(file, file.getFileType()); - try { - for (final ID indexId : myIndices.keySet()) { - if (shouldIndexFile(file, indexId)) { - if (fc == null) { - byte[] currentBytes; - try { - currentBytes = content.getBytes(); - } - catch (IOException e) { - currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY; - } - fc = new FileContentImpl(file, currentBytes); - - psiFile = content.getUserData(IndexingDataKeys.PSI_FILE); - if (psiFile != null) { - psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true); - fc.putUserData(IndexingDataKeys.PSI_FILE, psiFile); - } - if (project == null) { - project = ProjectUtil.guessProjectForFile(file); - } - fc.putUserData(IndexingDataKeys.PROJECT, project); - } - - try { - ProgressManager.checkCanceled(); - updateSingleIndex(indexId, file, fc); - } - catch (ProcessCanceledException e) { - myChangedFilesCollector.scheduleForUpdate(file); - throw e; - } - catch (StorageException e) { - requestRebuild(indexId); - LOG.info(e); - } - } - } - - if (psiFile != null) { - psiFile.putUserData(PsiFileImpl.BUILDING_STUB, null); - } - } finally { - FileTypeManagerImpl.cacheFileType(file, null); - } - } - - private void updateSingleIndex(final ID indexId, @NotNull final VirtualFile file, @Nullable final FileContent currentFC) - throws StorageException { - if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { - return; // the index is scheduled for rebuild, no need to update - } - myLocalModCount++; - - final StorageGuard.Holder lock = setDataBufferingEnabled(false); - - try { - final int inputId = Math.abs(getFileId(file)); - - final UpdatableIndex index = getIndex(indexId); - assert index != null; - - final Ref exRef = new Ref(null); - ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { - @Override - public void run() { - try { - index.update(inputId, currentFC); - } - catch (StorageException e) { - exRef.set(e); - } - } - }); - final StorageException storageException = exRef.get(); - if (storageException != null) { - throw storageException; - } - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - if (file.isValid()) { - if (currentFC != null) { - IndexingStamp.update(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); - } - else { - // mark the file as unindexed - IndexingStamp.update(file, indexId, -1L); - } - } - } - }); - } - finally { - lock.leave(); - } + return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } public static int getFileId(@NotNull final VirtualFile file) { @@ -1693,653 +47,68 @@ public class FileBasedIndex implements ApplicationComponent { throw new IllegalArgumentException("Virtual file doesn't support id: " + file + ", implementation class: " + file.getClass().getName()); } - private boolean needsFileContentLoading(ID indexId) { - return !myNotRequiringContentIndices.contains(indexId); + public void requestRebuild(ID indexId) { + requestRebuild(indexId, new Throwable()); } - private abstract static class InvalidationTask implements Runnable { - private final VirtualFile mySubj; - protected InvalidationTask(final VirtualFile subj) { - mySubj = subj; - } - - public VirtualFile getSubj() { - return mySubj; - } - } - - private final class ChangedFilesCollector extends VirtualFileAdapter { - private final Set myFilesToUpdate = new ConcurrentHashSet(); - private final Queue myFutureInvalidations = new ConcurrentLinkedQueue(); - - private final ManagingFS myManagingFS = ManagingFS.getInstance(); - // No need to react on movement events since files stay valid, their ids don't change and all associated attributes remain intact. - - @Override - public void fileCreated(@NotNull final VirtualFileEvent event) { - markDirty(event, false); - } - - @Override - public void fileDeleted(@NotNull final VirtualFileEvent event) { - myFilesToUpdate.remove(event.getFile()); // no need to update it anymore - } - - @Override - public void fileCopied(@NotNull final VirtualFileCopyEvent event) { - markDirty(event, false); - } - - @Override - public void beforeFileDeletion(@NotNull final VirtualFileEvent event) { - invalidateIndices(event.getFile(), false); - } - - @Override - public void beforeContentsChange(@NotNull final VirtualFileEvent event) { - invalidateIndices(event.getFile(), true); - } - - @Override - public void contentsChanged(@NotNull final VirtualFileEvent event) { - markDirty(event, true); - } - - @Override - public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { - if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { - // indexes may depend on file name - final VirtualFile file = event.getFile(); - if (!file.isDirectory()) { - // name change may lead to filetype change so the file might become not indexable - // in general case have to 'unindex' the file and index it again if needed after the name has been changed - invalidateIndices(file, false); - } - } - } - - @Override - public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) { - if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { - // indexes may depend on file name - if (!event.getFile().isDirectory()) { - markDirty(event, false); - } - } - } - - private void markDirty(@NotNull final VirtualFileEvent event, final boolean contentChange) { - final VirtualFile eventFile = event.getFile(); - cleanProcessedFlag(eventFile); - iterateIndexableFiles(eventFile, new Processor() { - @Override - public boolean process(@NotNull final VirtualFile file) { - if (!contentChange) ++myFilesModCount; - FileContent fileContent = null; - // handle 'content-less' indices separately - for (ID indexId : myNotRequiringContentIndices) { - if (getInputFilter(indexId).acceptInput(file)) { - try { - if (fileContent == null) { - fileContent = new FileContentImpl(file); - } - updateSingleIndex(indexId, file, fileContent); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - } - // For 'normal indices' schedule the file for update and stop iteration if at least one index accepts it - if (!isTooLarge(file)) { - for (ID indexId : myIndices.keySet()) { - if (needsFileContentLoading(indexId) && getInputFilter(indexId).acceptInput(file)) { - scheduleForUpdate(file); - break; // no need to iterate further, as the file is already marked - } - } - } - - return true; - } - }); - IndexingStamp.flushCache(); - } - - public void scheduleForUpdate(VirtualFile file) { - myFilesToUpdate.add(file); - } - - void invalidateIndices(@NotNull final VirtualFile file, final boolean markForReindex) { - if (isUnderConfigOrSystem(file)) { - return; - } - if (file.isDirectory()) { - if (isMock(file) || myManagingFS.wereChildrenAccessed(file)) { - final Iterable children = file instanceof NewVirtualFile - ? ((NewVirtualFile)file).iterInDbChildren() : Arrays.asList(file.getChildren()); - for (VirtualFile child : children) { - invalidateIndices(child, markForReindex); - } - } - } - else { - cleanProcessedFlag(file); - IndexingStamp.flushCache(); - final List> affectedIndices = new ArrayList>(myIndices.size()); - - for (final ID indexId : myIndices.keySet()) { - try { - if (!needsFileContentLoading(indexId)) { - if (shouldUpdateIndex(file, indexId)) { - updateSingleIndex(indexId, file, null); - } - } - else { // the index requires file content - if (shouldUpdateIndex(file, indexId)) { - affectedIndices.add(indexId); - } - } - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - - if (!affectedIndices.isEmpty()) { - if (markForReindex && !isTooLarge(file)) { - // only mark the file as unindexed, reindex will be done lazily - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - for (ID indexId : affectedIndices) { - IndexingStamp.update(file, indexId, -2L); - } - } - }); - // the file is for sure not a dir and it was previously indexed by at least one index - scheduleForUpdate(file); - } - else { - myFutureInvalidations.offer(new InvalidationTask(file) { - @Override - public void run() { - removeFileDataFromIndices(affectedIndices, file); - } - }); - } - } - if (!markForReindex) { - final boolean removedFromUpdateQueue = myFilesToUpdate.remove(file);// no need to update it anymore - if (removedFromUpdateQueue && affectedIndices.isEmpty()) { - // Currently the file is about to be deleted and previously it was scheduled for update and not processed up to now. - // Because the file was scheduled for update, at the moment of scheduling it was marked as unindexed, - // so, to be on the safe side, we have to schedule data invalidation from all content-requiring indices for this file - myFutureInvalidations.offer(new InvalidationTask(file) { - @Override - public void run() { - removeFileDataFromIndices(myRequiringContentIndices, file); - } - }); - } - } - - IndexingStamp.flushCache(); - } - } - - private void removeFileDataFromIndices(@NotNull Collection> affectedIndices, @NotNull VirtualFile file) { - Throwable unexpectedError = null; - for (ID indexId : affectedIndices) { - try { - updateSingleIndex(indexId, file, null); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - catch (ProcessCanceledException ignored) { - } - catch (Throwable e) { - LOG.info(e); - if (unexpectedError == null) { - unexpectedError = e; - } - } - } - IndexingStamp.flushCache(); - if (unexpectedError != null) { - LOG.error(unexpectedError); - } - } - - public int getNumberOfPendingInvalidations() { - return myFutureInvalidations.size(); - } - - public void ensureAllInvalidateTasksCompleted() { - final int size = getNumberOfPendingInvalidations(); - if (size == 0) { - return; - } - final ProgressIndicator current = ProgressManager.getInstance().getProgressIndicator(); - final ProgressIndicator indicator = current != null ? current : new EmptyProgressIndicator(); - indicator.setText(""); - int count = 0; - while (true) { - InvalidationTask task = myFutureInvalidations.poll(); - - if (task == null) { - break; - } - indicator.setFraction((double)count++ /size); - indicator.setText2(task.getSubj().getPresentableUrl()); - task.run(); - } - } - - private void iterateIndexableFiles(@NotNull final VirtualFile file, @NotNull final Processor processor) { - if (file.isDirectory()) { - final ContentIterator iterator = new ContentIterator() { - @Override - public boolean processFile(@NotNull final VirtualFile fileOrDir) { - if (!fileOrDir.isDirectory()) { - processor.process(fileOrDir); - } - return true; - } - }; - - for (IndexableFileSet set : myIndexableSets) { - if (set.isInSet(file)) { - set.iterateIndexableFilesIn(file, iterator); - } - } - } - else { - for (IndexableFileSet set : myIndexableSets) { - if (set.isInSet(file)) { - processor.process(file); - break; - } - } - } - } - - public Collection getAllFilesToUpdate() { - if (myFilesToUpdate.isEmpty()) { - return Collections.emptyList(); - } - return new ArrayList(myFilesToUpdate); - } - - private final Semaphore myForceUpdateSemaphore = new Semaphore(); - - private void forceUpdate(@Nullable Project project, @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedTo, - boolean onlyRemoveOutdatedData) { - myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); - for (VirtualFile file: getAllFilesToUpdate()) { - if (filter == null || filter.accept(file) || file == restrictedTo) { - try { - myForceUpdateSemaphore.down(); - // process only files that can affect result - processFileImpl(project, new com.intellij.ide.caches.FileContent(file), onlyRemoveOutdatedData); - } - finally { - myForceUpdateSemaphore.up(); - } - } - } - - // If several threads entered the method at the same time and there were files to update, - // all the threads should leave the method synchronously after all the files scheduled for update are reindexed, - // no matter which thread will do reindexing job. - // Thus we ensure that all the threads that entered the method will get the most recent data - - while (!myForceUpdateSemaphore.waitFor(500)) { // may need to wait until another thread is done with indexing - if (Thread.holdsLock(PsiLock.LOCK)) { - break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. - } - } - } - - private void processFileImpl(Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent, boolean onlyRemoveOutdatedData) { - final VirtualFile file = fileContent.getVirtualFile(); - final boolean reallyRemoved = myFilesToUpdate.remove(file); - if (reallyRemoved && file.isValid()) { - if (onlyRemoveOutdatedData) { - // on shutdown there is no need to re-index the file, just remove outdated data from indices - final List> affected = new ArrayList>(); - for (final ID indexId : myIndices.keySet()) { - if (getInputFilter(indexId).acceptInput(file)) { - affected.add(indexId); - } - } - removeFileDataFromIndices(affected, file); - } - else { - indexFileContent(project, fileContent); - } - IndexingStamp.flushCache(); - } - } - } - - private class UnindexedFilesFinder implements CollectingContentIterator { - private final List myFiles = new ArrayList(); - private final ProgressIndicator myProgressIndicator; - - private UnindexedFilesFinder() { - myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); - } - - @NotNull - @Override - public List getFiles() { - return myFiles; - } - - @Override - public boolean processFile(@NotNull final VirtualFile file) { - if (!file.isValid()) { - return true; - } - if (!file.isDirectory()) { - if (file instanceof NewVirtualFile && ((NewVirtualFile)file).getFlag(ALREADY_PROCESSED)) { - return true; - } - - if (file instanceof VirtualFileWithId) { - try { - FileTypeManagerImpl.cacheFileType(file, file.getFileType()); - - boolean oldStuff = true; - if (!isTooLarge(file)) { - for (ID indexId : myIndices.keySet()) { - try { - if (needsFileContentLoading(indexId) && shouldIndexFile(file, indexId)) { - myFiles.add(file); - oldStuff = false; - break; - } - } - catch (RuntimeException e) { - final Throwable cause = e.getCause(); - if (cause instanceof IOException || cause instanceof StorageException) { - LOG.info(e); - requestRebuild(indexId); - } - else { - throw e; - } - } - } - } - FileContent fileContent = null; - for (ID indexId : myNotRequiringContentIndices) { - if (shouldIndexFile(file, indexId)) { - oldStuff = false; - try { - if (fileContent == null) { - fileContent = new FileContentImpl(file); - } - updateSingleIndex(indexId, file, fileContent); - } - catch (StorageException e) { - LOG.info(e); - requestRebuild(indexId); - } - } - } - IndexingStamp.flushCache(); - - if (oldStuff && file instanceof NewVirtualFile) { - ((NewVirtualFile)file).setFlag(ALREADY_PROCESSED, true); - } - } - finally { - FileTypeManagerImpl.cacheFileType(file, null); - } - } - } - else { - if (myProgressIndicator != null) { - myProgressIndicator.setText("Scanning files to index"); - myProgressIndicator.setText2(file.getPresentableUrl()); - } - } - return true; - } - } - - private boolean shouldUpdateIndex(final VirtualFile file, final ID indexId) { - return getInputFilter(indexId).acceptInput(file) && - (isMock(file) || IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); - } - - private boolean shouldIndexFile(final VirtualFile file, final ID indexId) { - return getInputFilter(indexId).acceptInput(file) && - (isMock(file) || !IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); - } - - private boolean isUnderConfigOrSystem(@NotNull VirtualFile file) { - final String filePath = file.getPath(); - return myConfigPath != null && FileUtil.startsWith(filePath, myConfigPath) || - mySystemPath != null && FileUtil.startsWith(filePath, mySystemPath); - } - - private static boolean isMock(final VirtualFile file) { - return !(file instanceof NewVirtualFile); - } - - private boolean isTooLarge(@NotNull VirtualFile file) { - if (SingleRootFileViewProvider.isTooLarge(file)) { - final FileType type = file.getFileType(); - return !myNoLimitCheckTypes.contains(type); - } - return false; - } - - private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) { - if (SingleRootFileViewProvider.isTooLarge(file, contentSize)) { - final FileType type = file.getFileType(); - return !myNoLimitCheckTypes.contains(type); - } - return false; + @NonNls + @NotNull + public String getComponentName() { + return "FileBasedIndex"; } @NotNull - public CollectingContentIterator createContentIterator() { - ++myFilesModCount; - return new UnindexedFilesFinder(); - } + public abstract List getValues(@NotNull ID indexId, @NotNull K dataKey, @NotNull GlobalSearchScope filter); - public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { - myIndexableSets.add(set); - myIndexableSetToProjectMap.put(set, project); - } + @NotNull + public abstract Collection getContainingFiles(@NotNull ID indexId, + @NotNull K dataKey, + @NotNull GlobalSearchScope filter); - public void removeIndexableSet(@NotNull IndexableFileSet set) { - myChangedFilesCollector.forceUpdate(null, null, null, true); - myIndexableSets.remove(set); - myIndexableSetToProjectMap.remove(set); - } + public abstract boolean processValues(@NotNull ID indexId, + @NotNull K dataKey, + @Nullable VirtualFile inFile, + @NotNull FileBasedIndex.ValueProcessor processor, + @NotNull GlobalSearchScope filter); - @Nullable - private static PsiFile findLatestKnownPsiForUncomittedDocument(@NotNull Document doc, @NotNull Project project) { - return PsiDocumentManager.getInstance(project).getCachedPsiFile(doc); - } - - private static class IndexableFilesFilter implements InputFilter { - private final InputFilter myDelegate; + public abstract boolean processFilesContainingAllKeys(@NotNull ID indexId, + @NotNull Collection dataKeys, + @NotNull GlobalSearchScope filter, + @Nullable Condition valueChecker, + @NotNull Processor processor); - private IndexableFilesFilter(InputFilter delegate) { - myDelegate = delegate; - } + @NotNull + public abstract Collection getAllKeys(@NotNull ID indexId, @NotNull Project project); - @Override - public boolean acceptInput(final VirtualFile file) { - return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); - } - } + public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); - private static void cleanupProcessedFlag() { - final VirtualFile[] roots = ManagingFS.getInstance().getRoots(); - for (VirtualFile root : roots) { - cleanProcessedFlag(root); - } - } + protected abstract void ensureUpToDate(@NotNull ID indexId, + @Nullable Project project, + @Nullable GlobalSearchScope filter, + @Nullable VirtualFile restrictedFile); - private static void cleanProcessedFlag(@NotNull final VirtualFile file) { - if (!(file instanceof NewVirtualFile)) return; - - final NewVirtualFile nvf = (NewVirtualFile)file; - if (file.isDirectory()) { - for (VirtualFile child : nvf.getCachedChildren()) { - cleanProcessedFlag(child); - } - } - else { - nvf.setFlag(ALREADY_PROCESSED, false); - } - } + public abstract void requestRebuild(ID indexId, Throwable throwable); - public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { - if (project.isDisposed()) { - return; - } - final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - // iterate project content - projectFileIndex.iterateContent(processor); + public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); - if (project.isDisposed()) { - return; - } + public abstract void requestReindex(@NotNull VirtualFile file); - Set visitedRoots = new THashSet(); - for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { - //important not to depend on project here, to support per-project background reindex - // each client gives a project to FileBasedIndex - if (project.isDisposed()) { - return; - } - for (VirtualFile root : IndexableSetContributor.getRootsToIndex(provider)) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - for (VirtualFile root : IndexableSetContributor.getProjectRootsToIndex(provider, project)) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - } + public abstract void requestReindexExcluded(@NotNull VirtualFile file); - if (project.isDisposed()) { - return; - } - // iterate associated libraries - for (Module module : ModuleManager.getInstance(project).getModules()) { - if (module.isDisposed()) { - return; - } - OrderEntry[] orderEntries = ModuleRootManager.getInstance(module).getOrderEntries(); - for (OrderEntry orderEntry : orderEntries) { - if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { - if (orderEntry.isValid()) { - final VirtualFile[] libSources = orderEntry.getFiles(OrderRootType.SOURCES); - final VirtualFile[] libClasses = orderEntry.getFiles(OrderRootType.CLASSES); - for (VirtualFile[] roots : new VirtualFile[][]{libSources, libClasses}) { - for (VirtualFile root : roots) { - if (visitedRoots.add(root)) { - iterateRecursively(root, processor, indicator); - } - } - } - } - } - } - } - } + public abstract boolean getFilesWithKey(@NotNull ID indexId, + @NotNull Set dataKeys, + @NotNull Processor processor, + @NotNull GlobalSearchScope filter); - private static void iterateRecursively(@Nullable final VirtualFile root, @NotNull final ContentIterator processor, @Nullable ProgressIndicator indicator) { - if (root != null) { - if (indicator != null) { - indicator.checkCanceled(); - indicator.setText2(root.getPresentableUrl()); - } - - if (root.isDirectory()) { - for (VirtualFile file : root.getChildren()) { - if (file.isDirectory()) { - iterateRecursively(file, processor, indicator); - } - else { - processor.processFile(file); - } - } - } - else { - processor.processFile(root); - } - } - } - - private static class StorageGuard { - private int myHolds = 0; - - public interface Holder { - void leave(); - } - - private final Holder myTrueHolder = new Holder() { - @Override - public void leave() { - StorageGuard.this.leave(true); - } - }; - private final Holder myFalseHolder = new Holder() { - @Override - public void leave() { - StorageGuard.this.leave(false); - } - }; - - @NotNull - public synchronized Holder enter(boolean mode) { - if (mode) { - while (myHolds < 0) { - try { - wait(); - } - catch (InterruptedException ignored) { - } - } - myHolds++; - return myTrueHolder; - } - else { - while (myHolds > 0) { - try { - wait(); - } - catch (InterruptedException ignored) { - } - } - myHolds--; - return myFalseHolder; - } - } - - private synchronized void leave(boolean mode) { - myHolds += mode? -1 : 1; - if (myHolds == 0) { - notifyAll(); - } - } + public abstract boolean processAllKeys(@NotNull ID indexId, Processor processor, @Nullable Project project); + public interface ValueProcessor { + /** + * @param value a value to process + * @param file the file the value came from + * @return false if no further processing is needed, true otherwise + */ + boolean process(VirtualFile file, V value); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java new file mode 100644 index 000000000000..1cf3b2677d89 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -0,0 +1,2327 @@ +/* + * Copyright 2000-2012 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.util.indexing; + +import com.intellij.AppTopics; +import com.intellij.history.LocalHistory; +import com.intellij.ide.caches.CacheUpdater; +import com.intellij.lang.ASTNode; +import com.intellij.notification.NotificationDisplayType; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.application.ApplicationAdapter; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.impl.EditorHighlighterCache; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; +import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.*; +import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; +import com.intellij.openapi.project.*; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; +import com.intellij.openapi.vfs.newvfs.BulkFileListener; +import com.intellij.openapi.vfs.newvfs.ManagingFS; +import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.openapi.vfs.newvfs.events.VFileEvent; +import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon; +import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiDocumentTransactionListener; +import com.intellij.psi.impl.source.PsiFileImpl; +import com.intellij.psi.search.EverythingGlobalScope; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.stubs.SerializationManager; +import com.intellij.util.*; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ConcurrentHashSet; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.*; +import com.intellij.util.io.DataOutputStream; +import com.intellij.util.io.storage.HeavyProcessLatch; +import com.intellij.util.messages.MessageBus; +import com.intellij.util.messages.MessageBusConnection; +import gnu.trove.*; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.*; +import java.lang.ref.SoftReference; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Eugene Zhuravlev + * Date: Dec 20, 2007 + */ + +public class FileBasedIndexImpl extends FileBasedIndex { + private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.FileBasedIndexImpl"); + @NonNls + private static final String CORRUPTION_MARKER_NAME = "corruption.marker"; + private final Map, Pair, InputFilter>> myIndices = new THashMap, Pair, InputFilter>>(); + private final Map, Semaphore> myUnsavedDataIndexingSemaphores = new THashMap, Semaphore>(); + private final TObjectIntHashMap> myIndexIdToVersionMap = new TObjectIntHashMap>(); + private final Set> myNotRequiringContentIndices = new THashSet>(); + private final Set> myRequiringContentIndices = new THashSet>(); + private final Set myNoLimitCheckTypes = new THashSet(); + + private final PerIndexDocumentVersionMap myLastIndexedDocStamps = new PerIndexDocumentVersionMap(); + @NotNull private final ChangedFilesCollector myChangedFilesCollector; + + private final List myIndexableSets = ContainerUtil.createEmptyCOWList(); + private final Map myIndexableSetToProjectMap = new THashMap(); + + private static final int OK = 1; + private static final int REQUIRES_REBUILD = 2; + private static final int REBUILD_IN_PROGRESS = 3; + private static final Map, AtomicInteger> ourRebuildStatus = new THashMap, AtomicInteger>(); + + private final VirtualFileManagerEx myVfManager; + private final FileDocumentManager myFileDocumentManager; + private final FileTypeManager myFileTypeManager; + private final ConcurrentHashSet> myUpToDateIndices = new ConcurrentHashSet>(); + private final Map myTransactionMap = new THashMap(); + + private static final int ALREADY_PROCESSED = 0x04; + + @Nullable private final String myConfigPath; + @Nullable private final String mySystemPath; + private final boolean myIsUnitTestMode; + @Nullable private ScheduledFuture myFlushingFuture; + private volatile int myLocalModCount; + private volatile int myFilesModCount; + + @Override + public void requestReindex(@NotNull final VirtualFile file) { + myChangedFilesCollector.invalidateIndices(file, true); + } + + @Override + public void requestReindexExcluded(@NotNull final VirtualFile file) { + myChangedFilesCollector.invalidateIndices(file, false); + } + + public FileBasedIndexImpl(final VirtualFileManagerEx vfManager, + FileDocumentManager fdm, + FileTypeManager fileTypeManager, + @NotNull MessageBus bus, + SerializationManager sm + /*need this parameter to ensure component dependency*/) throws IOException { + myVfManager = vfManager; + myFileDocumentManager = fdm; + myFileTypeManager = fileTypeManager; + myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); + myConfigPath = calcConfigPath(PathManager.getConfigPath()); + mySystemPath = calcConfigPath(PathManager.getSystemPath()); + + final MessageBusConnection connection = bus.connect(); + connection.subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { + @Override + public void transactionStarted(final Document doc, final PsiFile file) { + if (file != null) { + synchronized (myTransactionMap) { + myTransactionMap.put(doc, file); + } + myUpToDateIndices.clear(); + } + } + + @Override + public void transactionCompleted(final Document doc, final PsiFile file) { + synchronized (myTransactionMap) { + myTransactionMap.remove(doc); + } + } + }); + + connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener() { + @Nullable private Map> myTypeToExtensionMap; + @Override + public void beforeFileTypesChanged(final FileTypeEvent event) { + cleanupProcessedFlag(); + myTypeToExtensionMap = new THashMap>(); + for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { + myTypeToExtensionMap.put(type, getExtensions(type)); + } + } + + @Override + public void fileTypesChanged(final FileTypeEvent event) { + final Map> oldExtensions = myTypeToExtensionMap; + myTypeToExtensionMap = null; + if (oldExtensions != null) { + final Map> newExtensions = new THashMap>(); + for (FileType type : myFileTypeManager.getRegisteredFileTypes()) { + newExtensions.put(type, getExtensions(type)); + } + // we are interested only in extension changes or removals. + // addition of an extension is handled separately by RootsChanged event + if (!newExtensions.keySet().containsAll(oldExtensions.keySet())) { + rebuildAllIndices(); + return; + } + for (Map.Entry> entry : oldExtensions.entrySet()) { + FileType fileType = entry.getKey(); + Set strings = entry.getValue(); + if (!newExtensions.get(fileType).containsAll(strings)) { + rebuildAllIndices(); + return; + } + } + } + } + + @NotNull + private Set getExtensions(@NotNull FileType type) { + final Set set = new THashSet(); + for (FileNameMatcher matcher : myFileTypeManager.getAssociations(type)) { + set.add(matcher.getPresentableString()); + } + return set; + } + + private void rebuildAllIndices() { + for (ID indexId : myIndices.keySet()) { + try { + clearIndex(indexId); + } + catch (StorageException e) { + LOG.info(e); + } + } + scheduleIndexRebuild(true); + } + }); + + connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + @Override + public void before(@NotNull List events) { + for (VFileEvent event : events) { + final Object requestor = event.getRequestor(); + if (requestor instanceof FileDocumentManager || requestor instanceof PsiManager || requestor == LocalHistory.VFS_EVENT_REQUESTOR) { + cleanupMemoryStorage(); + break; + } + } + } + + @Override + public void after(@NotNull List events) { + } + }); + + connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { + @Override + public void fileContentReloaded(VirtualFile file, @NotNull Document document) { + cleanupMemoryStorage(); + } + + @Override + public void unsavedDocumentsDropped() { + cleanupMemoryStorage(); + } + }); + + ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { + @Override + public void writeActionStarted(Object action) { + myUpToDateIndices.clear(); + } + }); + + myChangedFilesCollector = new ChangedFilesCollector(); + + /* + final File workInProgressFile = getMarkerFile(); + if (workInProgressFile.exists()) { + // previous IDEA session was closed incorrectly, so drop all indices + FileUtil.delete(PathManager.getIndexRoot()); + } + */ + + try { + final FileBasedIndexExtension[] extensions = Extensions.getExtensions(FileBasedIndexExtension.EXTENSION_POINT_NAME); + for (FileBasedIndexExtension extension : extensions) { + ourRebuildStatus.put(extension.getName(), new AtomicInteger(OK)); + } + + final File corruptionMarker = new File(PathManager.getIndexRoot(), CORRUPTION_MARKER_NAME); + final boolean currentVersionCorrupted = corruptionMarker.exists(); + boolean versionChanged = false; + for (FileBasedIndexExtension extension : extensions) { + versionChanged |= registerIndexer(extension, currentVersionCorrupted); + } + FileUtil.delete(corruptionMarker); + + String rebuildNotification = null; + if (currentVersionCorrupted) { + rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; + } + else if (versionChanged) { + rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; + } + if (rebuildNotification != null + && !ApplicationManager.getApplication().isHeadlessEnvironment() + && Registry.is("ide.showIndexRebuildMessage")) { + new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) + .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); + } + + dropUnregisteredIndices(); + + // check if rebuild was requested for any index during registration + for (ID indexId : myIndices.keySet()) { + if (ourRebuildStatus.get(indexId).compareAndSet(REQUIRES_REBUILD, OK)) { + try { + clearIndex(indexId); + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.error(e); + } + } + } + + myVfManager.addVirtualFileListener(myChangedFilesCollector); + + registerIndexableSet(new AdditionalIndexableFileSet(), null); + } + finally { + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + @Override + public void run() { + performShutdown(); + } + }); + //FileUtil.createIfDoesntExist(workInProgressFile); + saveRegisteredIndices(myIndices.keySet()); + myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() { + int lastModCount = 0; + @Override + public void run() { + if (lastModCount == myLocalModCount) { + flushAllIndices(lastModCount); + } + lastModCount = myLocalModCount; + } + }); + + } + } + + @Override + public void initComponent() { + } + + @Nullable + private static String calcConfigPath(final String path) { + try { + final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()); + return _path.endsWith("/")? _path : _path + "/" ; + } + catch (IOException e) { + LOG.info(e); + return null; + } + } + + /** + * @return true if registered index requires full rebuild for some reason, e.g. is just created or corrupted + * + * @param extension + * @param isCurrentVersionCorrupted + */ + private boolean registerIndexer(@NotNull final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) throws IOException { + final ID name = extension.getName(); + final int version = extension.getVersion(); + final File versionFile = IndexInfrastructure.getVersionFile(name); + final boolean versionFileExisted = versionFile.exists(); + boolean versionChanged = false; + if (isCurrentVersionCorrupted || IndexInfrastructure.versionDiffers(versionFile, version)) { + if (!isCurrentVersionCorrupted && versionFileExisted) { + versionChanged = true; + LOG.info("Version has changed for index " + name + ". The index will be rebuilt."); + } + FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + IndexInfrastructure.rewriteVersion(versionFile, version); + } + + for (int attempt = 0; attempt < 2; attempt++) { + try { + final MapIndexStorage storage = new MapIndexStorage(IndexInfrastructure.getStorageFile(name), extension.getKeyDescriptor(), extension.getValueExternalizer(), extension.getCacheSize()); + final MemoryIndexStorage memStorage = new MemoryIndexStorage(storage); + final UpdatableIndex index = createIndex(name, extension, memStorage); + final InputFilter inputFilter = extension.getInputFilter(); + + assert inputFilter != null : "Index extension " + name + " must provide non-null input filter"; + + myIndices.put(name, new Pair, InputFilter>(index, new IndexableFilesFilter(inputFilter))); + myUnsavedDataIndexingSemaphores.put(name, new Semaphore()); + myIndexIdToVersionMap.put(name, version); + if (!extension.dependsOnFileContent()) { + myNotRequiringContentIndices.add(name); + } + else { + myRequiringContentIndices.add(name); + } + myNoLimitCheckTypes.addAll(extension.getFileTypesWithSizeLimitNotApplicable()); + break; + } + catch (IOException e) { + LOG.info(e); + FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + IndexInfrastructure.rewriteVersion(versionFile, version); + } + } + return versionChanged; + } + + private static void saveRegisteredIndices(@NotNull Collection> ids) { + final File file = getRegisteredIndicesFile(); + try { + FileUtil.createIfDoesntExist(file); + final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); + try { + os.writeInt(ids.size()); + for (ID id : ids) { + IOUtil.writeString(id.toString(), os); + } + } + finally { + os.close(); + } + } + catch (IOException ignored) { + } + } + + @NotNull + private static Set readRegisteredIndexNames() { + final Set result = new THashSet(); + try { + final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(getRegisteredIndicesFile()))); + try { + final int size = in.readInt(); + for (int idx = 0; idx < size; idx++) { + result.add(IOUtil.readString(in)); + } + } + finally { + in.close(); + } + } + catch (IOException ignored) { + } + return result; + } + + @NotNull + private static File getRegisteredIndicesFile() { + return new File(PathManager.getIndexRoot(), "registered"); + } + + @NotNull + private UpdatableIndex createIndex(@NotNull final ID indexId, @NotNull final FileBasedIndexExtension extension, @NotNull final MemoryIndexStorage storage) throws IOException { + final MapReduceIndex index; + if (extension instanceof CustomImplementationFileBasedIndexExtension) { + final UpdatableIndex custom = ((CustomImplementationFileBasedIndexExtension)extension).createIndexImplementation(indexId, this, storage); + + assert custom != null : "Custom index implementation must not be null; index: " + indexId; + + if (!(custom instanceof MapReduceIndex)) { + return custom; + } + index = (MapReduceIndex)custom; + } + else { + index = new MapReduceIndex(indexId, extension.getIndexer(), storage); + } + + final KeyDescriptor keyDescriptor = extension.getKeyDescriptor(); + index.setInputIdToDataKeysIndex(new Factory>>() { + @Override + public PersistentHashMap> create() { + try { + return createIdToDataKeysIndex(indexId, keyDescriptor, storage); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }); + + return index; + } + + @NotNull + private static PersistentHashMap> createIdToDataKeysIndex(@NotNull final ID indexId, + @NotNull final KeyDescriptor keyDescriptor, + @NotNull MemoryIndexStorage storage) throws IOException { + final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId); + final Ref isBufferingMode = new Ref(false); + final TIntObjectHashMap> tempMap = new TIntObjectHashMap>(); + + final DataExternalizer> dataExternalizer = new DataExternalizer>() { + @Override + public void save(DataOutput out, @NotNull Collection value) throws IOException { + try { + DataInputOutputUtil.writeINT(out, value.size()); + for (K key : value) { + keyDescriptor.save(out, key); + } + } + catch (IllegalArgumentException e) { + throw new IOException("Error saving data for index " + indexId, e); + } + } + + @NotNull + @Override + public Collection read(DataInput in) throws IOException { + try { + final int size = DataInputOutputUtil.readINT(in); + final List list = new ArrayList(size); + for (int idx = 0; idx < size; idx++) { + list.add(keyDescriptor.read(in)); + } + return list; + } + catch (IllegalArgumentException e) { + throw new IOException("Error reading data for index " + indexId, e); + } + } + }; + + // Important! Update IdToDataKeysIndex depending on the sate of "buffering" flag from the MemoryStorage. + // If buffering is on, all changes should be done in memory (similar to the way it is done in memory storage). + // Otherwise data in IdToDataKeysIndex will not be in sync with the 'main' data in the index on disk and index updates will be based on the + // wrong sets of keys for the given file. This will lead to unpredictable results in main index because it will not be + // cleared properly before updating (removed data will still be present on disk). See IDEA-52223 for illustration of possible effects. + + final PersistentHashMap> map = new PersistentHashMap>( + indexStorageFile, EnumeratorIntegerDescriptor.INSTANCE, dataExternalizer + ) { + + @Override + protected Collection doGet(Integer integer) throws IOException { + if (isBufferingMode.get()) { + final Collection collection = tempMap.get(integer); + if (collection != null) { + return collection; + } + } + return super.doGet(integer); + } + + @Override + protected void doPut(Integer integer, @Nullable Collection ks) throws IOException { + if (isBufferingMode.get()) { + tempMap.put(integer, ks == null? Collections.emptySet() : ks); + } + else { + super.doPut(integer, ks); + } + } + + @Override + protected void doRemove(Integer integer) throws IOException { + if (isBufferingMode.get()) { + tempMap.put(integer, Collections.emptySet()); + } + else { + super.doRemove(integer); + } + } + }; + + storage.addBufferingStateListsner(new MemoryIndexStorage.BufferingStateListener() { + @Override + public void bufferingStateChanged(boolean newState) { + synchronized (map) { + isBufferingMode.set(newState); + } + } + @Override + public void memoryStorageCleared() { + synchronized (map) { + tempMap.clear(); + } + } + }); + return map; + } + + @Override + public void disposeComponent() { + performShutdown(); + } + + private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false); + + private void performShutdown() { + if (!myShutdownPerformed.compareAndSet(false, true)) { + return; // already shut down + } + try { + if (myFlushingFuture != null) { + myFlushingFuture.cancel(false); + myFlushingFuture = null; + } + + myFileDocumentManager.saveAllDocuments(); + } + finally { + LOG.info("START INDEX SHUTDOWN"); + try { + myChangedFilesCollector.forceUpdate(null, null, null, true); + + for (ID indexId : myIndices.keySet()) { + final UpdatableIndex index = getIndex(indexId); + assert index != null; + checkRebuild(indexId, true); // if the index was scheduled for rebuild, only clean it + //LOG.info("DISPOSING " + indexId); + index.dispose(); + } + + myVfManager.removeVirtualFileListener(myChangedFilesCollector); + + //FileUtil.delete(getMarkerFile()); + } + catch (Throwable e) { + LOG.info("Problems during index shutdown", e); + throw new RuntimeException(e); + } + LOG.info("END INDEX SHUTDOWN"); + } + } + + private void flushAllIndices(final long modCount) { + if (HeavyProcessLatch.INSTANCE.isRunning()) { + return; + } + IndexingStamp.flushCache(); + for (ID indexId : new ArrayList>(myIndices.keySet())) { + if (HeavyProcessLatch.INSTANCE.isRunning() || modCount != myLocalModCount) { + return; // do not interfere with 'main' jobs + } + try { + final UpdatableIndex index = getIndex(indexId); + if (index != null) { + index.flush(); + } + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + + if (!HeavyProcessLatch.INSTANCE.isRunning() && modCount == myLocalModCount) { // do not interfere with 'main' jobs + SerializationManager.getInstance().flushNameStorage(); + } + } + + /** + * @param project it is guaranteed to return data which is up-to-date withing the project + * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist + */ + @Override + @NotNull + public Collection getAllKeys(@NotNull final ID indexId, @NotNull Project project) { + Set allKeys = new THashSet(); + processAllKeys(indexId, new CommonProcessors.CollectProcessor(allKeys), project); + return allKeys; + } + + /** + * @param project it is guaranteed to return data which is up-to-date withing the project + * Keys obtained from the files which do not belong to the project specified may not be up-to-date or even exist + */ + @Override + public boolean processAllKeys(@NotNull final ID indexId, Processor processor, @Nullable Project project) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return true; + } + ensureUpToDate(indexId, project, project != null? GlobalSearchScope.allScope(project) : new EverythingGlobalScope()); + return index.processAllKeys(processor); + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + + return false; + } + + private static final ThreadLocal myUpToDateCheckState = new ThreadLocal(); + + public static void disableUpToDateCheckForCurrentThread() { + final Integer currentValue = myUpToDateCheckState.get(); + myUpToDateCheckState.set(currentValue == null? 1 : currentValue.intValue() + 1); + } + + public static void enableUpToDateCheckForCurrentThread() { + final Integer currentValue = myUpToDateCheckState.get(); + if (currentValue != null) { + final int newValue = currentValue.intValue() - 1; + if (newValue != 0) { + myUpToDateCheckState.set(newValue); + } + else { + myUpToDateCheckState.remove(); + } + } + } + + private static boolean isUpToDateCheckEnabled() { + final Integer value = myUpToDateCheckState.get(); + return value == null || value.intValue() == 0; + } + + + private final ThreadLocal myReentrancyGuard = new ThreadLocal() { + @Override + protected Boolean initialValue() { + return Boolean.FALSE; + } + }; + + /** + * DO NOT CALL DIRECTLY IN CLIENT CODE + * The method is internal to indexing engine end is called internally. The method is public due to implementation details + */ + @Override + public void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter) { + ensureUpToDate(indexId, project, filter, null); + } + + @Override + protected void ensureUpToDate(@NotNull final ID indexId, + @Nullable Project project, + @Nullable GlobalSearchScope filter, + @Nullable VirtualFile restrictedFile) { + if (!needsFileContentLoading(indexId)) { + return; //indexed eagerly in foreground while building unindexed file list + } + if (isDumb(project)) { + handleDumbMode(project); + } + + if (myReentrancyGuard.get().booleanValue()) { + //assert false : "ensureUpToDate() is not reentrant!"; + return; + } + myReentrancyGuard.set(Boolean.TRUE); + + try { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + if (isUpToDateCheckEnabled()) { + try { + checkRebuild(indexId, false); + myChangedFilesCollector.forceUpdate(project, filter, restrictedFile, false); + indexUnsavedDocuments(indexId, project, filter, restrictedFile); + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, e); + } + else { + throw e; + } + } + } + } + finally { + myReentrancyGuard.set(Boolean.FALSE); + } + } + + private static void handleDumbMode(@Nullable Project project) { + ProgressManager.checkCanceled(); // DumbModeAction.CANCEL + + if (project != null) { + final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); + if (progressIndicator instanceof BackgroundableProcessIndicator) { + final BackgroundableProcessIndicator indicator = (BackgroundableProcessIndicator)progressIndicator; + if (indicator.getDumbModeAction() == DumbModeAction.WAIT) { + assert !ApplicationManager.getApplication().isDispatchThread(); + DumbService.getInstance(project).waitForSmartMode(); + return; + } + } + } + + throw new IndexNotReadyException(); + } + + private static boolean isDumb(@Nullable Project project) { + if (project != null) { + return DumbServiceImpl.getInstance(project).isDumb(); + } + for (Project proj : ProjectManager.getInstance().getOpenProjects()) { + if (DumbServiceImpl.getInstance(proj).isDumb()) { + return true; + } + } + return false; + } + + @Override + @NotNull + public List getValues(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { + final List values = new SmartList(); + processValuesImpl(indexId, dataKey, true, null, new ValueProcessor() { + @Override + public boolean process(final VirtualFile file, final V value) { + values.add(value); + return true; + } + }, filter); + return values; + } + + @Override + @NotNull + public Collection getContainingFiles(@NotNull final ID indexId, @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { + final Set files = new THashSet(); + processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { + @Override + public boolean process(final VirtualFile file, final V value) { + files.add(file); + return true; + } + }, filter); + return files; + } + + + /** + * @return false if ValueProcessor.process() returned false; true otherwise or if ValueProcessor was not called at all + */ + @Override + public boolean processValues(@NotNull final ID indexId, @NotNull final K dataKey, @Nullable final VirtualFile inFile, + @NotNull ValueProcessor processor, @NotNull final GlobalSearchScope filter) { + return processValuesImpl(indexId, dataKey, false, inFile, processor, filter); + } + + + + + @Nullable + private R processExceptions(@NotNull final ID indexId, + @Nullable final VirtualFile restrictToFile, + @NotNull final GlobalSearchScope filter, + @NotNull ThrowableConvertor, R, StorageException> computable) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return null; + } + final Project project = filter.getProject(); + //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; + ensureUpToDate(indexId, project, filter, restrictToFile); + + try { + index.getReadLock().lock(); + return computable.convert(index); + } + finally { + index.getReadLock().unlock(); + } + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = getCauseToRebuildIndex(e); + if (cause != null) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + return null; + } + + private boolean processValuesImpl(@NotNull final ID indexId, final K dataKey, final boolean ensureValueProcessedOnce, + @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, + @NotNull final GlobalSearchScope filter) { + ThrowableConvertor, Boolean, StorageException> keyProcessor = new ThrowableConvertor, Boolean, StorageException>() { + @Override + public Boolean convert(@NotNull UpdatableIndex index) throws StorageException { + final ValueContainer container = index.getData(dataKey); + + boolean shouldContinue = true; + + if (restrictToFile != null) { + if (restrictToFile instanceof VirtualFileWithId) { + final int restrictedFileId = getFileId(restrictToFile); + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + final V value = valueIt.next(); + if (container.isAssociated(value, restrictedFileId)) { + shouldContinue = processor.process(restrictToFile, value); + if (!shouldContinue) { + break; + } + } + } + } + } + else { + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + ProjectIndexableFilesFilter projectFilesSet = projectIndexableFiles(filter.getProject()); + VALUES_LOOP: for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { + final V value = valueIt.next(); + for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { + final int id = inputIdsIterator.next(); + if (projectFilesSet != null && !projectFilesSet.contains(id)) continue; + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + shouldContinue = processor.process(file, value); + if (!shouldContinue) { + break VALUES_LOOP; + } + if (ensureValueProcessedOnce) { + break; // continue with the next value + } + } + } + } + } + return shouldContinue; + } + }; + final Boolean result = processExceptions(indexId, restrictToFile, filter, keyProcessor); + return result == null || result.booleanValue(); + } + + @Override + public boolean processFilesContainingAllKeys(@NotNull final ID indexId, + @NotNull final Collection dataKeys, + @NotNull final GlobalSearchScope filter, + @Nullable Condition valueChecker, + @NotNull final Processor processor) { + ProjectIndexableFilesFilter filesSet = projectIndexableFiles(filter.getProject()); + final TIntHashSet set = collectFileIdsContainingAllKeys(indexId, dataKeys, filter, valueChecker, filesSet); + return set != null && processVirtualFiles(set, filter, processor); + } + + private static final Key> ourProjectFilesSetKey = Key.create("projectFiles"); + + public static final class ProjectIndexableFilesFilter { + private static final int SHIFT = 6; + private static final int MASK = (1 << SHIFT) - 1; + private final long[] myBitMask; + private final int myModificationCount; + private final int myMinId; + private final int myMaxId; + + private ProjectIndexableFilesFilter(@NotNull TIntHashSet set, int modificationCount) { + myModificationCount = modificationCount; + final int[] minMax = new int[2]; + if (set.size() > 0) { + minMax[0] = minMax[1] = set.iterator().next(); + } + set.forEach(new TIntProcedure() { + @Override + public boolean execute(int value) { + minMax[0] = Math.min(minMax[0], value); + minMax[1] = Math.max(minMax[1], value); + return true; + } + }); + myMaxId = minMax[1]; + myMinId = minMax[0]; + myBitMask = new long[((myMaxId - myMinId) >> SHIFT) + 1]; + set.forEach(new TIntProcedure() { + @Override + public boolean execute(int value) { + value = value - myMinId; + myBitMask[value >> SHIFT] |= (1L << (value & MASK)); + return true; + } + }); + } + + public boolean contains(int id) { + if (id < myMinId) return false; + if (id > myMaxId) return false; + id -= myMinId; + return (myBitMask[id >> SHIFT] & (1L << (id & MASK))) != 0; + } + } + + @Nullable + public ProjectIndexableFilesFilter projectIndexableFiles(@Nullable Project project) { + if (project == null) return null; + + SoftReference reference = project.getUserData(ourProjectFilesSetKey); + ProjectIndexableFilesFilter data = reference != null ? reference.get() : null; + if (data != null && data.myModificationCount == myFilesModCount) return data; + + final TIntHashSet filesSet = new TIntHashSet(); + iterateIndexableFiles(new ContentIterator() { + @Override + public boolean processFile(@NotNull VirtualFile fileOrDir) { + filesSet.add(((VirtualFileWithId)fileOrDir).getId()); + return true; + } + }, project, ProgressManager.getInstance().getProgressIndicator()); + ProjectIndexableFilesFilter files = new ProjectIndexableFilesFilter(filesSet, myFilesModCount); + project.putUserData(ourProjectFilesSetKey, new SoftReference(files)); + return files; + } + + @Nullable + private TIntHashSet collectFileIdsContainingAllKeys(@NotNull final ID indexId, + @NotNull final Collection dataKeys, + @NotNull final GlobalSearchScope filter, + @Nullable final Condition valueChecker, + @Nullable final ProjectIndexableFilesFilter projectFilesFilter) { + final ThrowableConvertor, TIntHashSet, StorageException> convertor = + new ThrowableConvertor, TIntHashSet, StorageException>() { + @Nullable + @Override + public TIntHashSet convert(@NotNull UpdatableIndex index) throws StorageException { + TIntHashSet mainIntersection = null; + + for (K dataKey : dataKeys) { + ProgressManager.checkCanceled(); + final TIntHashSet copy = new TIntHashSet(); + final ValueContainer container = index.getData(dataKey); + + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + final V value = valueIt.next(); + if (valueChecker != null && !valueChecker.value(value)) { + continue; + } + + ValueContainer.IntIterator iterator = container.getInputIdsIterator(value); + + if (mainIntersection == null || iterator.size() < mainIntersection.size()) { + for (final ValueContainer.IntIterator inputIdsIterator = iterator; inputIdsIterator.hasNext(); ) { + final int id = inputIdsIterator.next(); + if (mainIntersection == null && (projectFilesFilter == null || projectFilesFilter.contains(id)) || + mainIntersection != null && mainIntersection.contains(id) + ) { + copy.add(id); + } + } + } else { + mainIntersection.forEach(new TIntProcedure() { + final ValueContainer.IntPredicate predicate = container.getValueAssociationPredicate(value); + @Override + public boolean execute(int id) { + if (predicate.contains(id)) copy.add(id); + return true; + } + }); + } + } + + mainIntersection = copy; + if (mainIntersection.isEmpty()) { + return new TIntHashSet(); + } + } + + return mainIntersection; + } + }; + + + return processExceptions(indexId, null, filter, convertor); + } + + private static boolean processVirtualFiles(@NotNull TIntHashSet ids, + @NotNull final GlobalSearchScope filter, + @NotNull final Processor processor) { + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + return ids.forEach(new TIntProcedure() { + @Override + public boolean execute(int id) { + ProgressManager.checkCanceled(); + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + return processor.process(file); + } + return true; + } + }); + } + + @Nullable + public static Throwable getCauseToRebuildIndex(@NotNull RuntimeException e) { + Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException || + cause instanceof IllegalArgumentException) return cause; + return null; + } + + @Override + public boolean getFilesWithKey(@NotNull final ID indexId, + @NotNull final Set dataKeys, + @NotNull Processor processor, + @NotNull GlobalSearchScope filter) { + try { + final UpdatableIndex index = getIndex(indexId); + if (index == null) { + return true; + } + final Project project = filter.getProject(); + //assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries"; + ensureUpToDate(indexId, project, filter); + + try { + index.getReadLock().lock(); + final List locals = new ArrayList(); + for (K dataKey : dataKeys) { + TIntHashSet local = new TIntHashSet(); + locals.add(local); + final ValueContainer container = index.getData(dataKey); + + for (final Iterator valueIt = container.getValueIterator(); valueIt.hasNext();) { + final V value = valueIt.next(); + for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext();) { + final int id = inputIdsIterator.next(); + local.add(id); + } + } + } + + if (locals.isEmpty()) { + return true; + } + + Collections.sort(locals, new Comparator() { + @Override + public int compare(TIntHashSet o1, TIntHashSet o2) { + return o1.size() - o2.size(); + } + }); + + final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + TIntIterator ids = join(locals).iterator(); + ProjectIndexableFilesFilter projectIndexableFilesFilter = projectIndexableFiles(project); + while (ids.hasNext()) { + int id = ids.next(); + if (projectIndexableFilesFilter != null && !projectIndexableFilesFilter.contains(id)) continue; + //VirtualFile file = IndexInfrastructure.findFileById(fs, id); + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && filter.accept(file)) { + if (!processor.process(file)) { + return false; + } + } + } + } + finally { + index.getReadLock().unlock(); + } + } + catch (StorageException e) { + scheduleRebuild(indexId, e); + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StorageException || cause instanceof IOException) { + scheduleRebuild(indexId, cause); + } + else { + throw e; + } + } + return true; + } + + @NotNull + private static TIntHashSet join(@NotNull List locals) { + TIntHashSet result = locals.get(0); + if (locals.size() > 1) { + TIntIterator it = result.iterator(); + + while (it.hasNext()) { + int id = it.next(); + for (int i = 1; i < locals.size(); i++) { + if (!locals.get(i).contains(id)) { + it.remove(); + break; + } + } + } + } + return result; + } + + @Override + public void scheduleRebuild(@NotNull final ID indexId, @NotNull final Throwable e) { + LOG.info(e); + requestRebuild(indexId); + try { + checkRebuild(indexId, false); + } + catch (ProcessCanceledException ignored) { + } + } + + private void checkRebuild(@NotNull final ID indexId, final boolean cleanupOnly) { + final AtomicInteger status = ourRebuildStatus.get(indexId); + if (status.get() == OK) return; + if (status.compareAndSet(REQUIRES_REBUILD, REBUILD_IN_PROGRESS)) { + cleanupProcessedFlag(); + + final Runnable rebuildRunnable = new Runnable() { + @Override + public void run() { + try { + clearIndex(indexId); + if (!cleanupOnly) { + scheduleIndexRebuild(false); + } + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.info(e); + } + finally { + status.compareAndSet(REBUILD_IN_PROGRESS, OK); + } + } + }; + + if (cleanupOnly || myIsUnitTestMode) { + rebuildRunnable.run(); + } + else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new Task.Modal(null, "Updating index", false) { + @Override + public void run(@NotNull final ProgressIndicator indicator) { + indicator.setIndeterminate(true); + rebuildRunnable.run(); + } + }.queue(); + } + }); + } + } + + if (status.get() == REBUILD_IN_PROGRESS) { + throw new ProcessCanceledException(); + } + } + + private void scheduleIndexRebuild(boolean forceDumbMode) { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + final Set updatersToRun = Collections.singleton(new UnindexedFilesUpdater(project, this)); + final DumbServiceImpl service = DumbServiceImpl.getInstance(project); + if (forceDumbMode) { + service.queueCacheUpdateInDumbMode(updatersToRun); + } + else { + service.queueCacheUpdate(updatersToRun); + } + } + } + + private void clearIndex(@NotNull final ID indexId) throws StorageException { + final UpdatableIndex index = getIndex(indexId); + assert index != null: "Index with key " + indexId + " not found or not registered properly"; + index.clear(); + try { + IndexInfrastructure.rewriteVersion(IndexInfrastructure.getVersionFile(indexId), myIndexIdToVersionMap.get(indexId)); + } + catch (IOException e) { + LOG.error(e); + } + } + + @NotNull + private Set getUnsavedOrTransactedDocuments() { + final Set docs = new THashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); + synchronized (myTransactionMap) { + docs.addAll(myTransactionMap.keySet()); + } + return docs; + } + + private void indexUnsavedDocuments(@NotNull ID indexId, + @Nullable Project project, + GlobalSearchScope filter, + VirtualFile restrictedFile) throws StorageException { + if (myUpToDateIndices.contains(indexId)) { + return; // no need to index unsaved docs + } + + final Set documents = getUnsavedOrTransactedDocuments(); + if (!documents.isEmpty()) { + // now index unsaved data + final StorageGuard.Holder guard = setDataBufferingEnabled(true); + try { + final Semaphore semaphore = myUnsavedDataIndexingSemaphores.get(indexId); + + assert semaphore != null : "Semaphore for unsaved data indexing was not initialized for index " + indexId; + + semaphore.down(); + boolean allDocsProcessed = true; + try { + for (Document document : documents) { + allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); + } + } + finally { + semaphore.up(); + + while (!semaphore.waitFor(500)) { // may need to wait until another thread is done with indexing + if (Thread.holdsLock(PsiLock.LOCK)) { + break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. + } + } + if (allDocsProcessed && !hasActiveTransactions()) { + myUpToDateIndices.add(indexId); // safe to set the flag here, because it will be cleared under the WriteAction + } + } + } + finally { + guard.leave(); + } + } + } + + private boolean hasActiveTransactions() { + synchronized (myTransactionMap) { + return !myTransactionMap.isEmpty(); + } + } + + private interface DocumentContent { + String getText(); + long getModificationStamp(); + } + + private static class AuthenticContent implements DocumentContent { + private final Document myDocument; + + private AuthenticContent(final Document document) { + myDocument = document; + } + + @Override + public String getText() { + return myDocument.getText(); + } + + @Override + public long getModificationStamp() { + return myDocument.getModificationStamp(); + } + } + + private static class PsiContent implements DocumentContent { + private final Document myDocument; + private final PsiFile myFile; + + private PsiContent(final Document document, final PsiFile file) { + myDocument = document; + myFile = file; + } + + @Override + public String getText() { + if (myFile.getModificationStamp() != myDocument.getModificationStamp()) { + final ASTNode node = myFile.getNode(); + assert node != null; + return node.getText(); + } + return myDocument.getText(); + } + + @Override + public long getModificationStamp() { + return myFile.getModificationStamp(); + } + } + +// returns false if doc was not indexed because the file does not fit in scope + private boolean indexUnsavedDocument(@NotNull final Document document, @NotNull final ID requestedIndexId, final Project project, + @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedFile) throws StorageException { + final VirtualFile vFile = myFileDocumentManager.getFile(document); + if (!(vFile instanceof VirtualFileWithId) || !vFile.isValid()) { + return true; + } + + if (restrictedFile != null) { + if(vFile != restrictedFile) { + return false; + } + } + else if (filter != null && !filter.accept(vFile)) { + return false; + } + + final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); + + final DocumentContent content; + if (dominantContentFile != null && dominantContentFile.getModificationStamp() != document.getModificationStamp()) { + content = new PsiContent(document, dominantContentFile); + } + else { + content = new AuthenticContent(document); + } + + final long currentDocStamp = content.getModificationStamp(); + if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp)) { + final Ref exRef = new Ref(null); + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + @Override + public void run() { + try { + final String contentText = content.getText(); + if (isTooLarge(vFile, contentText.length())) { + return; + } + + final FileContentImpl newFc = new FileContentImpl(vFile, contentText, vFile.getCharset()); + + if (dominantContentFile != null) { + dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, true); + newFc.putUserData(IndexingDataKeys.PSI_FILE, dominantContentFile); + } + + if (content instanceof AuthenticContent) { + newFc.putUserData(EDITOR_HIGHLIGHTER, EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)); + } + + if (getInputFilter(requestedIndexId).acceptInput(vFile)) { + newFc.putUserData(IndexingDataKeys.PROJECT, project); + final int inputId = Math.abs(getFileId(vFile)); + getIndex(requestedIndexId).update(inputId, newFc); + } + + if (dominantContentFile != null) { + dominantContentFile.putUserData(PsiFileImpl.BUILDING_STUB, null); + } + } + catch (StorageException e) { + exRef.set(e); + } + } + }); + final StorageException storageException = exRef.get(); + if (storageException != null) { + throw storageException; + } + } + return true; + } + + public static final Key EDITOR_HIGHLIGHTER = new Key("Editor"); + + @Nullable + private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { + synchronized (myTransactionMap) { + PsiFile psiFile = myTransactionMap.get(document); + if (psiFile != null) return psiFile; + } + + return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); + } + + private final StorageGuard myStorageLock = new StorageGuard(); + + @NotNull + private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) { + final StorageGuard.Holder holder = myStorageLock.enter(enabled); + for (ID indexId : myIndices.keySet()) { + final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); + assert index != null; + final IndexStorage indexStorage = index.getStorage(); + ((MemoryIndexStorage)indexStorage).setBufferingEnabled(enabled); + } + return holder; + } + + private void cleanupMemoryStorage() { + myLastIndexedDocStamps.clear(); + for (ID indexId : myIndices.keySet()) { + final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); + assert index != null; + final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage(); + index.getWriteLock().lock(); + try { + memStorage.clearMemoryMap(); + } + finally { + index.getWriteLock().unlock(); + } + memStorage.fireMemoryStorageCleared(); + } + } + + private void dropUnregisteredIndices() { + final Set indicesToDrop = readRegisteredIndexNames(); + for (ID key : myIndices.keySet()) { + indicesToDrop.remove(key.toString()); + } + for (String s : indicesToDrop) { + FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); + } + } + + @Override + public void requestRebuild(ID indexId, Throwable throwable) { + cleanupProcessedFlag(); + LOG.info("Rebuild requested for index " + indexId, throwable); + ourRebuildStatus.get(indexId).set(REQUIRES_REBUILD); + } + + private UpdatableIndex getIndex(ID indexId) { + final Pair, InputFilter> pair = myIndices.get(indexId); + + assert pair != null : "Index data is absent for index " + indexId; + + //noinspection unchecked + return (UpdatableIndex)pair.getFirst(); + } + + private InputFilter getInputFilter(ID indexId) { + final Pair, InputFilter> pair = myIndices.get(indexId); + + assert pair != null : "Index data is absent for index " + indexId; + + return pair.getSecond(); + } + + public int getNumberOfPendingInvalidations() { + return myChangedFilesCollector.getNumberOfPendingInvalidations(); + } + + @NotNull + public Collection getFilesToUpdate(final Project project) { + return ContainerUtil.findAll(myChangedFilesCollector.getAllFilesToUpdate(), new Condition() { + @Override + public boolean value(VirtualFile virtualFile) { + for (IndexableFileSet set : myIndexableSets) { + final Project proj = myIndexableSetToProjectMap.get(set); + if (proj != null && !proj.equals(project)) { + continue; // skip this set as associated with a different project + } + if (set.isInSet(virtualFile)) { + return true; + } + } + return false; + } + }); + } + + public void processRefreshedFile(@NotNull Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + myChangedFilesCollector.processFileImpl(project, fileContent, false); + } + + public void indexFileContent(@Nullable Project project, @NotNull com.intellij.ide.caches.FileContent content) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + final VirtualFile file = content.getVirtualFile(); + FileContentImpl fc = null; + + PsiFile psiFile = null; + + FileTypeManagerImpl.cacheFileType(file, file.getFileType()); + try { + for (final ID indexId : myIndices.keySet()) { + if (shouldIndexFile(file, indexId)) { + if (fc == null) { + byte[] currentBytes; + try { + currentBytes = content.getBytes(); + } + catch (IOException e) { + currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY; + } + fc = new FileContentImpl(file, currentBytes); + + psiFile = content.getUserData(IndexingDataKeys.PSI_FILE); + if (psiFile != null) { + psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true); + fc.putUserData(IndexingDataKeys.PSI_FILE, psiFile); + } + if (project == null) { + project = ProjectUtil.guessProjectForFile(file); + } + fc.putUserData(IndexingDataKeys.PROJECT, project); + } + + try { + ProgressManager.checkCanceled(); + updateSingleIndex(indexId, file, fc); + } + catch (ProcessCanceledException e) { + myChangedFilesCollector.scheduleForUpdate(file); + throw e; + } + catch (StorageException e) { + requestRebuild(indexId); + LOG.info(e); + } + } + } + + if (psiFile != null) { + psiFile.putUserData(PsiFileImpl.BUILDING_STUB, null); + } + } finally { + FileTypeManagerImpl.cacheFileType(file, null); + } + } + + private void updateSingleIndex(final ID indexId, @NotNull final VirtualFile file, @Nullable final FileContent currentFC) + throws StorageException { + if (ourRebuildStatus.get(indexId).get() == REQUIRES_REBUILD) { + return; // the index is scheduled for rebuild, no need to update + } + myLocalModCount++; + + final StorageGuard.Holder lock = setDataBufferingEnabled(false); + + try { + final int inputId = Math.abs(getFileId(file)); + + final UpdatableIndex index = getIndex(indexId); + assert index != null; + + final Ref exRef = new Ref(null); + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + @Override + public void run() { + try { + index.update(inputId, currentFC); + } + catch (StorageException e) { + exRef.set(e); + } + } + }); + final StorageException storageException = exRef.get(); + if (storageException != null) { + throw storageException; + } + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (file.isValid()) { + if (currentFC != null) { + IndexingStamp.update(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId)); + } + else { + // mark the file as unindexed + IndexingStamp.update(file, indexId, -1L); + } + } + } + }); + } + finally { + lock.leave(); + } + } + + private boolean needsFileContentLoading(ID indexId) { + return !myNotRequiringContentIndices.contains(indexId); + } + + private abstract static class InvalidationTask implements Runnable { + private final VirtualFile mySubj; + + protected InvalidationTask(final VirtualFile subj) { + mySubj = subj; + } + + public VirtualFile getSubj() { + return mySubj; + } + } + + private final class ChangedFilesCollector extends VirtualFileAdapter { + private final Set myFilesToUpdate = new ConcurrentHashSet(); + private final Queue myFutureInvalidations = new ConcurrentLinkedQueue(); + + private final ManagingFS myManagingFS = ManagingFS.getInstance(); + // No need to react on movement events since files stay valid, their ids don't change and all associated attributes remain intact. + + @Override + public void fileCreated(@NotNull final VirtualFileEvent event) { + markDirty(event, false); + } + + @Override + public void fileDeleted(@NotNull final VirtualFileEvent event) { + myFilesToUpdate.remove(event.getFile()); // no need to update it anymore + } + + @Override + public void fileCopied(@NotNull final VirtualFileCopyEvent event) { + markDirty(event, false); + } + + @Override + public void beforeFileDeletion(@NotNull final VirtualFileEvent event) { + invalidateIndices(event.getFile(), false); + } + + @Override + public void beforeContentsChange(@NotNull final VirtualFileEvent event) { + invalidateIndices(event.getFile(), true); + } + + @Override + public void contentsChanged(@NotNull final VirtualFileEvent event) { + markDirty(event, true); + } + + @Override + public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { + if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { + // indexes may depend on file name + final VirtualFile file = event.getFile(); + if (!file.isDirectory()) { + // name change may lead to filetype change so the file might become not indexable + // in general case have to 'unindex' the file and index it again if needed after the name has been changed + invalidateIndices(file, false); + } + } + } + + @Override + public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) { + if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) { + // indexes may depend on file name + if (!event.getFile().isDirectory()) { + markDirty(event, false); + } + } + } + + private void markDirty(@NotNull final VirtualFileEvent event, final boolean contentChange) { + final VirtualFile eventFile = event.getFile(); + cleanProcessedFlag(eventFile); + iterateIndexableFiles(eventFile, new Processor() { + @Override + public boolean process(@NotNull final VirtualFile file) { + if (!contentChange) ++myFilesModCount; + FileContent fileContent = null; + // handle 'content-less' indices separately + for (ID indexId : myNotRequiringContentIndices) { + if (getInputFilter(indexId).acceptInput(file)) { + try { + if (fileContent == null) { + fileContent = new FileContentImpl(file); + } + updateSingleIndex(indexId, file, fileContent); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + } + // For 'normal indices' schedule the file for update and stop iteration if at least one index accepts it + if (!isTooLarge(file)) { + for (ID indexId : myIndices.keySet()) { + if (needsFileContentLoading(indexId) && getInputFilter(indexId).acceptInput(file)) { + scheduleForUpdate(file); + break; // no need to iterate further, as the file is already marked + } + } + } + + return true; + } + }); + IndexingStamp.flushCache(); + } + + public void scheduleForUpdate(VirtualFile file) { + myFilesToUpdate.add(file); + } + + void invalidateIndices(@NotNull final VirtualFile file, final boolean markForReindex) { + if (isUnderConfigOrSystem(file)) { + return; + } + if (file.isDirectory()) { + if (isMock(file) || myManagingFS.wereChildrenAccessed(file)) { + final Iterable children = file instanceof NewVirtualFile + ? ((NewVirtualFile)file).iterInDbChildren() : Arrays.asList(file.getChildren()); + for (VirtualFile child : children) { + invalidateIndices(child, markForReindex); + } + } + } + else { + cleanProcessedFlag(file); + IndexingStamp.flushCache(); + final List> affectedIndices = new ArrayList>(myIndices.size()); + + for (final ID indexId : myIndices.keySet()) { + try { + if (!needsFileContentLoading(indexId)) { + if (shouldUpdateIndex(file, indexId)) { + updateSingleIndex(indexId, file, null); + } + } + else { // the index requires file content + if (shouldUpdateIndex(file, indexId)) { + affectedIndices.add(indexId); + } + } + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + + if (!affectedIndices.isEmpty()) { + if (markForReindex && !isTooLarge(file)) { + // only mark the file as unindexed, reindex will be done lazily + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + for (ID indexId : affectedIndices) { + IndexingStamp.update(file, indexId, -2L); + } + } + }); + // the file is for sure not a dir and it was previously indexed by at least one index + scheduleForUpdate(file); + } + else { + myFutureInvalidations.offer(new InvalidationTask(file) { + @Override + public void run() { + removeFileDataFromIndices(affectedIndices, file); + } + }); + } + } + if (!markForReindex) { + final boolean removedFromUpdateQueue = myFilesToUpdate.remove(file);// no need to update it anymore + if (removedFromUpdateQueue && affectedIndices.isEmpty()) { + // Currently the file is about to be deleted and previously it was scheduled for update and not processed up to now. + // Because the file was scheduled for update, at the moment of scheduling it was marked as unindexed, + // so, to be on the safe side, we have to schedule data invalidation from all content-requiring indices for this file + myFutureInvalidations.offer(new InvalidationTask(file) { + @Override + public void run() { + removeFileDataFromIndices(myRequiringContentIndices, file); + } + }); + } + } + + IndexingStamp.flushCache(); + } + } + + private void removeFileDataFromIndices(@NotNull Collection> affectedIndices, @NotNull VirtualFile file) { + Throwable unexpectedError = null; + for (ID indexId : affectedIndices) { + try { + updateSingleIndex(indexId, file, null); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + catch (ProcessCanceledException ignored) { + } + catch (Throwable e) { + LOG.info(e); + if (unexpectedError == null) { + unexpectedError = e; + } + } + } + IndexingStamp.flushCache(); + if (unexpectedError != null) { + LOG.error(unexpectedError); + } + } + + public int getNumberOfPendingInvalidations() { + return myFutureInvalidations.size(); + } + + public void ensureAllInvalidateTasksCompleted() { + final int size = getNumberOfPendingInvalidations(); + if (size == 0) { + return; + } + final ProgressIndicator current = ProgressManager.getInstance().getProgressIndicator(); + final ProgressIndicator indicator = current != null ? current : new EmptyProgressIndicator(); + indicator.setText(""); + int count = 0; + while (true) { + InvalidationTask task = myFutureInvalidations.poll(); + + if (task == null) { + break; + } + indicator.setFraction((double)count++ /size); + indicator.setText2(task.getSubj().getPresentableUrl()); + task.run(); + } + } + + private void iterateIndexableFiles(@NotNull final VirtualFile file, @NotNull final Processor processor) { + if (file.isDirectory()) { + final ContentIterator iterator = new ContentIterator() { + @Override + public boolean processFile(@NotNull final VirtualFile fileOrDir) { + if (!fileOrDir.isDirectory()) { + processor.process(fileOrDir); + } + return true; + } + }; + + for (IndexableFileSet set : myIndexableSets) { + if (set.isInSet(file)) { + set.iterateIndexableFilesIn(file, iterator); + } + } + } + else { + for (IndexableFileSet set : myIndexableSets) { + if (set.isInSet(file)) { + processor.process(file); + break; + } + } + } + } + + public Collection getAllFilesToUpdate() { + if (myFilesToUpdate.isEmpty()) { + return Collections.emptyList(); + } + return new ArrayList(myFilesToUpdate); + } + + private final Semaphore myForceUpdateSemaphore = new Semaphore(); + + private void forceUpdate(@Nullable Project project, @Nullable GlobalSearchScope filter, @Nullable VirtualFile restrictedTo, + boolean onlyRemoveOutdatedData) { + myChangedFilesCollector.ensureAllInvalidateTasksCompleted(); + for (VirtualFile file: getAllFilesToUpdate()) { + if (filter == null || filter.accept(file) || file == restrictedTo) { + try { + myForceUpdateSemaphore.down(); + // process only files that can affect result + processFileImpl(project, new com.intellij.ide.caches.FileContent(file), onlyRemoveOutdatedData); + } + finally { + myForceUpdateSemaphore.up(); + } + } + } + + // If several threads entered the method at the same time and there were files to update, + // all the threads should leave the method synchronously after all the files scheduled for update are reindexed, + // no matter which thread will do reindexing job. + // Thus we ensure that all the threads that entered the method will get the most recent data + + while (!myForceUpdateSemaphore.waitFor(500)) { // may need to wait until another thread is done with indexing + if (Thread.holdsLock(PsiLock.LOCK)) { + break; // hack. Most probably that other indexing threads is waiting for PsiLock, which we're are holding. + } + } + } + + private void processFileImpl(Project project, @NotNull final com.intellij.ide.caches.FileContent fileContent, boolean onlyRemoveOutdatedData) { + final VirtualFile file = fileContent.getVirtualFile(); + final boolean reallyRemoved = myFilesToUpdate.remove(file); + if (reallyRemoved && file.isValid()) { + if (onlyRemoveOutdatedData) { + // on shutdown there is no need to re-index the file, just remove outdated data from indices + final List> affected = new ArrayList>(); + for (final ID indexId : myIndices.keySet()) { + if (getInputFilter(indexId).acceptInput(file)) { + affected.add(indexId); + } + } + removeFileDataFromIndices(affected, file); + } + else { + indexFileContent(project, fileContent); + } + IndexingStamp.flushCache(); + } + } + } + + private class UnindexedFilesFinder implements CollectingContentIterator { + private final List myFiles = new ArrayList(); + private final ProgressIndicator myProgressIndicator; + + private UnindexedFilesFinder() { + myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); + } + + @NotNull + @Override + public List getFiles() { + return myFiles; + } + + @Override + public boolean processFile(@NotNull final VirtualFile file) { + if (!file.isValid()) { + return true; + } + if (!file.isDirectory()) { + if (file instanceof NewVirtualFile && ((NewVirtualFile)file).getFlag(ALREADY_PROCESSED)) { + return true; + } + + if (file instanceof VirtualFileWithId) { + try { + FileTypeManagerImpl.cacheFileType(file, file.getFileType()); + + boolean oldStuff = true; + if (!isTooLarge(file)) { + for (ID indexId : myIndices.keySet()) { + try { + if (needsFileContentLoading(indexId) && shouldIndexFile(file, indexId)) { + myFiles.add(file); + oldStuff = false; + break; + } + } + catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof IOException || cause instanceof StorageException) { + LOG.info(e); + requestRebuild(indexId); + } + else { + throw e; + } + } + } + } + FileContent fileContent = null; + for (ID indexId : myNotRequiringContentIndices) { + if (shouldIndexFile(file, indexId)) { + oldStuff = false; + try { + if (fileContent == null) { + fileContent = new FileContentImpl(file); + } + updateSingleIndex(indexId, file, fileContent); + } + catch (StorageException e) { + LOG.info(e); + requestRebuild(indexId); + } + } + } + IndexingStamp.flushCache(); + + if (oldStuff && file instanceof NewVirtualFile) { + ((NewVirtualFile)file).setFlag(ALREADY_PROCESSED, true); + } + } + finally { + FileTypeManagerImpl.cacheFileType(file, null); + } + } + } + else { + if (myProgressIndicator != null) { + myProgressIndicator.setText("Scanning files to index"); + myProgressIndicator.setText2(file.getPresentableUrl()); + } + } + return true; + } + } + + private boolean shouldUpdateIndex(final VirtualFile file, final ID indexId) { + return getInputFilter(indexId).acceptInput(file) && + (isMock(file) || IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); + } + + private boolean shouldIndexFile(final VirtualFile file, final ID indexId) { + return getInputFilter(indexId).acceptInput(file) && + (isMock(file) || !IndexingStamp.isFileIndexed(file, indexId, IndexInfrastructure.getIndexCreationStamp(indexId))); + } + + private boolean isUnderConfigOrSystem(@NotNull VirtualFile file) { + final String filePath = file.getPath(); + return myConfigPath != null && FileUtil.startsWith(filePath, myConfigPath) || + mySystemPath != null && FileUtil.startsWith(filePath, mySystemPath); + } + + private static boolean isMock(final VirtualFile file) { + return !(file instanceof NewVirtualFile); + } + + private boolean isTooLarge(@NotNull VirtualFile file) { + if (SingleRootFileViewProvider.isTooLarge(file)) { + final FileType type = file.getFileType(); + return !myNoLimitCheckTypes.contains(type); + } + return false; + } + + private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) { + if (SingleRootFileViewProvider.isTooLarge(file, contentSize)) { + final FileType type = file.getFileType(); + return !myNoLimitCheckTypes.contains(type); + } + return false; + } + + @NotNull + public CollectingContentIterator createContentIterator() { + ++myFilesModCount; + return new UnindexedFilesFinder(); + } + + public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { + myIndexableSets.add(set); + myIndexableSetToProjectMap.put(set, project); + } + + public void removeIndexableSet(@NotNull IndexableFileSet set) { + myChangedFilesCollector.forceUpdate(null, null, null, true); + myIndexableSets.remove(set); + myIndexableSetToProjectMap.remove(set); + } + + @Nullable + private static PsiFile findLatestKnownPsiForUncomittedDocument(@NotNull Document doc, @NotNull Project project) { + return PsiDocumentManager.getInstance(project).getCachedPsiFile(doc); + } + + private static class IndexableFilesFilter implements InputFilter { + private final InputFilter myDelegate; + + private IndexableFilesFilter(InputFilter delegate) { + myDelegate = delegate; + } + + @Override + public boolean acceptInput(final VirtualFile file) { + return file instanceof VirtualFileWithId && myDelegate.acceptInput(file); + } + } + + private static void cleanupProcessedFlag() { + final VirtualFile[] roots = ManagingFS.getInstance().getRoots(); + for (VirtualFile root : roots) { + cleanProcessedFlag(root); + } + } + + private static void cleanProcessedFlag(@NotNull final VirtualFile file) { + if (!(file instanceof NewVirtualFile)) return; + + final NewVirtualFile nvf = (NewVirtualFile)file; + if (file.isDirectory()) { + for (VirtualFile child : nvf.getCachedChildren()) { + cleanProcessedFlag(child); + } + } + else { + nvf.setFlag(ALREADY_PROCESSED, false); + } + } + + public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { + if (project.isDisposed()) { + return; + } + final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + // iterate project content + projectFileIndex.iterateContent(processor); + + if (project.isDisposed()) { + return; + } + + Set visitedRoots = new THashSet(); + for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) { + //important not to depend on project here, to support per-project background reindex + // each client gives a project to FileBasedIndex + if (project.isDisposed()) { + return; + } + for (VirtualFile root : IndexableSetContributor.getRootsToIndex(provider)) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + for (VirtualFile root : IndexableSetContributor.getProjectRootsToIndex(provider, project)) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + } + + if (project.isDisposed()) { + return; + } + // iterate associated libraries + for (Module module : ModuleManager.getInstance(project).getModules()) { + if (module.isDisposed()) { + return; + } + OrderEntry[] orderEntries = ModuleRootManager.getInstance(module).getOrderEntries(); + for (OrderEntry orderEntry : orderEntries) { + if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { + if (orderEntry.isValid()) { + final VirtualFile[] libSources = orderEntry.getFiles(OrderRootType.SOURCES); + final VirtualFile[] libClasses = orderEntry.getFiles(OrderRootType.CLASSES); + for (VirtualFile[] roots : new VirtualFile[][]{libSources, libClasses}) { + for (VirtualFile root : roots) { + if (visitedRoots.add(root)) { + iterateRecursively(root, processor, indicator); + } + } + } + } + } + } + } + } + + private static void iterateRecursively(@Nullable final VirtualFile root, @NotNull final ContentIterator processor, @Nullable ProgressIndicator indicator) { + if (root != null) { + if (indicator != null) { + indicator.checkCanceled(); + indicator.setText2(root.getPresentableUrl()); + } + + if (root.isDirectory()) { + for (VirtualFile file : root.getChildren()) { + if (file.isDirectory()) { + iterateRecursively(file, processor, indicator); + } + else { + processor.processFile(file); + } + } + } + else { + processor.processFile(root); + } + } + } + + private static class StorageGuard { + private int myHolds = 0; + + public interface Holder { + void leave(); + } + + private final Holder myTrueHolder = new Holder() { + @Override + public void leave() { + StorageGuard.this.leave(true); + } + }; + private final Holder myFalseHolder = new Holder() { + @Override + public void leave() { + StorageGuard.this.leave(false); + } + }; + + @NotNull + public synchronized Holder enter(boolean mode) { + if (mode) { + while (myHolds < 0) { + try { + wait(); + } + catch (InterruptedException ignored) { + } + } + myHolds++; + return myTrueHolder; + } + else { + while (myHolds > 0) { + try { + wait(); + } + catch (InterruptedException ignored) { + } + } + myHolds--; + return myFalseHolder; + } + } + + private synchronized void leave(boolean mode) { + myHolds += mode? -1 : 1; + if (myHolds == 0) { + notifyAll(); + } + } + + } +} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java index 7e1994218251..13fee5b720ab 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java @@ -42,12 +42,12 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; public class FileBasedIndexProjectHandler extends AbstractProjectComponent implements IndexableFileSet { - private final FileBasedIndex myIndex; + private final FileBasedIndexImpl myIndex; private final ProjectRootManagerEx myRootManager; private final FileTypeManager myFileTypeManager; private final ProjectFileExclusionManagerImpl myExclusionManager; - public FileBasedIndexProjectHandler(final FileBasedIndex index, final Project project, final ProjectRootManagerEx rootManager, FileTypeManager ftManager, final ProjectManager projectManager) { + public FileBasedIndexProjectHandler(final FileBasedIndexImpl index, final Project project, final ProjectRootManagerEx rootManager, FileTypeManager ftManager, final ProjectManager projectManager) { super(project); myIndex = index; myRootManager = rootManager; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index d8ea84dc00b0..efb1445da0be 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -33,11 +33,11 @@ import java.util.List; */ public class UnindexedFilesUpdater implements CacheUpdater { private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.UnindexedFilesUpdater"); - private final FileBasedIndex myIndex; + private final FileBasedIndexImpl myIndex; private final Project myProject; private long myStarted; - public UnindexedFilesUpdater(final Project project, FileBasedIndex index) { + public UnindexedFilesUpdater(final Project project, FileBasedIndexImpl index) { myIndex = index; myProject = project; } @@ -51,7 +51,7 @@ public class UnindexedFilesUpdater implements CacheUpdater { public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { CollectingContentIterator finder = myIndex.createContentIterator(); long l = System.currentTimeMillis(); - FileBasedIndex.iterateIndexableFiles(finder, myProject, indicator); + FileBasedIndexImpl.iterateIndexableFiles(finder, myProject, indicator); LOG.info("Indexable files iterated in " + (System.currentTimeMillis() - l) + " ms"); List files = finder.getFiles(); LOG.info("Unindexed files update started: " + files.size() + " files to update"); diff --git a/platform/platform-resources/src/componentSets/Lang.xml b/platform/platform-resources/src/componentSets/Lang.xml index f4ce41d26018..54e0cc2a543c 100644 --- a/platform/platform-resources/src/componentSets/Lang.xml +++ b/platform/platform-resources/src/componentSets/Lang.xml @@ -12,7 +12,8 @@ - com.intellij.util.indexing.FileBasedIndex + com.intellij.util.indexing.FileBasedIndex + com.intellij.util.indexing.FileBasedIndexImpl com.intellij.psi.stubs.StubIndex diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index a8ba4077789d..a7e2d39a9746 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -93,6 +93,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.LocalTimeCounter; import com.intellij.util.containers.CollectionFactory; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import com.intellij.util.indexing.IndexableFileSet; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.UIUtil; @@ -234,7 +235,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da throw new RuntimeException(e); } - FileBasedIndex.getInstance().registerIndexableSet(new IndexableFileSet() { + ((FileBasedIndexImpl)FileBasedIndex.getInstance()).registerIndexableSet(new IndexableFileSet() { @Override public boolean isInSet(@NotNull final VirtualFile file) { return ourSourceRoot != null && file.getFileSystem() == ourSourceRoot.getFileSystem() && ourProject.isOpen(); From 3bb4da93ec56c48fa937a6d4554ff066258710e7 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:02:03 +0200 Subject: [PATCH 17/67] Extra changes --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++++ .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 3 ++- .../src/com/intellij/util/indexing/UnindexedFilesUpdater.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index c2f3ad423b19..3ef57cafca3a 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -17,7 +17,9 @@ package com.intellij.util.indexing; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; @@ -35,6 +37,8 @@ import java.util.Set; * Author: dmitrylomov */ public abstract class FileBasedIndex implements ApplicationComponent { + public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); + public static FileBasedIndex getInstance() { return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 1cf3b2677d89..29e82dd6d2a6 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2189,7 +2189,8 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - public static void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { + @Override + public void iterateIndexableFiles(@NotNull final ContentIterator processor, @NotNull Project project, ProgressIndicator indicator) { if (project.isDisposed()) { return; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index efb1445da0be..a0e42f63198d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -51,7 +51,7 @@ public class UnindexedFilesUpdater implements CacheUpdater { public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) { CollectingContentIterator finder = myIndex.createContentIterator(); long l = System.currentTimeMillis(); - FileBasedIndexImpl.iterateIndexableFiles(finder, myProject, indicator); + FileBasedIndex.getInstance().iterateIndexableFiles(finder, myProject, indicator); LOG.info("Indexable files iterated in " + (System.currentTimeMillis() - l) + " ms"); List files = finder.getFiles(); LOG.info("Unindexed files update started: " + files.size() + " files to update"); From 29dfa01cf2eb6bc230626a108c433d41728c2cac Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:32:20 +0200 Subject: [PATCH 18/67] Extra methods --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++++ .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 3ef57cafca3a..f2dad634cf9f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -39,6 +39,10 @@ import java.util.Set; public abstract class FileBasedIndex implements ApplicationComponent { public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); + public abstract void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project); + + public abstract void removeIndexableSet(@NotNull IndexableFileSet set); + public static FileBasedIndex getInstance() { return ApplicationManager.getApplication().getComponent(FileBasedIndex.class); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 29e82dd6d2a6..b6043d4bef02 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2139,11 +2139,13 @@ public class FileBasedIndexImpl extends FileBasedIndex { return new UnindexedFilesFinder(); } + @Override public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) { myIndexableSets.add(set); myIndexableSetToProjectMap.put(set, project); } + @Override public void removeIndexableSet(@NotNull IndexableFileSet set) { myChangedFilesCollector.forceUpdate(null, null, null, true); myIndexableSets.remove(set); From 7c677fc88ae36f801dbb827fe7be1a5247392571 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 12:07:10 +0200 Subject: [PATCH 19/67] More fixed --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 5 ----- .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 1 - 2 files changed, 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index f2dad634cf9f..0c7c23ce6f62 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -91,11 +91,6 @@ public abstract class FileBasedIndex implements ApplicationComponent { public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); - protected abstract void ensureUpToDate(@NotNull ID indexId, - @Nullable Project project, - @Nullable GlobalSearchScope filter, - @Nullable VirtualFile restrictedFile); - public abstract void requestRebuild(ID indexId, Throwable throwable); public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index b6043d4bef02..a5f15bf670d1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -737,7 +737,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { ensureUpToDate(indexId, project, filter, null); } - @Override protected void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, From 1a49cf6aa4befc280320fc71f975a71cdc9c01e0 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Tue, 8 May 2012 18:26:13 +0200 Subject: [PATCH 20/67] FileBasedIndex --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 6 ++++++ .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 2 +- .../com/intellij/util/indexing/UnindexedFilesUpdater.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 0c7c23ce6f62..378801652209 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -37,6 +37,7 @@ import java.util.Set; * Author: dmitrylomov */ public abstract class FileBasedIndex implements ApplicationComponent { + public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); public abstract void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project); @@ -91,6 +92,11 @@ public abstract class FileBasedIndex implements ApplicationComponent { public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); + protected abstract void ensureUpToDate(@NotNull ID indexId, + @Nullable Project project, + @Nullable GlobalSearchScope filter, + @Nullable VirtualFile restrictedFile); + public abstract void requestRebuild(ID indexId, Throwable throwable); public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index a5f15bf670d1..d658dd11616b 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -737,6 +737,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { ensureUpToDate(indexId, project, filter, null); } + @Override protected void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, @@ -2144,7 +2145,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { myIndexableSetToProjectMap.put(set, project); } - @Override public void removeIndexableSet(@NotNull IndexableFileSet set) { myChangedFilesCollector.forceUpdate(null, null, null, true); myIndexableSets.remove(set); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index a0e42f63198d..ad0c20902d73 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. From 6d61ee0df41876a48764bc4bf7d832663bfb69d3 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:02:03 +0200 Subject: [PATCH 21/67] Extra changes --- .../lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 378801652209..f2dad634cf9f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -37,7 +37,6 @@ import java.util.Set; * Author: dmitrylomov */ public abstract class FileBasedIndex implements ApplicationComponent { - public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); public abstract void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project); From 4dfdbfb0be9a94ad8b029145e791de9ca8ef5047 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 11:32:20 +0200 Subject: [PATCH 22/67] Extra methods --- .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index d658dd11616b..b6043d4bef02 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2145,6 +2145,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { myIndexableSetToProjectMap.put(set, project); } + @Override public void removeIndexableSet(@NotNull IndexableFileSet set) { myChangedFilesCollector.forceUpdate(null, null, null, true); myIndexableSets.remove(set); From 414a38d0aa1044277e52cf5d2495a31e9143c64f Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 12:07:10 +0200 Subject: [PATCH 23/67] More fixed --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 5 ----- .../src/com/intellij/util/indexing/FileBasedIndexImpl.java | 1 - 2 files changed, 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index f2dad634cf9f..0c7c23ce6f62 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -91,11 +91,6 @@ public abstract class FileBasedIndex implements ApplicationComponent { public abstract void ensureUpToDate(@NotNull ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter); - protected abstract void ensureUpToDate(@NotNull ID indexId, - @Nullable Project project, - @Nullable GlobalSearchScope filter, - @Nullable VirtualFile restrictedFile); - public abstract void requestRebuild(ID indexId, Throwable throwable); public abstract void scheduleRebuild(@NotNull ID indexId, @NotNull Throwable e); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index b6043d4bef02..a5f15bf670d1 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -737,7 +737,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { ensureUpToDate(indexId, project, filter, null); } - @Override protected void ensureUpToDate(@NotNull final ID indexId, @Nullable Project project, @Nullable GlobalSearchScope filter, From 4805c0ebf3c6dd386bb11665db7dd889bf8d4bf6 Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Wed, 9 May 2012 13:35:15 +0200 Subject: [PATCH 24/67] +CoreJavaCodeStyleManager --- .../com/intellij/core/CoreJavaCodeStyleManager.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java new file mode 100644 index 000000000000..c5632dfdcf6f --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -0,0 +1,11 @@ +package com.intellij.core; + +/** + * Created with IntelliJ IDEA. + * User: pasynkov + * Date: 09.05.12 + * Time: 13:22 + * To change this template use File | Settings | File Templates. + */ +public class CoreJavaCodeStyleManager { +} From 40244034d5ff9bc9a70d9532a6be1e1a26c3b695 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 13:36:53 +0200 Subject: [PATCH 25/67] FileBasedIndex moved to indexing-impl --- .../src/com/intellij/openapi/roots/ContentIterator.java | 0 .../src/com/intellij/util/indexing/FileBasedIndex.java | 4 ++-- .../src/com/intellij/util/indexing/IndexableFileSet.java | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename platform/{platform-api => core-api}/src/com/intellij/openapi/roots/ContentIterator.java (100%) rename platform/{lang-impl => indexing-api}/src/com/intellij/util/indexing/FileBasedIndex.java (97%) rename platform/{lang-impl => indexing-api}/src/com/intellij/util/indexing/IndexableFileSet.java (100%) diff --git a/platform/platform-api/src/com/intellij/openapi/roots/ContentIterator.java b/platform/core-api/src/com/intellij/openapi/roots/ContentIterator.java similarity index 100% rename from platform/platform-api/src/com/intellij/openapi/roots/ContentIterator.java rename to platform/core-api/src/com/intellij/openapi/roots/ContentIterator.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java similarity index 97% rename from platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java rename to platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java index 0c7c23ce6f62..afcb32543471 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java @@ -16,7 +16,7 @@ package com.intellij.util.indexing; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.components.BaseComponent; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentIterator; @@ -36,7 +36,7 @@ import java.util.Set; /** * Author: dmitrylomov */ -public abstract class FileBasedIndex implements ApplicationComponent { +public abstract class FileBasedIndex implements BaseComponent { public abstract void iterateIndexableFiles(@NotNull ContentIterator processor, @NotNull Project project, ProgressIndicator indicator); public abstract void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexableFileSet.java b/platform/indexing-api/src/com/intellij/util/indexing/IndexableFileSet.java similarity index 100% rename from platform/lang-impl/src/com/intellij/util/indexing/IndexableFileSet.java rename to platform/indexing-api/src/com/intellij/util/indexing/IndexableFileSet.java From 82497269425ddf1701ea7bf5f9925132a2773e04 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Wed, 9 May 2012 13:37:05 +0200 Subject: [PATCH 26/67] FileBasedIndex moved to indexing-impl --- .../src/com/intellij/compiler/impl/CompilerContentIterator.java | 1 - .../testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java | 1 - .../testSrc/com/intellij/psi/search/UpdateCacheTest.java | 1 - .../src/com/intellij/testFramework/LightPlatformTestCase.java | 1 - 4 files changed, 4 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java index 74bba4091d7b..c7634804a18d 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerContentIterator.java @@ -19,7 +19,6 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.FileIndex; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import java.util.Collection; diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java index eaf7ae618ffe..bb43aac5a141 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/IdCacheTest.java @@ -21,7 +21,6 @@ import com.intellij.psi.search.UsageSearchContext; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.FileBasedIndexImpl; import java.io.File; import java.util.Arrays; diff --git a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java index be90964eafae..9ed5627cc09b 100644 --- a/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/search/UpdateCacheTest.java @@ -44,7 +44,6 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.FileBasedIndexImpl; import org.jetbrains.annotations.NonNls; import java.io.File; diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index a7e2d39a9746..2078af288a71 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -56,7 +56,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.project.ModuleAdapter; -import com.intellij.openapi.project.ModuleListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ex.ProjectEx; From bdc83cd8f62f258189cb60da854a026b825deef5 Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Wed, 9 May 2012 13:40:34 +0200 Subject: [PATCH 27/67] +CoreJavaCodeStyleManager --- .../core/CoreJavaCodeStyleManager.java | 134 ++++++++++++++++-- .../intellij/core/JavaCoreEnvironment.java | 2 + 2 files changed, 128 insertions(+), 8 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java index c5632dfdcf6f..7f651a21df0e 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -1,11 +1,129 @@ +/* + * Copyright 2000-2012 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.core; -/** - * Created with IntelliJ IDEA. - * User: pasynkov - * Date: 09.05.12 - * Time: 13:22 - * To change this template use File | Settings | File Templates. - */ -public class CoreJavaCodeStyleManager { +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.util.IncorrectOperationException; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { + @Override + public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { + return false; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element, + @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) + throws IncorrectOperationException { + return null; + } + + @NotNull + @Override + public String getPrefixByVariableKind(VariableKind variableKind) { + return ""; + } + + @NotNull + @Override + public String getSuffixByVariableKind(VariableKind variableKind) { + return ""; + } + + @Override + public int findEntryIndex(@NotNull PsiImportStatementBase statement) { + return 0; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { + return null; + } + + @Override + public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException { + } + + @Override + public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { + } + + @Override + public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { + return null; + } + + @Override + public VariableKind getVariableKind(@NotNull PsiVariable variable) { + return null; + } + + @Override + public SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, + @Nullable String propertyName, + @Nullable PsiExpression expr, + @Nullable PsiType type, + boolean correctKeywords) { + return null; + } + + @Override + public String variableNameToPropertyName(@NonNls String name, VariableKind variableKind) { + return null; + } + + @Override + public String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind) { + return null; + } + + @Override + public String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward) { + return null; + } + + @NotNull + @Override + public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward) { + return SuggestedNameInfo.NULL_INFO; + } + + @Override + public PsiElement qualifyClassReferences(@NotNull PsiElement element) { + return null; + } + + @Override + public void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException { + } + + @Override + public Collection findRedundantImports(PsiJavaFile file) { + return null; + } } diff --git a/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java b/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java index 46aa4080730f..16cdc8d46e90 100644 --- a/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java +++ b/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java @@ -30,6 +30,7 @@ import com.intellij.openapi.roots.PackageIndex; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.augment.PsiAugmentProvider; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade; import com.intellij.psi.impl.EmptySubstitutorImpl; import com.intellij.psi.impl.JavaPsiFacadeImpl; @@ -79,6 +80,7 @@ public class JavaCoreEnvironment extends CoreEnvironment { myProject.registerService(PackageIndex.class, myFileManager); myProject.registerService(JavaResolveCache.class, new JavaResolveCache(null)); myProject.registerService(JavaCodeStyleSettingsFacade.class, new CoreJavaCodeStyleSettingsFacade()); + myProject.registerService(JavaCodeStyleManager.class, new CoreJavaCodeStyleManager()); JavaPsiFacadeImpl javaPsiFacade = new JavaPsiFacadeImpl(myProject, myPsiManager, myFileManager, null); myProject.registerService(CoreJavaFileManager.class, myFileManager); From b0b991da7e70da244cd0666a0ed053a95bbb3f74 Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Wed, 9 May 2012 14:58:39 +0200 Subject: [PATCH 28/67] Better stub CoreJavaCodeStyleManager --- .../codeStyle/JavaCodeStyleManagerImpl.java | 2100 ++++++++--------- .../psi/codeStyle/JavaCodeStyleManager.java | 407 ++-- .../core/CoreJavaCodeStyleManager.java | 9 +- 3 files changed, 1254 insertions(+), 1262 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java index ed7ec70859e1..76ac3ac6a49b 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java @@ -1,1061 +1,1039 @@ -/* - * Copyright 2000-2011 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. - */ - -/* - * @author max - */ -package com.intellij.psi.impl.source.codeStyle; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.util.text.StringUtilRt; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.*; -import com.intellij.psi.impl.CheckUtil; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; -import com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatement; -import com.intellij.psi.impl.source.tree.TreeElement; -import com.intellij.psi.statistics.JavaStatisticsManager; -import com.intellij.psi.util.*; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashSet; -import gnu.trove.TObjectHashingStrategy; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.beans.Introspector; -import java.util.*; - -public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl"); - - @NonNls private static final String IMPL_TYPNAME_SUFFIX = "Impl"; - @NonNls private static final String GET_PREFIX = "get"; - @NonNls private static final String IS_PREFIX = "is"; - @NonNls private static final String FIND_PREFIX = "find"; - @NonNls private static final String CREATE_PREFIX = "create"; - @NonNls private static final String WITH_PREFIX = "with"; - @NonNls private static final String SET_PREFIX = "set"; - - private final Project myProject; - - public JavaCodeStyleManagerImpl(final Project project) { - myProject = project; - } - - @Override - public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { - return shortenClassReferences(element, 0); - } - - @Override - public PsiElement shortenClassReferences(@NotNull PsiElement element, int flags) throws IncorrectOperationException { - CheckUtil.checkWritable(element); - if (!SourceTreeToPsiMap.hasTreeElement(element)) return element; - - return SourceTreeToPsiMap.treeElementToPsi( - new ReferenceAdjuster(myProject).process((TreeElement)element.getNode(), (flags & DO_NOT_ADD_IMPORTS) == 0, - (flags & UNCOMPLETE_CODE) != 0)); - } - - @Override - public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) - throws IncorrectOperationException { - CheckUtil.checkWritable(element); - if (SourceTreeToPsiMap.hasTreeElement(element)) { - new ReferenceAdjuster(myProject).processRange((TreeElement)element.getNode(), startOffset, endOffset); - } - } - - @Override - public PsiElement qualifyClassReferences(@NotNull PsiElement element) { - return SourceTreeToPsiMap.treeElementToPsi(new ReferenceAdjuster(true, true).process((TreeElement)element.getNode(), false, false)); - } - - @Override - public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { - CheckUtil.checkWritable(file); - if (file instanceof PsiJavaFile) { - PsiImportList newList = prepareOptimizeImportsResult((PsiJavaFile)file); - if (newList != null) { - final PsiImportList importList = ((PsiJavaFile)file).getImportList(); - if (importList != null) { - importList.replace(newList); - } - } - } - } - - @Override - public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { - return new ImportHelper(getSettings()).prepareOptimizeImportsResult(file); - } - - @Override - public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { - return new ImportHelper(getSettings()).addImport(file, refClass); - } - - @Override - public void removeRedundantImports(@NotNull final PsiJavaFile file) throws IncorrectOperationException { - final Collection redundants = findRedundantImports(file); - if (redundants == null) return; - - for (final PsiImportStatementBase importStatement : redundants) { - final PsiJavaCodeReferenceElement ref = importStatement.getImportReference(); - //Do not remove non-resolving refs - if (ref == null || ref.resolve() == null) { - continue; - } - - importStatement.delete(); - } - } - - @Override - @Nullable - public Collection findRedundantImports(final PsiJavaFile file) { - final PsiImportList importList = file.getImportList(); - if (importList == null) return null; - final PsiImportStatementBase[] imports = importList.getAllImportStatements(); - if( imports.length == 0 ) return null; - - Set allImports = new THashSet(Arrays.asList(imports)); - final Collection redundants; - if (JspPsiUtil.isInJspFile(file)) { - // remove only duplicate imports - redundants = new THashSet(TObjectHashingStrategy.IDENTITY); - ContainerUtil.addAll(redundants, imports); - redundants.removeAll(allImports); - for (PsiImportStatementBase importStatement : imports) { - if (importStatement instanceof JspxImportStatement && ((JspxImportStatement)importStatement).isForeignFileImport()) { - redundants.remove(importStatement); - } - } - } - else { - redundants = allImports; - final List roots = file.getViewProvider().getAllFiles(); - for (PsiElement root : roots) { - root.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - if (!reference.isQualified()) { - final JavaResolveResult resolveResult = reference.advancedResolve(false); - if (!inTheSamePackage(file, resolveResult.getElement())) { - final PsiElement resolveScope = resolveResult.getCurrentFileResolveScope(); - if (resolveScope instanceof PsiImportStatementBase) { - final PsiImportStatementBase importStatementBase = (PsiImportStatementBase)resolveScope; - redundants.remove(importStatementBase); - } - } - } - super.visitReferenceElement(reference); - } - - private boolean inTheSamePackage(PsiJavaFile file, PsiElement element) { - if (element instanceof PsiClass && ((PsiClass)element).getContainingClass() == null) { - final PsiFile containingFile = element.getContainingFile(); - if (containingFile instanceof PsiJavaFile) { - return Comparing.strEqual(file.getPackageName(), ((PsiJavaFile)containingFile).getPackageName()); - } - } - return false; - } - }); - } - } - return redundants; - } - - @Override - public int findEntryIndex(@NotNull PsiImportStatementBase statement) { - return new ImportHelper(getSettings()).findEntryIndex(statement); - } - - @Override - public VariableKind getVariableKind(@NotNull PsiVariable variable) { - if (variable instanceof PsiField) { - if (variable.hasModifierProperty(PsiModifier.STATIC)) { - if (variable.hasModifierProperty(PsiModifier.FINAL)) { - return VariableKind.STATIC_FINAL_FIELD; - } - return VariableKind.STATIC_FIELD; - } - return VariableKind.FIELD; - } - else { - if (variable instanceof PsiParameter) { - if (((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { - return VariableKind.LOCAL_VARIABLE; - } - return VariableKind.PARAMETER; - } - return VariableKind.LOCAL_VARIABLE; - } - } - - @Override - public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, - @Nullable final String propertyName, - @Nullable final PsiExpression expr, - @Nullable PsiType type, - final boolean correctKeywords) { - LinkedHashSet names = new LinkedHashSet(); - - if (expr != null && type == null) { - type = expr.getType(); - } - - if (propertyName != null) { - String[] namesByName = getSuggestionsByName(propertyName, kind, false, correctKeywords); - sortVariableNameSuggestions(namesByName, kind, propertyName, null); - ContainerUtil.addAll(names, namesByName); - } - - final NamesByExprInfo namesByExpr; - if (expr != null) { - namesByExpr = suggestVariableNameByExpression(expr, kind, correctKeywords); - if (namesByExpr.propertyName != null) { - sortVariableNameSuggestions(namesByExpr.names, kind, namesByExpr.propertyName, null); - } - ContainerUtil.addAll(names, namesByExpr.names); - } - else { - namesByExpr = null; - } - - if (type != null) { - String[] namesByType = suggestVariableNameByType(type, kind, correctKeywords); - sortVariableNameSuggestions(namesByType, kind, null, type); - ContainerUtil.addAll(names, namesByType); - } - - final String _propertyName; - if (propertyName != null) { - _propertyName = propertyName; - } - else { - _propertyName = namesByExpr != null ? namesByExpr.propertyName : null; - } - - addNamesFromStatistics(names, kind, _propertyName, type); - - String[] namesArray = ArrayUtil.toStringArray(names); - sortVariableNameSuggestions(namesArray, kind, _propertyName, type); - - final PsiType _type = type; - return new SuggestedNameInfo(namesArray) { - @Override - public void nameChoosen(String name) { - if (_propertyName != null || _type != null && _type.isValid()) { - JavaStatisticsManager.incVariableNameUseCount(name, kind, _propertyName, _type); - } - } - }; - } - - private static void addNamesFromStatistics(Set names, VariableKind variableKind, @Nullable String propertyName, @Nullable PsiType type) { - String[] allNames = JavaStatisticsManager.getAllVariableNamesUsed(variableKind, propertyName, type); - - int maxFrequency = 0; - for (String name : allNames) { - int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); - maxFrequency = Math.max(maxFrequency, count); - } - - int frequencyLimit = Math.max(5, maxFrequency / 2); - - for (String name : allNames) { - if( names.contains( name ) ) - { - continue; - } - int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); - if (LOG.isDebugEnabled()) { - LOG.debug("new name:" + name + " count:" + count); - LOG.debug("frequencyLimit:" + frequencyLimit); - } - if (count >= frequencyLimit) { - names.add(name); - } - } - - if (propertyName != null && type != null) { - addNamesFromStatistics(names, variableKind, propertyName, null); - addNamesFromStatistics(names, variableKind, null, type); - } - } - - private String[] suggestVariableNameByType(PsiType type, final VariableKind variableKind, boolean correctKeywords) { - String longTypeName = getLongTypeName(type); - CodeStyleSettings.TypeToNameMap map = getMapByVariableKind(variableKind); - if (map != null && longTypeName != null) { - if (type.equals(PsiType.NULL)) { - longTypeName = CommonClassNames.JAVA_LANG_OBJECT; - } - String name = map.nameByType(longTypeName); - if (name != null && isIdentifier(name)) { - return new String[]{name}; - } - } - - Collection suggestions = new LinkedHashSet(); - - suggestNamesForCollectionInheritors(type, variableKind, suggestions, correctKeywords); - suggestNamesFromGenericParameters(type, variableKind, suggestions, correctKeywords); - - String typeName = normalizeTypeName(getTypeName(type)); - if (typeName != null) { - ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, type instanceof PsiArrayType, correctKeywords)); - } - - return ArrayUtil.toStringArray(suggestions); - } - - private void suggestNamesFromGenericParameters(final PsiType type, - final VariableKind variableKind, - final Collection suggestions, boolean correctKeywords) { - if (!(type instanceof PsiClassType)) { - return; - } - StringBuilder fullNameBuilder = new StringBuilder(); - final PsiType[] parameters = ((PsiClassType)type).getParameters(); - for (PsiType parameter : parameters) { - if (parameter instanceof PsiClassType) { - final String typeName = normalizeTypeName(getTypeName(parameter)); - if (typeName != null) { - fullNameBuilder.append(typeName); - } - } - } - String baseName = normalizeTypeName(getTypeName(type)); - if (baseName != null) { - fullNameBuilder.append(baseName); - ContainerUtil.addAll(suggestions, getSuggestionsByName(fullNameBuilder.toString(), variableKind, false, correctKeywords)); - } - } - - private void suggestNamesForCollectionInheritors(final PsiType type, - final VariableKind variableKind, - Collection suggestions, boolean correctKeywords) { - PsiType componentType = PsiUtil.extractIterableTypeParameter(type, false); - if( componentType == null ) { - return; - } - String typeName = normalizeTypeName(getTypeName(componentType)); - if (typeName != null) { - ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, true, correctKeywords)); - } - } - - @Nullable - private static String normalizeTypeName(String typeName) { - if( typeName == null ) - { - return null; - } - if (typeName.endsWith(IMPL_TYPNAME_SUFFIX) && typeName.length() > IMPL_TYPNAME_SUFFIX.length()) { - return typeName.substring(0, typeName.length() - IMPL_TYPNAME_SUFFIX.length()); - } - return typeName; - } - - @Nullable - private static String getTypeName(PsiType type) { - type = type.getDeepComponentType(); - if (type instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)type; - final String className = classType.getClassName(); - if (className != null) { - return className; - } - else { - final PsiClass aClass = classType.resolve(); - if (aClass instanceof PsiAnonymousClass) { - return ((PsiAnonymousClass)aClass).getBaseClassType().getClassName(); - } - else { - return null; - } - } - } - else { - if (type instanceof PsiPrimitiveType) { - return type.getPresentableText(); - } - else { - if (type instanceof PsiWildcardType) { - return getTypeName(((PsiWildcardType)type).getExtendsBound()); - } - else { - if (type instanceof PsiIntersectionType) { - return getTypeName(((PsiIntersectionType)type).getRepresentative()); - } - else { - if (type instanceof PsiCapturedWildcardType) { - return getTypeName(((PsiCapturedWildcardType)type).getWildcard()); - } - else { - if (type instanceof PsiDisjunctionType) { - return getTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); - } - else { - LOG.error("Unknown type:" + type); - return null; - } - } - } - } - } - } - } - - @Nullable - private static String getLongTypeName(PsiType type) { - if (type instanceof PsiClassType) { - PsiClass aClass = ((PsiClassType)type).resolve(); - if( aClass == null ) - { - return null; - } - if (aClass instanceof PsiAnonymousClass) { - PsiClass baseClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve(); - if( baseClass == null ) - { - return null; - } - return baseClass.getQualifiedName(); - } - return aClass.getQualifiedName(); - } - else { - if (type instanceof PsiArrayType) { - return getLongTypeName(((PsiArrayType)type).getComponentType()) + "[]"; - } - else { - if (type instanceof PsiPrimitiveType) { - return type.getPresentableText(); - } - else { - if (type instanceof PsiWildcardType) { - final PsiType bound = ((PsiWildcardType)type).getBound(); - if (bound != null) { - return getLongTypeName(bound); - } - else { - return "java.lang.Object"; - } - } - else { - if (type instanceof PsiCapturedWildcardType) { - final PsiType bound = ((PsiCapturedWildcardType)type).getWildcard().getBound(); - if (bound != null) { - return getLongTypeName(bound); - } - else { - return "java.lang.Object"; - } - } - else { - if (type instanceof PsiIntersectionType) { - return getLongTypeName(((PsiIntersectionType)type).getRepresentative()); - } - else { - if (type instanceof PsiDisjunctionType) { - return getLongTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); - } - else { - LOG.error("Unknown type:" + type); - return null; - } - } - } - } - } - } - } - } - - private static class NamesByExprInfo { - final String[] names; - final String propertyName; - - public NamesByExprInfo(String propertyName, String... names) { - this.names = names; - this.propertyName = propertyName; - } - } - - private NamesByExprInfo suggestVariableNameByExpression(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { - final NamesByExprInfo names1 = suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords); - final NamesByExprInfo names2 = suggestVariableNameByExpressionPlace(expr, variableKind, correctKeywords); - - PsiType type = expr.getType(); - final String[] names3; - if (type != null) { - names3 = suggestVariableNameByType(type, variableKind, correctKeywords); - } - else { - names3 = null; - } - - final LinkedHashSet names = new LinkedHashSet(); - final String[] fromLiterals = suggestVariableNameFromLiterals(expr, variableKind, correctKeywords); - if (fromLiterals != null) { - ContainerUtil.addAll(names, fromLiterals); - } - ContainerUtil.addAll(names, names1.names); - ContainerUtil.addAll(names, names2.names); - if (names3 != null) { - ContainerUtil.addAll(names, names3); - } - - String[] namesArray = ArrayUtil.toStringArray(names); - String propertyName = names1.propertyName != null ? names1.propertyName : names2.propertyName; - return new NamesByExprInfo(propertyName, namesArray); - } - - @Nullable - private String[] suggestVariableNameFromLiterals(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { - final PsiElement[] literals = PsiTreeUtil.collectElements(expr, new PsiElementFilter() { - @Override - public boolean isAccepted(PsiElement element) { - if (isStringPsiLiteral(element) && StringUtil.isJavaIdentifier(StringUtil.unquoteString(element.getText()))) { - final PsiElement exprList = element.getParent(); - if (exprList instanceof PsiExpressionList) { - final PsiElement call = exprList.getParent(); - if (call instanceof PsiNewExpression) { - return true; - } else if (call instanceof PsiMethodCallExpression) { - //TODO: exclude or not getA().getB("name").getC(); or getA(getB("name").getC()); It works fine for now in the most cases - return true; - } - } - } - return false; - } - }); - - if (literals.length == 1) { - final String text = StringUtil.unquoteString(literals[0].getText()); - return getSuggestionsByName(text, variableKind, expr.getType() instanceof PsiArrayType, correctKeywords); - } - return null; - } - - private NamesByExprInfo suggestVariableNameByExpressionOnly(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { - if (expr instanceof PsiMethodCallExpression) { - PsiReferenceExpression methodExpr = ((PsiMethodCallExpression)expr).getMethodExpression(); - String methodName = methodExpr.getReferenceName(); - if (methodName != null) { - String[] words = NameUtil.nameToWords(methodName); - if (words.length > 0) { - final String firstWord = words[0]; - if (GET_PREFIX.equals(firstWord) - || IS_PREFIX.equals(firstWord) - || FIND_PREFIX.equals(firstWord) - || CREATE_PREFIX.equals(firstWord)) { - if (words.length > 1) { - final String propertyName = methodName.substring(firstWord.length()); - String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); - final PsiExpression qualifierExpression = methodExpr.getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() instanceof PsiVariable) { - names = ArrayUtil.append(names, StringUtil.sanitizeJavaIdentifier(changeIfNotIdentifier(qualifierExpression.getText() + StringUtil.capitalize(propertyName)))); - } - return new NamesByExprInfo(propertyName, names); - } - } - else if (words.length == 1) { - return new NamesByExprInfo(methodName, getSuggestionsByName(methodName, variableKind, false, correctKeywords)); - } - } - } - } - else if (expr instanceof PsiReferenceExpression) { - String propertyName = ((PsiReferenceExpression)expr).getReferenceName(); - PsiElement refElement = ((PsiReferenceExpression)expr).resolve(); - if (refElement instanceof PsiVariable) { - VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); - propertyName = variableNameToPropertyName(propertyName, refVariableKind); - } - if (refElement != null && propertyName != null) { - String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); - return new NamesByExprInfo(propertyName, names); - } - } - else if (expr instanceof PsiArrayAccessExpression) { - PsiExpression arrayExpr = ((PsiArrayAccessExpression)expr).getArrayExpression(); - if (arrayExpr instanceof PsiReferenceExpression) { - String arrayName = ((PsiReferenceExpression)arrayExpr).getReferenceName(); - PsiElement refElement = ((PsiReferenceExpression)arrayExpr).resolve(); - if (refElement instanceof PsiVariable) { - VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); - arrayName = variableNameToPropertyName(arrayName, refVariableKind); - } - - if (arrayName != null) { - String name = StringUtil.unpluralize(arrayName); - if (name != null) { - String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); - return new NamesByExprInfo(name, names); - } - } - } - } - else if (expr instanceof PsiLiteralExpression && variableKind == VariableKind.STATIC_FINAL_FIELD) { - final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expr; - final Object value = literalExpression.getValue(); - if (value instanceof String) { - final String stringValue = (String)value; - String[] names = getSuggestionsByValue(stringValue); - if (names.length > 0) { - return new NamesByExprInfo(null, constantValueToConstantName(names)); - } - } - } else if (expr instanceof PsiParenthesizedExpression) { - return suggestVariableNameByExpressionOnly(((PsiParenthesizedExpression)expr).getExpression(), variableKind, correctKeywords); - } else if (expr instanceof PsiTypeCastExpression) { - return suggestVariableNameByExpressionOnly(((PsiTypeCastExpression)expr).getOperand(), variableKind, correctKeywords); - } else if (expr instanceof PsiLiteralExpression) { - final String text = StringUtil.stripQuotesAroundValue(expr.getText()); - if (isIdentifier(text)) { - return new NamesByExprInfo(text, getSuggestionsByName(text, variableKind, false, correctKeywords)); - } - } - - return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); - } - - private static String constantValueToConstantName(final String[] names) { - final StringBuilder result = new StringBuilder(); - for (int i = 0; i < names.length; i++) { - if (i > 0) result.append("_"); - result.append(names[i]); - } - return result.toString(); - } - - private static String[] getSuggestionsByValue(final String stringValue) { - List result = new ArrayList(); - StringBuffer currentWord = new StringBuffer(); - - boolean prevIsUpperCase = false; - - for (int i = 0; i < stringValue.length(); i++) { - final char c = stringValue.charAt(i); - if (Character.isUpperCase(c)) { - if (currentWord.length() > 0 && !prevIsUpperCase) { - result.add(currentWord.toString()); - currentWord = new StringBuffer(); - } - currentWord.append(c); - } else if (Character.isLowerCase(c)) { - currentWord.append(Character.toUpperCase(c)); - } else if (Character.isJavaIdentifierPart(c) && c != '_') { - if (Character.isJavaIdentifierStart(c) || currentWord.length() > 0 || !result.isEmpty()) { - currentWord.append(c); - } - } else { - if (currentWord.length() > 0) { - result.add(currentWord.toString()); - currentWord = new StringBuffer(); - } - } - - prevIsUpperCase = Character.isUpperCase(c); - } - - if (currentWord.length() > 0) { - result.add(currentWord.toString()); - } - return ArrayUtil.toStringArray(result); - } - - private NamesByExprInfo suggestVariableNameByExpressionPlace(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { - if (expr.getParent() instanceof PsiExpressionList) { - PsiExpressionList list = (PsiExpressionList)expr.getParent(); - PsiElement listParent = list.getParent(); - PsiSubstitutor subst = PsiSubstitutor.EMPTY; - PsiMethod method = null; - if (listParent instanceof PsiMethodCallExpression) { - final JavaResolveResult resolveResult = ((PsiMethodCallExpression)listParent).getMethodExpression().advancedResolve(false); - method = (PsiMethod)resolveResult.getElement(); - subst = resolveResult.getSubstitutor(); - } - else { - if (listParent instanceof PsiAnonymousClass) { - listParent = listParent.getParent(); - } - if (listParent instanceof PsiNewExpression) { - method = ((PsiNewExpression)listParent).resolveConstructor(); - } - } - - if (method != null) { - final PsiElement navElement = method.getNavigationElement(); - if (navElement instanceof PsiMethod) { - method = (PsiMethod)navElement; - } - PsiExpression[] expressions = list.getExpressions(); - int index = -1; - for (int i = 0; i < expressions.length; i++) { - if (expressions[i] == expr) { - index = i; - break; - } - } - PsiParameter[] parms = method.getParameterList().getParameters(); - if (index < parms.length) { - String name = parms[index].getName(); - if (name != null && TypeConversionUtil.areTypesAssignmentCompatible(subst.substitute(parms[index].getType()), expr)) { - name = variableNameToPropertyName(name, VariableKind.PARAMETER); - String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); - if (expressions.length == 1) { - final String methodName = method.getName(); - String[] words = NameUtil.nameToWords(methodName); - if (words.length > 0) { - final String firstWord = words[0]; - if (SET_PREFIX.equals(firstWord)) { - final String propertyName = methodName.substring(firstWord.length()); - final String[] setterNames = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); - names = ArrayUtil.mergeArrays(names, setterNames); - } - } - } - return new NamesByExprInfo(name, names); - } - } - } - } - else if (expr.getParent() instanceof PsiAssignmentExpression && variableKind == VariableKind.PARAMETER) { - final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expr.getParent(); - if (expr == assignmentExpression.getRExpression()) { - final PsiExpression leftExpression = assignmentExpression.getLExpression(); - if (leftExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression) leftExpression).getQualifier() == null) { - String name = leftExpression.getText(); - if (name != null) { - final PsiElement resolve = ((PsiReferenceExpression)leftExpression).resolve(); - if (resolve instanceof PsiVariable) { - name = variableNameToPropertyName(name, getVariableKind((PsiVariable)resolve)); - } - String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); - return new NamesByExprInfo(name, names); - } - } - } - } - - return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); - } - - @Override - public String variableNameToPropertyName(String name, VariableKind variableKind) { - if (variableKind == VariableKind.STATIC_FINAL_FIELD) { - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < name.length(); i++) { - char c = name.charAt(i); - if (c != '_') { - if( Character.isLowerCase( c ) ) - { - return variableNameToPropertyNameInner( name, variableKind ); - } - - buffer.append(Character.toLowerCase(c)); - continue; - } - i++; - if (i < name.length()) { - c = name.charAt(i); - buffer.append(c); - } - } - return buffer.toString(); - } - - return variableNameToPropertyNameInner(name, variableKind); - } - - private String variableNameToPropertyNameInner(String name, VariableKind variableKind) { - String prefix = getPrefixByVariableKind(variableKind); - String suffix = getSuffixByVariableKind(variableKind); - boolean doDecapitalize = false; - - if (name.startsWith(prefix) && name.length() > prefix.length()) { - name = name.substring(prefix.length()); - doDecapitalize = true; - } - - if (name.endsWith(suffix) && name.length() > suffix.length()) { - name = name.substring(0, name.length() - suffix.length()); - doDecapitalize = true; - } - - if (name.startsWith(IS_PREFIX) && name.length() > IS_PREFIX.length() && Character.isUpperCase(name.charAt(IS_PREFIX.length()))) { - name = name.substring(IS_PREFIX.length()); - doDecapitalize = true; - } - - if (doDecapitalize) { - name = Introspector.decapitalize(name); - } - - return name; - } - - @Override - public String propertyNameToVariableName(String propertyName, VariableKind variableKind) { - if (variableKind == VariableKind.STATIC_FINAL_FIELD) { - String[] words = NameUtil.nameToWords(propertyName); - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < words.length; i++) { - String word = words[i]; - if (i > 0) { - buffer.append("_"); - } - buffer.append(StringUtilRt.toUpperCase(word)); - } - return buffer.toString(); - } - - String prefix = getPrefixByVariableKind(variableKind); - String name = propertyName; - if (name.length() > 0 && prefix.length() > 0 && !StringUtil.endsWithChar(prefix, '_')) { - name = Character.toUpperCase(name.charAt(0)) + name.substring(1); - } - name = prefix + name + getSuffixByVariableKind(variableKind); - name = changeIfNotIdentifier(name); - return name; - } - - private String[] getSuggestionsByName(String name, VariableKind variableKind, boolean isArray, boolean correctKeywords) { - boolean upperCaseStyle = variableKind == VariableKind.STATIC_FINAL_FIELD; - boolean preferLongerNames = getSettings().PREFER_LONGER_NAMES; - String prefix = getPrefixByVariableKind(variableKind); - String suffix = getSuffixByVariableKind(variableKind); - - List answer = new ArrayList(); - for (String suggestion : NameUtil.getSuggestionsByName(name, prefix, suffix, upperCaseStyle, preferLongerNames, isArray)) { - answer.add(correctKeywords ? changeIfNotIdentifier(suggestion) : suggestion); - } - - return ArrayUtil.toStringArray(answer); - } - - @Override - public String suggestUniqueVariableName(String baseName, PsiElement place, boolean lookForward) { - int index = 0; - PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); - NextName: - while (true) { - String name = baseName; - if (index > 0) { - name += index; - } - index++; - if (PsiUtil.isVariableNameUnique(name, place)) { - if (lookForward) { - final String name1 = name; - PsiElement run = scope; - while (run != null) { - class CancelException extends RuntimeException { - } - try { - run.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitAnonymousClass(final PsiAnonymousClass aClass) { - } - - @Override public void visitVariable(PsiVariable variable) { - if (name1.equals(variable.getName())) { - throw new CancelException(); - } - } - }); - } - catch (CancelException e) { - continue NextName; - } - run = run.getNextSibling(); - if (scope instanceof PsiMethod) {//do not check next member for param name conflict - break; - } - } - - } - return name; - } - } - } - - @Override - @NotNull - public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean ignorePlaceName, - boolean lookForward) { - final String[] names = baseNameInfo.names; - final LinkedHashSet uniqueNames = new LinkedHashSet(names.length); - for (String name : names) { - if (ignorePlaceName && place instanceof PsiNamedElement) { - final String placeName = ((PsiNamedElement)place).getName(); - if (Comparing.strEqual(placeName, name)) { - uniqueNames.add(name); - continue; - } - } - uniqueNames.add(suggestUniqueVariableName(name, place, lookForward)); - } - - return new SuggestedNameInfo(ArrayUtil.toStringArray(uniqueNames)) { - @Override - public void nameChoosen(String name) { - baseNameInfo.nameChoosen(name); - } - }; - } - - private static void sortVariableNameSuggestions(String[] names, - final VariableKind variableKind, - @Nullable final String propertyName, - @Nullable final PsiType type) { - if( names.length <= 1 ) { - return; - } - - if (LOG.isDebugEnabled()) { - LOG.debug("sorting names:" + variableKind); - if (propertyName != null) { - LOG.debug("propertyName:" + propertyName); - } - if (type != null) { - LOG.debug("type:" + type); - } - for (String name : names) { - int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); - LOG.debug(name + " : " + count); - } - } - - Comparator comparator = new Comparator() { - @Override - public int compare(String s1, String s2) { - int count1 = JavaStatisticsManager.getVariableNameUseCount(s1, variableKind, propertyName, type); - int count2 = JavaStatisticsManager.getVariableNameUseCount(s2, variableKind, propertyName, type); - return count2 - count1; - } - }; - Arrays.sort(names, comparator); - } - - @Override - @NotNull - public String getPrefixByVariableKind(VariableKind variableKind) { - String prefix = ""; - switch (variableKind) { - case FIELD: - prefix = getSettings().FIELD_NAME_PREFIX; - break; - case STATIC_FIELD: - prefix = getSettings().STATIC_FIELD_NAME_PREFIX; - break; - case PARAMETER: - prefix = getSettings().PARAMETER_NAME_PREFIX; - break; - case LOCAL_VARIABLE: - prefix = getSettings().LOCAL_VARIABLE_NAME_PREFIX; - break; - case STATIC_FINAL_FIELD: - prefix = ""; - break; - default: - LOG.assertTrue(false); - break; - } - if (prefix == null) { - prefix = ""; - } - return prefix; - } - - @Override - @NotNull - public String getSuffixByVariableKind(VariableKind variableKind) { - String suffix = ""; - switch (variableKind) { - case FIELD: - suffix = getSettings().FIELD_NAME_SUFFIX; - break; - case STATIC_FIELD: - suffix = getSettings().STATIC_FIELD_NAME_SUFFIX; - break; - case PARAMETER: - suffix = getSettings().PARAMETER_NAME_SUFFIX; - break; - case LOCAL_VARIABLE: - suffix = getSettings().LOCAL_VARIABLE_NAME_SUFFIX; - break; - case STATIC_FINAL_FIELD: - suffix = ""; - break; - default: - LOG.assertTrue(false); - break; - } - if (suffix == null) { - suffix = ""; - } - return suffix; - } - - @Nullable - private CodeStyleSettings.TypeToNameMap getMapByVariableKind(VariableKind variableKind) { - if (variableKind == VariableKind.FIELD) return getSettings().FIELD_TYPE_TO_NAME; - if (variableKind == VariableKind.STATIC_FIELD) return getSettings().STATIC_FIELD_TYPE_TO_NAME; - if (variableKind == VariableKind.PARAMETER) return getSettings().PARAMETER_TYPE_TO_NAME; - if (variableKind == VariableKind.LOCAL_VARIABLE) return getSettings().LOCAL_VARIABLE_TYPE_TO_NAME; - return null; - } - - @NonNls - private String changeIfNotIdentifier(String name) { - if (!isIdentifier(name)) { - return StringUtil.fixVariableNameDerivedFromPropertyName(name); - } - return name; - } - - private boolean isIdentifier(String name) { - return JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(name, LanguageLevel.HIGHEST); - } - - private CodeStyleSettings getSettings() { - return CodeStyleSettingsManager.getSettings(myProject); - } - - public static boolean isStringPsiLiteral(PsiElement element) { - if (element instanceof PsiLiteralExpression) { - final String text = element.getText(); - return text.length() > 1 && StringUtil.isQuotedString(text); - } - return false; - } -} +/* + * Copyright 2000-2011 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. + */ + +/* + * @author max + */ +package com.intellij.psi.impl.source.codeStyle; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.util.text.StringUtilRt; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.*; +import com.intellij.psi.impl.CheckUtil; +import com.intellij.psi.impl.source.SourceTreeToPsiMap; +import com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatement; +import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.statistics.JavaStatisticsManager; +import com.intellij.psi.util.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.beans.Introspector; +import java.util.*; + +public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl"); + + @NonNls private static final String IMPL_TYPNAME_SUFFIX = "Impl"; + @NonNls private static final String GET_PREFIX = "get"; + @NonNls private static final String IS_PREFIX = "is"; + @NonNls private static final String FIND_PREFIX = "find"; + @NonNls private static final String CREATE_PREFIX = "create"; + @NonNls private static final String WITH_PREFIX = "with"; + @NonNls private static final String SET_PREFIX = "set"; + + private final Project myProject; + + public JavaCodeStyleManagerImpl(final Project project) { + myProject = project; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { + return shortenClassReferences(element, 0); + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element, int flags) throws IncorrectOperationException { + CheckUtil.checkWritable(element); + if (!SourceTreeToPsiMap.hasTreeElement(element)) return element; + + return SourceTreeToPsiMap.treeElementToPsi( + new ReferenceAdjuster(myProject).process((TreeElement)element.getNode(), (flags & DO_NOT_ADD_IMPORTS) == 0, + (flags & UNCOMPLETE_CODE) != 0)); + } + + @Override + public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) + throws IncorrectOperationException { + CheckUtil.checkWritable(element); + if (SourceTreeToPsiMap.hasTreeElement(element)) { + new ReferenceAdjuster(myProject).processRange((TreeElement)element.getNode(), startOffset, endOffset); + } + } + + @Override + public PsiElement qualifyClassReferences(@NotNull PsiElement element) { + return SourceTreeToPsiMap.treeElementToPsi(new ReferenceAdjuster(true, true).process((TreeElement)element.getNode(), false, false)); + } + + @Override + public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { + CheckUtil.checkWritable(file); + if (file instanceof PsiJavaFile) { + PsiImportList newList = prepareOptimizeImportsResult((PsiJavaFile)file); + if (newList != null) { + final PsiImportList importList = ((PsiJavaFile)file).getImportList(); + if (importList != null) { + importList.replace(newList); + } + } + } + } + + @Override + public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { + return new ImportHelper(getSettings()).prepareOptimizeImportsResult(file); + } + + @Override + public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { + return new ImportHelper(getSettings()).addImport(file, refClass); + } + + @Override + public void removeRedundantImports(@NotNull final PsiJavaFile file) throws IncorrectOperationException { + final Collection redundants = findRedundantImports(file); + if (redundants == null) return; + + for (final PsiImportStatementBase importStatement : redundants) { + final PsiJavaCodeReferenceElement ref = importStatement.getImportReference(); + //Do not remove non-resolving refs + if (ref == null || ref.resolve() == null) { + continue; + } + + importStatement.delete(); + } + } + + @Override + @Nullable + public Collection findRedundantImports(final PsiJavaFile file) { + final PsiImportList importList = file.getImportList(); + if (importList == null) return null; + final PsiImportStatementBase[] imports = importList.getAllImportStatements(); + if( imports.length == 0 ) return null; + + Set allImports = new THashSet(Arrays.asList(imports)); + final Collection redundants; + if (JspPsiUtil.isInJspFile(file)) { + // remove only duplicate imports + redundants = new THashSet(TObjectHashingStrategy.IDENTITY); + ContainerUtil.addAll(redundants, imports); + redundants.removeAll(allImports); + for (PsiImportStatementBase importStatement : imports) { + if (importStatement instanceof JspxImportStatement && ((JspxImportStatement)importStatement).isForeignFileImport()) { + redundants.remove(importStatement); + } + } + } + else { + redundants = allImports; + final List roots = file.getViewProvider().getAllFiles(); + for (PsiElement root : roots) { + root.accept(new JavaRecursiveElementWalkingVisitor() { + @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + if (!reference.isQualified()) { + final JavaResolveResult resolveResult = reference.advancedResolve(false); + if (!inTheSamePackage(file, resolveResult.getElement())) { + final PsiElement resolveScope = resolveResult.getCurrentFileResolveScope(); + if (resolveScope instanceof PsiImportStatementBase) { + final PsiImportStatementBase importStatementBase = (PsiImportStatementBase)resolveScope; + redundants.remove(importStatementBase); + } + } + } + super.visitReferenceElement(reference); + } + + private boolean inTheSamePackage(PsiJavaFile file, PsiElement element) { + if (element instanceof PsiClass && ((PsiClass)element).getContainingClass() == null) { + final PsiFile containingFile = element.getContainingFile(); + if (containingFile instanceof PsiJavaFile) { + return Comparing.strEqual(file.getPackageName(), ((PsiJavaFile)containingFile).getPackageName()); + } + } + return false; + } + }); + } + } + return redundants; + } + + @Override + public int findEntryIndex(@NotNull PsiImportStatementBase statement) { + return new ImportHelper(getSettings()).findEntryIndex(statement); + } + + @Override + public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, + @Nullable final String propertyName, + @Nullable final PsiExpression expr, + @Nullable PsiType type, + final boolean correctKeywords) { + LinkedHashSet names = new LinkedHashSet(); + + if (expr != null && type == null) { + type = expr.getType(); + } + + if (propertyName != null) { + String[] namesByName = getSuggestionsByName(propertyName, kind, false, correctKeywords); + sortVariableNameSuggestions(namesByName, kind, propertyName, null); + ContainerUtil.addAll(names, namesByName); + } + + final NamesByExprInfo namesByExpr; + if (expr != null) { + namesByExpr = suggestVariableNameByExpression(expr, kind, correctKeywords); + if (namesByExpr.propertyName != null) { + sortVariableNameSuggestions(namesByExpr.names, kind, namesByExpr.propertyName, null); + } + ContainerUtil.addAll(names, namesByExpr.names); + } + else { + namesByExpr = null; + } + + if (type != null) { + String[] namesByType = suggestVariableNameByType(type, kind, correctKeywords); + sortVariableNameSuggestions(namesByType, kind, null, type); + ContainerUtil.addAll(names, namesByType); + } + + final String _propertyName; + if (propertyName != null) { + _propertyName = propertyName; + } + else { + _propertyName = namesByExpr != null ? namesByExpr.propertyName : null; + } + + addNamesFromStatistics(names, kind, _propertyName, type); + + String[] namesArray = ArrayUtil.toStringArray(names); + sortVariableNameSuggestions(namesArray, kind, _propertyName, type); + + final PsiType _type = type; + return new SuggestedNameInfo(namesArray) { + @Override + public void nameChoosen(String name) { + if (_propertyName != null || _type != null && _type.isValid()) { + JavaStatisticsManager.incVariableNameUseCount(name, kind, _propertyName, _type); + } + } + }; + } + + private static void addNamesFromStatistics(Set names, VariableKind variableKind, @Nullable String propertyName, @Nullable PsiType type) { + String[] allNames = JavaStatisticsManager.getAllVariableNamesUsed(variableKind, propertyName, type); + + int maxFrequency = 0; + for (String name : allNames) { + int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); + maxFrequency = Math.max(maxFrequency, count); + } + + int frequencyLimit = Math.max(5, maxFrequency / 2); + + for (String name : allNames) { + if( names.contains( name ) ) + { + continue; + } + int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); + if (LOG.isDebugEnabled()) { + LOG.debug("new name:" + name + " count:" + count); + LOG.debug("frequencyLimit:" + frequencyLimit); + } + if (count >= frequencyLimit) { + names.add(name); + } + } + + if (propertyName != null && type != null) { + addNamesFromStatistics(names, variableKind, propertyName, null); + addNamesFromStatistics(names, variableKind, null, type); + } + } + + private String[] suggestVariableNameByType(PsiType type, final VariableKind variableKind, boolean correctKeywords) { + String longTypeName = getLongTypeName(type); + CodeStyleSettings.TypeToNameMap map = getMapByVariableKind(variableKind); + if (map != null && longTypeName != null) { + if (type.equals(PsiType.NULL)) { + longTypeName = CommonClassNames.JAVA_LANG_OBJECT; + } + String name = map.nameByType(longTypeName); + if (name != null && isIdentifier(name)) { + return new String[]{name}; + } + } + + Collection suggestions = new LinkedHashSet(); + + suggestNamesForCollectionInheritors(type, variableKind, suggestions, correctKeywords); + suggestNamesFromGenericParameters(type, variableKind, suggestions, correctKeywords); + + String typeName = normalizeTypeName(getTypeName(type)); + if (typeName != null) { + ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, type instanceof PsiArrayType, correctKeywords)); + } + + return ArrayUtil.toStringArray(suggestions); + } + + private void suggestNamesFromGenericParameters(final PsiType type, + final VariableKind variableKind, + final Collection suggestions, boolean correctKeywords) { + if (!(type instanceof PsiClassType)) { + return; + } + StringBuilder fullNameBuilder = new StringBuilder(); + final PsiType[] parameters = ((PsiClassType)type).getParameters(); + for (PsiType parameter : parameters) { + if (parameter instanceof PsiClassType) { + final String typeName = normalizeTypeName(getTypeName(parameter)); + if (typeName != null) { + fullNameBuilder.append(typeName); + } + } + } + String baseName = normalizeTypeName(getTypeName(type)); + if (baseName != null) { + fullNameBuilder.append(baseName); + ContainerUtil.addAll(suggestions, getSuggestionsByName(fullNameBuilder.toString(), variableKind, false, correctKeywords)); + } + } + + private void suggestNamesForCollectionInheritors(final PsiType type, + final VariableKind variableKind, + Collection suggestions, boolean correctKeywords) { + PsiType componentType = PsiUtil.extractIterableTypeParameter(type, false); + if( componentType == null ) { + return; + } + String typeName = normalizeTypeName(getTypeName(componentType)); + if (typeName != null) { + ContainerUtil.addAll(suggestions, getSuggestionsByName(typeName, variableKind, true, correctKeywords)); + } + } + + @Nullable + private static String normalizeTypeName(String typeName) { + if( typeName == null ) + { + return null; + } + if (typeName.endsWith(IMPL_TYPNAME_SUFFIX) && typeName.length() > IMPL_TYPNAME_SUFFIX.length()) { + return typeName.substring(0, typeName.length() - IMPL_TYPNAME_SUFFIX.length()); + } + return typeName; + } + + @Nullable + private static String getTypeName(PsiType type) { + type = type.getDeepComponentType(); + if (type instanceof PsiClassType) { + final PsiClassType classType = (PsiClassType)type; + final String className = classType.getClassName(); + if (className != null) { + return className; + } + else { + final PsiClass aClass = classType.resolve(); + if (aClass instanceof PsiAnonymousClass) { + return ((PsiAnonymousClass)aClass).getBaseClassType().getClassName(); + } + else { + return null; + } + } + } + else { + if (type instanceof PsiPrimitiveType) { + return type.getPresentableText(); + } + else { + if (type instanceof PsiWildcardType) { + return getTypeName(((PsiWildcardType)type).getExtendsBound()); + } + else { + if (type instanceof PsiIntersectionType) { + return getTypeName(((PsiIntersectionType)type).getRepresentative()); + } + else { + if (type instanceof PsiCapturedWildcardType) { + return getTypeName(((PsiCapturedWildcardType)type).getWildcard()); + } + else { + if (type instanceof PsiDisjunctionType) { + return getTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); + } + else { + LOG.error("Unknown type:" + type); + return null; + } + } + } + } + } + } + } + + @Nullable + private static String getLongTypeName(PsiType type) { + if (type instanceof PsiClassType) { + PsiClass aClass = ((PsiClassType)type).resolve(); + if( aClass == null ) + { + return null; + } + if (aClass instanceof PsiAnonymousClass) { + PsiClass baseClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve(); + if( baseClass == null ) + { + return null; + } + return baseClass.getQualifiedName(); + } + return aClass.getQualifiedName(); + } + else { + if (type instanceof PsiArrayType) { + return getLongTypeName(((PsiArrayType)type).getComponentType()) + "[]"; + } + else { + if (type instanceof PsiPrimitiveType) { + return type.getPresentableText(); + } + else { + if (type instanceof PsiWildcardType) { + final PsiType bound = ((PsiWildcardType)type).getBound(); + if (bound != null) { + return getLongTypeName(bound); + } + else { + return "java.lang.Object"; + } + } + else { + if (type instanceof PsiCapturedWildcardType) { + final PsiType bound = ((PsiCapturedWildcardType)type).getWildcard().getBound(); + if (bound != null) { + return getLongTypeName(bound); + } + else { + return "java.lang.Object"; + } + } + else { + if (type instanceof PsiIntersectionType) { + return getLongTypeName(((PsiIntersectionType)type).getRepresentative()); + } + else { + if (type instanceof PsiDisjunctionType) { + return getLongTypeName(((PsiDisjunctionType)type).getLeastUpperBound()); + } + else { + LOG.error("Unknown type:" + type); + return null; + } + } + } + } + } + } + } + } + + private static class NamesByExprInfo { + final String[] names; + final String propertyName; + + public NamesByExprInfo(String propertyName, String... names) { + this.names = names; + this.propertyName = propertyName; + } + } + + private NamesByExprInfo suggestVariableNameByExpression(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { + final NamesByExprInfo names1 = suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords); + final NamesByExprInfo names2 = suggestVariableNameByExpressionPlace(expr, variableKind, correctKeywords); + + PsiType type = expr.getType(); + final String[] names3; + if (type != null) { + names3 = suggestVariableNameByType(type, variableKind, correctKeywords); + } + else { + names3 = null; + } + + final LinkedHashSet names = new LinkedHashSet(); + final String[] fromLiterals = suggestVariableNameFromLiterals(expr, variableKind, correctKeywords); + if (fromLiterals != null) { + ContainerUtil.addAll(names, fromLiterals); + } + ContainerUtil.addAll(names, names1.names); + ContainerUtil.addAll(names, names2.names); + if (names3 != null) { + ContainerUtil.addAll(names, names3); + } + + String[] namesArray = ArrayUtil.toStringArray(names); + String propertyName = names1.propertyName != null ? names1.propertyName : names2.propertyName; + return new NamesByExprInfo(propertyName, namesArray); + } + + @Nullable + private String[] suggestVariableNameFromLiterals(PsiExpression expr, VariableKind variableKind, boolean correctKeywords) { + final PsiElement[] literals = PsiTreeUtil.collectElements(expr, new PsiElementFilter() { + @Override + public boolean isAccepted(PsiElement element) { + if (isStringPsiLiteral(element) && StringUtil.isJavaIdentifier(StringUtil.unquoteString(element.getText()))) { + final PsiElement exprList = element.getParent(); + if (exprList instanceof PsiExpressionList) { + final PsiElement call = exprList.getParent(); + if (call instanceof PsiNewExpression) { + return true; + } else if (call instanceof PsiMethodCallExpression) { + //TODO: exclude or not getA().getB("name").getC(); or getA(getB("name").getC()); It works fine for now in the most cases + return true; + } + } + } + return false; + } + }); + + if (literals.length == 1) { + final String text = StringUtil.unquoteString(literals[0].getText()); + return getSuggestionsByName(text, variableKind, expr.getType() instanceof PsiArrayType, correctKeywords); + } + return null; + } + + private NamesByExprInfo suggestVariableNameByExpressionOnly(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { + if (expr instanceof PsiMethodCallExpression) { + PsiReferenceExpression methodExpr = ((PsiMethodCallExpression)expr).getMethodExpression(); + String methodName = methodExpr.getReferenceName(); + if (methodName != null) { + String[] words = NameUtil.nameToWords(methodName); + if (words.length > 0) { + final String firstWord = words[0]; + if (GET_PREFIX.equals(firstWord) + || IS_PREFIX.equals(firstWord) + || FIND_PREFIX.equals(firstWord) + || CREATE_PREFIX.equals(firstWord)) { + if (words.length > 1) { + final String propertyName = methodName.substring(firstWord.length()); + String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); + final PsiExpression qualifierExpression = methodExpr.getQualifierExpression(); + if (qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() instanceof PsiVariable) { + names = ArrayUtil.append(names, StringUtil.sanitizeJavaIdentifier(changeIfNotIdentifier(qualifierExpression.getText() + StringUtil.capitalize(propertyName)))); + } + return new NamesByExprInfo(propertyName, names); + } + } + else if (words.length == 1) { + return new NamesByExprInfo(methodName, getSuggestionsByName(methodName, variableKind, false, correctKeywords)); + } + } + } + } + else if (expr instanceof PsiReferenceExpression) { + String propertyName = ((PsiReferenceExpression)expr).getReferenceName(); + PsiElement refElement = ((PsiReferenceExpression)expr).resolve(); + if (refElement instanceof PsiVariable) { + VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); + propertyName = variableNameToPropertyName(propertyName, refVariableKind); + } + if (refElement != null && propertyName != null) { + String[] names = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); + return new NamesByExprInfo(propertyName, names); + } + } + else if (expr instanceof PsiArrayAccessExpression) { + PsiExpression arrayExpr = ((PsiArrayAccessExpression)expr).getArrayExpression(); + if (arrayExpr instanceof PsiReferenceExpression) { + String arrayName = ((PsiReferenceExpression)arrayExpr).getReferenceName(); + PsiElement refElement = ((PsiReferenceExpression)arrayExpr).resolve(); + if (refElement instanceof PsiVariable) { + VariableKind refVariableKind = getVariableKind((PsiVariable)refElement); + arrayName = variableNameToPropertyName(arrayName, refVariableKind); + } + + if (arrayName != null) { + String name = StringUtil.unpluralize(arrayName); + if (name != null) { + String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); + return new NamesByExprInfo(name, names); + } + } + } + } + else if (expr instanceof PsiLiteralExpression && variableKind == VariableKind.STATIC_FINAL_FIELD) { + final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expr; + final Object value = literalExpression.getValue(); + if (value instanceof String) { + final String stringValue = (String)value; + String[] names = getSuggestionsByValue(stringValue); + if (names.length > 0) { + return new NamesByExprInfo(null, constantValueToConstantName(names)); + } + } + } else if (expr instanceof PsiParenthesizedExpression) { + return suggestVariableNameByExpressionOnly(((PsiParenthesizedExpression)expr).getExpression(), variableKind, correctKeywords); + } else if (expr instanceof PsiTypeCastExpression) { + return suggestVariableNameByExpressionOnly(((PsiTypeCastExpression)expr).getOperand(), variableKind, correctKeywords); + } else if (expr instanceof PsiLiteralExpression) { + final String text = StringUtil.stripQuotesAroundValue(expr.getText()); + if (isIdentifier(text)) { + return new NamesByExprInfo(text, getSuggestionsByName(text, variableKind, false, correctKeywords)); + } + } + + return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); + } + + private static String constantValueToConstantName(final String[] names) { + final StringBuilder result = new StringBuilder(); + for (int i = 0; i < names.length; i++) { + if (i > 0) result.append("_"); + result.append(names[i]); + } + return result.toString(); + } + + private static String[] getSuggestionsByValue(final String stringValue) { + List result = new ArrayList(); + StringBuffer currentWord = new StringBuffer(); + + boolean prevIsUpperCase = false; + + for (int i = 0; i < stringValue.length(); i++) { + final char c = stringValue.charAt(i); + if (Character.isUpperCase(c)) { + if (currentWord.length() > 0 && !prevIsUpperCase) { + result.add(currentWord.toString()); + currentWord = new StringBuffer(); + } + currentWord.append(c); + } else if (Character.isLowerCase(c)) { + currentWord.append(Character.toUpperCase(c)); + } else if (Character.isJavaIdentifierPart(c) && c != '_') { + if (Character.isJavaIdentifierStart(c) || currentWord.length() > 0 || !result.isEmpty()) { + currentWord.append(c); + } + } else { + if (currentWord.length() > 0) { + result.add(currentWord.toString()); + currentWord = new StringBuffer(); + } + } + + prevIsUpperCase = Character.isUpperCase(c); + } + + if (currentWord.length() > 0) { + result.add(currentWord.toString()); + } + return ArrayUtil.toStringArray(result); + } + + private NamesByExprInfo suggestVariableNameByExpressionPlace(PsiExpression expr, final VariableKind variableKind, boolean correctKeywords) { + if (expr.getParent() instanceof PsiExpressionList) { + PsiExpressionList list = (PsiExpressionList)expr.getParent(); + PsiElement listParent = list.getParent(); + PsiSubstitutor subst = PsiSubstitutor.EMPTY; + PsiMethod method = null; + if (listParent instanceof PsiMethodCallExpression) { + final JavaResolveResult resolveResult = ((PsiMethodCallExpression)listParent).getMethodExpression().advancedResolve(false); + method = (PsiMethod)resolveResult.getElement(); + subst = resolveResult.getSubstitutor(); + } + else { + if (listParent instanceof PsiAnonymousClass) { + listParent = listParent.getParent(); + } + if (listParent instanceof PsiNewExpression) { + method = ((PsiNewExpression)listParent).resolveConstructor(); + } + } + + if (method != null) { + final PsiElement navElement = method.getNavigationElement(); + if (navElement instanceof PsiMethod) { + method = (PsiMethod)navElement; + } + PsiExpression[] expressions = list.getExpressions(); + int index = -1; + for (int i = 0; i < expressions.length; i++) { + if (expressions[i] == expr) { + index = i; + break; + } + } + PsiParameter[] parms = method.getParameterList().getParameters(); + if (index < parms.length) { + String name = parms[index].getName(); + if (name != null && TypeConversionUtil.areTypesAssignmentCompatible(subst.substitute(parms[index].getType()), expr)) { + name = variableNameToPropertyName(name, VariableKind.PARAMETER); + String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); + if (expressions.length == 1) { + final String methodName = method.getName(); + String[] words = NameUtil.nameToWords(methodName); + if (words.length > 0) { + final String firstWord = words[0]; + if (SET_PREFIX.equals(firstWord)) { + final String propertyName = methodName.substring(firstWord.length()); + final String[] setterNames = getSuggestionsByName(propertyName, variableKind, false, correctKeywords); + names = ArrayUtil.mergeArrays(names, setterNames); + } + } + } + return new NamesByExprInfo(name, names); + } + } + } + } + else if (expr.getParent() instanceof PsiAssignmentExpression && variableKind == VariableKind.PARAMETER) { + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expr.getParent(); + if (expr == assignmentExpression.getRExpression()) { + final PsiExpression leftExpression = assignmentExpression.getLExpression(); + if (leftExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression) leftExpression).getQualifier() == null) { + String name = leftExpression.getText(); + if (name != null) { + final PsiElement resolve = ((PsiReferenceExpression)leftExpression).resolve(); + if (resolve instanceof PsiVariable) { + name = variableNameToPropertyName(name, getVariableKind((PsiVariable)resolve)); + } + String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords); + return new NamesByExprInfo(name, names); + } + } + } + } + + return new NamesByExprInfo(null, ArrayUtil.EMPTY_STRING_ARRAY); + } + + @Override + public String variableNameToPropertyName(String name, VariableKind variableKind) { + if (variableKind == VariableKind.STATIC_FINAL_FIELD) { + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c != '_') { + if( Character.isLowerCase( c ) ) + { + return variableNameToPropertyNameInner( name, variableKind ); + } + + buffer.append(Character.toLowerCase(c)); + continue; + } + i++; + if (i < name.length()) { + c = name.charAt(i); + buffer.append(c); + } + } + return buffer.toString(); + } + + return variableNameToPropertyNameInner(name, variableKind); + } + + private String variableNameToPropertyNameInner(String name, VariableKind variableKind) { + String prefix = getPrefixByVariableKind(variableKind); + String suffix = getSuffixByVariableKind(variableKind); + boolean doDecapitalize = false; + + if (name.startsWith(prefix) && name.length() > prefix.length()) { + name = name.substring(prefix.length()); + doDecapitalize = true; + } + + if (name.endsWith(suffix) && name.length() > suffix.length()) { + name = name.substring(0, name.length() - suffix.length()); + doDecapitalize = true; + } + + if (name.startsWith(IS_PREFIX) && name.length() > IS_PREFIX.length() && Character.isUpperCase(name.charAt(IS_PREFIX.length()))) { + name = name.substring(IS_PREFIX.length()); + doDecapitalize = true; + } + + if (doDecapitalize) { + name = Introspector.decapitalize(name); + } + + return name; + } + + @Override + public String propertyNameToVariableName(String propertyName, VariableKind variableKind) { + if (variableKind == VariableKind.STATIC_FINAL_FIELD) { + String[] words = NameUtil.nameToWords(propertyName); + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < words.length; i++) { + String word = words[i]; + if (i > 0) { + buffer.append("_"); + } + buffer.append(StringUtilRt.toUpperCase(word)); + } + return buffer.toString(); + } + + String prefix = getPrefixByVariableKind(variableKind); + String name = propertyName; + if (name.length() > 0 && prefix.length() > 0 && !StringUtil.endsWithChar(prefix, '_')) { + name = Character.toUpperCase(name.charAt(0)) + name.substring(1); + } + name = prefix + name + getSuffixByVariableKind(variableKind); + name = changeIfNotIdentifier(name); + return name; + } + + private String[] getSuggestionsByName(String name, VariableKind variableKind, boolean isArray, boolean correctKeywords) { + boolean upperCaseStyle = variableKind == VariableKind.STATIC_FINAL_FIELD; + boolean preferLongerNames = getSettings().PREFER_LONGER_NAMES; + String prefix = getPrefixByVariableKind(variableKind); + String suffix = getSuffixByVariableKind(variableKind); + + List answer = new ArrayList(); + for (String suggestion : NameUtil.getSuggestionsByName(name, prefix, suffix, upperCaseStyle, preferLongerNames, isArray)) { + answer.add(correctKeywords ? changeIfNotIdentifier(suggestion) : suggestion); + } + + return ArrayUtil.toStringArray(answer); + } + + @Override + public String suggestUniqueVariableName(String baseName, PsiElement place, boolean lookForward) { + int index = 0; + PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); + NextName: + while (true) { + String name = baseName; + if (index > 0) { + name += index; + } + index++; + if (PsiUtil.isVariableNameUnique(name, place)) { + if (lookForward) { + final String name1 = name; + PsiElement run = scope; + while (run != null) { + class CancelException extends RuntimeException { + } + try { + run.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitAnonymousClass(final PsiAnonymousClass aClass) { + } + + @Override public void visitVariable(PsiVariable variable) { + if (name1.equals(variable.getName())) { + throw new CancelException(); + } + } + }); + } + catch (CancelException e) { + continue NextName; + } + run = run.getNextSibling(); + if (scope instanceof PsiMethod) {//do not check next member for param name conflict + break; + } + } + + } + return name; + } + } + } + + @Override + @NotNull + public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward) { + final String[] names = baseNameInfo.names; + final LinkedHashSet uniqueNames = new LinkedHashSet(names.length); + for (String name : names) { + if (ignorePlaceName && place instanceof PsiNamedElement) { + final String placeName = ((PsiNamedElement)place).getName(); + if (Comparing.strEqual(placeName, name)) { + uniqueNames.add(name); + continue; + } + } + uniqueNames.add(suggestUniqueVariableName(name, place, lookForward)); + } + + return new SuggestedNameInfo(ArrayUtil.toStringArray(uniqueNames)) { + @Override + public void nameChoosen(String name) { + baseNameInfo.nameChoosen(name); + } + }; + } + + private static void sortVariableNameSuggestions(String[] names, + final VariableKind variableKind, + @Nullable final String propertyName, + @Nullable final PsiType type) { + if( names.length <= 1 ) { + return; + } + + if (LOG.isDebugEnabled()) { + LOG.debug("sorting names:" + variableKind); + if (propertyName != null) { + LOG.debug("propertyName:" + propertyName); + } + if (type != null) { + LOG.debug("type:" + type); + } + for (String name : names) { + int count = JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type); + LOG.debug(name + " : " + count); + } + } + + Comparator comparator = new Comparator() { + @Override + public int compare(String s1, String s2) { + int count1 = JavaStatisticsManager.getVariableNameUseCount(s1, variableKind, propertyName, type); + int count2 = JavaStatisticsManager.getVariableNameUseCount(s2, variableKind, propertyName, type); + return count2 - count1; + } + }; + Arrays.sort(names, comparator); + } + + @Override + @NotNull + public String getPrefixByVariableKind(VariableKind variableKind) { + String prefix = ""; + switch (variableKind) { + case FIELD: + prefix = getSettings().FIELD_NAME_PREFIX; + break; + case STATIC_FIELD: + prefix = getSettings().STATIC_FIELD_NAME_PREFIX; + break; + case PARAMETER: + prefix = getSettings().PARAMETER_NAME_PREFIX; + break; + case LOCAL_VARIABLE: + prefix = getSettings().LOCAL_VARIABLE_NAME_PREFIX; + break; + case STATIC_FINAL_FIELD: + prefix = ""; + break; + default: + LOG.assertTrue(false); + break; + } + if (prefix == null) { + prefix = ""; + } + return prefix; + } + + @Override + @NotNull + public String getSuffixByVariableKind(VariableKind variableKind) { + String suffix = ""; + switch (variableKind) { + case FIELD: + suffix = getSettings().FIELD_NAME_SUFFIX; + break; + case STATIC_FIELD: + suffix = getSettings().STATIC_FIELD_NAME_SUFFIX; + break; + case PARAMETER: + suffix = getSettings().PARAMETER_NAME_SUFFIX; + break; + case LOCAL_VARIABLE: + suffix = getSettings().LOCAL_VARIABLE_NAME_SUFFIX; + break; + case STATIC_FINAL_FIELD: + suffix = ""; + break; + default: + LOG.assertTrue(false); + break; + } + if (suffix == null) { + suffix = ""; + } + return suffix; + } + + @Nullable + private CodeStyleSettings.TypeToNameMap getMapByVariableKind(VariableKind variableKind) { + if (variableKind == VariableKind.FIELD) return getSettings().FIELD_TYPE_TO_NAME; + if (variableKind == VariableKind.STATIC_FIELD) return getSettings().STATIC_FIELD_TYPE_TO_NAME; + if (variableKind == VariableKind.PARAMETER) return getSettings().PARAMETER_TYPE_TO_NAME; + if (variableKind == VariableKind.LOCAL_VARIABLE) return getSettings().LOCAL_VARIABLE_TYPE_TO_NAME; + return null; + } + + @NonNls + private String changeIfNotIdentifier(String name) { + if (!isIdentifier(name)) { + return StringUtil.fixVariableNameDerivedFromPropertyName(name); + } + return name; + } + + private boolean isIdentifier(String name) { + return JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(name, LanguageLevel.HIGHEST); + } + + private CodeStyleSettings getSettings() { + return CodeStyleSettingsManager.getSettings(myProject); + } + + public static boolean isStringPsiLiteral(PsiElement element) { + if (element instanceof PsiLiteralExpression) { + final String text = element.getText(); + return text.length() > 1 && StringUtil.isQuotedString(text); + } + return false; + } +} diff --git a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java index 5bc23c8e1cf1..9f24c2a5085c 100644 --- a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java +++ b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java @@ -1,194 +1,213 @@ -/* - * Copyright 2000-2011 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. - */ - -/* - * @author max - */ -package com.intellij.psi.codeStyle; - -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; -import org.intellij.lang.annotations.MagicConstant; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; - -public abstract class JavaCodeStyleManager { - public static JavaCodeStyleManager getInstance(Project project) { - return ServiceManager.getService(project, JavaCodeStyleManager.class); - } - - public static final int DO_NOT_ADD_IMPORTS = 0x1000; - public static final int UNCOMPLETE_CODE = 0x2000; - - public abstract boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass); - public abstract PsiElement shortenClassReferences(@NotNull PsiElement element, @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) throws IncorrectOperationException; - - @NotNull public abstract String getPrefixByVariableKind(VariableKind variableKind); - @NotNull public abstract String getSuffixByVariableKind(VariableKind variableKind); - - public abstract int findEntryIndex(@NotNull PsiImportStatementBase statement); - - /** - * Replaces fully-qualified class names in the contents of the specified element with - * non-qualified names and adds import statements as necessary. - * - * @param element the element to shorten references in. - * @return the element in the PSI tree after the shorten references operation corresponding - * to the original element. - * @throws com.intellij.util.IncorrectOperationException if the file to shorten references in is read-only. - */ - public abstract PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException; - - /** - * Replaces fully-qualified class names in a part of contents of the specified element with - * non-qualified names and adds import statements as necessary. - * - * @param element the element to shorten references in. - * @param startOffset the start offset in the element of the part where class references are - * shortened. - * @param endOffset the end offset in the element of the part where class references are - * shortened. - * @throws IncorrectOperationException if the file to shorten references in is read-only. - */ - public abstract void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException; - - /** - * Optimizes imports in the specified Java or JSP file. - * - * @param file the file to optimize the imports in. - * @throws IncorrectOperationException if the file is read-only. - */ - public abstract void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException; - - /** - * Calculates the import list that would be substituted in the specified Java or JSP - * file if an Optimize Imports operation was performed on it. - * - * @param file the file to calculate the import list for. - * @return the calculated import list. - */ - public abstract PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file); - - /** - * Returns the kind of the specified variable (local, parameter, field, static field or static - * final field). - * - * @param variable the variable to get the kind for. - * @return the variable kind. - */ - public abstract VariableKind getVariableKind(@NotNull PsiVariable variable); - - public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, - @Nullable final String propertyName, - @Nullable final PsiExpression expr, - @Nullable PsiType type) { - return suggestVariableName(kind, propertyName, expr, type, true); - } - - - public abstract SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, - @Nullable String propertyName, - @Nullable PsiExpression expr, - @Nullable PsiType type, - boolean correctKeywords); - /** - * Generates a stripped-down name (with no code style defined prefixes or suffixes, usable as - * a property name) from the specified name of a variable of the specified kind. - * - * @param name the name of the variable. - * @param variableKind the kind of the variable. - * @return the stripped-down name. - */ - public abstract String variableNameToPropertyName(@NonNls String name, VariableKind variableKind); - - /** - * Appends code style defined prefixes and/or suffixes for the specified variable kind - * to the specified variable name. - * - * @param propertyName the base name of the variable. - * @param variableKind the kind of the variable. - * @return the variable name. - */ - public abstract String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind); - - /** - * Suggests a unique name for the variable used at the specified location. - * - * @param baseName the base name for the variable. - * @param place the location where the variable will be used. - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward - * @return the generated unique name, - */ - public abstract String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward); - - /** - * Suggests a unique name for the variable used at the specified location. - * - * @param baseNameInfo the base name info for the variable. - * @param place the location where the variable will be used. - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward - * @return the generated unique name - */ - @NotNull - public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean lookForward) { - return suggestUniqueVariableName(baseNameInfo, place, false, lookForward); - } - - /** - * Suggests a unique name for the variable used at the specified location. - * - * - * @param baseNameInfo the base name info for the variable. - * @param place the location where the variable will be used. - * @param ignorePlaceName if true and place is PsiNamedElement, place.getName() would be still treated as unique name - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward @return the generated unique name, - * @return the generated unique name - */ - @NotNull public abstract SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean ignorePlaceName, - boolean lookForward); - - /** - * Replaces all references to Java classes in the contents of the specified element, - * except for references to classes in the same package or in implicitly imported packages, - * with full-qualified references. - * - * @param element the element to replace the references in. - * @return the element in the PSI tree after the qualify operation corresponding to the - * original element. - */ - public abstract PsiElement qualifyClassReferences(@NotNull PsiElement element); - - /** - * Removes unused import statements from the specified Java file. - * - * @param file the file to remove the import statements from. - * @throws IncorrectOperationException if the operation fails for some reason (for example, - * the file is read-only). - */ - public abstract void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException; - - @Nullable - public abstract Collection findRedundantImports(PsiJavaFile file); -} +/* + * Copyright 2000-2011 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. + */ + +/* + * @author max + */ +package com.intellij.psi.codeStyle; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public abstract class JavaCodeStyleManager { + public static JavaCodeStyleManager getInstance(Project project) { + return ServiceManager.getService(project, JavaCodeStyleManager.class); + } + + public static final int DO_NOT_ADD_IMPORTS = 0x1000; + public static final int UNCOMPLETE_CODE = 0x2000; + + public abstract boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass); + public abstract PsiElement shortenClassReferences(@NotNull PsiElement element, @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) throws IncorrectOperationException; + + @NotNull public abstract String getPrefixByVariableKind(VariableKind variableKind); + @NotNull public abstract String getSuffixByVariableKind(VariableKind variableKind); + + public abstract int findEntryIndex(@NotNull PsiImportStatementBase statement); + + /** + * Replaces fully-qualified class names in the contents of the specified element with + * non-qualified names and adds import statements as necessary. + * + * @param element the element to shorten references in. + * @return the element in the PSI tree after the shorten references operation corresponding + * to the original element. + * @throws com.intellij.util.IncorrectOperationException if the file to shorten references in is read-only. + */ + public abstract PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException; + + /** + * Replaces fully-qualified class names in a part of contents of the specified element with + * non-qualified names and adds import statements as necessary. + * + * @param element the element to shorten references in. + * @param startOffset the start offset in the element of the part where class references are + * shortened. + * @param endOffset the end offset in the element of the part where class references are + * shortened. + * @throws IncorrectOperationException if the file to shorten references in is read-only. + */ + public abstract void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException; + + /** + * Optimizes imports in the specified Java or JSP file. + * + * @param file the file to optimize the imports in. + * @throws IncorrectOperationException if the file is read-only. + */ + public abstract void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException; + + /** + * Calculates the import list that would be substituted in the specified Java or JSP + * file if an Optimize Imports operation was performed on it. + * + * @param file the file to calculate the import list for. + * @return the calculated import list. + */ + public abstract PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file); + + /** + * Returns the kind of the specified variable (local, parameter, field, static field or static + * final field). + * + * @param variable the variable to get the kind for. + * @return the variable kind. + */ + public VariableKind getVariableKind(@NotNull PsiVariable variable){ + if (variable instanceof PsiField) { + if (variable.hasModifierProperty(PsiModifier.STATIC)) { + if (variable.hasModifierProperty(PsiModifier.FINAL)) { + return VariableKind.STATIC_FINAL_FIELD; + } + return VariableKind.STATIC_FIELD; + } + return VariableKind.FIELD; + } + else { + if (variable instanceof PsiParameter) { + if (((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { + return VariableKind.LOCAL_VARIABLE; + } + return VariableKind.PARAMETER; + } + return VariableKind.LOCAL_VARIABLE; + } + } + + public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, + @Nullable final String propertyName, + @Nullable final PsiExpression expr, + @Nullable PsiType type) { + return suggestVariableName(kind, propertyName, expr, type, true); + } + + + public abstract SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, + @Nullable String propertyName, + @Nullable PsiExpression expr, + @Nullable PsiType type, + boolean correctKeywords); + /** + * Generates a stripped-down name (with no code style defined prefixes or suffixes, usable as + * a property name) from the specified name of a variable of the specified kind. + * + * @param name the name of the variable. + * @param variableKind the kind of the variable. + * @return the stripped-down name. + */ + public abstract String variableNameToPropertyName(@NonNls String name, VariableKind variableKind); + + /** + * Appends code style defined prefixes and/or suffixes for the specified variable kind + * to the specified variable name. + * + * @param propertyName the base name of the variable. + * @param variableKind the kind of the variable. + * @return the variable name. + */ + public abstract String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind); + + /** + * Suggests a unique name for the variable used at the specified location. + * + * @param baseName the base name for the variable. + * @param place the location where the variable will be used. + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward + * @return the generated unique name, + */ + public abstract String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward); + + /** + * Suggests a unique name for the variable used at the specified location. + * + * @param baseNameInfo the base name info for the variable. + * @param place the location where the variable will be used. + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward + * @return the generated unique name + */ + @NotNull + public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean lookForward) { + return suggestUniqueVariableName(baseNameInfo, place, false, lookForward); + } + + /** + * Suggests a unique name for the variable used at the specified location. + * + * + * @param baseNameInfo the base name info for the variable. + * @param place the location where the variable will be used. + * @param ignorePlaceName if true and place is PsiNamedElement, place.getName() would be still treated as unique name + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward @return the generated unique name, + * @return the generated unique name + */ + @NotNull public abstract SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward); + + /** + * Replaces all references to Java classes in the contents of the specified element, + * except for references to classes in the same package or in implicitly imported packages, + * with full-qualified references. + * + * @param element the element to replace the references in. + * @return the element in the PSI tree after the qualify operation corresponding to the + * original element. + */ + public abstract PsiElement qualifyClassReferences(@NotNull PsiElement element); + + /** + * Removes unused import statements from the specified Java file. + * + * @param file the file to remove the import statements from. + * @throws IncorrectOperationException if the operation fails for some reason (for example, + * the file is read-only). + */ + public abstract void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException; + + @Nullable + public abstract Collection findRedundantImports(PsiJavaFile file); +} diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java index 7f651a21df0e..4e9f5e68a6f8 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -75,18 +75,13 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { return null; } - @Override - public VariableKind getVariableKind(@NotNull PsiVariable variable) { - return null; - } - @Override public SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, @Nullable String propertyName, @Nullable PsiExpression expr, @Nullable PsiType type, boolean correctKeywords) { - return null; + return SuggestedNameInfo.NULL_INFO; } @Override @@ -115,7 +110,7 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { @Override public PsiElement qualifyClassReferences(@NotNull PsiElement element) { - return null; + return element; } @Override From 74574bcb0f869958389878fae41bc9afbdd8944e Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Thu, 10 May 2012 10:07:19 +0200 Subject: [PATCH 29/67] Move EmptyProgressIndicator to core --- .../openapi/progress/EmptyProgressIndicator.java | 9 --------- .../intellij/util/graph/KShortestPathsFinderTest.java | 1 - .../com/intellij/util/continuation/GeneralRunner.java | 5 ----- .../org/jetbrains/idea/maven/MavenImportingTestCase.java | 1 - 4 files changed, 16 deletions(-) rename platform/{platform-api => core-api}/src/com/intellij/openapi/progress/EmptyProgressIndicator.java (94%) diff --git a/platform/platform-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java b/platform/core-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java similarity index 94% rename from platform/platform-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java rename to platform/core-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java index b367ea3c9aa7..1e745be27edb 100644 --- a/platform/platform-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java +++ b/platform/core-api/src/com/intellij/openapi/progress/EmptyProgressIndicator.java @@ -95,15 +95,6 @@ public class EmptyProgressIndicator implements ProgressIndicator { return false; } - - public void finish(final Task task) { - myFinished = true; - } - - public boolean isFinished(final Task task) { - return myFinished; - } - public void setIndeterminate(boolean indeterminate) { } diff --git a/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java b/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java index daf7f42780af..9763626760d3 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java @@ -18,7 +18,6 @@ package com.intellij.util.graph; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.util.text.StringUtil; import com.intellij.testFramework.UsefulTestCase; -import com.intellij.util.graph.impl.KShortestPathsFinder; import java.util.*; diff --git a/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java b/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java index 3a3e1e7bbe3b..6cd97ac1e322 100644 --- a/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java +++ b/platform/vcs-impl/src/com/intellij/util/continuation/GeneralRunner.java @@ -15,11 +15,7 @@ */ package com.intellij.util.continuation; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; -import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.CalledInAny; import com.intellij.openapi.vcs.CalledInAwt; @@ -28,7 +24,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; /** * @author irengrig diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java index 13b1770f6776..793cb5c86874 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java @@ -34,7 +34,6 @@ import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TestDialog; import com.intellij.openapi.util.AsyncResult; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtil; From 4081b7eda276b1f4e6e0954ef1e3c7454c0d1d39 Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Thu, 10 May 2012 10:09:18 +0200 Subject: [PATCH 30/67] Instantiate ProgressIndicatorProvider.ourInstance in CoreEnvironment --- .../com/intellij/core/CoreEnvironment.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java index 60949a95f064..3d683f9bd677 100644 --- a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java +++ b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java @@ -29,6 +29,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.ExtensionsArea; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.progress.*; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; @@ -148,6 +149,26 @@ public class CoreEnvironment { myProject.registerService(PsiDirectoryFactory.class, new PsiDirectoryFactoryImpl(myPsiManager)); myProject.registerService(ProjectScopeBuilder.class, new CoreProjectScopeBuilder(myProject, myFileIndexFacade)); myProject.registerService(DumbService.class, new MockDumbService(myProject)); + + ProgressIndicatorProvider.ourInstance = new ProgressIndicatorProvider() { + @Override + public ProgressIndicator getProgressIndicator() { + return new EmptyProgressIndicator(); + } + + @Override + protected void doCheckCanceled() throws ProcessCanceledException { + } + + @Override + public NonCancelableSection startNonCancelableSection() { + return new NonCancelableSection() { + @Override + public void done() { + } + }; + } + }; } public Project getProject() { From ffa6944b7a8358b3de1186e4e569c3037c23771c Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Fri, 11 May 2012 14:00:35 +0200 Subject: [PATCH 31/67] Move PsiExpressionEvaluator and register it in JavaCoreEnvironment --- .../src/com/intellij/core/JavaCoreEnvironment.java | 6 ++---- .../src/com/intellij/psi/impl/PsiExpressionEvaluator.java | 0 2 files changed, 2 insertions(+), 4 deletions(-) rename java/{java-impl => java-psi-impl}/src/com/intellij/psi/impl/PsiExpressionEvaluator.java (100%) diff --git a/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java b/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java index 16cdc8d46e90..42e9c4cb9ca2 100644 --- a/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java +++ b/java/java-psi-impl/src/com/intellij/core/JavaCoreEnvironment.java @@ -32,10 +32,7 @@ import com.intellij.psi.*; import com.intellij.psi.augment.PsiAugmentProvider; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade; -import com.intellij.psi.impl.EmptySubstitutorImpl; -import com.intellij.psi.impl.JavaPsiFacadeImpl; -import com.intellij.psi.impl.JavaPsiImplementationHelper; -import com.intellij.psi.impl.PsiElementFactoryImpl; +import com.intellij.psi.impl.*; import com.intellij.psi.impl.compiled.ClassFileStubBuilder; import com.intellij.psi.impl.compiled.ClsStubBuilderFactory; import com.intellij.psi.impl.compiled.DefaultClsStubBuilderFactory; @@ -63,6 +60,7 @@ public class JavaCoreEnvironment extends CoreEnvironment { registerFileType(JavaFileType.INSTANCE, "java"); addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new CoreJavaASTFactory()); addExplicitExtension(LanguageParserDefinitions.INSTANCE, JavaLanguage.INSTANCE, new JavaParserDefinition()); + addExplicitExtension(LanguageConstantExpressionEvaluator.INSTANCE, JavaLanguage.INSTANCE, new PsiExpressionEvaluator()); registerProjectExtensionPoint(PsiElementFinder.EP_NAME, PsiElementFinder.class); registerExtensionPoint(Extensions.getRootArea(), ClsStubBuilderFactory.EP_NAME, ClsStubBuilderFactory.class); diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiExpressionEvaluator.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiExpressionEvaluator.java similarity index 100% rename from java/java-impl/src/com/intellij/psi/impl/PsiExpressionEvaluator.java rename to java/java-psi-impl/src/com/intellij/psi/impl/PsiExpressionEvaluator.java From 0a7f10796fdcfedd45fd19977fa48654ce468c2d Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Fri, 11 May 2012 18:05:10 +0200 Subject: [PATCH 32/67] Splitting IdTableBuilding --- .../impl/search/JspIndexPatternBuilder.java | 4 +- .../cacheBuilder/CacheBuilderRegistry.java | 0 .../cacheBuilder/DefaultWordsScanner.java | 0 .../lang/cacheBuilder/SimpleWordsScanner.java | 2 +- .../lang/cacheBuilder/WordOccurrence.java | 2 +- .../lang/cacheBuilder/WordsScanner.java | 2 +- .../findUsages/EmptyFindUsagesProvider.java | 2 +- .../lang/findUsages/FindUsagesProvider.java | 2 +- .../lang/findUsages/LanguageFindUsages.java | 2 +- .../psi/CustomHighlighterTokenType.java | 0 .../com/intellij/psi/search/IndexPattern.java | 0 .../psi/search/IndexPatternProvider.java | 0 .../psi/search/UsageSearchContext.java | 2 +- platform/indexing-impl/indexing-impl.iml | 1 + .../custom/AbstractCustomLexer.java | 0 .../custom/CustomFileTypeLexer.java | 0 .../ide/highlighter/custom/SyntaxTable.java | 0 .../custom/tokens/BraceTokenParser.java | 0 .../custom/tokens/HexNumberParser.java | 0 .../custom/tokens/IdentifierParser.java | 0 .../custom/tokens/KeywordParser.java | 0 .../custom/tokens/LineCommentParser.java | 0 .../custom/tokens/MultilineCommentParser.java | 0 .../custom/tokens/NumberParser.java | 0 .../custom/tokens/PrefixedTokenParser.java | 0 .../custom/tokens/PunctuationParser.java | 0 .../custom/tokens/QuotedStringParser.java | 0 .../highlighter/custom/tokens/TokenInfo.java | 0 .../custom/tokens/TokenParser.java | 0 .../custom/tokens/WhitespaceParser.java | 0 .../psi/impl/cache/impl/IndexPatternUtil.java | 0 .../impl/cache/impl/OccurrenceConsumer.java | 0 .../impl/cache/impl/id/FileTypeIdIndexer.java | 2 +- .../psi/impl/cache/impl/id/IdIndexEntry.java | 2 +- .../psi/impl/cache/impl/id/IdIndexers.java | 2 +- .../impl/cache/impl/todo/TodoIndexEntry.java | 0 .../impl/cache/impl/todo/TodoIndexers.java | 0 .../util/indexing/IdDataConsumer.java | 3 +- .../intellij/psi/search/PsiSearchHelper.java | 2 +- platform/lang-impl/lang-impl.iml | 2 +- .../DefaultFindUsagesHandlerFactory.java | 1 - .../PlainTextSyntaxHighlighterFactory.java | 2 - .../impl/cache/impl/BaseFilterLexerUtil.java | 2 - .../impl/cache/impl/id/IdTableBuilding.java | 170 +------------- .../impl/id/PlatformIdTableBuilding.java | 211 ++++++++++++++++++ .../psi/impl/cache/impl/todo/TodoIndex.java | 4 +- .../psi/impl/search/PsiSearchHelperImpl.java | 2 +- platform/platform-impl/platform-impl.iml | 2 + .../highlighter/custom/impl/ReadFileType.java | 1 - 49 files changed, 237 insertions(+), 190 deletions(-) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/cacheBuilder/CacheBuilderRegistry.java (100%) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java (100%) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java (98%) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/cacheBuilder/WordOccurrence.java (98%) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/cacheBuilder/WordsScanner.java (97%) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/findUsages/EmptyFindUsagesProvider.java (97%) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/findUsages/FindUsagesProvider.java (98%) rename platform/{lang-api => indexing-api}/src/com/intellij/lang/findUsages/LanguageFindUsages.java (95%) rename platform/{lang-api => indexing-api}/src/com/intellij/psi/CustomHighlighterTokenType.java (100%) rename platform/{lang-api => indexing-api}/src/com/intellij/psi/search/IndexPattern.java (100%) rename platform/{lang-api => indexing-api}/src/com/intellij/psi/search/IndexPatternProvider.java (100%) rename platform/{lang-api => indexing-api}/src/com/intellij/psi/search/UsageSearchContext.java (96%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java (100%) rename platform/{platform-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/SyntaxTable.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/BraceTokenParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/HexNumberParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/MultilineCommentParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/QuotedStringParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/TokenInfo.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/IndexPatternUtil.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/OccurrenceConsumer.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java (95%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/id/IdIndexEntry.java (97%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/id/IdIndexers.java (95%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexEntry.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java (100%) rename platform/{lang-impl => indexing-impl}/src/com/intellij/util/indexing/IdDataConsumer.java (97%) create mode 100644 platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java diff --git a/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java b/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java index c5124896d19b..6011081b0051 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java @@ -26,7 +26,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.JspPsiUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.cache.impl.id.IdTableBuilding; +import com.intellij.psi.impl.cache.impl.id.PlatformIdTableBuilding; import com.intellij.psi.impl.source.tree.StdTokenSets; import com.intellij.psi.jsp.JspFile; import com.intellij.psi.jsp.JspTokenType; @@ -47,7 +47,7 @@ public class JspIndexPatternBuilder implements IndexPatternBuilder { boolean alreadyInitializedHighlighter = false; if ((cachedEditorHighlighter = EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document)) != null && - IdTableBuilding.checkCanUseCachedEditorHighlighter(file.getText(), cachedEditorHighlighter)) { + PlatformIdTableBuilding.checkCanUseCachedEditorHighlighter(file.getText(), cachedEditorHighlighter)) { highlighter = cachedEditorHighlighter; alreadyInitializedHighlighter = true; } diff --git a/platform/lang-api/src/com/intellij/lang/cacheBuilder/CacheBuilderRegistry.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/CacheBuilderRegistry.java similarity index 100% rename from platform/lang-api/src/com/intellij/lang/cacheBuilder/CacheBuilderRegistry.java rename to platform/indexing-api/src/com/intellij/lang/cacheBuilder/CacheBuilderRegistry.java diff --git a/platform/lang-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java similarity index 100% rename from platform/lang-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java rename to platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java diff --git a/platform/lang-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java similarity index 98% rename from platform/lang-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java rename to platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java index 0254640eb460..6273654982a9 100644 --- a/platform/lang-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java +++ b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-api/src/com/intellij/lang/cacheBuilder/WordOccurrence.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/WordOccurrence.java similarity index 98% rename from platform/lang-api/src/com/intellij/lang/cacheBuilder/WordOccurrence.java rename to platform/indexing-api/src/com/intellij/lang/cacheBuilder/WordOccurrence.java index 596dce8076d1..9a9018cb9078 100644 --- a/platform/lang-api/src/com/intellij/lang/cacheBuilder/WordOccurrence.java +++ b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/WordOccurrence.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-api/src/com/intellij/lang/cacheBuilder/WordsScanner.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/WordsScanner.java similarity index 97% rename from platform/lang-api/src/com/intellij/lang/cacheBuilder/WordsScanner.java rename to platform/indexing-api/src/com/intellij/lang/cacheBuilder/WordsScanner.java index 4ffba0bc283a..0bfd41d0e483 100644 --- a/platform/lang-api/src/com/intellij/lang/cacheBuilder/WordsScanner.java +++ b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/WordsScanner.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-api/src/com/intellij/lang/findUsages/EmptyFindUsagesProvider.java b/platform/indexing-api/src/com/intellij/lang/findUsages/EmptyFindUsagesProvider.java similarity index 97% rename from platform/lang-api/src/com/intellij/lang/findUsages/EmptyFindUsagesProvider.java rename to platform/indexing-api/src/com/intellij/lang/findUsages/EmptyFindUsagesProvider.java index 617cd8c775a6..c3400711ac1b 100644 --- a/platform/lang-api/src/com/intellij/lang/findUsages/EmptyFindUsagesProvider.java +++ b/platform/indexing-api/src/com/intellij/lang/findUsages/EmptyFindUsagesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java b/platform/indexing-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java similarity index 98% rename from platform/lang-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java rename to platform/indexing-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java index 9b7ccbc7b733..a56b0e126acc 100644 --- a/platform/lang-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java +++ b/platform/indexing-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-api/src/com/intellij/lang/findUsages/LanguageFindUsages.java b/platform/indexing-api/src/com/intellij/lang/findUsages/LanguageFindUsages.java similarity index 95% rename from platform/lang-api/src/com/intellij/lang/findUsages/LanguageFindUsages.java rename to platform/indexing-api/src/com/intellij/lang/findUsages/LanguageFindUsages.java index 0a2820262e5f..9a830f393286 100644 --- a/platform/lang-api/src/com/intellij/lang/findUsages/LanguageFindUsages.java +++ b/platform/indexing-api/src/com/intellij/lang/findUsages/LanguageFindUsages.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-api/src/com/intellij/psi/CustomHighlighterTokenType.java b/platform/indexing-api/src/com/intellij/psi/CustomHighlighterTokenType.java similarity index 100% rename from platform/lang-api/src/com/intellij/psi/CustomHighlighterTokenType.java rename to platform/indexing-api/src/com/intellij/psi/CustomHighlighterTokenType.java diff --git a/platform/lang-api/src/com/intellij/psi/search/IndexPattern.java b/platform/indexing-api/src/com/intellij/psi/search/IndexPattern.java similarity index 100% rename from platform/lang-api/src/com/intellij/psi/search/IndexPattern.java rename to platform/indexing-api/src/com/intellij/psi/search/IndexPattern.java diff --git a/platform/lang-api/src/com/intellij/psi/search/IndexPatternProvider.java b/platform/indexing-api/src/com/intellij/psi/search/IndexPatternProvider.java similarity index 100% rename from platform/lang-api/src/com/intellij/psi/search/IndexPatternProvider.java rename to platform/indexing-api/src/com/intellij/psi/search/IndexPatternProvider.java diff --git a/platform/lang-api/src/com/intellij/psi/search/UsageSearchContext.java b/platform/indexing-api/src/com/intellij/psi/search/UsageSearchContext.java similarity index 96% rename from platform/lang-api/src/com/intellij/psi/search/UsageSearchContext.java rename to platform/indexing-api/src/com/intellij/psi/search/UsageSearchContext.java index ec8e3e86419f..34935e4fbf26 100644 --- a/platform/lang-api/src/com/intellij/psi/search/UsageSearchContext.java +++ b/platform/indexing-api/src/com/intellij/psi/search/UsageSearchContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/indexing-impl/indexing-impl.iml b/platform/indexing-impl/indexing-impl.iml index 373eaa417d53..8446a9dbc69c 100644 --- a/platform/indexing-impl/indexing-impl.iml +++ b/platform/indexing-impl/indexing-impl.iml @@ -8,6 +8,7 @@ + diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java diff --git a/platform/platform-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java similarity index 100% rename from platform/platform-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/BraceTokenParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/BraceTokenParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/BraceTokenParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/BraceTokenParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/HexNumberParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/HexNumberParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/HexNumberParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/HexNumberParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/MultilineCommentParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/MultilineCommentParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/MultilineCommentParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/MultilineCommentParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/QuotedStringParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/QuotedStringParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/QuotedStringParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/QuotedStringParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenInfo.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenInfo.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenInfo.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenInfo.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java b/platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java similarity index 100% rename from platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java rename to platform/indexing-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexPatternUtil.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/IndexPatternUtil.java similarity index 100% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexPatternUtil.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/IndexPatternUtil.java diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/OccurrenceConsumer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/OccurrenceConsumer.java similarity index 100% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/OccurrenceConsumer.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/OccurrenceConsumer.java diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java similarity index 95% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java index 3b62ced1aa00..f770ac1d5d97 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexEntry.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexEntry.java similarity index 97% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexEntry.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexEntry.java index 9a940cf41241..2dc2842021db 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexEntry.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexers.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexers.java similarity index 95% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexers.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexers.java index 77fa23144eda..db1fcf6d91b1 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexers.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexers.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexEntry.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexEntry.java similarity index 100% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexEntry.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexEntry.java diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java similarity index 100% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IdDataConsumer.java b/platform/indexing-impl/src/com/intellij/util/indexing/IdDataConsumer.java similarity index 97% rename from platform/lang-impl/src/com/intellij/util/indexing/IdDataConsumer.java rename to platform/indexing-impl/src/com/intellij/util/indexing/IdDataConsumer.java index 18088f3b5f61..841be6f90278 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IdDataConsumer.java +++ b/platform/indexing-impl/src/com/intellij/util/indexing/IdDataConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -22,7 +22,6 @@ import gnu.trove.THashMap; import gnu.trove.TIntIntHashMap; import gnu.trove.TIntIntProcedure; -import java.util.HashMap; import java.util.Map; /** diff --git a/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java b/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java index ed5c1f093bec..15ff4815a4b8 100644 --- a/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java +++ b/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/lang-impl/lang-impl.iml b/platform/lang-impl/lang-impl.iml index cf57ba46c814..7c6fff5ea654 100644 --- a/platform/lang-impl/lang-impl.iml +++ b/platform/lang-impl/lang-impl.iml @@ -22,7 +22,7 @@ - + diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/DefaultFindUsagesHandlerFactory.java b/platform/lang-impl/src/com/intellij/find/findUsages/DefaultFindUsagesHandlerFactory.java index 4bbbef3f1274..5c921cc9471d 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/DefaultFindUsagesHandlerFactory.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/DefaultFindUsagesHandlerFactory.java @@ -16,7 +16,6 @@ package com.intellij.find.findUsages; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.psi.PsiFileSystemItem; import org.jetbrains.annotations.NotNull; diff --git a/platform/lang-impl/src/com/intellij/openapi/fileTypes/PlainTextSyntaxHighlighterFactory.java b/platform/lang-impl/src/com/intellij/openapi/fileTypes/PlainTextSyntaxHighlighterFactory.java index 6251aa3a93eb..927e4c729737 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileTypes/PlainTextSyntaxHighlighterFactory.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileTypes/PlainTextSyntaxHighlighterFactory.java @@ -20,13 +20,11 @@ package com.intellij.openapi.fileTypes; import com.intellij.ide.highlighter.custom.AbstractCustomLexer; -import com.intellij.ide.highlighter.custom.CustomHighlighterColors; import com.intellij.ide.highlighter.custom.tokens.*; import com.intellij.lexer.Lexer; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.CustomHighlighterTokenType; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/BaseFilterLexerUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/BaseFilterLexerUtil.java index 1e7c3d7c7743..7ac97fa442fa 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/BaseFilterLexerUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/BaseFilterLexerUtil.java @@ -21,7 +21,6 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.psi.impl.cache.impl.id.IdIndexEntry; import com.intellij.psi.impl.cache.impl.id.IdTableBuilding; import com.intellij.psi.impl.cache.impl.id.LexerBasedIdIndexer; -import com.intellij.psi.impl.cache.impl.todo.LexerBasedTodoIndexer; import com.intellij.psi.impl.cache.impl.todo.TodoIndexEntry; import com.intellij.psi.search.IndexPattern; import com.intellij.util.indexing.FileContent; @@ -29,7 +28,6 @@ import com.intellij.util.indexing.IdDataConsumer; import gnu.trove.THashMap; import java.util.Collections; -import java.util.HashMap; import java.util.Map; public class BaseFilterLexerUtil { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java index bb8dc7f3104f..7d61c806e49d 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java @@ -16,39 +16,26 @@ package com.intellij.psi.impl.cache.impl.id; -import com.intellij.ide.highlighter.HighlighterFactory; import com.intellij.ide.highlighter.custom.CustomFileTypeLexer; -import com.intellij.idea.LoggerFactory; import com.intellij.lang.Language; -import com.intellij.lang.LanguageParserDefinitions; -import com.intellij.lang.ParserDefinition; import com.intellij.lang.cacheBuilder.*; import com.intellij.lang.findUsages.FindUsagesProvider; import com.intellij.lang.findUsages.LanguageFindUsages; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.LanguageFileType; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.fileTypes.impl.AbstractFileType; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.CustomHighlighterTokenType; -import com.intellij.psi.impl.cache.impl.BaseFilterLexer; -import com.intellij.psi.impl.cache.impl.CacheUtil; import com.intellij.psi.impl.cache.impl.IndexPatternUtil; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; import com.intellij.psi.impl.cache.impl.todo.TodoIndexEntry; import com.intellij.psi.impl.cache.impl.todo.TodoIndexers; import com.intellij.psi.search.IndexPattern; import com.intellij.psi.search.UsageSearchContext; -import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.util.Processor; -import com.intellij.util.containers.CollectionFactory; -import com.intellij.util.indexing.*; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.FileContent; +import com.intellij.util.indexing.IdDataConsumer; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -123,8 +110,6 @@ public class IdTableBuilding { } private static final HashMap ourIdIndexers = new HashMap(); - private static final HashMap> ourTodoIndexers = - new HashMap>(); @Deprecated public static void registerIdIndexer(FileType fileType, FileTypeIdIndexer indexer) { @@ -133,7 +118,7 @@ public class IdTableBuilding { @Deprecated public static void registerTodoIndexer(FileType fileType, DataIndexer indexer) { - ourTodoIndexers.put(fileType, indexer); + PlatformIdTableBuilding.ourTodoIndexers.put(fileType, indexer); } public static boolean isIdIndexerRegistered(FileType fileType) { @@ -144,18 +129,7 @@ public class IdTableBuilding { return ourIdIndexers.containsKey(fileType) || TodoIndexers.INSTANCE.forFileType(fileType) != null; } - static { - registerIdIndexer(FileTypes.PLAIN_TEXT, new PlainTextIndexer()); - registerTodoIndexer(FileTypes.PLAIN_TEXT, new PlainTextTodoIndexer()); - registerIdIndexer(StdFileTypes.IDEA_MODULE, null); - registerIdIndexer(StdFileTypes.IDEA_WORKSPACE, null); - registerIdIndexer(StdFileTypes.IDEA_PROJECT, null); - - registerTodoIndexer(StdFileTypes.IDEA_MODULE, null); - registerTodoIndexer(StdFileTypes.IDEA_WORKSPACE, null); - registerTodoIndexer(StdFileTypes.IDEA_PROJECT, null); - } @Nullable public static FileTypeIdIndexer getFileTypeIndexer(FileType fileType) { @@ -201,46 +175,6 @@ public class IdTableBuilding { } - private static final TokenSet ABSTRACT_FILE_COMMENT_TOKENS = - TokenSet.create(CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.MULTI_LINE_COMMENT); - - @Nullable - public static DataIndexer getTodoIndexer(FileType fileType, final VirtualFile virtualFile) { - final DataIndexer indexer = ourTodoIndexers.get(fileType); - - if (indexer != null) { - return indexer; - } - - final DataIndexer extIndexer; - if (fileType instanceof SubstitutedFileType) { - SubstitutedFileType sft = (SubstitutedFileType)fileType; - extIndexer = - new CompositeTodoIndexer(getTodoIndexer(sft.getOriginalFileType(), virtualFile), getTodoIndexer(sft.getFileType(), virtualFile)); - } - else { - extIndexer = TodoIndexers.INSTANCE.forFileType(fileType); - } - if (extIndexer != null) { - return extIndexer; - } - - if (fileType instanceof LanguageFileType) { - final Language lang = ((LanguageFileType)fileType).getLanguage(); - final ParserDefinition parserDef = LanguageParserDefinitions.INSTANCE.forLanguage(lang); - final TokenSet commentTokens = parserDef != null ? parserDef.getCommentTokens() : null; - if (commentTokens != null) { - return new TokenSetTodoIndexer(commentTokens, virtualFile); - } - } - - if (fileType instanceof AbstractFileType) { - return new TokenSetTodoIndexer(ABSTRACT_FILE_COMMENT_TOKENS, virtualFile); - } - - return null; - } - private static class WordsScannerFileTypeIdIndexerAdapter extends FileTypeIdIndexer { private final WordsScanner myScanner; @@ -279,102 +213,6 @@ public class IdTableBuilding { } } - private static class CompositeTodoIndexer implements DataIndexer { - - private final DataIndexer[] indexers; - - public CompositeTodoIndexer(DataIndexer... indexers) { - this.indexers = indexers; - } - - @NotNull - @Override - public Map map(FileContent inputData) { - Map result = CollectionFactory.newTroveMap(); - for (DataIndexer indexer : indexers) { - for (Map.Entry entry : indexer.map(inputData).entrySet()) { - TodoIndexEntry key = entry.getKey(); - if (result.containsKey(key)) { - result.put(key, result.get(key) + entry.getValue()); - } else { - result.put(key, entry.getValue()); - } - } - } - return result; - } - } - - private static class TokenSetTodoIndexer implements DataIndexer { - @NotNull private final TokenSet myCommentTokens; - private final VirtualFile myFile; - - public TokenSetTodoIndexer(@NotNull final TokenSet commentTokens, @NotNull final VirtualFile file) { - myCommentTokens = commentTokens; - myFile = file; - } - - @Override - @NotNull - public Map map(final FileContent inputData) { - if (IndexPatternUtil.getIndexPatternCount() > 0) { - final CharSequence chars = inputData.getContentAsText(); - final OccurrenceConsumer occurrenceConsumer = new OccurrenceConsumer(null, true); - EditorHighlighter highlighter; - - final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndexImpl.EDITOR_HIGHLIGHTER); - if (editorHighlighter != null && checkCanUseCachedEditorHighlighter(chars, editorHighlighter)) { - highlighter = editorHighlighter; - } - else { - highlighter = HighlighterFactory.createHighlighter(null, myFile); - highlighter.setText(chars); - } - - final int documentLength = chars.length(); - BaseFilterLexer.TodoScanningData[] todoScanningDatas = null; - final HighlighterIterator iterator = highlighter.createIterator(0); - - while (!iterator.atEnd()) { - final IElementType token = iterator.getTokenType(); - - if (myCommentTokens.contains(token) || CacheUtil.isInComments(token)) { - int start = iterator.getStart(); - if (start >= documentLength) break; - int end = iterator.getEnd(); - - todoScanningDatas = BaseFilterLexer.advanceTodoItemsCount( - chars.subSequence(start, Math.min(end, documentLength)), - occurrenceConsumer, - todoScanningDatas - ); - if (end > documentLength) break; - } - iterator.advance(); - } - final Map map = new HashMap(); - for (IndexPattern pattern : IndexPatternUtil.getIndexPatterns()) { - final int count = occurrenceConsumer.getOccurrenceCount(pattern); - if (count > 0) { - map.put(new TodoIndexEntry(pattern.getPatternString(), pattern.isCaseSensitive()), count); - } - } - return map; - } - return Collections.emptyMap(); - } - } - - public static boolean checkCanUseCachedEditorHighlighter(final CharSequence chars, final EditorHighlighter editorHighlighter) { - assert editorHighlighter instanceof LexerEditorHighlighter; - final boolean b = ((LexerEditorHighlighter)editorHighlighter).checkContentIsEqualTo(chars); - if (!b) { - final Logger logger = LoggerFactory.getInstance().getLoggerInstance(IdTableBuilding.class.getName()); - logger.warn("Unexpected mismatch of editor highlighter content with indexing content"); - } - return b; - } - public static void scanWords(final ScanWordProcessor processor, final CharSequence chars, final int startOffset, final int endOffset) { scanWords(processor, chars, CharArrayUtil.fromSequenceWithoutCopying(chars), startOffset, endOffset, false); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java new file mode 100644 index 000000000000..80c6f558cd85 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java @@ -0,0 +1,211 @@ +/* + * Copyright 2000-2012 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.psi.impl.cache.impl.id; + +import com.intellij.ide.highlighter.HighlighterFactory; +import com.intellij.lang.Language; +import com.intellij.lang.LanguageParserDefinitions; +import com.intellij.lang.ParserDefinition; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.highlighter.HighlighterIterator; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.CustomHighlighterTokenType; +import com.intellij.psi.impl.cache.impl.BaseFilterLexer; +import com.intellij.psi.impl.cache.impl.CacheUtil; +import com.intellij.psi.impl.cache.impl.IndexPatternUtil; +import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; +import com.intellij.psi.impl.cache.impl.todo.TodoIndexEntry; +import com.intellij.psi.impl.cache.impl.todo.TodoIndexers; +import com.intellij.psi.search.IndexPattern; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import com.intellij.util.containers.CollectionFactory; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.FileBasedIndexImpl; +import com.intellij.util.indexing.FileContent; +import com.intellij.util.indexing.SubstitutedFileType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Author: dmitrylomov + */ +public abstract class PlatformIdTableBuilding { + static final HashMap> ourTodoIndexers = + new HashMap>(); + private static final TokenSet ABSTRACT_FILE_COMMENT_TOKENS = + TokenSet.create(CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.MULTI_LINE_COMMENT); + + private PlatformIdTableBuilding() {} + + @Nullable + public static DataIndexer getTodoIndexer(FileType fileType, final VirtualFile virtualFile) { + final DataIndexer indexer = ourTodoIndexers.get(fileType); + + if (indexer != null) { + return indexer; + } + + final DataIndexer extIndexer; + if (fileType instanceof SubstitutedFileType) { + SubstitutedFileType sft = (SubstitutedFileType)fileType; + extIndexer = + new CompositeTodoIndexer(getTodoIndexer(sft.getOriginalFileType(), virtualFile), getTodoIndexer(sft.getFileType(), virtualFile)); + } + else { + extIndexer = TodoIndexers.INSTANCE.forFileType(fileType); + } + if (extIndexer != null) { + return extIndexer; + } + + if (fileType instanceof LanguageFileType) { + final Language lang = ((LanguageFileType)fileType).getLanguage(); + final ParserDefinition parserDef = LanguageParserDefinitions.INSTANCE.forLanguage(lang); + final TokenSet commentTokens = parserDef != null ? parserDef.getCommentTokens() : null; + if (commentTokens != null) { + return new TokenSetTodoIndexer(commentTokens, virtualFile); + } + } + + if (fileType instanceof AbstractFileType) { + return new TokenSetTodoIndexer(ABSTRACT_FILE_COMMENT_TOKENS, virtualFile); + } + + return null; + } + + public static boolean checkCanUseCachedEditorHighlighter(final CharSequence chars, final EditorHighlighter editorHighlighter) { + assert editorHighlighter instanceof LexerEditorHighlighter; + final boolean b = ((LexerEditorHighlighter)editorHighlighter).checkContentIsEqualTo(chars); + if (!b) { + final Logger logger = Logger.getInstance(IdTableBuilding.class.getName()); + logger.warn("Unexpected mismatch of editor highlighter content with indexing content"); + } + return b; + } + + + private static class CompositeTodoIndexer implements DataIndexer { + + private final DataIndexer[] indexers; + + public CompositeTodoIndexer(DataIndexer... indexers) { + this.indexers = indexers; + } + + @NotNull + @Override + public Map map(FileContent inputData) { + Map result = CollectionFactory.newTroveMap(); + for (DataIndexer indexer : indexers) { + for (Map.Entry entry : indexer.map(inputData).entrySet()) { + TodoIndexEntry key = entry.getKey(); + if (result.containsKey(key)) { + result.put(key, result.get(key) + entry.getValue()); + } else { + result.put(key, entry.getValue()); + } + } + } + return result; + } + } + + private static class TokenSetTodoIndexer implements DataIndexer { + @NotNull private final TokenSet myCommentTokens; + private final VirtualFile myFile; + + public TokenSetTodoIndexer(@NotNull final TokenSet commentTokens, @NotNull final VirtualFile file) { + myCommentTokens = commentTokens; + myFile = file; + } + + @Override + @NotNull + public Map map(final FileContent inputData) { + if (IndexPatternUtil.getIndexPatternCount() > 0) { + final CharSequence chars = inputData.getContentAsText(); + final OccurrenceConsumer occurrenceConsumer = new OccurrenceConsumer(null, true); + EditorHighlighter highlighter; + + final EditorHighlighter editorHighlighter = inputData.getUserData(FileBasedIndexImpl.EDITOR_HIGHLIGHTER); + if (editorHighlighter != null && checkCanUseCachedEditorHighlighter(chars, editorHighlighter)) { + highlighter = editorHighlighter; + } + else { + highlighter = HighlighterFactory.createHighlighter(null, myFile); + highlighter.setText(chars); + } + + final int documentLength = chars.length(); + BaseFilterLexer.TodoScanningData[] todoScanningDatas = null; + final HighlighterIterator iterator = highlighter.createIterator(0); + + while (!iterator.atEnd()) { + final IElementType token = iterator.getTokenType(); + + if (myCommentTokens.contains(token) || CacheUtil.isInComments(token)) { + int start = iterator.getStart(); + if (start >= documentLength) break; + int end = iterator.getEnd(); + + todoScanningDatas = BaseFilterLexer.advanceTodoItemsCount( + chars.subSequence(start, Math.min(end, documentLength)), + occurrenceConsumer, + todoScanningDatas + ); + if (end > documentLength) break; + } + iterator.advance(); + } + final Map map = new HashMap(); + for (IndexPattern pattern : IndexPatternUtil.getIndexPatterns()) { + final int count = occurrenceConsumer.getOccurrenceCount(pattern); + if (count > 0) { + map.put(new TodoIndexEntry(pattern.getPatternString(), pattern.isCaseSensitive()), count); + } + } + return map; + } + return Collections.emptyMap(); + } + } + + static { + IdTableBuilding.registerIdIndexer(FileTypes.PLAIN_TEXT, new IdTableBuilding.PlainTextIndexer()); + IdTableBuilding.registerTodoIndexer(FileTypes.PLAIN_TEXT, new IdTableBuilding.PlainTextTodoIndexer()); + + IdTableBuilding.registerIdIndexer(StdFileTypes.IDEA_MODULE, null); + IdTableBuilding.registerIdIndexer(StdFileTypes.IDEA_WORKSPACE, null); + IdTableBuilding.registerIdIndexer(StdFileTypes.IDEA_PROJECT, null); + + IdTableBuilding.registerTodoIndexer(StdFileTypes.IDEA_MODULE, null); + IdTableBuilding.registerTodoIndexer(StdFileTypes.IDEA_WORKSPACE, null); + IdTableBuilding.registerTodoIndexer(StdFileTypes.IDEA_PROJECT, null); + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index e4c91b7904da..19809f52fa41 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -26,6 +26,7 @@ import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.impl.cache.impl.id.IdTableBuilding; +import com.intellij.psi.impl.cache.impl.id.PlatformIdTableBuilding; import com.intellij.psi.search.IndexPatternProvider; import com.intellij.psi.tree.TokenSet; import com.intellij.util.indexing.*; @@ -101,7 +102,8 @@ public class TodoIndex extends FileBasedIndexExtension @NotNull public Map map(final FileContent inputData) { final VirtualFile file = inputData.getFile(); - final DataIndexer indexer = IdTableBuilding.getTodoIndexer(inputData.getFileType(), file); + final DataIndexer indexer = PlatformIdTableBuilding + .getTodoIndexer(inputData.getFileType(), file); if (indexer != null) { return indexer.map(inputData); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index 1c115224b026..c8245d5fe416 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/platform-impl/platform-impl.iml b/platform/platform-impl/platform-impl.iml index 11055551a29d..1732f622dc68 100644 --- a/platform/platform-impl/platform-impl.iml +++ b/platform/platform-impl/platform-impl.iml @@ -29,6 +29,8 @@ + + diff --git a/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/ReadFileType.java b/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/ReadFileType.java index bc63896eda7f..32491f6346da 100644 --- a/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/ReadFileType.java +++ b/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/ReadFileType.java @@ -17,7 +17,6 @@ package com.intellij.ide.highlighter.custom.impl; import com.intellij.ide.highlighter.custom.SyntaxTable; import com.intellij.openapi.fileTypes.impl.AbstractFileType; -import com.intellij.openapi.options.SettingsEditor; import org.jdom.Element; public class ReadFileType extends AbstractFileType { From 6169cf7a3eaaef7222f6ac51b4a7fc0261dceb00 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 14 May 2012 10:43:53 +0400 Subject: [PATCH 33/67] IDEA-19061 Integrate the Rearranger-plugin into core-IDEA Initial bundling iteration. The changes to the initial version available at http://java.net/projects/rearranger/sources: * switched from log4j to IJ logging; * 'Rearranger' component is service now; * plugin descriptor is adapted to the common IJ scheme (id, vendor etc); * IJ project is configured to have new 'rearranger' module; * build script is adjusted to process 'rearranger' plugin as well; * almost all tests are commented and their refactoring is started; --- .idea/modules.xml | 1 + build/scripts/layouts.gant | 6 + community-main.iml | 1 + plugins/rearranger/rearranger.iml | 21 + plugins/rearranger/src/META-INF/plugin.xml | 46 + .../com/wrq/rearranger/ClassInitializer.png | Bin 0 -> 775 bytes .../wrq/rearranger/LiveRearrangerAction.java | 36 + .../LiveRearrangerActionHandler.java | 206 ++ .../com/wrq/rearranger/ModifierConstants.java | 59 + .../rearranger/ProjectTreeActionHandler.java | 347 +++ .../src/com/wrq/rearranger/Rearranger.java | 212 ++ .../com/wrq/rearranger/RearrangerAction.java | 34 + .../rearranger/RearrangerActionHandler.java | 227 ++ .../src/com/wrq/rearranger/RearrangerIcon.png | Bin 0 -> 2139 bytes .../src/com/wrq/rearranger/ShowComments.png | Bin 0 -> 148 bytes .../src/com/wrq/rearranger/ShowFields.png | Bin 0 -> 637 bytes .../com/wrq/rearranger/ShowMatchedRules.png | Bin 0 -> 744 bytes .../src/com/wrq/rearranger/ShowParamNames.png | Bin 0 -> 757 bytes .../src/com/wrq/rearranger/ShowParamTypes.png | Bin 0 -> 752 bytes .../src/com/wrq/rearranger/ShowRules.png | Bin 0 -> 748 bytes .../wrq/rearranger/ShowTypeAfterMethod.png | Bin 0 -> 650 bytes .../wrq/rearranger/StaticClassInitializer.png | Bin 0 -> 783 bytes .../src/com/wrq/rearranger/TestOverImpl.java | 58 + .../com/wrq/rearranger/WaitableBoolean.java | 69 + .../configuration/ChoiceObject.java | 66 + .../rearranger/configuration/ChoicePanel.java | 155 ++ .../ClassMemberSettingsPane.java | 95 + .../configuration/ClassOrderSettingsPane.java | 65 + .../configuration/ExtractedMethodsPane.java | 428 ++++ .../configuration/IListManagerObject.java | 35 + .../IListManagerObjectFactory.java | 31 + .../configuration/IntTextField.java | 94 + .../rearranger/configuration/ListManager.java | 303 +++ .../rearranger/configuration/MethodSpec.java | 227 ++ .../RearrangerSettingsPanel.java | 566 +++++ .../configuration/RelatedByNamePane.java | 217 ++ .../configuration/SettingsPane.java | 549 +++++ .../rearranger/configuration/SpacingPane.java | 145 ++ .../configuration/StringTextArea.java | 58 + .../configuration/StringTextField.java | 56 + .../rearranger/configuration/TableMap.java | 103 + .../rearranger/configuration/TableSorter.java | 341 +++ .../wrq/rearranger/defaultConfiguration.xml | 360 +++ .../rearranger/entry/ClassContentsEntry.java | 68 + .../com/wrq/rearranger/entry/ClassEntry.java | 576 +++++ .../entry/ClassInitializerEntry.java | 68 + .../com/wrq/rearranger/entry/FieldEntry.java | 116 + .../entry/IPopupTreeRangeEntry.java | 45 + .../wrq/rearranger/entry/IRelatableEntry.java | 61 + .../rearranger/entry/MemberAttributes.java | 41 + .../com/wrq/rearranger/entry/MethodEntry.java | 1288 ++++++++++ .../entry/MiscellaneousTextEntry.java | 67 + .../wrq/rearranger/entry/PsiFileEntry.java | 93 + .../com/wrq/rearranger/entry/RangeEntry.java | 306 +++ .../rearranger/popup/FileStructurePopup.java | 352 +++ .../wrq/rearranger/popup/IFilePopupEntry.java | 41 + .../wrq/rearranger/popup/IHasScrollPane.java | 32 + .../wrq/rearranger/popup/ILiveRearranger.java | 34 + .../src/com/wrq/rearranger/popup/IconBox.java | 229 ++ .../popup/LiveRearrangerDialog.java | 321 +++ .../rearranger/popup/LiveRearrangerPopup.java | 638 +++++ .../com/wrq/rearranger/popup/PopupTree.java | 283 +++ .../rearranger/popup/PopupTreeComponent.java | 361 +++ .../rearranger/popup/RearrangerTreeNode.java | 35 + .../popup/TransferableTreeNode.java | 57 + .../wrq/rearranger/popup/TreeDragSource.java | 93 + .../wrq/rearranger/popup/TreeDropTarget.java | 273 ++ .../wrq/rearranger/rearrangement/Emitter.java | 69 + .../rearrangement/GenericRearranger.java | 202 ++ .../wrq/rearranger/rearrangement/Mover.java | 66 + .../wrq/rearranger/rearrangement/Parser.java | 74 + .../wrq/rearranger/rearrangement/Spacer.java | 685 ++++++ .../ruleinstance/CommentRuleInstance.java | 187 ++ .../CommentRuleInstanceFactory.java | 47 + .../ruleinstance/CommonRuleInstance.java | 160 ++ .../ruleinstance/DefaultRuleInstance.java | 35 + .../EmitAlwaysCommentRuleInstance.java | 43 + .../HeaderTrailerRuleInstance.java | 81 + .../ruleinstance/IRuleInstance.java | 71 + .../ruleinstance/InterfaceInstance.java | 146 ++ .../ruleinstance/InterfaceRuleInstance.java | 136 + .../PrecedingCommentRuleInstance.java | 49 + .../SubsequentCommentRuleInstance.java | 50 + .../SurroundingCommentRuleInstance.java | 57 + .../settings/CommentFillString.java | 196 ++ .../wrq/rearranger/settings/CommentRule.java | 613 +++++ .../settings/ForceBlankLineSetting.java | 131 + .../settings/PrimaryMethodSetting.java | 386 +++ .../settings/RearrangerSettings.java | 683 +++++ .../RelatedByNameMethodsSettings.java | 45 + .../settings/RelatedMethodsSettings.java | 247 ++ .../settings/SecondaryMethodSetting.java | 307 +++ .../atomicAttributes/AbstractAttribute.java | 55 + .../atomicAttributes/AndNotAttribute.java | 152 ++ .../atomicAttributes/AtomicAttribute.java | 33 + .../atomicAttributes/EnumAttribute.java | 55 + .../atomicAttributes/FinalAttribute.java | 55 + .../ImplementedAttribute.java | 54 + .../ImplementingAttribute.java | 53 + .../InitToAnonClassAttribute.java | 53 + .../InitializerAttribute.java | 55 + .../atomicAttributes/IntegerAttribute.java | 172 ++ .../atomicAttributes/MaxParamsAttribute.java | 53 + .../atomicAttributes/MinParamsAttribute.java | 53 + .../atomicAttributes/NameAttribute.java | 57 + .../atomicAttributes/NativeAttribute.java | 55 + .../atomicAttributes/OverriddenAttribute.java | 54 + .../atomicAttributes/OverridingAttribute.java | 53 + .../ProtectionLevelAttributes.java | 264 ++ .../atomicAttributes/ReturnTypeAttribute.java | 57 + .../atomicAttributes/SortOptions.java | 259 ++ .../atomicAttributes/StaticAttribute.java | 55 + .../atomicAttributes/StringAttribute.java | 171 ++ .../SynchronizedAttribute.java | 55 + .../atomicAttributes/TransientAttribute.java | 55 + .../atomicAttributes/TypeAttribute.java | 58 + .../atomicAttributes/VolatileAttribute.java | 55 + .../attributeGroups/AttributeGroup.java | 36 + .../attributeGroups/ClassAttributes.java | 180 ++ .../attributeGroups/CommonAttributes.java | 184 ++ .../settings/attributeGroups/DefaultRule.java | 72 + .../attributeGroups/FieldAttributes.java | 214 ++ .../GetterSetterDefinition.java | 326 +++ .../settings/attributeGroups/HeaderRule.java | 66 + .../IHasGetterSetterDefinition.java | 30 + .../attributeGroups/IPrioritizableRule.java | 29 + .../IRestrictMethodExtraction.java | 32 + .../settings/attributeGroups/IRule.java | 63 + .../attributeGroups/InnerClassAttributes.java | 174 ++ .../attributeGroups/InterfaceAttributes.java | 459 ++++ .../attributeGroups/ItemAttributes.java | 62 + .../attributeGroups/MethodAttributes.java | 680 +++++ .../settings/attributeGroups/RegexUtil.java | 344 +++ .../settings/attributeGroups/TrailerRule.java | 66 + .../com/wrq/rearranger/util/CommentUtil.java | 244 ++ .../com/wrq/rearranger/util/Constraints.java | 321 +++ .../src/com/wrq/rearranger/util/IconUtil.java | 77 + .../com/wrq/rearranger/util/MethodUtil.java | 241 ++ .../wrq/rearranger/util/ModifierUtils.java | 52 + .../com/wrq/rearranger/InteractiveTest.java | 163 ++ .../com/wrq/rearranger/RearrangerTest.groovy | 2188 +++++++++++++++++ .../settings/CommentFillStringTest.java | 27 + .../attributeGroups/MethodAttributesTest.java | 66 + .../attributeGroups/RegexUtilTest.java | 25 + .../rearranger/testClasses/TestClass1.java | 19 + .../rearranger/testClasses/TestClass2.java | 38 + .../wrq/rearranger/testClasses/TestEnum.java | 24 + .../testClasses/TestImplementation.java | 13 + .../rearranger/testClasses/TestInterface.java | 19 + .../rearranger/testClasses/TestOverride.java | 20 + .../wrq/rearranger/util/CommentUtilTest.java | 57 + .../com/wrq/rearranger/BitFieldResult.java | 388 +++ .../com/wrq/rearranger/BitFieldTest.java | 375 +++ .../rearranger/CommentSeparatorResult1.java | 6 + .../wrq/rearranger/CommentSeparatorTest1.java | 3 + .../rearranger/CorruptRespacingResult.java | 15 + .../wrq/rearranger/CorruptRespacingTest.java | 12 + .../com/wrq/rearranger/CorruptionConfig.xml | 557 +++++ .../wrq/rearranger/DomainExpanderResult.java | 230 ++ .../wrq/rearranger/DomainExpanderTest.java | 231 ++ .../com/wrq/rearranger/Enum1Result.java | 715 ++++++ .../com/wrq/rearranger/Enum1Test.java | 696 ++++++ .../com/wrq/rearranger/Enum2AResult.java | 26 + .../com/wrq/rearranger/Enum2Result.java | 31 + .../com/wrq/rearranger/Enum2Test.java | 24 + .../com/wrq/rearranger/GenericsResult1.java | 8 + .../com/wrq/rearranger/GenericsTest1.java | 5 + .../GetFieldReturnsFieldResult.java | 33 + .../wrq/rearranger/GetFieldReturnsResult.java | 33 + .../rearranger/GetPrefixImmaterialResult.java | 32 + .../GetPrefixReturnsFieldResult.java | 33 + .../rearranger/GetPrefixReturnsResult.java | 33 + .../wrq/rearranger/GetterDefinitionTest.java | 33 + .../wrq/rearranger/IncompleteLineResult.java | 22 + .../wrq/rearranger/IncompleteLineTest.java | 20 + .../com/wrq/rearranger/InterfaceResult1.java | 8 + .../com/wrq/rearranger/InterfaceTest1.java | 9 + .../NoRearrangeInnerClassResult.java | 25 + .../rearranger/NoRearrangeInnerClassTest.java | 12 + .../NoRearrangementInnerClassCfg.xml | 185 ++ .../rearranger/NoRearrangementResult1.java | 57 + .../com/wrq/rearranger/OpsBlockingQueue.java | 70 + .../rearranger/OpsBlockingQueueIndented.java | 75 + .../OpsBlockingQueueIndentedResult.java | 71 + .../com/wrq/rearranger/OverloadedConfig.xml | 500 ++++ .../com/wrq/rearranger/OverloadedResult1.java | 11 + .../com/wrq/rearranger/OverloadedTest1.java | 11 + .../wrq/rearranger/RearrangementResult10.java | 58 + .../wrq/rearranger/RearrangementResult11.java | 8 + .../wrq/rearranger/RearrangementResult12.java | 21 + .../wrq/rearranger/RearrangementResult13.java | 28 + .../rearranger/RearrangementResult13BA.java | 28 + .../rearranger/RearrangementResult13BI.java | 28 + .../RearrangementResult13BIELC.java | 52 + .../RearrangementResult13BIEMC.java | 84 + .../RearrangementResult13BINFC.java | 32 + .../RearrangementResult13BITLC.java | 36 + .../rearranger/RearrangementResult13BO.java | 28 + .../rearranger/RearrangementResult13DA.java | 28 + .../rearranger/RearrangementResult13DI.java | 28 + .../RearrangementResult13DIELC.java | 60 + .../RearrangementResult13DIEMC.java | 84 + .../RearrangementResult13DINFC.java | 32 + .../RearrangementResult13DITLC.java | 36 + .../rearranger/RearrangementResult13DO.java | 28 + .../rearranger/RearrangementResult13Ex.java | 28 + .../wrq/rearranger/RearrangementResult14.java | 14 + .../wrq/rearranger/RearrangementResult18.java | 34 + .../rearranger/RearrangementResult18A.java | 35 + .../rearranger/RearrangementResult18B.java | 29 + .../rearranger/RearrangementResult19A.java | 24 + .../rearranger/RearrangementResult19B.java | 24 + .../rearranger/RearrangementResult19C.java | 25 + .../wrq/rearranger/RearrangementResult1A.java | 58 + .../wrq/rearranger/RearrangementResult2.java | 57 + .../wrq/rearranger/RearrangementResult20.java | 18 + .../wrq/rearranger/RearrangementResult21.java | 3 + .../wrq/rearranger/RearrangementResult22.java | 11 + .../RearrangementResult23BNNANXME.java | 39 + .../RearrangementResult23NNIANXME.java | 42 + .../RearrangementResult23NNNANXMA.java | 42 + .../RearrangementResult23NNNANXME.java | 42 + .../RearrangementResult23NNNANXMI.java | 42 + .../wrq/rearranger/RearrangementResult25.java | 24 + .../wrq/rearranger/RearrangementResult26.java | 16 + .../wrq/rearranger/RearrangementResult27.java | 45 + .../wrq/rearranger/RearrangementResult28.java | 50 + .../wrq/rearranger/RearrangementResult3.java | 57 + .../wrq/rearranger/RearrangementResult30.java | 328 +++ .../wrq/rearranger/RearrangementResult31.java | 176 ++ .../wrq/rearranger/RearrangementResult32.java | 11 + .../wrq/rearranger/RearrangementResult33.java | 7 + .../wrq/rearranger/RearrangementResult34.java | 15 + .../rearranger/RearrangementResult34B.java | 13 + .../wrq/rearranger/RearrangementResult35.java | 7 + .../wrq/rearranger/RearrangementResult37.java | 21 + .../wrq/rearranger/RearrangementResult39.java | 8 + .../rearranger/RearrangementResult39A.java | 8 + .../rearranger/RearrangementResult39B.java | 8 + .../rearranger/RearrangementResult39C.java | 8 + .../wrq/rearranger/RearrangementResult4.java | 58 + .../wrq/rearranger/RearrangementResult40.java | 31 + .../wrq/rearranger/RearrangementResult41.java | 5 + .../wrq/rearranger/RearrangementResult42.java | 5 + .../wrq/rearranger/RearrangementResult43.java | 13 + .../wrq/rearranger/RearrangementResult44.java | 6 + .../wrq/rearranger/RearrangementResult45.java | 59 + .../rearranger/RearrangementResult46A.java | 19 + .../rearranger/RearrangementResult46B.java | 19 + .../rearranger/RearrangementResult46C.java | 19 + .../rearranger/RearrangementResult46D.java | 19 + .../rearranger/RearrangementResult46E.java | 19 + .../wrq/rearranger/RearrangementResult47.java | 9 + .../wrq/rearranger/RearrangementResult5.java | 57 + .../wrq/rearranger/RearrangementResult6.java | 8 + .../wrq/rearranger/RearrangementResult7.java | 14 + .../wrq/rearranger/RearrangementResult8.java | 58 + .../wrq/rearranger/RearrangementResult8A.java | 19 + .../wrq/rearranger/RearrangementResult9.java | 58 + .../com/wrq/rearranger/RearrangementTest.java | 57 + .../wrq/rearranger/RearrangementTest11.java | 5 + .../wrq/rearranger/RearrangementTest12.java | 20 + .../wrq/rearranger/RearrangementTest13.java | 28 + .../wrq/rearranger/RearrangementTest14.java | 13 + .../wrq/rearranger/RearrangementTest15.java | 15 + .../wrq/rearranger/RearrangementTest16.java | 18 + .../wrq/rearranger/RearrangementTest17.xml | 5 + .../wrq/rearranger/RearrangementTest18.java | 34 + .../wrq/rearranger/RearrangementTest18B.java | 27 + .../wrq/rearranger/RearrangementTest19.java | 24 + .../wrq/rearranger/RearrangementTest2.java | 8 + .../wrq/rearranger/RearrangementTest20.java | 17 + .../wrq/rearranger/RearrangementTest21.java | 3 + .../wrq/rearranger/RearrangementTest22.java | 11 + .../wrq/rearranger/RearrangementTest23.java | 39 + .../wrq/rearranger/RearrangementTest24.java | 137 ++ .../wrq/rearranger/RearrangementTest25.java | 25 + .../wrq/rearranger/RearrangementTest26.java | 15 + .../wrq/rearranger/RearrangementTest27.java | 45 + .../wrq/rearranger/RearrangementTest28.java | 46 + .../wrq/rearranger/RearrangementTest29.java | 26 + .../wrq/rearranger/RearrangementTest30.java | 328 +++ .../wrq/rearranger/RearrangementTest31.java | 175 ++ .../wrq/rearranger/RearrangementTest32.java | 10 + .../wrq/rearranger/RearrangementTest33.java | 9 + .../wrq/rearranger/RearrangementTest34.java | 10 + .../wrq/rearranger/RearrangementTest35.java | 7 + .../wrq/rearranger/RearrangementTest36.java | 48 + .../wrq/rearranger/RearrangementTest37.java | 21 + .../wrq/rearranger/RearrangementTest38.java | 19 + .../wrq/rearranger/RearrangementTest38cfg.xml | 274 +++ .../wrq/rearranger/RearrangementTest39.java | 8 + .../wrq/rearranger/RearrangementTest39A.java | 8 + .../wrq/rearranger/RearrangementTest40.java | 31 + .../wrq/rearranger/RearrangementTest41.java | 7 + .../wrq/rearranger/RearrangementTest42.java | 5 + .../wrq/rearranger/RearrangementTest43.java | 13 + .../wrq/rearranger/RearrangementTest44.java | 5 + .../wrq/rearranger/RearrangementTest45.java | 45 + .../wrq/rearranger/RearrangementTest46.java | 19 + .../wrq/rearranger/RearrangementTest47.java | 9 + .../wrq/rearranger/RearrangementTest7.java | 14 + .../wrq/rearranger/RearrangementTest8.java | 19 + .../com/wrq/rearranger/SpaceResult1.java | 13 + .../com/wrq/rearranger/SpaceResult2.java | 20 + .../com/wrq/rearranger/SpaceResult3.java | 18 + .../com/wrq/rearranger/SpaceResult4.java | 335 +++ .../com/wrq/rearranger/SpaceResult5.java | 41 + .../com/wrq/rearranger/SpaceResult6.java | 37 + .../com/wrq/rearranger/SpaceResult7.java | 97 + .../com/wrq/rearranger/SpaceResult8.java | 11 + .../com/wrq/rearranger/SpaceTest1.java | 22 + .../com/wrq/rearranger/SpaceTest2.java | 16 + .../com/wrq/rearranger/SpaceTest3.java | 18 + .../com/wrq/rearranger/SpaceTest4.java | 337 +++ .../com/wrq/rearranger/SpaceTest5.java | 42 + .../com/wrq/rearranger/SpaceTest6.java | 38 + .../com/wrq/rearranger/SpaceTest7.java | 100 + .../com/wrq/rearranger/SpaceTest7cfg.xml | 325 +++ .../com/wrq/rearranger/SpaceTest8.java | 9 + .../test/testData/defaultConfiguration.xml | 262 ++ 321 files changed, 34764 insertions(+) create mode 100644 plugins/rearranger/rearranger.iml create mode 100644 plugins/rearranger/src/META-INF/plugin.xml create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ClassInitializer.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/LiveRearrangerAction.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/LiveRearrangerActionHandler.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ModifierConstants.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ProjectTreeActionHandler.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/Rearranger.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/RearrangerAction.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/RearrangerIcon.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ShowComments.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ShowFields.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ShowMatchedRules.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ShowParamNames.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ShowParamTypes.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ShowRules.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ShowTypeAfterMethod.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/StaticClassInitializer.png create mode 100644 plugins/rearranger/src/com/wrq/rearranger/TestOverImpl.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/WaitableBoolean.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/ChoiceObject.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/ChoicePanel.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/ClassMemberSettingsPane.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/ClassOrderSettingsPane.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/ExtractedMethodsPane.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObject.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObjectFactory.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/IntTextField.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/ListManager.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/MethodSpec.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/RearrangerSettingsPanel.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/RelatedByNamePane.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextArea.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextField.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/TableMap.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/configuration/TableSorter.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/defaultConfiguration.xml create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/ClassInitializerEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/FieldEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/IPopupTreeRangeEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/IRelatableEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/MemberAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/MiscellaneousTextEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/PsiFileEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/IFilePopupEntry.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/IHasScrollPane.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/IconBox.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/RearrangerTreeNode.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/TransferableTreeNode.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/TreeDragSource.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/popup/TreeDropTarget.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/rearrangement/Parser.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstanceFactory.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/IRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/CommentFillString.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/ForceBlankLineSetting.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/PrimaryMethodSetting.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/RelatedByNameMethodsSettings.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/RelatedMethodsSettings.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/SecondaryMethodSetting.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AbstractAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AndNotAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AtomicAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/EnumAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/FinalAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementedAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementingAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitToAnonClassAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitializerAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/IntegerAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MaxParamsAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MinParamsAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NameAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NativeAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverriddenAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverridingAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ProtectionLevelAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ReturnTypeAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SortOptions.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StaticAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StringAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SynchronizedAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TransientAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TypeAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/VolatileAttribute.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ClassAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/FieldAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/GetterSetterDefinition.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IHasGetterSetterDefinition.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IPrioritizableRule.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRestrictMethodExtraction.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRule.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InnerClassAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ItemAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributes.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/RegexUtil.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/util/Constraints.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/util/IconUtil.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/util/MethodUtil.java create mode 100644 plugins/rearranger/src/com/wrq/rearranger/util/ModifierUtils.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/settings/CommentFillStringTest.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributesTest.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/RegexUtilTest.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass1.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass2.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestEnum.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestImplementation.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestInterface.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestOverride.java create mode 100644 plugins/rearranger/test/src/com/wrq/rearranger/util/CommentUtilTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorResult1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorTest1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/CorruptionConfig.xml create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Result.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Test.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/Enum2AResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Result.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Test.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GenericsResult1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GenericsTest1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/GetterDefinitionTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceResult1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceTest1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementResult1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueue.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndented.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndentedResult.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedConfig.xml create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedResult1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedTest1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult10.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult11.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult12.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BA.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BI.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIELC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIEMC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BINFC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BITLC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BO.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DA.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DI.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIELC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIEMC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DINFC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DITLC.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DO.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13Ex.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult14.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18A.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18B.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19A.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19B.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult1A.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult2.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult21.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23BNNANXME.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNIANXME.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMA.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXME.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMI.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult25.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult26.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult27.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult28.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult3.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult30.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult31.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult32.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult33.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34B.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult35.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult37.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39A.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39B.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39C.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult4.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult40.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult41.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult42.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult43.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult44.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult45.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46A.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46B.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46C.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46D.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46E.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult47.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult5.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult6.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult7.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8A.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult9.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest11.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest12.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest13.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest14.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest15.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest16.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest17.xml create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18B.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest19.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest2.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest20.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest21.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest22.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest23.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest24.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest25.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest26.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest27.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest28.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest29.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest30.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest31.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest32.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest33.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest34.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest35.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest36.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest37.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38cfg.xml create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39A.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest40.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest41.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest42.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest43.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest44.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest45.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest46.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest47.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest7.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest8.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult2.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult3.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult4.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult7.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest1.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest2.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest3.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest4.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest5.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest6.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7.java create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml create mode 100644 plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest8.java create mode 100644 plugins/rearranger/test/testData/defaultConfiguration.xml diff --git a/.idea/modules.xml b/.idea/modules.xml index ed5c32e269fe..8500e622a7bf 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -91,6 +91,7 @@ + diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index f299b61a63fd..19c53fae82b7 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -226,6 +226,12 @@ public def layoutCommunityPlugins(String home) { module("gradle") } } + + layoutPlugin("rearranger") { + jar("rearranger.jar") { + module("rearranger") + } + } layoutPlugin("git4idea") { jar("git4idea-rt.jar") { diff --git a/community-main.iml b/community-main.iml index 0dbcfb09ce10..68ce7b7be166 100644 --- a/community-main.iml +++ b/community-main.iml @@ -89,6 +89,7 @@ + diff --git a/plugins/rearranger/rearranger.iml b/plugins/rearranger/rearranger.iml new file mode 100644 index 000000000000..a4214d4850e2 --- /dev/null +++ b/plugins/rearranger/rearranger.iml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/rearranger/src/META-INF/plugin.xml b/plugins/rearranger/src/META-INF/plugin.xml new file mode 100644 index 000000000000..067d2828af8a --- /dev/null +++ b/plugins/rearranger/src/META-INF/plugin.xml @@ -0,0 +1,46 @@ + + org.jetbrains.plugins.rearranger + Rearranger + + Rearranges (reorders) class and class member declarations according to a user-specified order and/or method call hierarchy; + generates section-marking comments; + provides several controls for spacing within and between methods and classes; and + permits the user to manually rearrange items. + + JetBrains Inc. + + com.intellij.modules.lang + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/rearranger/src/com/wrq/rearranger/ClassInitializer.png b/plugins/rearranger/src/com/wrq/rearranger/ClassInitializer.png new file mode 100644 index 0000000000000000000000000000000000000000..069d412ce72cc8c262df0e321c12692319edb1a3 GIT binary patch literal 775 zcmV+i1Ni)jP)PDo5ZiFtPD7~=|={7;A zh;kqiWkD+y5{66ZLL99oI88lsM-Th+dXDdV&in7@#WZ*FTz1j#>fy)peE5AHeqZ>H zN;PY?w0Ft+p)HtvfuMSq;><+?zf6`U3PB#cY&hGi0Ub~E%4=`G%PTu}kSRmK06}U)x;yfL*VL(dir0I!(SX{aG(!kDJ%u`L|Cc`eoa^iGv><6y!Y~x z&AgO)sB-M530@fLqq9|!Qwl#2s*w;S5NEI$W|S&*Zp`1|!;#)cY7Zu|0Y=|B#HN8h zI`WDqwC2y7^Bn#BB*nQB#u#>N-^%dtiv*EgfdIB^B%#JXFxP97FE8Absl`N=vrLw& zfsF3|SWb*jO0km4iOE^nw&#FM|9xA2yA{i^^LOOn_tVnVGa#$&biTcd){eELDfst< zQ@_tpD73SE>oCQt(7mpQ(Kq+9WOp!E$v`xY< outerClasses = p.parseOuterLevel(); + if (outerClasses.size() > 0) { + final Mover mover = new Mover(outerClasses, settings); + final List resultRuleInstances = mover.rearrangeOuterClasses(); + fsp.setResultRuleInstances(resultRuleInstances); + fsp.liveRearranger(); + } + LOG.debug("exit liveRearrangeDocument on thread " + Thread.currentThread().getName()); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/ModifierConstants.java b/plugins/rearranger/src/com/wrq/rearranger/ModifierConstants.java new file mode 100644 index 000000000000..e5b02062d9e6 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ModifierConstants.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger; + +/** Additional "modifier" flags, used to identify other boolean attributes of a field, method or class. */ +public final class ModifierConstants { +// ------------------------------ FIELDS ------------------------------ + + /* + * dummy modifier values -- chosen to not conflict with other Java modifiers + */ + public static final int OVERRIDDEN = 0x2000; + public static final int CONSTRUCTOR = 0x4000; + public static final int CANONICAL = 0x200000; + public static final int OTHER_METHOD = 0x10000; + public static final int OVERRIDING = 0x20000; + public static final int IMPLEMENTING = 0x100000; + public static final int INIT_TO_ANON_CLASS = 0x40000; + public static final int INITIALIZER = 0x80000; + public static final int IMPLEMENTED = 0x400000; + public static final int ENUM = 0x800000; + + private ModifierConstants() { + } + + public static String toString(int constants) { + String result = ""; + if ((constants & OVERRIDDEN) > 0) result += "OVERRIDDEN "; + if ((constants & CONSTRUCTOR) > 0) result += "CONSTRUCTOR "; + if ((constants & CANONICAL) > 0) result += "CANONICAL "; + if ((constants & OTHER_METHOD) > 0) result += "OTHER_METHOD "; + if ((constants & OVERRIDING) > 0) result += "OVERRIDING "; + if ((constants & IMPLEMENTED) > 0) result += "IMPLEMENTED "; + if ((constants & IMPLEMENTING) > 0) result += "IMPLEMENTING "; + if ((constants & INIT_TO_ANON_CLASS) > 0) result += "INIT_TO_ANON_CLASS "; + if ((constants & INITIALIZER) > 0) result += "INITIALIZER "; + if ((constants & ENUM) > 0) result += "ENUM "; + return result.trim(); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ProjectTreeActionHandler.java b/plugins/rearranger/src/com/wrq/rearranger/ProjectTreeActionHandler.java new file mode 100644 index 000000000000..f2f47be70cf8 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ProjectTreeActionHandler.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/** Handles right-click in project view; applies rearrangement to a directory and its files recursively. */ +public final class ProjectTreeActionHandler + extends AnAction +{ +// ------------------------------ FIELDS ------------------------------ + + private static final Logger LOG = Logger.getInstance("#" + ProjectTreeActionHandler.class.getName()); + +// -------------------------- OTHER METHODS -------------------------- + + public final void actionPerformed(final AnActionEvent anActionEvent) { + LOG.debug("entered actionPerformed"); + // we're being called on the Swing event dispatch thread. Spin off another thread to do the + // rearranging and let Swing's thread go. + Thread t = new Thread( + new Runnable() { + public void run() { + new RearrangeIt(anActionEvent.getDataContext()).run(); + } + }, "RearrangerThread" + ); + t.start(); + } + +// -------------------------- INNER CLASSES -------------------------- + + abstract class VirtualFileVisitor { + volatile boolean cancel = false; + + final void accept(final VirtualFile f) { + if (f != null) { + visitVirtualFile(f); + } + final VirtualFile[] vfa = f.getChildren(); + if (vfa != null) { + for (VirtualFile aVfa : vfa) { + if (!cancel) { + accept(aVfa); + } + } + } + } + + abstract void visitVirtualFile(VirtualFile f); + } + + final class RearrangeIt + implements Runnable + { + final DataContext dc; + final Project project; + final JProgressBar bar = new JProgressBar(JProgressBar.HORIZONTAL); + final JLabel filename = new JLabel(); + + class BoolHolder { + boolean value; + } + + public RearrangeIt(final DataContext dc) { + this.dc = dc; + if (dc != null) { + this.project = (Project)dc.getData(DataConstants.PROJECT); + } + else { + this.project = null; + } + } + + public final void run() { + final VirtualFile virtualFile = (VirtualFile)dc.getData(DataConstants.VIRTUAL_FILE); + final List files = new ArrayList(); + final IntHolder count = new IntHolder(); + final VirtualFileVisitor counter = new VirtualFileVisitor() { + void visitVirtualFile(final VirtualFile file) { + if (!file.isDirectory()) { + count.n++; + LOG.debug("" + count.n + ": file " + file.getName()); + files.add(file); + } + } + }; + + final Application application = ApplicationManager.getApplication(); + application.runReadAction( + new Runnable() { + public void run() { + counter.accept(virtualFile); + } + } + ); + + LOG.debug("counted " + count.n + " files"); + final RearrangerActionHandler rah = new RearrangerActionHandler(); + final PsiDocumentManager dm = PsiDocumentManager.getInstance(project); + final PsiManager pm = PsiManager.getInstance(project); + final BoolHolder cancelled = new BoolHolder(); + final JDialog dialog = getProgressFrame(cancelled, count.n); + dialog.setVisible(true); + for (int currentCount = 0; currentCount < files.size(); currentCount++) { + if (cancelled.value) { + LOG.debug("cancelled rearrangement"); + break; + } + final VirtualFile f = files.get(currentCount); + final int k = currentCount; + Runnable fn = new Runnable() { + public void run() { + final PsiFile psiFile = pm.findFile(f); + LOG.debug("SDT setting filename to " + psiFile.getName()); + filename.setText(psiFile.getName()); + filename.repaint(); + } + }; + Runnable r = new Runnable() { + public void run() { + final PsiFile psiFile = pm.findFile(f); + if (psiFile != null && + psiFile.getName().endsWith(".java") && + psiFile.isWritable()) + { + LOG.debug("SDT rearranging file " + psiFile.getName()); + final Document document = dm.getDocument(psiFile); + final Application application = ApplicationManager.getApplication(); + application.runWriteAction( + new Runnable() { + public void run() { + final Application application = ApplicationManager.getApplication(); + final Rearranger rearranger = application.getComponent(Rearranger.class); + RearrangerSettings settings = rearranger.getSettings(); + settings = settings.deepCopy(); + // avoid showing confirmation dialog for each file done + settings.setAskBeforeRearranging(false); + rah.runWriteActionRearrangement(project, document, psiFile, settings); + } + + ; + } + ); + } + ; + if (!cancelled.value) { + LOG.debug("SDT setting progress bar value to " + (k + 1)); + bar.setValue(k + 1); + bar.repaint(); + } + } + }; + + try { + SwingUtilities.invokeAndWait(fn); + SwingUtilities.invokeAndWait(r); + } + catch (InterruptedException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + catch (InvocationTargetException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + dialog.setVisible(false); + dialog.dispose(); + } + + final JDialog getProgressFrame(final BoolHolder cancelled, final int max) { + Object parent = null; + if (project != null) { + parent = WindowManager.getInstance().suggestParentWindow(project); + } + LOG.debug("suggested parent window=" + parent); + final JDialog dialog = parent == null ? + new JDialog() : + (parent instanceof JDialog ? + new JDialog((JDialog)parent) : + new JDialog((JFrame)parent)); + final Container pane = dialog.getContentPane(); + final JLabel rearrangingLabel = new JLabel("Rearranging files, please wait..."); + final JPanel progressPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.newRow(); + constraints.insets = new Insets(15, 15, 0, 0); + progressPanel.add(rearrangingLabel, constraints.weightedLastCol()); + constraints.newRow(); + bar.setMinimum(0); + bar.setMaximum(max); + bar.setPreferredSize(new Dimension(500, 15)); + bar.setMinimumSize(new Dimension(500, 15)); + bar.setStringPainted(true); + constraints.insets = new Insets(15, 15, 5, 15); + progressPanel.add(bar, constraints.weightedFirstCol()); + constraints.insets = new Insets(9, 0, 5, 15); + final JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + LOG.debug("cancel button pressed"); + filename.setText("cancelling..."); + cancelled.value = true; + } + } + ); + + progressPanel.add(cancelButton, constraints.weightedLastCol()); + constraints.weightedLastRow(); + constraints.insets = new Insets(0, 15, 15, 0); + filename.setSize(500, 15); + filename.setPreferredSize(new Dimension(500, 15)); +// filename.setFont(new Font("dialog", Font.PLAIN, 12)); + progressPanel.add(filename, constraints.weightedLastCol()); + pane.add(progressPanel, BorderLayout.CENTER); + dialog.setTitle(Rearranger.COMPONENT_NAME); + dialog.addWindowListener( + new WindowListener() { + public void windowClosed(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowActivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowClosing(final WindowEvent e) { + LOG.debug("dialog closed, cancel Rearranger"); + filename.setText("cancelling..."); + cancelled.value = true; + } + + public void windowDeactivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowDeiconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowIconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowOpened(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + } + ); + + dialog.pack(); + return dialog; + } + + final class IntHolder { + public int n; + } + } + +// --------------------------- main() method --------------------------- + + /** + * Test progress bar functionality. Read 10 "filenames" from console, pausing between each to update the + * progress bar dialog. Handle cancel button and dialog window close button properly. + * + * @param args + */ + public static void main(final String[] args) { +// test the progress bar. + final BufferedReader reader; + final ProjectTreeActionHandler ptah = new ProjectTreeActionHandler(); + final RearrangeIt ri = ptah.new RearrangeIt(null); + final RearrangeIt.IntHolder cancelled = ri.new IntHolder(); + reader = new BufferedReader(new InputStreamReader(System.in)); + RearrangeIt.BoolHolder c = ri.new BoolHolder(); + + final JDialog dialog = ri.getProgressFrame(c, 10); + int count = 0; + dialog.pack(); + dialog.setVisible(true); + while (count <= 10 && cancelled.n == 0) { + String s = null; + try { + s = reader.readLine(); + } + catch (IOException e) { + e.printStackTrace(); + } + if (cancelled.n == 0) { + ri.filename.setText(s); + count++; + ri.bar.setValue(count); + } + } + dialog.setVisible(false); + dialog.dispose(); + System.exit(0); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/Rearranger.java b/plugins/rearranger/src/com/wrq/rearranger/Rearranger.java new file mode 100644 index 000000000000..2f9b590023bd --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/Rearranger.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger; + +import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.util.JDOMExternalizable; +import com.wrq.rearranger.configuration.RearrangerSettingsPanel; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.IconUtil; +import org.jdom.Element; + +import javax.swing.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +/** + * The rearranger is an IntelliJ IDEA plugin that rearranges the order of class declarations and + * class member declarations within a Java file. The user configures an ordering of fields, methods, and classes. + * Subsequently, whenever the rearranger plugin is invoked on a Java file, the order of declarations is rearranged + * according to the configuration. + */ +public final class Rearranger + implements ApplicationComponent, Configurable, JDOMExternalizable +{ +// ------------------------------ FIELDS ------------------------------ + + public static final String COMPONENT_NAME = "Rearranger"; + public static final String VERSION = "5.5"; + private static final Logger LOG = Logger.getInstance("#" + Rearranger.class.getName()); + + private transient RearrangerSettingsPanel preferencesPanel; + private RearrangerSettings settings = new RearrangerSettings(); + private boolean haveReadExternalSettings; + +// --------------------------- CONSTRUCTORS --------------------------- + + public Rearranger() { +// logger.setAdditivity(false); +// logger.addAppender(new ConsoleAppender(new PatternLayout("[%7r] %6p - %30.30c - %m \n"))); +// logger.setLevel(Level.DEBUG); +// logger.setLevel(Level.INFO); + LOG.debug("constructor called for " + COMPONENT_NAME + " plugin version " + VERSION); + preferencesPanel = null; + /** + * If the Reformat plugin is present, register for a callback after code reformatting + * takes place. This allows user to optimize imports, reformat code, and rearrange all + * with one keystroke. + */ + try { + if (Class.forName("org.intellij.psi.codeStyle.ReformatManager") != null) { + /** + * Reformat plugin is available. Hook it by calling code in RearrangeUtility. + * Do this dynamically using reflection so we don't get class loading problems. + */ + LOG.debug("found ReformatManager class, attempting to hook."); + /** + * if the Reformat plugin is present, obtain a reference to our RearrangerUtility class, which will register + * for callbacks from the Reformat plugin. + */ + Class rearrangerUtilityClass = Class.forName("org.intellij.psi.codeStyle.RearrangerUtility"); + final Method hookit = rearrangerUtilityClass.getMethod("hookReformatPlugin", new Class[]{}); + hookit.invoke(null, (Object)null); + } + } + catch (ClassNotFoundException e) { + /** + * no reformat plugin available. Just continue with normal rearranger plugin behavior. + */ + LOG.debug("did not find class org.intellij.psi.codeStyle.RearrangerUtility"); + } + catch (NoSuchMethodException e) { + LOG.info(e.toString(), e); + } + catch (IllegalAccessException e) { + LOG.info(e.toString(), e); + } + catch (InvocationTargetException e) { + LOG.info(e.toString(), e); + } + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + // End Methods of Interface JDOMExternalizable + public RearrangerSettings getSettings() { + return settings; + } + + public void setSettings(RearrangerSettings settings) { + this.settings = settings; + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface BaseComponent --------------------- + + + public void initComponent() { + LOG.debug("initComponent()"); + } + + public void disposeComponent() { + LOG.debug("disposeComponent()"); + } + +// --------------------- Interface Configurable --------------------- + + public String getDisplayName() { + return COMPONENT_NAME; + } + + public Icon getIcon() { + return IconUtil.getIcon("RearrangerIcon"); + } + + public String getHelpTopic() { + return null; + } + +// --------------------- Interface JDOMExternalizable --------------------- + + public void readExternal(final Element element) //throws InvalidDataException + { + LOG.debug("rearranger.readExternal()"); + haveReadExternalSettings = true; + final List entries = element.getChildren(COMPONENT_NAME); + if (entries.size() > 0) { + LOG.debug("element 'Rearranger' seen; configuration loading"); + final Element entry = (Element)entries.get(0); + LOG.debug("element has " + entry.getChildren().size() + " children"); + settings.readExternal(entry); + } + } + + public void writeExternal(final Element element) //throws WriteExternalException + { + LOG.debug("rearranger.writeExternal()"); + final Element our_element = new Element(COMPONENT_NAME); + settings.writeExternal(our_element); + element.getChildren().clear(); + element.addContent(our_element); + } + +// --------------------- Interface NamedComponent --------------------- + + public String getComponentName() { + return COMPONENT_NAME; + } + +// --------------------- Interface UnnamedConfigurable --------------------- + + public JComponent createComponent() { + LOG.debug("createComponent: haveReadExternalSettings=" + haveReadExternalSettings); + RearrangerSettings rs; + if (!haveReadExternalSettings) { + LOG.debug("createComponent: reading default settings"); + rs = RearrangerSettings.getDefaultSettings(); + if (rs == null) { + LOG.debug("createComponent: could not find default settings"); + } + haveReadExternalSettings = true; + } + else { + rs = settings; + } + preferencesPanel = new RearrangerSettingsPanel(rs); + return preferencesPanel; + } + + public boolean isModified() { + final boolean result = !preferencesPanel.settings.equals(settings); + LOG.debug("rearranger.isModified(): returning " + result); + return result; + } + + public void apply() { + LOG.debug("rearranger.apply()"); + settings = preferencesPanel.settings.deepCopy(); + } + + public void reset() { + LOG.debug("rearranger.reset()"); + } + + public void disposeUIResources() { + preferencesPanel = null; + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/RearrangerAction.java b/plugins/rearranger/src/com/wrq/rearranger/RearrangerAction.java new file mode 100644 index 000000000000..328eefc61177 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/RearrangerAction.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger; + +import com.intellij.openapi.editor.actionSystem.EditorAction; + +public final class RearrangerAction + extends EditorAction +{ +// --------------------------- CONSTRUCTORS --------------------------- + + public RearrangerAction() { + super(new RearrangerActionHandler()); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java b/plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java new file mode 100644 index 000000000000..97d333290b3b --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger; + +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.popup.FileStructurePopup; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.rearrangement.Mover; +import com.wrq.rearranger.rearrangement.Parser; +import com.wrq.rearranger.rearrangement.Spacer; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.CommentUtil; + +import java.awt.dnd.DragSource; +import java.util.List; + +/** This class performs rearrangement actions requested by the user. */ +public final class RearrangerActionHandler extends EditorActionHandler { + +// ------------------------------ FIELDS ------------------------------ + + private static final Logger LOG = Logger.getInstance("#" + RearrangerActionHandler.class.getName()); + private static int rightMargin; + private static int tabSize; + +// -------------------------- STATIC METHODS -------------------------- + + public static int getRightMargin() { + return rightMargin; + } + + public static int getTabSize() { + return tabSize; + } + + public void setTabSize(int tabSize) { + RearrangerActionHandler.tabSize = tabSize; + } +// -------------------------- OTHER METHODS -------------------------- + + public final void execute(final Editor editor, final DataContext context) { + if (editor == null) { + return; + } + LOG.debug("enter RearrangerActionHandler.execute()"); + final Project project = (Project)context.getData(DataConstants.PROJECT); + final Document document = editor.getDocument(); + final PsiFile psiFile = getFile(editor, context); + LOG.debug("suggested tool window = " + + WindowManager.getInstance().suggestParentWindow(project)); + LOG.debug("drag source image supported = " + DragSource.isDragImageSupported()); + if (!psiFile.getName().endsWith(".java")) { + LOG.debug("not a .java file -- skipping " + psiFile.getName()); + return; + } + if (!psiFile.isWritable()) { + LOG.debug("not a writable .java file -- skipping " + psiFile.getName()); + return; + } + rightMargin = editor.getSettings().getRightMargin(project); + tabSize = editor.getSettings().getTabSize(project); + LOG.debug("right margin=" + rightMargin + ", tabSize=" + tabSize); + final Application application = ApplicationManager.getApplication(); + application.runWriteAction(new Runnable() { + public void run() { + final Rearranger rearranger = ServiceManager.getService(Rearranger.class); + final RearrangerSettings settings = rearranger.getSettings(); + runWriteActionRearrangement(project, document, psiFile, settings); + } + } + ); + } + + private static PsiFile getFile(final Editor editor, + final DataContext context) + { + final Project project = (Project)context.getData(DataConstants.PROJECT); + final Document document = editor.getDocument(); + final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + final VirtualFile virtualFile = fileDocumentManager.getFile(document); + final PsiManager psiManager = PsiManager.getInstance(project); + return psiManager.findFile(virtualFile); + } + + /** + * must be called from within an IDEA write-action thread. + * + * @param project + * @param document + * @param psiFile + */ + void runWriteActionRearrangement(final Project project, + final Document document, + final PsiFile psiFile, + final RearrangerSettings settings) + { + /** + * Per instructions from IntelliJ, we have to commit any changes to the document to the Psi + * tree. + */ + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + documentManager.commitDocument(document); + final WaitableBoolean wb = new WaitableBoolean(); + if (psiFile != null && + isFileWritable(psiFile) && + psiFile.getName().endsWith(".java")) + { + LOG.debug("schedule rearranger task"); + final Runnable task = new rearrangerTask(project, psiFile, settings, document, wb); + CommandProcessor.getInstance().executeCommand(project, task, "Rearrange", null); + } + try { + LOG.debug("wait for rearranger task to complete."); + wb.whenTrue(); + } + catch (InterruptedException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + LOG.debug("end execute"); + } + + public static boolean isFileWritable(PsiElement element) { + VirtualFile file = element.getContainingFile().getVirtualFile(); + return file != null && file.isWritable(); + } + + public final void rearrangeDocument(final Project project, + final PsiFile psiFile, + final RearrangerSettings settings, + final Document document) + { + LOG.debug("enter rearrangeDocument"); + new CommentUtil(settings); // create CommentUtil singleton + final Parser p = new Parser(project, settings, psiFile); + final List outerClasses = p.parseOuterLevel(); + if (outerClasses.size() > 0) { + final Mover m = new Mover(outerClasses, settings); + final List resultRuleInstances = m.rearrangeOuterClasses(); + boolean rearrange = true; + if (settings.isAskBeforeRearranging()) { + FileStructurePopup fsp = new FileStructurePopup(settings, resultRuleInstances, psiFile); + rearrange = fsp.displayRearrangement(); + } + if (rearrange) { + final Emitter e = new Emitter(psiFile, resultRuleInstances, document); + e.emitRearrangedDocument(); + } + } + LOG.debug("respacing document"); + PsiDocumentManager.getInstance(project).commitDocument(document); + Spacer spacer = new Spacer(project, psiFile, document, settings); + if (spacer.respace()) { + PsiDocumentManager.getInstance(project).commitDocument(document); + } + LOG.debug("exit rearrangeDocument"); + } + +// -------------------------- INNER CLASSES -------------------------- + + final class rearrangerTask implements Runnable { + final Project project; + final PsiFile psiFile; + final RearrangerSettings settings; + final Document document; + final WaitableBoolean wb; + + public rearrangerTask(final Project project, + final PsiFile psiFile, + final RearrangerSettings settings, + final Document document, + final WaitableBoolean wb) + { + this.project = project; + this.psiFile = psiFile; + this.settings = settings; + this.document = document; + this.wb = wb; + } + + public final void run() { + try { + rearrangeDocument(project, psiFile, settings, document); + } + finally { + wb.set(); + } + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/RearrangerIcon.png b/plugins/rearranger/src/com/wrq/rearranger/RearrangerIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..f4047ce53faab06181ef2bc0405c705732e6a450 GIT binary patch literal 2139 zcmWkwX;>477M;mJ7BWBtfeDLAaRK|egvAZi41y7~6-xVrrxu1779R>yXhm5vK?x{S zaKlg+f={ViMG+Ad$w0!sy1b%KTM`5j5s9)G$TE#T&OP7#aemx;&i%f7By8&@Yb$3f z0068*f`h`%%>4p7)m&2#9-K6jMSQ@w0RT|hy2|qCh`DE{ZH!F&J~=LJf6Py@K!7M& z7|RXW8xtQJ9vdS%kkS^r7652tAwdB@r2k)NAW6OwrQm>2h+qHpq&mtvmTH#5fh|aoKjeaLz}5EY7O@>*yg>cPC*1Owm7SY z<~#1u8_$=N7=hW}&O6B7B3BiDqaMwq36xv;%Wk3aDZY zmwbJX1NYZw#p|XW5I;UXZJ4ozSzD=5HuI<}--zMl8oF?SK;#cn^240famI;_@4Hf| z(iWon^Sp!+8a6jN+W^Vh*ld%DWd7poL34pTco964lL(`3u;J?aio|gL-}PW=LvD{b zZSI3WlpxMgYKxX-L$ikEya*pkf&0caHdL?0@=GkKL;1d|)hd%0jlF z9^B$5Rj7ki@n1~YeE398T_zl@kiZrd%P~)K#xl)g}SgTb@zzv|gUPoVx`tfdbDn&9DnM*K(0L(>sq8@2;{{=AOHsn8seO5bAW3 z9?Cyy&T#zS`97JtrXH;|(szTB1Mei~lbF_aNs;S0Qg^rbN?`mw^r& z<8wS-@RKBd_dkx+xCbg4VHS@={Y$KnjRI^iz<7InDEVw z3c~l}Sq z6>*}7F*iv*;B<<_8*Gk=_MM-!J%>-C#B^{^&Rt#PFINgX2f zrdXY6l&N&V0<@pTGNgHxeD7D_Kx(qW`<&h+)v*0NAb-9+?=M5Fu10s=uD4syGoJ%} zoi*LZU>MdGjc}BC`#H#k`b?$PV04leq0RmH(h&`#qddfCo1Ij0I(t&<>g zpOJXV1n1PENMvTpaA>;;DD&4!3O8i12beY`6`lh`5)3o zefNH{B4X>MrInY;K*>mTx?|+9W%ES4sP4G8@(O&hiteAVJh(b&@bY(;-#ASrCvQLe zUlyHqb?D)ItN0xqf~LNl9e{TSW{I-s7Xuw-6>5?c#U$PjTd8^cGU^w0+;l@{;4m}j zsO0a?=mWvgO-jc>_leJrJ3gI@sMQu6iA)$5%^v$t(?a%7^E~gP(*m!cnwswGY=zMt z@9=&OvZyhhss8Us^6Ovivwjo`*RqZ+U07{k?AbI{UXZ?b89_UtZ*q39Chsc$l1_ZR zgs&f;JVG8V2#NJvx5DaK;X!*=`2)v86HFbQJGoQa6hxfU44pm$FA?LG49^U&Kwls5 z&~K$~k$ov%Ak#&#PoivXr}V(`FrDo+SM+Bn9}qC@Z|xI;Z|qiL>_+lzS-{xxD<3EF8^8xRhP)R<@& zMy-GZn3Oc;9g&Rr^GNXkMJP9Np0jKDP)9-N4Y+Rn0P?)-w)o(b;a|+&V@|D(6bn|( z1K()Uk zzL+#jz3wZ@>(9=9_)#;eXD0X8*XiEBxYH5V!T;(dgN5q02Nm{qQ~j%dY|S}bTK<^! z6!0G8RIi?en&h=6%clN)ck=;Ceu_M!1ps~3k9Oez1YBi*Rs6thO|SVo075oy4Z67j G%lQZFbkFwy literal 0 HcmV?d00001 diff --git a/plugins/rearranger/src/com/wrq/rearranger/ShowComments.png b/plugins/rearranger/src/com/wrq/rearranger/ShowComments.png new file mode 100644 index 0000000000000000000000000000000000000000..150f22dcaa7602042943fc6e42ea4425e475e635 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1|*Ak?@s|z(Vi}jAr*6y6C_xbGswDmVRMd1Pg9@)mmA|r28ICsKK-xpF2O)+7(8A5T-G@yGywo@_AlrF literal 0 HcmV?d00001 diff --git a/plugins/rearranger/src/com/wrq/rearranger/ShowFields.png b/plugins/rearranger/src/com/wrq/rearranger/ShowFields.png new file mode 100644 index 0000000000000000000000000000000000000000..d85a07398be38f4c94170578357123b1c0a5677d GIT binary patch literal 637 zcmV-@0)qXCP)(ITS7iH!k^#4Z7gh>b!T(}=+$rnCwKK{y+^#t<#U zG8?c+nFvCzNRcANHi6qBuv;A5Kpw2c?#45BXD%`2{pGyb`R0Fb-dh;zf;DoUkGyMs zdgrzWjtdrcc0-~l1bceDGXcHpe!8+a%k1R+JfdJ@u*&vslh?}u+dmustohes3h79n zCaMprY4B+QV+`N|k^zaqCSYTtDB<15Eo!SlU+ATiff&**XV<)R?fpE)jDqpOt3XM> z=}5AIDG5u@DpYP%x@zQaM=-|Na!D(mCtU@b>!zK$)d=z;5>Lna(9>cOG z1-UFeft|;W0`5te>K_<+QLE5OI#S}}JaJ9F>3X`uE*PLzY3wKYeM@p^Oxt!ek~_mO zV9F@M*01n%U{9%z)W7XyMGGfZ;iwI^BhL|}R7S+G_9H}FNzc1D*h?dlu77yJ#Jyq= z+PSmibwtYG7#jN_Q_t%}QS=``!1KJc_U17Yw@e;UaGO z+v6>gPCp!H=I$sHl`>)sl!dSf^^HAhs{yDE{+6CaQP)!aj=CB*3HsEJ4s!{KTwE+5;~M* zk>F$s4qb${AoPYpGgP>x&>Mtg2=oIF&f#)3&0X3iI*AViF7J2m^SsaZz2AHAAAcE% zL6WTDw14x41%?S8?Cd(Yt^?lLe0>R8SJM9Lrv(ZVW9^6ruK}KBYxj^RFKcXV+oy7# zT=elt#1}DoXVkBKSU@QSn1BR=G{9?u*T8j~EWg{NxK`^adLa^N;76PdTYmZNW0V>K zl?E#dNdcqdB~MUEVd+7Z?6qu!BZLu&sHoG0xhc|?1)@OGOh0b&^!1EfY8j&Z=dDr^#hUpye=@5gb>8D6|e5$TVOiGt`G*q;ZY{XP$;u zKa!EnbL_~oh*mZ~eTm|>Q>B-yQ@D}kW@8+1gHNTtgIFjy$U`N?A*rgDmx44Ra9lQn23uFTKIpQ a3%>wWsU0$F2G`~Q0000b=s6owRz|J86KOi${ zVvpOAafcGlcNL1INZKaQ3GS+015cAqO+(vZW>Rom4WiIGC?L~->B+?T2?qi*DiQASsq0S0s|~)E#QT>?hOu7a7fypp~6EwOXC(QH%AZ9DFZ> zrx8;T?9ihL2gm^JX=;Zp(o+(6&_M%*e3sOB1AXj(w~Id3U?{NS=vIf_Z%!oP&^zo= z7%RQ62Fi4^tGEk~AeCq^1hL|XD9WE5bh{P#FP^W{i1;7hER($x7D6XDfOoQvNE{4B z?a(2&RKj)LKOh8b+xClV56Iq7U5iGpDzHpM6c|FS?vPvA#yxU|#=Thc7V+oqrJ28- zAe)LKN}FM`}`#t&bMFFREb0j<%V9!dIt<3xIXvET!2Zx&_1m^Li?OJ2zki5<*P@r`Jo6}=wLTW**ni6WV!;o;e*dTgMEQmoP&g_rqf$1^ n79z5>jY`=l49mzR{t12p;Pf)`V)Z1N00000NkvXXu0mjfg@9lS literal 0 HcmV?d00001 diff --git a/plugins/rearranger/src/com/wrq/rearranger/ShowParamTypes.png b/plugins/rearranger/src/com/wrq/rearranger/ShowParamTypes.png new file mode 100644 index 0000000000000000000000000000000000000000..474a783ed31e34db34d50e035a18e1f98ac42570 GIT binary patch literal 752 zcmVXx!Q@#i1>9Fm9F((n;zfs362eLWhzr z;%Ed1mqIHD$xvv93bzz;Lm?Rg`M`s7xLi$>OOx78(*Jb4d++~$|L?u~4z6&?i2X~E zJ)ZRM-m$?j!Gp@agX=or4d*+TpnWsxzj=`(H#^gbXz&`~Y4-N(Jbztg???4a&QmXa z@M8m-n0_$rmp`telmbjZ0zn$!HNk7(x=l7d>{8e&4-~!D8)$&v=WN{eOYfecR032I z>=al6Mpu$2C`(v>k|K30)yEOS=nbd{r>iUTByAf+fh1XY`iiMZ#X-#>Zo$UdGRmj| zE@HxZF3rNrnjbaOK8GPbhfYQOxku?>L5%Pi+a$+@(%U@gRGf|XMX<97z;BqIFtNw% zNZx^h^Bsp`DU!Acw1Zi-s^DqTsVQhV%uEQ5t3ec62Mc5xFg1}FU9f*~+JQ4qLn|P4 z4iCUEsUJ5;SacRg2Zv$_a$OAM@`n3vhb?}o<>YX zP@#tl_K5-7(^LY+n+ zsfg>k7Z3z&+x81QMYzqp(#5tw+C0&x7pjv>*O0zVB2(1hhtbdZ_6CjZ@Zhi}}7=etWYJ%Pr>p z?ae~0J1>k!<@UygcF|juTg>}mtoOOMCaURf4FB-Ex(vyB-JaFpNEnnHMLcS4h`t~2 iWuRMhq#0h}BKQMVAS9@r`zU7s0000rU?#YE!v@0yA9nX#JkJIHY`${|+E+5c>!*40MJ& zo)`=uNOehK{ngV7A!B$ zq6`P{5EGX2Ii{aigQPu;IgC(_oQedK_i|x@7|}8|$qWj`H}mAOX_i-3!Ja?>e!|F* ziGA5l=#b!g8bqOWSU{!$!$SkT3&snl89MVd zG(uAMU>^*VqaQT}ELw%5!$q+KxhRQ(C-zVSW~Z3ezs0B>lUBY~ahxiw4{ABuBAd1D)AXA`l~h$xC*Ty&$Jcouu>G$O(0m08AaM}^P~6Y!765lMrg za1LB1W>)b$?+*k4+qQ$k;(f-ht5!rKmlRkgA_@$_sk%(emGBPTuDs`K-Xg)|-5gW5 z1{lkx5v3q4xJR(MQKhh60j+!QrRTxK_(%}l7L|?7zIpy}QSXwKjx+Q!f*uIRNS+*z8EveF4A(a&C eH}U`I3BLda8y-5g2a*5)0000?Co~wk~EV6bGq- z($OwL-HekNgl2HKC6EJ$+)%g&J~)TF#w|4PP5|{ALTZI@WGzLVG$NRUbcKabX?|Kr7H8XsG@0SlN6>?c3g|NC%AE zD{i#&s)A)%AQDe%Kn0*;;^0@n>ib=)Z?}dfJ=dpf%89n0J;fTgV9JS~@kv0%8;tm6 z2~@7RH6a%R)~*-9kfBJ8&OowObSuf3@3*OJY-5cH zp4Xy$x5)12@9cXm9+s|hc>)ML<{cZ`p2Tl@iIdp~RnH(tC|C7NpF+vzuqSd|HEq95 zxm2Wb+huKYo8_AYDmUhM{bmPj2hkw{%uPFkGE_a&A?O<)4khS2!w z;XZke-}Hv=G)EhVL`w?=ikI>fF2s#M1R6oe)|VR9k2|P?;B0zn9}I~^1j*)52W^yA kpicj%7-57FM)*JY15%pf$h+8>j{pDw07*qoM6N<$f{Gg?OaK4? literal 0 HcmV?d00001 diff --git a/plugins/rearranger/src/com/wrq/rearranger/StaticClassInitializer.png b/plugins/rearranger/src/com/wrq/rearranger/StaticClassInitializer.png new file mode 100644 index 0000000000000000000000000000000000000000..dad14aa70729dc3ba0aea87585229145eec6430a GIT binary patch literal 783 zcmV+q1MvKbP)Hj58<~|B4DF^V3eql`oro?35nM<_+l`2?jSC|Y zD}oB5*s9R9(Sj&GyC@aXhSvB@%p_uxNv<<@<~}|bn#ZWwx$vz1{NemK=i|UflJcR? zlG1Ydtf3Jz5+`eq(%bzP*~|+9-%}9et+VK@PX#3ARLS>ScJRg8^+Y03@~)7{3qzwe z_wU~1>hS~eM7c2u7za*GR9Uk^_MJFQU2Qd{rl2X1_k>|b$T-5wTtMH85n5Nz{!lMP z8L!g*>kXDQR8tmJ2rCMitY8;}f(LE@L%D$TSe~c-gY5pYYO>nfL^?pr_C3_sR+ES* zRH!QdJnN_Jr;GIVr7=yDwarbWQp?E})He`7H%#$xn1C5pOitc?CijOt83_Uzv9r>$ zZLgf|xFx+~zMQ?)BVTX$LAo9f$nEE@wBH$&AAjkR^2%D7+D?s>mJ?0P!uKKbO6dHv zn|QpG=B5k5{pkRBKzY?`tIoR193~m3TgOg6g+UefSluU{_s9J4^_Ok#c|lgvdiW!ly7$(VSY^w zrmmu^8fwTw6qT`28+$avm6OM~c4Y4KiN34J~P^Y`^m zZeDC-&Voj|F0CnoOe@_mB|0-HGiJ}1=**-TR;*}z3s*MFbly)#uK~&> 1; + constraints.gridwidth = (i % 2 == 1) ? + GridBagConstraints.REMAINDER : 1; + constraints.weightx = (i % 2 == 1) ? 1 : 0; + add(buttons[i], constraints); + choices[i].editingObject = choices[i].choiceObject.deepCopy(); + panels[i] = choices[i].createJPanel(); + /** + * calculate largest dimension of any of the replaceable panels. + */ + final Dimension dimension = panels[i].getPreferredSize(); + if (dimension.height > max.height) max.height = dimension.height; + if (dimension.width > max.width) max.width = dimension.width; + } + buttons[choice].setSelected(true); + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.gridwidth = 2; + constraints.weighty = 1; + constraints.gridx = 0; + constraints.gridy = (choices.length >> 1) + 1; + for (int i = 0; i < choices.length; i++) { + final int j = i; + panels[i].setPreferredSize(max); + buttons[i].addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + if (buttons[j].isSelected()) { + remove(choices.length); + add(panels[j], constraints); + panels[j].invalidate(); + panels[j].repaint(); + validate(); + choice = j; + } + } + }); + } + final JPanel beginning_panel = panels[choice]; + add(beginning_panel, constraints); + } + + void copyChoices(final ChoicePanel currentMsg) { + System.arraycopy(currentMsg.choices, 0, choices, 0, choices.length); + choice = currentMsg.choice; + } + + void acceptEdited() { + for (ChoiceObject choice1 : choices) { + choice1.acceptEdited(); + } + } + + ChoiceObject getChoice() { + return choices[choice]; + } + + public ChoiceObject[] getChoices() { + return choices; + } + + public void setChoice(int choice) { + this.choice = choice; + } + + public String getChoicePanelName() { + return choicePanelName; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/ClassMemberSettingsPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/ClassMemberSettingsPane.java new file mode 100644 index 000000000000..682961995469 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/ClassMemberSettingsPane.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.FieldAttributes; +import com.wrq.rearranger.settings.attributeGroups.InnerClassAttributes; +import com.wrq.rearranger.settings.attributeGroups.InterfaceAttributes; +import com.wrq.rearranger.settings.attributeGroups.MethodAttributes; + +import javax.swing.*; + +/** UI code for Class Member (field, method, inner class) dialog. */ +final class ClassMemberSettingsPane + extends SettingsPane +{ +// --------------------------- CONSTRUCTORS --------------------------- + + ClassMemberSettingsPane(final RearrangerSettings settings) { + super(settings, settings.getItemOrderAttributeList()); + } + +// -------------------------- OTHER METHODS -------------------------- + + ChoicePanel createChoicePanel() { + final ChoiceObject[] choices = new ChoiceObject[5]; + int index = 0; + choices[index++] = new ChoiceObject("Field") { + void createObject() { + choiceObject = new FieldAttributes(); + } + + JPanel createJPanel() { + return ((FieldAttributes)editingObject).getFieldAttributes(); + } + }; + choices[index++] = new ChoiceObject("Method") { + void createObject() { + choiceObject = new MethodAttributes(settings.getDefaultGSDefinition()); + } + + JPanel createJPanel() { + return ((MethodAttributes)editingObject).getMethodAttributes(); + } + }; + choices[index++] = new ChoiceObject("Interface Methods") { + void createObject() { + choiceObject = new InterfaceAttributes(); + } + + JPanel createJPanel() { + return ((InterfaceAttributes)editingObject).getInterfaceAttributes(); + } + }; + choices[index++] = new ChoiceObject("Inner Class") { + void createObject() { + choiceObject = new InnerClassAttributes(); + } + + JPanel createJPanel() { + return ((InnerClassAttributes)editingObject).getInnerClassAttributes(); + } + }; + choices[index++] = new ChoiceObject("Separator Comment") { + void createObject() { + choiceObject = new CommentRule(); + } + + JPanel createJPanel() { + return ((CommentRule)editingObject).getCommentPanel(); + } + }; + return new ChoicePanel(choices, "Class Member Order"); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/ClassOrderSettingsPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/ClassOrderSettingsPane.java new file mode 100644 index 000000000000..e1152f0b94a3 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/ClassOrderSettingsPane.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.ClassAttributes; + +import javax.swing.*; + +/** UI code for Outer Class order dialog. */ +final class ClassOrderSettingsPane + extends SettingsPane +{ +// --------------------------- CONSTRUCTORS --------------------------- + + public ClassOrderSettingsPane(final RearrangerSettings settings) { + super(settings, settings.getClassOrderAttributeList()); + } + +// -------------------------- OTHER METHODS -------------------------- + + ChoicePanel createChoicePanel() { + final ChoiceObject[] choices = new ChoiceObject[2]; + choices[0] = new ChoiceObject("Class") { + void createObject() { + choiceObject = new ClassAttributes(); + } + + JPanel createJPanel() { + return ((ClassAttributes)editingObject).getClassAttributesPanel(); + } + }; + choices[1] = new ChoiceObject("Separator Comment") { + void createObject() { + choiceObject = new CommentRule(); + } + + JPanel createJPanel() { + return ((CommentRule)editingObject).getCommentPanel(); + } + }; + final ChoicePanel panel = new ChoicePanel(choices, "Outer Class Order"); + return panel; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/ExtractedMethodsPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/ExtractedMethodsPane.java new file mode 100644 index 000000000000..f97308afec0c --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/ExtractedMethodsPane.java @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RelatedMethodsSettings; +import com.wrq.rearranger.util.Constraints; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.TitledBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** Configuration settings for handling ordering of extracted methods. */ +public class ExtractedMethodsPane { +// --------------------------- main() method --------------------------- + + +// ---------- START Level 1 ---------- + + +// ---------- START Level 2 ---------- + + JPanel getExtractedMethodsPane(final RelatedMethodsSettings rms) { + final JPanel containerPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + final JTabbedPane pane = new JTabbedPane(); + final JPanel relatedMethodsArrangementPane = getExtractedMethodsArrangementPane(rms); + final JPanel relatedMethodsCommentsPane = getRelatedMethodsCommentsPane(rms); + pane.addTab("Arrangement", null, relatedMethodsArrangementPane, + "Options controlling arrangement of extracted methods"); + pane.addTab("Comments", null, relatedMethodsCommentsPane, + "Extracted method comments"); + pane.setSelectedIndex(0); + containerPanel.add(pane, constraints.weightedLastCol()); + return containerPanel; + } + +// ---------- START Level 3 ---------- + + + private JPanel getExtractedMethodsArrangementPane(final RelatedMethodsSettings rms) { + final JPanel pane = new JPanel(new GridBagLayout()); + final JPanel innerPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + final TitledBorder tb = new TitledBorder(border, "Options controlling arrangement of extracted methods"); + innerPanel.setBorder(tb); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + JPanel traversalOrderPanel = getTraversalOrderPanel(rms); + JPanel orderingPanel = getOrderingPanel(rms); + JPanel extractedPanel = getExtractedPanel(rms); + innerPanel.add(getMoveMethodsPanel(rms, new JPanel[]{traversalOrderPanel, orderingPanel, extractedPanel}), + constraints.weightedLastCol()); + constraints.newRow(); + constraints.insets = new Insets(0, 20, 0, 0); + innerPanel.add(traversalOrderPanel, constraints.weightedLastCol()); + constraints.newRow(); + innerPanel.add(orderingPanel, constraints.weightedLastCol()); + constraints.weightedLastRow(); + innerPanel.add(extractedPanel, constraints); + Dimension d = innerPanel.getPreferredSize(); + innerPanel.setPreferredSize(d); + innerPanel.setMaximumSize(d); + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = constraints.gridy = 0; + pane.add(innerPanel, constraints); + return pane; + } + +// ---------- START Level 4 ---------- + + + JPanel getTraversalOrderPanel(final RelatedMethodsSettings rms) { + final JPanel traversalOrderPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + { + constraints.insets = new Insets(5, 5, 5, 0); + JLabel performLabel = new JLabel("Perform"); + traversalOrderPanel.add(performLabel, constraints.firstCol()); + } + { + final JComboBox traversalOrderBox = new JComboBox(new String[]{"depth first", "breadth first"}); + traversalOrderPanel.add(traversalOrderBox, constraints.nextCol()); + traversalOrderBox.setSelectedIndex(1); + Dimension d = traversalOrderBox.getPreferredSize(); + d.width += 3; + traversalOrderBox.setPreferredSize(d); + traversalOrderBox.setSelectedIndex(rms.isDepthFirstOrdering() ? 0 : 1); + traversalOrderBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + rms.setDepthFirstOrdering(traversalOrderBox.getSelectedIndex() == 0); + } + }); + } + { + JLabel remainderLabel = new JLabel("ordering on nested method calls"); + traversalOrderPanel.add(remainderLabel, constraints.lastCol()); + } + return traversalOrderPanel; + } + + JPanel getOrderingPanel(final RelatedMethodsSettings rms) { + final JPanel orderingPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + final TitledBorder tb = new TitledBorder(border, "Ordering options"); + orderingPanel.setBorder(tb); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + final JRadioButton invocationButton = new JRadioButton("Place in order of invocation"); + final JRadioButton originalButton = new JRadioButton("Retain original order"); + final JRadioButton alphabetizeButton = new JRadioButton("Alphabetize"); + ButtonGroup group = new ButtonGroup(); + group.add(invocationButton); + group.add(originalButton); + group.add(alphabetizeButton); + orderingPanel.add(invocationButton, constraints.weightedLastCol()); + constraints.newRow(); + orderingPanel.add(originalButton, constraints.weightedLastCol()); + constraints.weightedLastRow(); + orderingPanel.add(alphabetizeButton, constraints.weightedLastCol()); + switch (rms.getOrdering()) { + case RelatedMethodsSettings.INVOCATION_ORDER: + invocationButton.setSelected(true); + break; + case RelatedMethodsSettings.RETAIN_ORIGINAL_ORDER: + originalButton.setSelected(true); + break; + case RelatedMethodsSettings.ALPHABETICAL_ORDER: + alphabetizeButton.setSelected(true); + break; + } + + invocationButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (invocationButton.isSelected()) { + rms.setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); + } + } + }); + + originalButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (originalButton.isSelected()) { + rms.setOrdering(RelatedMethodsSettings.RETAIN_ORIGINAL_ORDER); + } + } + }); + + alphabetizeButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (alphabetizeButton.isSelected()) { + rms.setOrdering(RelatedMethodsSettings.ALPHABETICAL_ORDER); + } + } + }); + return orderingPanel; + } + + JPanel getExtractedPanel(final RelatedMethodsSettings rms) { + final JPanel extractedPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.insets = new Insets(5, 5, 5, 0); + JLabel label = new JLabel("Consider a non-private method as an extracted method:"); + extractedPanel.add(label, constraints.weightedLastCol()); + constraints.insets = new Insets(0, 15, 0, 0); + final JRadioButton neverButton = new JRadioButton("never"); + constraints.newRow(); + extractedPanel.add(neverButton, constraints.weightedLastCol()); + final JRadioButton oneButton = new JRadioButton("when it is called by only one method in the class"); + constraints.newRow(); + extractedPanel.add(oneButton, constraints.weightedLastCol()); + final JRadioButton moreButton = new JRadioButton("when it has one or more callers in the class"); + constraints.weightedLastRow(); + extractedPanel.add(moreButton, constraints.weightedLastCol()); + ButtonGroup g = new ButtonGroup(); + g.add(neverButton); + g.add(oneButton); + g.add(moreButton); + switch (rms.getNonPrivateTreatment()) { + case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_NEVER: + neverButton.setSelected(true); + break; + case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ONE_CALLER: + oneButton.setSelected(true); + break; + case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ANY_CALLERS: + moreButton.setSelected(true); + break; + } + neverButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (neverButton.isSelected()) { + rms.setNonPrivateTreatment(RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_NEVER); + } + } + }); + oneButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (oneButton.isSelected()) { + rms.setNonPrivateTreatment(RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ONE_CALLER); + } + } + }); + moreButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (moreButton.isSelected()) { + rms.setNonPrivateTreatment(RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ANY_CALLERS); + } + } + }); + return extractedPanel; + } + + JPanel getMoveMethodsPanel(final RelatedMethodsSettings rms, final JPanel[] dependentPanels) { + final JPanel moveMethodsPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.weightedLastRow(); + { + constraints.insets = new Insets(5, 5, 5, 0); + final JCheckBox moveBox = new JCheckBox("Move extracted methods below"); + moveBox.setSelected(rms.isMoveExtractedMethods()); + moveBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + rms.setMoveExtractedMethods(moveBox.isSelected()); + enableComponents(moveMethodsPanel, moveBox.isSelected()); + enableOtherComponents(dependentPanels, moveBox.isSelected()); + } + }); + moveMethodsPanel.add(moveBox, constraints.firstCol()); + } + { + final JComboBox firstLastBox = new JComboBox(new String[]{"first", "last"}); + firstLastBox.setSelectedIndex(0); + Dimension d = firstLastBox.getPreferredSize(); + d.width += 3; + firstLastBox.setPreferredSize(d); + firstLastBox.setSelectedIndex(rms.isBelowFirstCaller() ? 0 : 1); + firstLastBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + rms.setBelowFirstCaller(firstLastBox.getSelectedIndex() == 0); + } + }); + moveMethodsPanel.add(firstLastBox, constraints.nextCol()); + } + { + constraints.insets = new Insets(8, 5, 5, 0); + JLabel usageLabel = new JLabel("usage"); + moveMethodsPanel.add(usageLabel, constraints.weightedLastCol()); + } + enableComponents(moveMethodsPanel, rms.isMoveExtractedMethods()); + enableOtherComponents(dependentPanels, rms.isMoveExtractedMethods()); + return moveMethodsPanel; + } + +// ---------- START Level 5 ---------- + + + private void enableComponents(JPanel pane, boolean selected) { + for (int i = 1; i < pane.getComponents().length; i++) { + pane.getComponents()[i].setEnabled(selected); + } + } + + private void enableOtherComponents(JPanel[] otherPanels, boolean selected) { + for (JPanel otherPanel : otherPanels) { + enablePanel(otherPanel, selected); + } + } + +// ---------- START Level 6 ---------- + + + private void enablePanel(JPanel otherPanel, boolean selected) { + for (int i = 0; i < otherPanel.getComponents().length; i++) { + Component c = otherPanel.getComponents()[i]; + if (c instanceof JPanel) { + enablePanel((JPanel)c, selected); + } + else { + c.setEnabled(selected); + } + } + } + +// ---------- END Level 6 ---------- + + +// ---------- END Level 5 ---------- + + +// ---------- END Level 4 ---------- + + + private JPanel getRelatedMethodsCommentsPane(final RelatedMethodsSettings rms) { + JPanel rmcPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0.0d; + constraints.weighty = 0.0d; + JLabel commentTypeLabel = new JLabel("Emit comment at"); + final JComboBox commentType = new JComboBox(new String[]{ + "top level", + "each level", + "each method", + "family change (up level, or next sibling has children)" + }); + commentType.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + rms.setCommentType(commentType.getSelectedIndex()); + } + }); + commentType.setSelectedIndex(rms.getCommentType()); + JLabel legendLabel = new JLabel("Comment Substitutions: use"); + JLabel legendLabel_1 = new JLabel("%TL% for top level method"); + JLabel legendLabel_2 = new JLabel("%MN% for method name"); + JLabel legendLabel_4 = new JLabel("%LV% for level number"); + JLabel legendLabel_3 = new JLabel("%AM% for all method names"); + JLabel precedingCommentLabel = new JLabel("Preceding Comment:"); + JLabel trailingCommentLabel = new JLabel("Trailing Comment:"); + JPanel precedingCommentPanel = getCommentAreaPanel(rms.getPrecedingComment()); + JPanel trailingCommentPanel = getCommentAreaPanel(rms.getTrailingComment()); + constraints.insets = new Insets(3, 5, 0, 0); + rmcPanel.add(commentTypeLabel, constraints.firstCol()); + rmcPanel.add(commentType, constraints.lastCol()); + JPanel legendPanel = new JPanel(new GridBagLayout()); + { + final Border border = BorderFactory.createEtchedBorder(); + legendPanel.setBorder(border); + final Constraints legendConstraints = new Constraints(GridBagConstraints.NORTHWEST); + legendConstraints.fill = GridBagConstraints.BOTH; + + legendConstraints.insets = new Insets(5, 5, 0, 0); + legendPanel.add(legendLabel, legendConstraints.firstCol()); + legendConstraints.insets = new Insets(5, 5, 0, 5); + legendPanel.add(legendLabel_1, legendConstraints.nextCol()); + legendPanel.add(legendLabel_2, legendConstraints.lastCol()); + legendConstraints.newRow(); + legendConstraints.firstCol(); // skip first column + legendConstraints.insets = new Insets(5, 5, 5, 5); + legendPanel.add(legendLabel_3, legendConstraints.nextCol()); + legendPanel.add(legendLabel_4, legendConstraints.lastCol()); + } + constraints.newRow(); + constraints.insets = new Insets(5, 5, 0, 5); + rmcPanel.add(legendPanel, constraints.weightedLastCol()); + constraints.newRow(); + rmcPanel.add(precedingCommentLabel, constraints.weightedLastCol()); + constraints.weightedNewRow(0.50d); + rmcPanel.add(precedingCommentPanel, constraints.weightedLastCol()); + constraints.newRow(); + rmcPanel.add(trailingCommentLabel, constraints.weightedLastCol()); + constraints.weightedNewRow(0.50d); + constraints.insets = new Insets(5, 5, 5, 5); + rmcPanel.add(trailingCommentPanel, constraints.weightedLastCol()); + constraints.lastRow(); + rmcPanel.add(rms.getCommentFillString().getCommentFillStringPanel(), constraints.weightedLastCol()); + return rmcPanel; + } + +// ---------- START Level 4 ---------- + + + private JPanel getCommentAreaPanel(final CommentRule comment) { + JPanel commentPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + final JTextArea commentArea = new JTextArea(4, 40); + commentArea.setText(comment.getCommentText()); + final JScrollPane scrollPane = new JScrollPane(commentArea); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + commentPanel.add(scrollPane, constraints.weightedFirstCol()); + commentArea.getDocument().addDocumentListener(new DocumentListener() { + public void changedUpdate(final DocumentEvent e) { + comment.setCommentText(commentArea.getText()); + } + + public void insertUpdate(final DocumentEvent e) { + comment.setCommentText(commentArea.getText()); + } + + public void removeUpdate(final DocumentEvent e) { + comment.setCommentText(commentArea.getText()); + } + }); + return commentPanel; + } + +// ---------- END Level 4 ---------- + + +// ---------- END Level 3 ---------- + + +// ---------- END Level 2 ---------- + + +// ---------- END Level 1 ---------- +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObject.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObject.java new file mode 100644 index 000000000000..2b2b56bd288b --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObject.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import javax.swing.*; + +/** Describes objects that can be handled by ListManager. */ +public interface IListManagerObject { + String getDescription(); + + void setDescription(String description); + + JPanel getPanel(); + + IListManagerObject deepcopy(); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObjectFactory.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObjectFactory.java new file mode 100644 index 000000000000..1324f3f2611d --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/IListManagerObjectFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import java.util.List; + +/** Handles creation and removal of list manager objects. */ +public interface IListManagerObjectFactory { + IListManagerObject create(String name); + + List getObjectList(); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/IntTextField.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/IntTextField.java new file mode 100644 index 000000000000..82eabd895268 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/IntTextField.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.DefaultFormatterFactory; +import javax.swing.text.NumberFormatter; +import java.awt.*; +import java.text.NumberFormat; + +/** + * A JTextField tied to a numeric field. Initialize the JTextField from the field and update + * the field whenever the JTextField's text changes. + */ +public class IntTextField + extends JFormattedTextField +{ + public interface IGetSet { + public int get(); + + public void set(int value); + } + + public IntTextField(final IGetSet getset, final Integer minimum, final Integer maximum) { + final NumberFormat integerInstance = NumberFormat.getIntegerInstance(); + int maxDigits = 2; + if (maximum != null && (maximum) > 99) { + maxDigits = maximum.toString().length(); + } + integerInstance.setMaximumIntegerDigits(maxDigits); + integerInstance.setMinimumIntegerDigits(1); + setFormatterFactory(new DefaultFormatterFactory(new NumberFormatter(integerInstance))); + setValue(maximum != null ? maximum : new Integer("88")); + final Dimension d = getPreferredSize(); + d.width += 3; + setPreferredSize(d); + setValue(getset.get()); + setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT); + setText("" + getValue()); + getDocument().addDocumentListener(new DocumentListener() { + private void setit() { + try { + // allow empty string, else must be valid number + if (getText().length() != 0) { + int value = Integer.parseInt(getText()); + if (minimum != null) { + if (value < (minimum)) value = (minimum); + } + if (maximum != null) { + if (value > (maximum)) value = (maximum); + } + getset.set(value); + } + } + catch (NumberFormatException e) { + // leave value alone + } + } + + public void insertUpdate(DocumentEvent e) { + setit(); + } + + public void removeUpdate(DocumentEvent e) { + setit(); + } + + public void changedUpdate(DocumentEvent e) { + setit(); + } + }); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/ListManager.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/ListManager.java new file mode 100644 index 000000000000..9ea313d9a573 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/ListManager.java @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.util.IconUtil; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Generic manager for a panel with a list combo box, add/delete/copy buttons, + * a name field, and a subpanel to get contents of current item. + */ +public class ListManager + extends JPanel +{ + JLabel nameLabel; + JTextField name; + JButton addButton; + JButton removeButton; + JButton copyButton; + JList list; + GridBagConstraints constraints; + final IListManagerObjectFactory factory; + IListManagerObject currentObject; + boolean buttonPressInProgress; + + private JButton makeButton(String iconName) { + Icon icon = IconUtil.getIcon(iconName); + JButton result = new JButton(icon); + result.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight())); + return result; + } + + public ListManager(final IListManagerObjectFactory factory, String nameLabelText) { + super(new GridBagLayout()); + this.factory = factory; + currentObject = null; + nameLabel = new JLabel(nameLabelText); + name = new JTextField(3); + addButton = makeButton("general/add"); + removeButton = makeButton("general/remove"); + copyButton = makeButton("general/copy"); + list = new JList(new DefaultListModel()); + /** + * declare callback handlers for buttons. + */ + addButton.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + buttonPressInProgress = true; + currentObject = factory.create(getUniqueName("unnamed")); + factory.getObjectList().add(currentObject); + ((DefaultListModel)list.getModel()).addElement(currentObject); + list.setSelectedIndex(list.getModel().getSize() - 1); + updateListSelection(); + buttonPressInProgress = false; + } + } + ); + removeButton.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + buttonPressInProgress = true; + DefaultListModel dlm = ((DefaultListModel)list.getModel()); + int selectedIndex = list.getSelectedIndex(); + IListManagerObject lmo = (IListManagerObject)dlm.getElementAt(selectedIndex); + factory.getObjectList().remove(lmo); + dlm.remove(selectedIndex); + if (selectedIndex >= dlm.getSize()) { + selectedIndex = dlm.getSize() - 1; + } + list.setSelectedIndex(selectedIndex); + currentObject = + (IListManagerObject)(selectedIndex < 0 ? null : dlm.getElementAt(selectedIndex)); + updateListSelection(); + buttonPressInProgress = false; + } + } + ); + copyButton.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + buttonPressInProgress = true; + DefaultListModel dlm = ((DefaultListModel)list.getModel()); + int selectedIndex = list.getSelectedIndex(); + IListManagerObject lmo = (IListManagerObject)dlm.getElementAt(selectedIndex); + currentObject = lmo.deepcopy(); + currentObject.setDescription(getUniqueName(lmo.getDescription())); + dlm.addElement(currentObject); + list.setSelectedIndex(list.getModel().getSize() - 1); + updateListSelection(); + buttonPressInProgress = false; + } + } + ); + name.getDocument().addDocumentListener( + new DocumentListener() { + private void updateList() { + if (buttonPressInProgress) { + return; + } + String newText = name.getText(); + final IListManagerObject listObject = (IListManagerObject)list.getSelectedValue(); + if (listObject != null) { + listObject.setDescription(newText); + } + int index = list.getSelectedIndex(); + DefaultListModel dlm = ((DefaultListModel)list.getModel()); + dlm.setElementAt(listObject, index); + validate(); + } + + public void changedUpdate(DocumentEvent e) { + updateList(); + } + + public void insertUpdate(DocumentEvent e) { + updateList(); + } + + public void removeUpdate(DocumentEvent e) { + updateList(); + } + } + ); + list.addListSelectionListener( + new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if (buttonPressInProgress) { + return; // list selection changes due to add/remove/copy button handled elsewhere + } + buttonPressInProgress = true; + int selectedIndex = list.getSelectedIndex(); + DefaultListModel dlm = ((DefaultListModel)list.getModel()); + currentObject = + (IListManagerObject)(selectedIndex < 0 ? null : ((java.lang.Object)dlm.getElementAt(selectedIndex))); + updateListSelection(); + buttonPressInProgress = false; + } + } + ); + } + + public final JPanel getPane() { + constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = 1; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.weightx = 0.0d; + constraints.weighty = 0.0d; + constraints.gridy = constraints.gridx = 0; + constraints.insets = new Insets(0, 0, 0, 5); + JPanel buttonPanel = new JPanel(new GridBagLayout()); + buttonPanel.setBorder(BorderFactory.createEtchedBorder()); // todo remove + addButton.setBorderPainted(false); + removeButton.setBorderPainted(false); + copyButton.setBorderPainted(false); + buttonPanel.add(addButton, constraints); + constraints.gridx++; + buttonPanel.add(removeButton, constraints); + constraints.gridx++; +// constraints.gridwidth = GridBagConstraints.REMAINDER; +// constraints.weightx = 1; + buttonPanel.add(copyButton, constraints); + + constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0.0d; + constraints.weighty = 0.0d; + constraints.gridy = constraints.gridx = 0; + constraints.insets = new Insets(3, 3, 3, 3); + add(buttonPanel, constraints); + buttonPanel.setPreferredSize(buttonPanel.getPreferredSize()); // todo determine effect if any + constraints.gridx++; + add(nameLabel, constraints); + constraints.gridx++; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1; + constraints.fill = GridBagConstraints.HORIZONTAL; + add(name, constraints); + + + list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); +// addButton.setEnabled(true); + JScrollPane scrollPane = new JScrollPane(list); + Dimension d = buttonPanel.getPreferredSize(); + d.width = d.width * 5 / 3; + scrollPane.setPreferredSize(d); + scrollPane.setMinimumSize(d); + for (Object object : factory.getObjectList()) { + ((DefaultListModel)list.getModel()).addElement(object); + } + list.setSelectedIndex(list.getModel().getSize() - 1); + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.gridwidth = 1; + constraints.gridx = 0; + constraints.gridy++; + constraints.weightx = 0; + constraints.weighty = 0; + constraints.fill = GridBagConstraints.VERTICAL; + add(scrollPane, constraints); + constraints.gridx++; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1; + constraints.weighty = 1; + final JPanel contents = new JPanel(); + contents.setBorder(BorderFactory.createEtchedBorder()); // todo remove + add(contents, constraints); + updateListSelection(); + validate(); + return this; + } + + /** + * Enable add/remove/copy buttons and fill in name of selected list item. Called whenever + * the list selection changes. + */ + private void updateListSelection() { + if (list.getModel().getSize() > 0) { + name.setEnabled(true); + nameLabel.setEnabled(true); + name.setText(((IListManagerObject)list.getSelectedValue()).getDescription()); + removeButton.setEnabled(true); + copyButton.setEnabled(true); + } + else { + name.setEnabled(false); + nameLabel.setEnabled(false); + removeButton.setEnabled(false); + copyButton.setEnabled(false); + name.setText(""); + } + remove(getComponentCount() - 1); + final JPanel contents = new JPanel(); + contents.setBorder(BorderFactory.createEtchedBorder()); // todo remove + add(currentObject == null ? contents : ((javax.swing.JPanel)currentObject.getPanel()), constraints); + validate(); + } + + public String getUniqueName(String name) { + String result; + if (name != null) { + // test initially supplied name; if not duplicate, return it. + if (!dupName(name)) { + return name; + } + } + result = (name == null) ? "unnamed" : name; + int suffix = 0; + String testName; + do { + suffix++; + testName = result + "_" + suffix; + } + while (dupName(testName)); + return testName; + } + + /** + * @param name + * @return true if the supplied name is identical to any other primary method name. + */ + public boolean dupName(String name) { + for (int i = 0; i < list.getModel().getSize(); i++) { + IListManagerObject lmo = (IListManagerObject)list.getModel().getElementAt(i); + if (lmo.getDescription().equals(name)) { + return true; + } + } + return false; //To change body of created methods use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/MethodSpec.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/MethodSpec.java new file mode 100644 index 000000000000..6ed83ca6a999 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/MethodSpec.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.intellij.ui.DocumentAdapter; +import com.wrq.rearranger.util.Constraints; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; +import java.text.NumberFormat; + +/** + * Getters and setters are defined by their method names (eg., beginning with "get"), number of parameters, + * return type, and body contents. This class provides support for these common rule attributes. + * Other attributes, like number of parameters or return type, are already specified in MethodAttributes. + */ +public class MethodSpec { + /** + * pattern for property name. Must contain one or more regular expression groups, one of which will be + * regarded as the property. Will be matched against the candidate method's name. + */ + String propertyPattern; + /** Group number which identifies which regex group contains the pattern. */ + int propertyGroup; + /** true if first letter of property should be lowercased. */ + boolean lowercaseFirstLetterOfProperty; + /** if true, the property name must match a field in the class, else the method will not match. */ + boolean propertyMustMatchField; + /** + * pattern of method body (excluding comments and newline characters). Substitutions will be performed + * in this pattern before matching against the method's body as follows: + *
+   * %PATTERN%        this method's pattern
+   * %TYPE%           this method's type
+   * %PARAMNAME%   name of parameter ,  = 1, 2, 3, ...
+   * $PARAMTYPE%   type of parameter ,  = 1, 2, 3, ...
+   * $PARENT%         parent's property
+   * 
+ */ + String body; + /** true if body matching should be done against method body stripped of comments. */ + boolean ignoreComments; + /** + * value of "parent property", which is the property of the field or method executing this rule. + * If this is the top level rule (not being called by another rule to associate methods matching this + * rule with the parent), then there is no parent property. + */ + final String parentProperty; + + public MethodSpec(String parentProperty) { + this.parentProperty = parentProperty; + } + + public String getPropertyPattern() { + return propertyPattern; + } + + public void setPropertyPattern(String propertyPattern) { + this.propertyPattern = propertyPattern; + } + + public int getPropertyGroup() { + return propertyGroup; + } + + public void setPropertyGroup(int propertyGroup) { + this.propertyGroup = propertyGroup; + } + + public boolean isLowercaseFirstLetterOfProperty() { + return lowercaseFirstLetterOfProperty; + } + + public void setLowercaseFirstLetterOfProperty(boolean lowercaseFirstLetterOfProperty) { + this.lowercaseFirstLetterOfProperty = lowercaseFirstLetterOfProperty; + } + + public boolean isPropertyMustMatchField() { + return propertyMustMatchField; + } + + public void setPropertyMustMatchField(boolean propertyMustMatchField) { + this.propertyMustMatchField = propertyMustMatchField; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public boolean isIgnoreComments() { + return ignoreComments; + } + + public void setIgnoreComments(boolean ignoreComments) { + this.ignoreComments = ignoreComments; + } + + boolean isMatch() { + return false; // todo + } + + private JFormattedTextField getIntField(int initialValue) { + final NumberFormat integerInstance = NumberFormat.getIntegerInstance(); + integerInstance.setMaximumIntegerDigits(2); + integerInstance.setMinimumIntegerDigits(1); + final JFormattedTextField intField = new JFormattedTextField(integerInstance); + intField.setValue(new Integer("88")); + final Dimension d = intField.getPreferredSize(); + d.width += 3; + intField.setPreferredSize(d); + intField.setValue(initialValue); + intField.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT); + return intField; + } + + public JPanel getPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + Constraints constraints = new Constraints(); + constraints.insets = new Insets(3, 3, 3, 3); + JLabel propertyPatternLabel = new JLabel("Property pattern:"); + propertyPatternLabel.setToolTipText("Regex pattern which method name must match; " + + "parenthesize portion which will be regarded as the method's property" + + ", e.g. \"(get|is|has)([A-Z]\\w*)\""); + panel.add(propertyPatternLabel, constraints.firstCol()); + constraints.fill = GridBagConstraints.HORIZONTAL; + final JTextField propertyPatternField = new JTextField(this.propertyPattern); + propertyPatternField.getDocument().addDocumentListener( + new DocumentAdapter() { + protected void textChanged(DocumentEvent event) { + propertyPattern = propertyPatternField.getText(); + } + } + ); + panel.add(propertyPatternField, constraints.weightedLastCol(0.5)); + constraints.newRow(); + constraints.fill = GridBagConstraints.NONE; + final JLabel propertyGroupLabel = new JLabel("Property group number:"); + propertyGroupLabel.setToolTipText("Regular expression parenthesized group corresponding to the property name"); + panel.add(propertyGroupLabel, constraints.firstCol()); + final JFormattedTextField propertyGroupField = getIntField(propertyGroup); + panel.add(propertyGroupField, constraints.nextCol()); + constraints.newRow(); + JCheckBox lowerCase = new JCheckBox("Lowercase first letter of property"); + lowerCase.setToolTipText("If selected, lower cases the first letter of the property found in the regular expression"); + panel.add(lowerCase, constraints.lastCol()); + constraints.newRow(); + JCheckBox mustMatch = new JCheckBox("Property must match field name"); + mustMatch.setToolTipText("If selected, the property name derived from the regular expression must match the " + + "name of a field in the same class as the method; if no such field exists, the " + + "method will not match the rule"); + panel.add(mustMatch, constraints.lastCol()); +// propertyGroupField.get + constraints.newRow(); + JLabel bodyLabel = new JLabel("Body:"); + bodyLabel.setToolTipText("Regex pattern for method body (excluding comments);\n" + + "use \"%FN%\" for field name, \"%P1%\" for param 1, etc."); + constraints.fill = GridBagConstraints.NONE; + panel.add(bodyLabel, constraints.firstCol()); + JCheckBox stripComments = new JCheckBox("Strip comments"); + stripComments.setToolTipText("If selected, comments will be stripped from the method body before attempting" + + " to match the supplied expression"); + panel.add(stripComments, constraints.lastCol()); + constraints.weightedLastRow(); + constraints.fill = GridBagConstraints.BOTH; + JTextArea body = new JTextArea(4, 40); + JScrollPane sp = new JScrollPane(body); + panel.add(sp, constraints.weightedLastCol()); + + return panel; + } + + public MethodSpec deepcopy() { + MethodSpec result = new MethodSpec(parentProperty); + result.body = body; + result.ignoreComments = ignoreComments; + result.lowercaseFirstLetterOfProperty = lowercaseFirstLetterOfProperty; + result.propertyGroup = propertyGroup; + result.propertyMustMatchField = propertyMustMatchField; + result.propertyPattern = propertyPattern; + result.body = body; + return result; + } + + public static void main(String[] args) { + MethodSpec ms = new MethodSpec(null); + final JDialog frame = new JDialog((Frame)null, "SwingApplication"); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1.0d; + constraints.weighty = 1.0d; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 0; + constraints.gridy = 0; + frame.getContentPane().setLayout(new GridBagLayout()); + frame.getContentPane().add(ms.getPanel(), constraints); + //Finish setting up the frame, and show it. + frame.pack(); + frame.setResizable(true); + frame.setModal(true); + frame.setVisible(true); + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/RearrangerSettingsPanel.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/RearrangerSettingsPanel.java new file mode 100644 index 000000000000..75a340fa150f --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/RearrangerSettingsPanel.java @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.Rearranger; +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; +import com.wrq.rearranger.settings.attributeGroups.RegexUtil; +import com.wrq.rearranger.util.CommentUtil; +import com.wrq.rearranger.util.Constraints; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.TitledBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.PatternSyntaxException; + +/** Code for top level configuration panel. */ +public final class RearrangerSettingsPanel + extends JPanel +{ +// ------------------------------ FIELDS ------------------------------ + + public RearrangerSettings settings; + +// --------------------------- CONSTRUCTORS --------------------------- + + // ---------- START Level 1 ---------- + public RearrangerSettingsPanel(final RearrangerSettings externalSettings) { + RearrangerSettings settings = externalSettings.deepCopy(); + setLayout(new GridBagLayout()); + createSettingsPanel(settings); + } + +// ---------- START Level 2 ---------- + + private void createSettingsPanel(RearrangerSettings settings) { + this.settings = settings; + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + while (getComponents().length > 0) { + remove(0); + } + add(getSettingsPanel(), constraints.weightedLastCol()); + validate(); + } + +// ---------- START Level 3 ---------- + + private JPanel getSettingsPanel() { + final JPanel containerPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + final JTabbedPane pane = new JTabbedPane(); + final SettingsPane classMemberSettingsPane = new ClassMemberSettingsPane(settings); + final SettingsPane classOrderSettingsPane = new ClassOrderSettingsPane(settings); + final SpacingPane spacingPane = new SpacingPane(settings); + final ExtractedMethodsPane extractedMethodsSettings = new ExtractedMethodsPane(); + final JPanel generalSettingsPane = getGeneralSettingsPane(); + final RelatedByNamePane rbnp = new RelatedByNamePane(settings.getExtractedMethodsSettings().getRbnms()); + pane.addTab( + "Class Member Order", + null, + classMemberSettingsPane.getPane(), + "Options controlling arrangement of fields, methods and inner classes" + ); + pane.addTab( + "Outer Class Order", + null, + classOrderSettingsPane.getPane(), + "Options controlling arrangement of outer classes" + ); + pane.addTab( + "Extracted Methods", + null, + extractedMethodsSettings.getExtractedMethodsPane(settings.getExtractedMethodsSettings()), + "Options controlling arrangement of extracted methods" + ); + pane.addTab( + "General", + null, + generalSettingsPane, + "General options" + ); + pane.addTab( + "Spacing", + null, + spacingPane.getPane(), + "Options controlling number of blank lines before and after braces" + ); + pane.addTab( + "Configuration", + null, + getConfigurationPane(), + "Load, save, clear configuration, or set to default" + ); +// pane.addTab("Related By Name", null, // todo - add when ready; replace "Extracted Methods" pane above +// rbnp.getPane(), "Global definitions for methods related by name (\"getters/setters\")"); + pane.setSelectedIndex(0); + containerPanel.add(pane, constraints.weightedLastCol()); + return containerPanel; + } + +// ---------- START Level 4 ---------- + + private JPanel getGeneralSettingsPane() { + final JPanel gsPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + gsPanel.setBorder(border); + final GridBagConstraints constraints = new GridBagConstraints(); + + constraints.fill = GridBagConstraints.BOTH; + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0; + constraints.weighty = 0; + constraints.gridx = constraints.gridy = 0; + constraints.insets = new Insets(5, 5, 0, 0); + final JCheckBox getterSetterBox = new JCheckBox("Keep getters/setters together"); + getterSetterBox.setSelected(settings.isKeepGettersSettersTogether()); + final JCheckBox gettersSettersWithPropertyBox = new JCheckBox("Keep getters/setters with property"); + gettersSettersWithPropertyBox.setSelected(settings.isKeepGettersSettersWithProperty()); + gettersSettersWithPropertyBox.setEnabled(settings.isKeepGettersSettersTogether()); + final JCheckBox overloadedMethodsBox = new JCheckBox("Keep overloaded methods/constructors together"); + overloadedMethodsBox.setSelected(settings.isKeepOverloadedMethodsTogether()); + final JLabel overloadOrderLabel = new JLabel("Ordering of constructors and overloaded methods:"); + final JComboBox overloadOrderBox = new JComboBox( + new String[]{ + "Retain original order", + "Order by number of parameters (ascending)", + "Order by number of parameters (descending)" + } + ); + overloadOrderLabel.setEnabled(settings.isKeepOverloadedMethodsTogether()); + overloadOrderBox.setEnabled(settings.isKeepOverloadedMethodsTogether()); + overloadOrderBox.setSelectedIndex(settings.getOverloadedOrder()); + overloadedMethodsBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + settings.setKeepOverloadedMethodsTogether(overloadedMethodsBox.isSelected()); + overloadOrderLabel.setEnabled(settings.isKeepOverloadedMethodsTogether()); + overloadOrderBox.setEnabled(settings.isKeepOverloadedMethodsTogether()); + } + } + ); + final JCheckBox confirmBox = new JCheckBox("Confirm before rearranging"); + confirmBox.setSelected(settings.isAskBeforeRearranging()); + confirmBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + settings.setAskBeforeRearranging(confirmBox.isSelected()); + } + } + ); + + final JCheckBox rearrangeInnerClasses = new JCheckBox("Rearrange contents of inner classes"); + rearrangeInnerClasses.setSelected(settings.isRearrangeInnerClasses()); + rearrangeInnerClasses.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + settings.setRearrangeInnerClasses(rearrangeInnerClasses.isSelected()); + } + }); + gsPanel.add(getterSetterBox, constraints); + constraints.gridy++; + gsPanel.add(gettersSettersWithPropertyBox, constraints); + constraints.gridy++; +// constraints.insets = new Insets(0, 0, 0, 0); + gsPanel.add(overloadedMethodsBox, constraints); + constraints.gridy++; + constraints.insets = new Insets(0, 30, 3, 0); + gsPanel.add(overloadOrderLabel, constraints); + constraints.gridy++; + constraints.insets = new Insets(0, 30, 10, 0); + constraints.fill = GridBagConstraints.NONE; + gsPanel.add(overloadOrderBox, constraints); + constraints.fill = GridBagConstraints.BOTH; + constraints.gridy++; + constraints.insets = new Insets(5, 5, 0, 0); + gsPanel.add(confirmBox, constraints); + constraints.gridy++; + gsPanel.add(rearrangeInnerClasses, constraints); + constraints.gridy++; + // + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1.0d; + constraints.weighty = 0.0d; + final JPanel gsDefaultPane = settings.getDefaultGSDefinition().getGSDefinitionPanel(); + constraints.insets = new Insets(5, 5, 0, 5); + constraints.gridx = 1; + int oldGridy = constraints.gridy; + constraints.gridheight = constraints.gridy; + constraints.gridy = 0; + Border b = gsDefaultPane.getBorder(); + TitledBorder tb = BorderFactory.createTitledBorder(b, "Default Getter/Setter Definition"); + gsDefaultPane.setBorder(tb); + gsPanel.add(gsDefaultPane, constraints); + constraints.gridy = oldGridy; + // + constraints.gridx = 0; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.gridy++; + constraints.weightx = 0; // was 1 + constraints.insets = new Insets(5, 5, 0, 0); + final JLabel commentLabel = new JLabel("Comment pattern:"); + final JButton createPatternButton = new JButton("Generate pattern"); + final JButton verifyCommentsButton = new JButton("Verify comments against pattern"); + gsPanel.add(commentLabel, constraints); + constraints.gridx++; + constraints.anchor = GridBagConstraints.NORTH; + gsPanel.add(createPatternButton, constraints); + constraints.anchor = GridBagConstraints.NORTHEAST; + constraints.gridx++; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1; // was 0 + constraints.insets = new Insets(5, 0, 0, 5); + constraints.fill = GridBagConstraints.NONE; // new line + gsPanel.add(verifyCommentsButton, constraints); + constraints.fill = GridBagConstraints.BOTH; + constraints.gridx = 0; + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.insets = new Insets(5, 5, 5, 5); + constraints.gridy++; + constraints.weighty = 1.0d; + constraints.gridheight = GridBagConstraints.REMAINDER; + final JTextArea commentArea = new JTextArea(4, 40); + commentArea.setText(settings.getGlobalCommentPattern()); + constraints.gridheight = GridBagConstraints.REMAINDER; + final JScrollPane scrollPane = new JScrollPane(commentArea); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + gsPanel.add(scrollPane, constraints); + + getterSetterBox.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + settings.setKeepGettersSettersTogether(getterSetterBox.isSelected()); + gettersSettersWithPropertyBox.setEnabled(settings.isKeepGettersSettersTogether()); + } + } + ); + + gettersSettersWithPropertyBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + settings.setKeepGettersSettersWithProperty(gettersSettersWithPropertyBox.isSelected()); + } + }); + + overloadOrderBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + settings.setOverloadedOrder(overloadOrderBox.getSelectedIndex()); + } + } + ); + + commentArea.getDocument().addDocumentListener( + new DocumentListener() { + public void changedUpdate(final DocumentEvent e) { + settings.setGlobalCommentPattern(commentArea.getText()); + } + + public void insertUpdate(final DocumentEvent e) { + settings.setGlobalCommentPattern(commentArea.getText()); + } + + public void removeUpdate(final DocumentEvent e) { + settings.setGlobalCommentPattern(commentArea.getText()); + } + } + ); + + createPatternButton.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + String t = commentArea.getText(); + if (t.length() > 0) { + int result = JOptionPane.showConfirmDialog( + null, "This will replace the existing comment pattern with the generated pattern." + + " Are you sure?", + "Replace existing pattern", + JOptionPane.YES_NO_CANCEL_OPTION + ); + if (result != 0) return; + } + String s = generateCommentPattern(settings); + commentArea.setText(s); + } + } + ); + + verifyCommentsButton.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + checkCommentsAgainstGlobalPattern(settings); + } + } + ); + return gsPanel; + } + +// ---------- START Level 5 ---------- + + private String generateCommentPattern(RearrangerSettings settings) { + new CommentUtil(settings); + String result = RegexUtil.combineExpressions(CommentUtil.getCommentStrings()); + return result; + } + + /** + * Compare all comments specified by the user against the global comment pattern. If all match, then + * the global pattern will catch all the user's comments and remove them before rearranging and inserting + * new ones. If any don't match, bring up a dialog box listing them. + * + * @param settings current Rearranger settings. + */ + public void checkCommentsAgainstGlobalPattern(RearrangerSettings settings) { + String pattern = settings.getGlobalCommentPattern(); + if (pattern == null || pattern.trim().length() == 0) { + JOptionPane.showMessageDialog( + null, "No global comment pattern exists!" + , "Verify Comments Against Pattern", + JOptionPane.WARNING_MESSAGE + ); + return; + } + try { + " ".matches(pattern); + } + catch (PatternSyntaxException pse) { + JOptionPane.showMessageDialog( + null, + "Invalid global pattern:" + pse.toString(), + "Verify Comments Against Pattern", + JOptionPane.ERROR_MESSAGE + ); + return; + } + int nCommentsSeen = 0; + List mismatches = new ArrayList(); + // first check all rules in the class order settings panes. + nCommentsSeen = + checkAttributeListForErrors(settings.getClassOrderAttributeList(), nCommentsSeen, pattern, mismatches); + // now check all the class member attributes. + nCommentsSeen = + checkAttributeListForErrors(settings.getItemOrderAttributeList(), nCommentsSeen, pattern, mismatches); + + // now check all comments for extracted methods. Expand keywords to make the match realistic. + CommentRule rule = settings.getExtractedMethodsSettings().getPrecedingComment(); + String preceding = rule.getCommentText(); + if (preceding != null && preceding.trim().length() > 0) { + nCommentsSeen++; + checkExtractedComment(rule, "Preceding", pattern, mismatches); + } + rule = settings.getExtractedMethodsSettings().getTrailingComment(); + String trailing = rule.getCommentText(); + if (preceding != null && preceding.trim().length() > 0) { + nCommentsSeen++; + checkExtractedComment(rule, "Trailing", pattern, mismatches); + } + /** + * if any strings mismatch, display a dialog showing them; otherwise display a dialog indicating that + * everything is ok. + */ + if (nCommentsSeen == 0) { + JOptionPane.showMessageDialog( + null, "No user-defined comments have been configured" + , "Verify Comments Against Pattern", + JOptionPane.PLAIN_MESSAGE + ); + } + else if (mismatches.size() == 0) { + JOptionPane.showMessageDialog( + null, + nCommentsSeen + + " user-defined comments seen; " + + "all match the global comment pattern", + "Verify Comments Against Pattern", + JOptionPane.PLAIN_MESSAGE + ); + } + else { + mismatches.add(0, nCommentsSeen + " user-defined comments seen; following comments did not match:"); + JOptionPane.showMessageDialog( + null, mismatches.toArray(), + "Verify Comments Against Pattern", JOptionPane.WARNING_MESSAGE + ); + } + } + +// ---------- START Level 6 ---------- + + private int checkAttributeListForErrors(List list, + int nCommentsSeen, + String pattern, + List mismatches) + { + int index = 0; + for (AttributeGroup group : list) { + index++; + nCommentsSeen += group.getCommentCount(); + if (!group.commentsMatchGlobalPattern(pattern)) { + List badComments = group.getOffendingPatterns(pattern); + for (Object badComment : badComments) { + mismatches.add("Class Member item #" + index + ": \"" + badComment + "\""); + } + } + } + return nCommentsSeen; + } + + private void checkExtractedComment(final CommentRule commentRule, + final String which, + String pattern, + List mismatches) + { + String comment = commentRule.getCommentText(); + if (comment.length() == 0) return; + // make some 'typical' substitutions for wildcard expansion to check against pattern. + // hand-expand the %FS% (fill string) because the fill string could contain special characters that + // replaceAll interprets and changes. + String expanded = comment.replaceAll("%LV%", "12"); + expanded = expanded.replaceAll("%TL%", "topLevelMethod()"); + expanded = expanded.replaceAll("%MN%", "methodName()"); + expanded = expanded.replaceAll("%AM%", "method1().[method1A(),method1B()]"); + expanded = expanded.replaceAll("%IF%", "Interface_ExampleName0"); + expanded = RegexUtil.replaceAllFS(expanded, commentRule.getCommentFillString().getFillString()); + if (!expanded.matches(pattern)) { + mismatches.add(which + " comment for extracted methods: \"" + comment + "\""); + } + } + +// ---------- END Level 6 ---------- + + +// ---------- END Level 5 ---------- + + private JPanel getConfigurationPane() { + final JPanel gcPanel = new JPanel(new GridBagLayout()); + Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.insets = new Insets(5, 5, 0, 5); + final JButton clearConfig = new JButton("Clear configuration"); + final JButton loadDefaultConfig = new JButton("Load default configuration"); + final JButton readConfig = new JButton("Read configuration from file..."); + final JButton writeConfig = new JButton("Write configuration to file..."); + clearConfig.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + createSettingsPanel(new RearrangerSettings()); + } + }); + loadDefaultConfig.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + RearrangerSettings defaultSettings = RearrangerSettings.getDefaultSettings(); + if (defaultSettings == null) { + JOptionPane.showMessageDialog(null, "Could not obtain default configuration.", + "No default configuration available", JOptionPane.WARNING_MESSAGE); + } + else { + createSettingsPanel(defaultSettings); + } + } + }); + readConfig.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JFileChooser fc = new JFileChooser(); + int returnVal = fc.showOpenDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + RearrangerSettings fileSettings = RearrangerSettings.getSettingsFromFile(file); + if (fileSettings == null) { + JOptionPane.showMessageDialog(null, "Could not read configuration.", + "File or file contents invalid", JOptionPane.WARNING_MESSAGE); + } + else { + createSettingsPanel(fileSettings); + } + } + } + }); + writeConfig.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JFileChooser fc = new JFileChooser(); + int returnVal = fc.showSaveDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + settings.writeSettingsToFile(file); + } + } + }); + gcPanel.add(clearConfig, constraints.weightedLastCol()); + constraints.newRow(); + gcPanel.add(loadDefaultConfig, constraints.weightedLastCol()); + constraints.newRow(); + gcPanel.add(readConfig, constraints.weightedLastCol()); + constraints.newRow(); + gcPanel.add(writeConfig, constraints.weightedLastCol()); + + // now create outer panel so that buttons aren't stretched across creation. + JPanel outerPanel = new JPanel(new GridBagLayout()); + constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.weightedLastRow(); + outerPanel.add(gcPanel, constraints.weightedLastCol()); + JPanel extraPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + extraPanel.setBorder(border); + constraints = new Constraints(GridBagConstraints.SOUTHEAST); + extraPanel.add(outerPanel, constraints.firstCol()); + constraints.weightedNewRow(); + constraints.firstCol(); // skip first column + extraPanel.add(new JLabel(), constraints.weightedNextCol()); + constraints.lastRow(); + constraints.firstCol(); // skip first column + constraints.nextCol(); // skip second column + constraints.weightx = constraints.weighty = 0; + constraints.insets = new Insets(5, 5, 5, 5); + JLabel version = new JLabel("Rearranger plugin, version " + Rearranger.VERSION); + extraPanel.add(version, constraints.lastCol()); + return extraPanel; + } + +// --------------------------- main() method --------------------------- + +// ---------- END Level 4 ---------- +// ---------- END Level 3 ---------- + + +// ---------- END Level 2 ---------- + + +// ---------- END Level 1 ---------- +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/RelatedByNamePane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/RelatedByNamePane.java new file mode 100644 index 000000000000..16eb362ec6ba --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/RelatedByNamePane.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.settings.PrimaryMethodSetting; +import com.wrq.rearranger.settings.RelatedByNameMethodsSettings; + +import javax.swing.*; +import java.util.List; + +/** Configuration settings for handling ordering of extracted methods. */ +public class RelatedByNamePane { + RelatedByNameMethodsSettings rbnms; + + public RelatedByNamePane(RelatedByNameMethodsSettings rbnms) { + this.rbnms = rbnms; + } + + public final JPanel getPane() { + IListManagerObjectFactory lmof = new IListManagerObjectFactory() { + public IListManagerObject create(String name) { + PrimaryMethodSetting pms = new PrimaryMethodSetting(); + pms.setDescription(name); + return pms; + } + + public List getObjectList() { + return rbnms.getMethodList(); + } + }; + ListManager result = new ListManager(lmof, "Primary method name:"); +// constraints = new GridBagConstraints(); +// constraints.anchor = GridBagConstraints.NORTHWEST; +// constraints.fill = GridBagConstraints.NONE; +// constraints.gridwidth = 1; +// constraints.gridheight = 1; +// constraints.weightx = 0.0d; +// constraints.weighty = 0.0d; +// constraints.gridy = constraints.gridx = 0; +// constraints.insets = new Insets(3, 3, 3, 3); +// addButton.setBorderPainted(false); +// removeButton.setBorderPainted(false); +// copyButton.setBorderPainted(false); +// containerPanel.add(addButton, constraints); +// constraints.gridx++; +// containerPanel.add(removeButton, constraints); +// constraints.gridx++; +// containerPanel.add(copyButton, constraints); +// constraints.gridx++; +// containerPanel.add(nameLabel, constraints); +// constraints.gridx++; +// constraints.gridwidth = GridBagConstraints.REMAINDER; +// constraints.weightx = 1; +// constraints.fill = GridBagConstraints.HORIZONTAL; +// containerPanel.add(name, constraints); +// /** +// * declare callback handlers for buttons. +// */ +// addButton.addActionListener(new ActionListener() +// { +// public void actionPerformed(ActionEvent e) +// { +// PrimaryMethodSetting pms = new PrimaryMethodSetting(); +// pms.setName("unnamed"); +// ((DefaultListModel)rbnmlist.getModel()).addElement(pms); +// rbnmlist.setSelectedIndex(rbnmlist.getModel().getSize() - 1); +// updateListSelection(); +// } +// }); +// removeButton.addActionListener(new ActionListener() +// { +// public void actionPerformed(ActionEvent e) +// { +// DefaultListModel dlm = ((DefaultListModel)rbnmlist.getModel()); +// int selectedIndex = rbnmlist.getSelectedIndex(); +// PrimaryMethodSetting pms = (PrimaryMethodSetting) dlm.getElementAt(selectedIndex); +// rbnms.getMethodList().remove(pms); +// dlm.remove(selectedIndex); +// if (selectedIndex >= dlm.getSize()) { +// selectedIndex = dlm.getSize() - 1; +// } +// rbnmlist.setSelectedIndex(selectedIndex); +// updateListSelection(); +// } +// }); +// copyButton.addActionListener(new ActionListener() +// { +// public void actionPerformed(ActionEvent e) +// { +// DefaultListModel dlm = ((DefaultListModel)rbnmlist.getModel()); +// int selectedIndex = rbnmlist.getSelectedIndex(); +// PrimaryMethodSetting pms = (PrimaryMethodSetting) dlm.getElementAt(selectedIndex); +// dlm.addElement(pms.deepcopy()); +// rbnmlist.setSelectedIndex(rbnmlist.getModel().getSize() - 1); +// updateListSelection(); +// } +// }); +// rbnmlist.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); +// addButton.setEnabled(true); +// name.getDocument().addDocumentListener(new DocumentListener() +// { +// private void updateList() +// { +// String newText = name.getText(); +// final PrimaryMethodSetting primaryMethodSetting = (PrimaryMethodSetting)rbnmlist.getSelectedValue(); +// primaryMethodSetting.setName(newText); +// int index = rbnmlist.getSelectedIndex(); +// DefaultListModel dlm = ((DefaultListModel)rbnmlist.getModel()); +// dlm.remove(index); +// dlm.add(index, primaryMethodSetting); +// rbnmlist.setSelectedIndex(index); +// } +// public void changedUpdate(DocumentEvent e) +// { +// updateList(); +// } +// +// public void insertUpdate(DocumentEvent e) +// { +// updateList(); +// } +// +// public void removeUpdate(DocumentEvent e) +// { +// updateList(); +// } +// }); +// JScrollPane scrollPane = new JScrollPane(rbnmlist); +// scrollPane.setPreferredSize(new Dimension(80, 300)); +// ListIterator li = rbnms.getMethodList().listIterator(); +// while (li.hasNext()) +// { +// PrimaryMethodSetting pms = (PrimaryMethodSetting) li.next(); +// ((DefaultListModel)rbnmlist.getModel()).addElement(pms); +// } +// rbnmlist.setSelectedIndex(rbnmlist.getModel().getSize() - 1); +// constraints.gridheight = GridBagConstraints.REMAINDER; +// constraints.gridx = 0; +// constraints.gridy++; +// constraints.gridwidth = 3; +// constraints.weightx = .2; +// constraints.weighty = 1; +// constraints.fill = GridBagConstraints.BOTH; +// containerPanel.add(scrollPane, constraints); +// constraints.gridx += 3; +// constraints.gridwidth = GridBagConstraints.REMAINDER; +// constraints.fill = GridBagConstraints.BOTH; +// constraints.weightx = .8; +// containerPanel.add(getPrimaryMethodPanel(), constraints); +// updateListSelection(); + return result.getPane(); + } + + /** + * Enable add/remove/copy buttons and fill in name of selected list item. Called whenever + * the list selection changes. + */ +// private void updateListSelection() +// { +// if (rbnmlist.getModel().getSize() > 0) +// { +// rbnmlist.setSelectedIndex(0); +// name.setEnabled(true); +// nameLabel.setEnabled(true); +// name.setText(((PrimaryMethodSetting) rbnmlist.getSelectedValue()).getName()); +// removeButton.setEnabled(true); +// copyButton.setEnabled(true); +// } +// else +// { +// name.setEnabled(false); +// nameLabel.setEnabled(false); +// removeButton.setEnabled(false); +// copyButton.setEnabled(false); +// name.setText(""); +// } +// containerPanel.remove(containerPanel.getComponentCount() - 1); +// containerPanel.add(getPrimaryMethodPanel(), constraints); +// containerPanel.validate(); +// } + + /** + * Get a primary method panel based on values for the currently selected primary item. + * @return + */ +// private JPanel getPrimaryMethodPanel() +// { +// PrimaryMethodSetting pms = (PrimaryMethodSetting) rbnmlist.getSelectedValue(); +// if (pms == null) { +// return new JPanel(); // empty +// } +// else { +// return pms.getPanel(); +// } +// } + +// ---------- START Level 4 ---------- +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java new file mode 100644 index 000000000000..358a2312e225 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; +import com.wrq.rearranger.settings.attributeGroups.IPrioritizableRule; +import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.util.Constraints; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.*; +import java.awt.*; +import java.awt.event.*; +import java.util.ArrayList; +import java.util.List; + +/** Code common to dialog managing creation and maintenance of a list of rules. */ +public abstract class SettingsPane { +// ------------------------------ FIELDS ------------------------------ + + public static final int SEQUENCE_COLUMN = 0; + public static final int PRIORITY_COLUMN = 1; + public static final int DESCRIPTION_COLUMN = 2; + public static final int NUM_COLUMNS = 3; + protected final RearrangerSettings settings; + + private final List list; + private List modelData; + private JTable jTable; + private AbstractTableModel model; + private JPanel pane; + +// --------------------------- CONSTRUCTORS --------------------------- + + SettingsPane(final RearrangerSettings settings, List list) { + this.settings = settings; + this.list = list; + modelData = new ArrayList(list.size()); + createConfigurationPane(); + } + + private void createConfigurationPane() { + pane = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEmptyBorder(); + pane.setBorder(border); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.weightedNewRow(); + constraints.fill = GridBagConstraints.BOTH; + constraints.insets = new Insets(10, 10, 10, 10); + pane.add(createScrollableTablePanel(), constraints.weightedFirstCol()); + pane.add(createAddRemovePanel(), constraints.nextCol()); + } + + private JPanel createScrollableTablePanel() { + final JPanel cmlPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.weightedLastRow(); + constraints.fill = GridBagConstraints.BOTH; + final JTextField priorityField = new JTextField(); + priorityField.setHorizontalAlignment(JTextField.RIGHT); + TableCellEditor priorityEditor = new DefaultCellEditor(priorityField); + model = new AbstractTableModel() { + public int getColumnCount() { + return NUM_COLUMNS; // sequence, priority, rule description + } + + public int getRowCount() { + return list.size(); + } + + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case SEQUENCE_COLUMN: + return rowIndex + 1; + + case PRIORITY_COLUMN: + ChoicePanel cp = (modelData.get(rowIndex)); + IRule rule = cp.getChoice().getChoiceObject(); + return new Priority(rule.getPriority()); + + case DESCRIPTION_COLUMN: + return list.get(rowIndex).toString(); + } + return null; + } + + public String getColumnName(int column) { + switch (column) { + case SEQUENCE_COLUMN: + return "Seq"; + + case PRIORITY_COLUMN: + return "Pri"; + + case DESCRIPTION_COLUMN: + return "Rule"; + } + return null; + } + + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case SEQUENCE_COLUMN: + return Integer.class; + + case PRIORITY_COLUMN: + return Priority.class; + + case DESCRIPTION_COLUMN: + return String.class; + } + return Object.class; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + if (columnIndex == PRIORITY_COLUMN && rowIndex >= 0) { + ChoicePanel cp = (modelData.get(rowIndex)); + IRule rule = cp.getChoice().getChoiceObject(); + if (rule instanceof IPrioritizableRule) { + return true; + } + } + return false; + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + if (columnIndex == PRIORITY_COLUMN) { + ChoicePanel cp = (modelData.get(rowIndex)); + IRule rule = cp.getChoice().getChoiceObject(); + if (rule instanceof IPrioritizableRule) { + int priority; + try { + priority = (new Integer((String)aValue)); + } + catch (NumberFormatException nfe) { + return; + } + if (priority > 0 && priority < 100) { + rule.setPriority(priority); + fireTableCellUpdated(rowIndex, columnIndex); + } + } + } + } + }; + TableCellRenderer priorityRenderer = new DefaultTableCellRenderer() { + protected void setValue(Object value) { + Priority p = (Priority)value; + if (p.priority <= 0) { + setText("n/a"); + setHorizontalAlignment(JLabel.CENTER); + } + else { + setText("" + p.priority + " "); + setHorizontalAlignment(JLabel.RIGHT); + } + } + }; + TableSorter sorter = new TableSorter(model) { + public void sortByColumn(int column, boolean ascending) { + if (column == SEQUENCE_COLUMN || + column == PRIORITY_COLUMN) + { + super.sortByColumn(column, ascending); + } + } + + public boolean defaultSortOrderAscending(int column) { + switch (column) { + case SEQUENCE_COLUMN: + return true; + case PRIORITY_COLUMN: + return false; + } + return true; + } + }; + jTable = new JTable(sorter); + sorter.addMouseListenerToHeaderInTable(jTable); + jTable.setShowHorizontalLines(false); + jTable.setShowVerticalLines(true); + jTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + jTable.setDragEnabled(false); + jTable.setRowSelectionAllowed(true); + jTable.setColumnSelectionAllowed(false); + jTable.setPreferredScrollableViewportSize(jTable.getPreferredSize()); + jTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); + + TableColumnModel tcm = jTable.getColumnModel(); + tcm.getColumn(0).setPreferredWidth(new JLabel("SEQ").getWidth() * 3); + tcm.getColumn(1).setPreferredWidth(new JLabel("MMM").getWidth() * 3); + tcm.getColumn(1).setCellRenderer(priorityRenderer); + tcm.getColumn(1).setCellEditor(priorityEditor); + final JScrollPane scrollPane = new JScrollPane(jTable); + for (AttributeGroup ca : list) { + modelData.add(createOptionsPaneMsg(ca)); + } + if (list.size() > 0) { + jTable.getSelectionModel().setSelectionInterval(0, 0); + } + cmlPanel.add(scrollPane, constraints.weightedLastCol()); + setTableColumnWidths(); + return cmlPanel; + } + + /** + * @param ca FieldAttributes, MethodAttributes, InnerClassAttributes, or CommentRule object + * @return ItemPanel corresponding to the value of param. + */ + private ChoicePanel createOptionsPaneMsg(final AttributeGroup ca) { + final ChoicePanel result = createChoicePanel(); + for (int i = 0; i < result.getChoices().length; i++) { + final AttributeGroup choiceObject = result.getChoices()[i].getChoiceObject(); + if (ca.getClass() == choiceObject.getClass()) { + result.setChoice(i); + result.getChoice().choiceObject = ca; + break; + } + } + return result; + } + + abstract ChoicePanel createChoicePanel(); + + private void setTableColumnWidths() { + int columnCount = jTable.getColumnCount(); + TableColumnModel tcm = jTable.getColumnModel(); + final int SPARE = 24; + + for (int i = 0; i < columnCount; i++) { + int width = calculateColumnWidth(i); + width += SPARE; + TableColumn column = tcm.getColumn(i); + column.setMinWidth(width); + if (i < columnCount - 1) { + column.setMaxWidth(width); + } + } + } + + private int calculateColumnWidth(int columnIndex) { + int result = 0; + int rowCount = jTable.getRowCount(); + for (int i = 0; i < rowCount; i++) { + TableCellRenderer tcr = jTable.getCellRenderer(i, columnIndex); + Component comp = tcr.getTableCellRendererComponent( + jTable, + jTable.getValueAt(i, columnIndex), + true, true, i, columnIndex + ); + int compWidth = comp.getPreferredSize().width; + if (compWidth > result) { + result = compWidth; + } + } + TableCellRenderer tcr = jTable.getColumnModel().getColumn(columnIndex).getHeaderRenderer(); + if (tcr == null) { + tcr = jTable.getDefaultRenderer(String.class); + } + Component comp = tcr.getTableCellRendererComponent( + jTable, + model.getColumnName(columnIndex), true, true, -1, columnIndex + ); + int compWidth = comp.getPreferredSize().width; + if (compWidth > result) { + result = compWidth; + } + if (columnIndex == DESCRIPTION_COLUMN) { + if (result < 400) result = 400; + } + return result; + } + + private JPanel createAddRemovePanel() { + final JPanel addRemovePanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTH); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.insets = new Insets(0, 0, 10, 0); + final JButton addButton = new JButton("Add"); + final JButton editButton = new JButton("Edit"); + final JButton removeButton = new JButton("Remove"); + final JButton duplicateButton = new JButton("Duplicate"); + final JButton moveUpButton = new JButton("Move up"); + final JButton moveDownButton = new JButton("Move down"); + addRemovePanel.add(addButton, constraints.firstCol()); + constraints.newRow(); + addRemovePanel.add(editButton, constraints.firstCol()); + constraints.newRow(); + addRemovePanel.add(duplicateButton, constraints.firstCol()); + constraints.newRow(); + addRemovePanel.add(removeButton, constraints.firstCol()); + constraints.newRow(); + addRemovePanel.add(moveUpButton, constraints.firstCol()); + constraints.weightedNewRow(); + constraints.insets = new Insets(0, 0, 0, 0); + addRemovePanel.add(moveDownButton, constraints.firstCol()); + if (jTable.getSelectedRow() < 0) { + editButton.setEnabled(false); + duplicateButton.setEnabled(false); + removeButton.setEnabled(false); + moveUpButton.setEnabled(false); + moveDownButton.setEnabled(false); + } + if (jTable.getSelectedRow() == 0) { + moveUpButton.setEnabled(false); + } + if (jTable.getSelectedRowCount() > 0 && + jTable.getSelectedRows()[jTable.getSelectedRowCount() - 1] == jTable.getModel().getRowCount() - 1) + { + moveDownButton.setEnabled(false); + } + jTable.getSelectionModel().addListSelectionListener( + new ListSelectionListener() { + public void valueChanged(final ListSelectionEvent e) { + if (e.getValueIsAdjusting() || (e.getFirstIndex() < 0)) { + return; + } + final int index = jTable.getSelectedRow(); + final boolean selectionExists = index >= 0; + editButton.setEnabled(selectionExists); + duplicateButton.setEnabled(selectionExists); + removeButton.setEnabled(selectionExists); + moveUpButton.setEnabled(selectionExists && index > 0); + int lastSelectedRow = 0; + if (selectionExists) { + lastSelectedRow = jTable.getSelectedRows()[jTable.getSelectedRowCount() - 1]; + } + moveDownButton.setEnabled(selectionExists && + lastSelectedRow < jTable.getModel().getRowCount() - 1); + } + } + ); + jTable.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + int index = jTable.getSelectedRow(); + editRow(addRemovePanel); + jTable.getSelectionModel().setLeadSelectionIndex(index); + } + } + }); + addButton.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + // add new rule after last selected rule + final int currentIndex; + if (jTable.getSelectedRowCount() <= 0) { + currentIndex = 0; + } + else { + currentIndex = jTable.getSelectedRows()[jTable.getSelectedRowCount() - 1] + 1; + } + final ChoicePanel choicePanel = getOptionsPaneMsg(null); + final JOptionPane op = new JOptionPane( + choicePanel, + JOptionPane.PLAIN_MESSAGE, + JOptionPane.OK_CANCEL_OPTION, + null, null, null + ); + final JDialog jd = op.createDialog(addRemovePanel, choicePanel.getChoicePanelName()); + jd.setVisible(true); + final Object result = op.getValue(); + if (result != null && + ((Integer)result) == JOptionPane.OK_OPTION) + { + final ChoicePanel value = (ChoicePanel)op.getMessage(); + value.acceptEdited(); + modelData.add(currentIndex, value); + list.add(currentIndex, ((com.wrq.rearranger.settings.attributeGroups.AttributeGroup)value.getChoice().getChoiceObject())); + model.fireTableRowsInserted(currentIndex, currentIndex); + jTable.getSelectionModel().setSelectionInterval(currentIndex, currentIndex); + } + setTableColumnWidths(); + } + } + ); + editButton.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + editRow(addRemovePanel); + } + } + ); + jTable.addMouseListener( + new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() >= 2) { + editRow(addRemovePanel); + } + } + } + ); + + duplicateButton.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + // duplicate all selected rows as a block + AttributeGroup[] newRules = new AttributeGroup[jTable.getSelectedRowCount()]; + for (int row = 0; row < jTable.getSelectedRowCount(); row++) { + final int currentIndex = jTable.getSelectedRows()[row]; + final ChoicePanel choicePanel = (modelData.get(currentIndex)); + AttributeGroup rule = choicePanel.getChoice().getChoiceObject(); + AttributeGroup newRule = rule.deepCopy(); + newRules[row] = newRule; + } + // now insert the new rows at the correct place + final int offset = jTable.getSelectedRows()[jTable.getSelectedRowCount() - 1] + 1; + for (int row = 0; row < newRules.length; row++) { + final AttributeGroup newRule = newRules[row]; + modelData.add(row + offset, createOptionsPaneMsg(newRule)); + list.add(row + offset, newRule); + model.fireTableRowsInserted(row + offset, row + offset); + } + } + } + ); + removeButton.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + // remove a block of rules. + final int currentIndex = jTable.getSelectedRow(); + if (currentIndex >= 0) { + final int first = jTable.getSelectedRows()[0]; + final int last = jTable.getSelectedRows()[jTable.getSelectedRowCount() - 1]; + for (int i = first; i <= last; i++) { + list.remove(currentIndex); + modelData.remove(currentIndex); + } + model.fireTableRowsDeleted(currentIndex, currentIndex); + int newSelIndex = (currentIndex >= model.getRowCount()) + ? model.getRowCount() - 1 + : currentIndex; + jTable.getSelectionModel().setSelectionInterval(newSelIndex, newSelIndex); + setTableColumnWidths(); + } + } + } + ); + moveUpButton.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + final int first = jTable.getSelectedRows()[0]; + if (first <= 0) return; + final int last = jTable.getSelectedRows()[jTable.getSelectedRowCount() - 1]; + for (int i = first; i <= last; i++) { + list.add(i - 1, list.remove(i)); + modelData.add(i - 1, modelData.remove(i)); + model.fireTableRowsUpdated(i - 1, i); + } + jTable.getSelectionModel().setSelectionInterval(first - 1, last - 1); + } + } + ); + moveDownButton.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + final int first = jTable.getSelectedRows()[0]; + final int last = jTable.getSelectedRows()[jTable.getSelectedRowCount() - 1]; + if (last + 1 >= jTable.getModel().getRowCount()) return; + for (int i = last; i >= first; i--) { + list.add(i + 1, (list.remove(i))); + modelData.add(i + 1, (modelData.remove(i))); + model.fireTableRowsUpdated(i, i + 1); + } + jTable.getSelectionModel().setSelectionInterval(first + 1, last + 1); + } + } + ); + return addRemovePanel; + } + + private ChoicePanel getOptionsPaneMsg(final ChoicePanel currentMsg) { + final ChoicePanel result = createChoicePanel(); + if (currentMsg != null) { + result.copyChoices(currentMsg); + } + result.configurePanel(); + return result; + } + + private void editRow(final JPanel addRemovePanel) { + // edit first row of all rows selected + final int currentIndex = jTable.getSelectedRow(); + final ChoicePanel o = modelData.get(currentIndex); + final ChoicePanel choicePanel = getOptionsPaneMsg(o); + final JOptionPane op = new JOptionPane( + choicePanel, + JOptionPane.PLAIN_MESSAGE, + JOptionPane.OK_CANCEL_OPTION, + null, null, null + ); + final JDialog jd = op.createDialog(addRemovePanel, choicePanel.getChoicePanelName()); + jd.setVisible(true); + final Object result = op.getValue(); + if (result != null && + ((Integer)result) == JOptionPane.OK_OPTION) + { + final ChoicePanel value = (ChoicePanel)op.getMessage(); + value.acceptEdited(); + modelData.set(currentIndex, value); + list.set(currentIndex, ((com.wrq.rearranger.settings.attributeGroups.AttributeGroup)value.getChoice().getChoiceObject())); + model.fireTableRowsUpdated(currentIndex, currentIndex); + } + setTableColumnWidths(); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public final JPanel getPane() { + return pane; + } + +// -------------------------- INNER CLASSES -------------------------- + + class Priority { + int priority; + + public Priority(int priority) { + this.priority = priority; + } + + public String toString() { + return "" + priority; + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java new file mode 100644 index 000000000000..1e92633e5ec5 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import com.wrq.rearranger.settings.ForceBlankLineSetting; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.text.NumberFormat; + +/** UI code for Spacing rules dialog. */ +public class SpacingPane { +// ------------------------------ FIELDS ------------------------------ + + private final RearrangerSettings settings; + +// --------------------------- CONSTRUCTORS --------------------------- + + public SpacingPane(RearrangerSettings settings) { + this.settings = settings; + } + +// -------------------------- OTHER METHODS -------------------------- + + public JPanel getPane() { + final JPanel panel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + panel.setBorder(border); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1.0d; + constraints.insets = new Insets(3, 3, 0, 0); + panel.add(getForceBlankLinePanel(settings.getAfterClassLBrace()), constraints.weightedLastCol()); + constraints.newRow(); + panel.add(getForceBlankLinePanel(settings.getBeforeClassRBrace()), constraints.weightedLastCol()); + constraints.newRow(); + panel.add(getForceBlankLinePanel(settings.getAfterClassRBrace()), constraints.weightedLastCol()); + constraints.newRow(); + panel.add(getForceBlankLinePanel(settings.getBeforeMethodLBrace()), constraints.weightedLastCol()); + constraints.newRow(); + panel.add(getForceBlankLinePanel(settings.getAfterMethodLBrace()), constraints.weightedLastCol()); + constraints.newRow(); + panel.add(getForceBlankLinePanel(settings.getBeforeMethodRBrace()), constraints.weightedLastCol()); + constraints.newRow(); + panel.add(getForceBlankLinePanel(settings.getAfterMethodRBrace()), constraints.weightedLastCol()); + constraints.newRow(); + panel.add(getForceBlankLinePanel(settings.getNewlinesAtEOF()), constraints.weightedLastCol()); + constraints.weightedLastRow(); + final JCheckBox insideBlockBox = new JCheckBox("Remove initial and final blank lines inside code block"); + insideBlockBox.setSelected(settings.isRemoveBlanksInsideCodeBlocks()); + panel.add(insideBlockBox, constraints.weightedLastCol()); + insideBlockBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + settings.setRemoveBlanksInsideCodeBlocks(insideBlockBox.isSelected()); + } + }); + return panel; + } + + private JPanel getForceBlankLinePanel(final ForceBlankLineSetting fbl) { + final JPanel panel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(); + constraints.fill = GridBagConstraints.BOTH; + constraints.lastRow(); + + final JCheckBox forceBox = new JCheckBox("Force"); + forceBox.setSelected(fbl.isForce()); + panel.add(forceBox, constraints.weightedFirstCol()); + final NumberFormat integerInstance = NumberFormat.getIntegerInstance(); + integerInstance.setMaximumIntegerDigits(2); + integerInstance.setMinimumIntegerDigits(1); + final JFormattedTextField nBlankLines = new JFormattedTextField(integerInstance); + nBlankLines.setValue(new Integer("88")); + Dimension d = nBlankLines.getPreferredSize(); + d.width += 3; + nBlankLines.setPreferredSize(d); + nBlankLines.setValue(fbl.getnBlankLines()); + nBlankLines.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT); + constraints.insets = new Insets(0, 3, 0, 0); + panel.add(nBlankLines, constraints.weightedNextCol()); + nBlankLines.addPropertyChangeListener("value", new PropertyChangeListener() { + public void propertyChange(final PropertyChangeEvent evt) { + int n = ((Number)nBlankLines.getValue()).intValue(); + if (n < 0) { + n = 0; + nBlankLines.setValue(n); + } + fbl.setnBlankLines(n); + } + }); + String labelText = "blank lines " + + (fbl.isBefore() ? "before" : "after"); + switch (fbl.getObject()) { + case ForceBlankLineSetting.CLASS_OBJECT: + labelText += " class "; + break; + case ForceBlankLineSetting.METHOD_OBJECT: + labelText += " method "; + break; + } + labelText += fbl.isOpenBrace() ? "open brace \"{\"" + : "close brace \"}\""; + if (fbl.getObject() == ForceBlankLineSetting.EOF_OBJECT) { + labelText = "newline characters at end of file"; + } + final JLabel blankLineLabel = new JLabel(labelText); + panel.add(blankLineLabel, constraints.lastCol()); + nBlankLines.setEnabled(forceBox.isSelected()); + blankLineLabel.setEnabled(forceBox.isSelected()); + forceBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + fbl.setForce(forceBox.isSelected()); + nBlankLines.setEnabled(forceBox.isSelected()); + blankLineLabel.setEnabled(forceBox.isSelected()); + } + }); + return panel; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextArea.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextArea.java new file mode 100644 index 000000000000..5e5b815e8a8c --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextArea.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + + +/** + * A JTextArea tied to a String field of this class. Initialize the JTextField from the field and update + * the field whenever the JTextField's text changes. + */ +public abstract class StringTextArea + extends JTextArea +{ + + abstract public void setValue(String value); + + abstract public String getValue(); + + public StringTextArea() { + super(); + setText(getValue()); + getDocument().addDocumentListener(new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + setValue(getText()); + } + + public void removeUpdate(DocumentEvent e) { + setValue(getText()); + } + + public void changedUpdate(DocumentEvent e) { + setValue(getText()); + } + }); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextField.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextField.java new file mode 100644 index 000000000000..4170141255b9 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/StringTextField.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +/** + * A JTextField tied to a String field of this class. Initialize the JTextField from the field and update + * the field whenever the JTextField's text changes. + */ +public abstract class StringTextField + extends JTextField +{ + abstract public void setValue(String value); + + abstract public String getValue(); + + public StringTextField() { + super(); + setText(getValue()); + getDocument().addDocumentListener(new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + setValue(getText()); + } + + public void removeUpdate(DocumentEvent e) { + setValue(getText()); + } + + public void changedUpdate(DocumentEvent e) { + setValue(getText()); + } + }); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/TableMap.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/TableMap.java new file mode 100644 index 000000000000..df6f86f1ac44 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/TableMap.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +/** + * In a chain of data manipulators some behaviour is common. TableMap + * provides most of this behaviour and can be subclassed by filters + * that only need to override a handful of specific methods. TableMap + * implements TableModel by routing all requests to its model, and + * TableModelListener by routing all events to its listeners. Inserting + * a TableMap which has not been subclassed into a chain of table filters + * should have no effect. + * + * @version 1.4 12/17/97 + * @author Philip Milne + */ + +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +public class TableMap + extends AbstractTableModel + implements TableModelListener +{ +// ------------------------------ FIELDS ------------------------------ + + protected TableModel model; + +// --------------------- GETTER / SETTER METHODS --------------------- + + public void setModel(TableModel model) { + this.model = model; + model.addTableModelListener(this); + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface TableModel --------------------- + + + public int getColumnCount() { + return (model == null) ? 0 : model.getColumnCount(); + } + + public int getRowCount() { + return (model == null) ? 0 : model.getRowCount(); + } + + public boolean isCellEditable(int row, int column) { + return model.isCellEditable(row, column); + } + + public Class getColumnClass(int aColumn) { + return model.getColumnClass(aColumn); + } + + // By default, implement TableModel by forwarding all messages + // to the model. + + public Object getValueAt(int aRow, int aColumn) { + return model.getValueAt(aRow, aColumn); + } + + public void setValueAt(Object aValue, int aRow, int aColumn) { + model.setValueAt(aValue, aRow, aColumn); + } + + public String getColumnName(int aColumn) { + return model.getColumnName(aColumn); + } + +// --------------------- Interface TableModelListener --------------------- + + // +// Implementation of the TableModelListener interface, +// + // By default forward all events to all the listeners. + public void tableChanged(TableModelEvent e) { + fireTableChanged(e); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/TableSorter.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/TableSorter.java new file mode 100644 index 000000000000..1b4a48c96dd2 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/TableSorter.java @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.configuration; + +/** + * A sorter for TableModels. The sorter has a model (conforming to TableModel) + * and itself implements TableModel. TableSorter does not store or copy + * the data in the TableModel, instead it maintains an array of + * integers which it keeps the same size as the number of rows in its + * model. When the model changes it notifies the sorter that something + * has changed eg. "rowsAdded" so that its internal array of integers + * can be reallocated. As requests are made of the sorter (like + * getValueAt(row, col) it redirects them to its model via the mapping + * array. That way the TableSorter appears to hold another copy of the table + * with the rows in a different order. The sorting algorthm used is stable + * which means that it does not move around rows when its comparison + * function returns 0 to denote that they are equivalent. + * + * @version 1.5 12/17/97 + * @author Philip Milne + */ + +import javax.swing.*; +import javax.swing.event.TableModelEvent; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableColumnModel; +import javax.swing.table.TableModel; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Date; +import java.util.List; +import java.util.Vector; + +public class TableSorter extends TableMap { +// ------------------------------ FIELDS ------------------------------ + + int[] indexes; + List sortingColumns = new Vector(); + boolean ascending = true; + int compares; + +// --------------------------- CONSTRUCTORS --------------------------- + + public TableSorter() { + indexes = new int[0]; // for consistency + } + + public TableSorter(TableModel model) { + setModel(model); + } + + public void setModel(TableModel model) { + super.setModel(model); + reallocateIndexes(); + } + + public void reallocateIndexes() { + int rowCount = model.getRowCount(); + + // Set up a new array of indexes with the right number of elements + // for the new data model. + indexes = new int[rowCount]; + + // Initialise with the identity mapping. + for (int row = 0; row < rowCount; row++) { + indexes[row] = row; + } + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface TableModel --------------------- + + + // The mapping only affects the contents of the data rows. + // Pass all requests to these rows through the mapping array: "indexes". + + public Object getValueAt(int aRow, int aColumn) { + checkModel(); + return model.getValueAt(indexes[aRow], aColumn); + } + + public void setValueAt(Object aValue, int aRow, int aColumn) { + checkModel(); + model.setValueAt(aValue, indexes[aRow], aColumn); + } + +// --------------------- Interface TableModelListener --------------------- + + public void tableChanged(TableModelEvent e) { + reallocateIndexes(); + super.tableChanged(e); + } + +// -------------------------- OTHER METHODS -------------------------- + + // There is nowhere else to put this. + // Add a mouse listener to the Table to trigger a table sort + // when a column heading is clicked in the JTable. + public void addMouseListenerToHeaderInTable(JTable table) { + final TableSorter sorter = this; + final JTable tableView = table; + tableView.setColumnSelectionAllowed(false); + MouseAdapter listMouseListener = new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + TableColumnModel columnModel = tableView.getColumnModel(); + int viewColumn = columnModel.getColumnIndexAtX(e.getX()); + int column = tableView.convertColumnIndexToModel(viewColumn); + if (e.getClickCount() == 1 && column != -1) { + int shiftPressed = e.getModifiers() & InputEvent.SHIFT_MASK; + boolean ascending = defaultSortOrderAscending(column) ^ (shiftPressed != 0); + sorter.sortByColumn(column, ascending); + } + } + }; + JTableHeader th = tableView.getTableHeader(); + th.addMouseListener(listMouseListener); + } + + public boolean defaultSortOrderAscending(int column) { + return true; + } + + public void sortByColumn(int column, boolean ascending) { + this.ascending = ascending; + sortingColumns.clear(); + sortingColumns.add(column); + sort(this); + super.tableChanged(new TableModelEvent(this)); + } + + public void sort(TableSorter sender) { + checkModel(); + + compares = 0; + // n2sort(); + // qsort(0, indexes.length-1); + shuttlesort(indexes.clone(), indexes, 0, indexes.length); + } + + public void checkModel() { + if (indexes.length != model.getRowCount()) { + throw new RuntimeException("Sorter not informed of a change in model."); + } + } + + // This is a home-grown implementation which we have not had time + // to research - it may perform poorly in some circumstances. It + // requires twice the space of an in-place algorithm and makes + // NlogN assigments shuttling the values between the two + // arrays. The number of compares appears to vary between N-1 and + // NlogN depending on the initial order but the main reason for + // using it here is that, unlike qsort, it is stable. + public void shuttlesort(int[] from, int[] to, int low, int high) { + if (high - low < 2) { + return; + } + int middle = (low + high) / 2; + shuttlesort(to, from, low, middle); + shuttlesort(to, from, middle, high); + + int p = low; + int q = middle; + + /* This is an optional short-cut; at each recursive call, +check to see if the elements in this subset are already +ordered. If so, no further comparisons are needed; the +sub-array can just be copied. The array must be copied rather +than assigned otherwise sister calls in the recursion might +get out of sinc. When the number of elements is three they +are partitioned so that the first set, [low, mid), has one +element and and the second, [mid, high), has two. We skip the +optimisation when the number of elements is three or less as +the first compare in the normal merge will produce the same +sequence of steps. This optimisation seems to be worthwhile +for partially ordered lists but some analysis is needed to +find out how the performance drops to Nlog(N) as the initial +order diminishes - it may drop very quickly. */ + + if (high - low >= 4 && compare(from[middle - 1], from[middle]) <= 0) { + for (int i = low; i < high; i++) { + to[i] = from[i]; + } + return; + } + + // A normal merge. + + for (int i = low; i < high; i++) { + if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) { + to[i] = from[p++]; + } + else { + to[i] = from[q++]; + } + } + } + + public int compare(int row1, int row2) { + compares++; + for (Integer column : sortingColumns) { + int result = compareRowsByColumn(row1, row2, column); + if (result != 0) { + return ascending ? result : -result; + } + } + return 0; + } + + public int compareRowsByColumn(int row1, int row2, int column) { + Class type = model.getColumnClass(column); + TableModel data = model; + + // Check for nulls. + + Object o1 = data.getValueAt(row1, column); + Object o2 = data.getValueAt(row2, column); + + // If both values are null, return 0. + if (o1 == null && o2 == null) { + return 0; + } + else if (o1 == null) { // Define null less than everything. + return -1; + } + else if (o2 == null) { + return 1; + } + + /* + * We copy all returned values from the getValue call in case + * an optimised model is reusing one object to return many + * values. The Number subclasses in the JDK are immutable and + * so will not be used in this way but other subclasses of + * Number might want to do this to save space and avoid + * unnecessary heap allocation. + */ + + if (type.getSuperclass() == java.lang.Number.class) { + Number n1 = (Number)data.getValueAt(row1, column); + double d1 = n1.doubleValue(); + Number n2 = (Number)data.getValueAt(row2, column); + double d2 = n2.doubleValue(); + + if (d1 < d2) { + return -1; + } + else if (d1 > d2) { + return 1; + } + else { + return 0; + } + } + else if (type == java.util.Date.class) { + Date d1 = (Date)data.getValueAt(row1, column); + long n1 = d1.getTime(); + Date d2 = (Date)data.getValueAt(row2, column); + long n2 = d2.getTime(); + + if (n1 < n2) { + return -1; + } + else if (n1 > n2) { + return 1; + } + else { + return 0; + } + } + else if (type == String.class) { + String s1 = (String)data.getValueAt(row1, column); + String s2 = (String)data.getValueAt(row2, column); + int result = s1.compareTo(s2); + + if (result < 0) { + return -1; + } + else if (result > 0) { + return 1; + } + else { + return 0; + } + } + else if (type == Boolean.class) { + Boolean bool1 = (Boolean)data.getValueAt(row1, column); + boolean b1 = bool1; + Boolean bool2 = (Boolean)data.getValueAt(row2, column); + boolean b2 = bool2; + + if (b1 == b2) { + return 0; + } + else if (b1) { // Define false < true + return 1; + } + else { + return -1; + } + } + else { + Object v1 = data.getValueAt(row1, column); + String s1 = v1.toString(); + Object v2 = data.getValueAt(row2, column); + String s2 = v2.toString(); + int result = s1.compareTo(s2); + + if (result < 0) { + return -1; + } + else if (result > 0) { + return 1; + } + else { + return 0; + } + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/defaultConfiguration.xml b/plugins/rearranger/src/com/wrq/rearranger/defaultConfiguration.xml new file mode 100644 index 000000000000..ff91276bbcac --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/defaultConfiguration.xml @@ -0,0 +1,360 @@ + + + + + + \n//\ ------------------------------\ FIELDS\ + ------------------------------\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n//\ --------------------------\ STATIC\ METHODS\ + --------------------------\n + + + + + + + + + + + + + + + + + + + + + + \n//\ ---------------------------\ CONSTRUCTORS\ + ---------------------------\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n//\ ---------------------\ GETTER\ /\ SETTER\ METHODS\ + ---------------------\n + + + + + + + + + + + + + + + + + + + + + + \n//\ ------------------------\ CANONICAL\ METHODS\ + ------------------------\n + + + + + + + + + + + + + + + + + + + + + + \n//\ ------------------------\ INTERFACE\ METHODS\ + ------------------------\n + + + + + \n//\ ---------------------\ Interface\ %IF%\ + ---------------------\n + + + + + + + \n//\ --------------------------\ OTHER\ METHODS\ + --------------------------\n + + + + + + + + + + + + + + + + + + + + + + \n//\ --------------------------\ ENUMERATIONS\ + --------------------------\n + + + + + + + + + + + \n//\ --------------------------\ INNER\ CLASSES\ + --------------------------\n + + + + + + + + + + + \n//\ ---------------------------\ main()\ method\ + ---------------------------\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java new file mode 100644 index 000000000000..1739647d8bc6 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.RearrangerTreeNode; +import com.wrq.rearranger.settings.RearrangerSettings; + +import javax.swing.tree.DefaultMutableTreeNode; + +/** + * Describes the fields, methods, and inner class declarations of a class. This information is used to reorder + * these declarations within an outer class. + */ +public abstract class ClassContentsEntry + extends RangeEntry + implements IFilePopupEntry +{ + public ClassContentsEntry(final PsiElement start, + final PsiElement end, + final int modifiers, + final String modifierString, + final String name, + final String type) + { + super(start, end, modifiers, modifierString, name, type); + } + + public ClassContentsEntry(final PsiElement start, + final PsiElement end, + final boolean fixedHeader, + final boolean fixedTrailer) + { + super(start, end, fixedHeader, fixedTrailer); + } + + public DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings) { + DefaultMutableTreeNode node = null; + if ((end instanceof PsiField && settings.isShowFields()) || + (this instanceof ClassEntry)) + { + node = new RearrangerTreeNode(this, name); + parent.add(node); + } + return node; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java new file mode 100644 index 000000000000..028f08352cd7 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.searches.OverridingMethodsSearch; +import com.intellij.util.Query; +import com.wrq.rearranger.ModifierConstants; +import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.rearrangement.GenericRearranger; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.ModifierUtils; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * Describes an entire class's range and type. + * This information is used when reordering outer classes. + */ +public class ClassEntry + extends ClassContentsEntry + implements IFilePopupEntry +{ + private static final Logger LOG = Logger.getInstance("#" + ClassEntry.class.getName()); + + protected final List contents; + private List resultRuleInstances; + private final RearrangerSettings settings; + private final int nestingLevel; + + public ClassEntry(PsiElement start, + PsiElement end, + int modifiers, + String modifierString, + String name, + int nestingLevel, + RearrangerSettings settings) + { + super(start, end, modifiers, modifierString, name, ""); + contents = new ArrayList(); + resultRuleInstances = null; + this.settings = settings; + this.nestingLevel = nestingLevel; + } + + public String getTypeIconName() { + String result = "nodes/class"; + if (end.getParent() instanceof PsiClass) { + PsiClass psiClass = (PsiClass)end.getParent(); + if (psiClass.isEnum()) { + result = "nodes/enum"; + } + else if (psiClass.isInterface()) { + result = "nodes/interface"; + } + } + return result; + } + + public String[] getAdditionalIconNames() { + if (end instanceof PsiJavaToken && end.getText().equals("{")) { + PsiClass psiClass = (PsiClass)end.getParent(); + if (psiClass.getModifierList().hasModifierProperty(PsiModifier.PUBLIC)) { + return new String[]{"nodes/c_public"}; + } + if (psiClass.getModifierList().hasModifierProperty(PsiModifier.PROTECTED)) { + return new String[]{"nodes/c_protected"}; + } + if (psiClass.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) { + return new String[]{"nodes/c_private"}; + } + return new String[]{"nodes/c_plocal"}; + } + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return new JLabel(name); + } + + protected void parseRemainingClassContents(final Project project, + int startingIndex, + final PsiElement psiClass + ) + { + final PsiSearchHelper psh = PsiSearchHelper.SERVICE.getInstance(project); + int lastIndex = startingIndex; + /** + * if option indicates, don't parse inner class contents; leave them unchanged. + */ + if (settings.isRearrangeInnerClasses() || nestingLevel <= 1) { + for (int i = startingIndex; i < psiClass.getChildren().length; i++) { + PsiElement child = psiClass.getChildren()[i]; + if (child instanceof PsiJavaToken && child.getText().equals("{")) { + lastIndex = i + 1; // first item of a class starts immediately after the class left brace. + } + LOG.debug(psiClass.toString() + " child " + i + ":" + child.toString()); + if (child instanceof PsiField || + child instanceof PsiMethod || + child instanceof PsiClass || + child instanceof PsiClassInitializer) + { + MemberAttributes attributes = new MemberAttributes(); + PsiElement startElement = psiClass.getChildren()[lastIndex]; + + ClassContentsEntry classContentsEntry = null; + if (child instanceof PsiField) { + i = parseField(child, attributes, i, (PsiClass)psiClass); + // a field declaration with multiple fields like "int x, y;" must advance child to "y;" + // to prevent splitting. + child = psiClass.getChildren()[i]; + classContentsEntry = new FieldEntry( + startElement, + child, + attributes.modifiers, + attributes.modifierString, + attributes.name, + attributes.type + ); + } + if (child instanceof PsiMethod) { + parseMethod(child, attributes, psh); + classContentsEntry = new MethodEntry( + startElement, + child, + attributes.modifiers, + attributes.modifierString, + attributes.name, + attributes.type, + attributes.nParameters, + attributes.interfaceName + ); + } + if (child instanceof PsiClass) { + parseClassAttributes(child, attributes); + // + // if child is an enum, set the last entry past the LBrace to the final enumeration or the + // semicolon thereafter, if any. + // + PsiClass clazz = (PsiClass)child; + PsiElement clazzEnd; + int startElementIndex = 0; + if (clazz.isEnum()) { + // we want to skip all the enumeration fields, including terminating semicolon if present. + // class parsing begins after these. + startElementIndex = findLastEnumTerminator(clazz); + clazzEnd = clazz.getChildren()[startElementIndex]; + startElementIndex++; + } + else { + // normal class: parse everything after the left brace. + clazzEnd = clazz.getLBrace(); + startElementIndex = Arrays.asList(clazz.getChildren()).indexOf(clazzEnd) + 1; + } + ClassEntry entry = new ClassEntry( + startElement, + clazzEnd, + attributes.modifiers, + attributes.modifierString, + attributes.name, + nestingLevel + 1, + settings + ); + classContentsEntry = entry; + entry.parseRemainingClassContents( + project, + startElementIndex, + child); + } + if (child instanceof PsiClassInitializer) { + parseClassInitializer(child, attributes); + classContentsEntry = new ClassInitializerEntry(startElement, + child, + attributes.modifiers, + attributes.modifierString, + attributes.name); + } + contents.add(classContentsEntry); + classContentsEntry.checkForComment(); + lastIndex = i + 1; // next class includes everything since the end of the prior class. + } + } + } + if (lastIndex < psiClass.getChildren().length) { + if (lastIndex < 0) { + lastIndex = 0; + } + // create a dummy trailer entry to cover anything after the last class. + final MiscellaneousTextEntry miscellaneousTextEntry = new MiscellaneousTextEntry( + psiClass.getChildren()[lastIndex], + psiClass.getChildren()[psiClass.getChildren().length - 1], + false, true + ); + contents.add(miscellaneousTextEntry); + miscellaneousTextEntry.checkForComment(); + } + } + + /** + * Search for the end of the enumeration's fields. It may be terminated with a semicolon, in which case we want + * to point to the next item. If no semicolon is found, we want to point to the enum's right brace. + * + * @param clazz + * @return starting element index for the portion of the enumeration class following its enum declarations. + */ + private int findLastEnumTerminator(PsiClass clazz) { + int startElementIndex = 0; + // go until we hit RBrace (non-inclusive), or semicolon (inclusive) + boolean foundLBrace = false; + for (int j = 0; j < clazz.getChildren().length; j++) { + PsiElement psiElement = clazz.getChildren()[j]; + if (!foundLBrace) { + if (psiElement == clazz.getLBrace()) { + foundLBrace = true; + } + } + else { + startElementIndex = j; + if (psiElement == clazz.getRBrace()) { + break; + } + if (psiElement instanceof PsiJavaToken && + ((PsiJavaToken)psiElement).getTokenType() == JavaTokenType.SEMICOLON) + { + break; + } + } + } + return startElementIndex; + } + + private int parseField(PsiElement child, MemberAttributes attributes, int i, final PsiClass psiClass) { + attributes.field = (PsiField)child; + LOG.debug("enter parseField: child=" + + (child == null ? "null" : child.toString())); + attributes.name = attributes.field.getName(); + if (attributes.field.getTypeElement() == null) { + attributes.type = attributes.field.getContainingClass().getName(); // if enum, use class as type + } + else { + attributes.type = attributes.field.getTypeElement().getText(); + } + attributes.modifierString = attributes.field.getModifierList().getText(); + attributes.modifiers = ModifierUtils.getModifierMask(attributes.modifierString); + if (attributes.field.getContainingClass().isInterface()) { + // all fields in an interface are constants, hence "public static final" + attributes.modifiers |= Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; + } + if (attributes.field.getInitializer() instanceof PsiNewExpression) { + final PsiElement lc = attributes.field.getInitializer().getLastChild(); + if (lc instanceof PsiAnonymousClass) { + attributes.modifiers |= ModifierConstants.INIT_TO_ANON_CLASS; + } + } + LOG.debug( + "parseField: name=" + + attributes.name + + ", modifiers=" + + Integer.toHexString(attributes.modifiers) + ); + /** + * handle multiple declarations here. While this field declaration does not end + * in a semicolon, skip whitespace and intervening comma; move child ahead to + * next field. This prevents declarations like "int b, a;" from being split. + */ + PsiElement myChild = child; + boolean done = false; + while (!done) { + PsiElement lastElement = myChild.getLastChild(); + LOG.debug("parseField: getLastChild=" + + (lastElement == null ? "null" : lastElement.toString())); + if (lastElement == null) break; + if (lastElement instanceof PsiErrorElement) break; + if (lastElement instanceof PsiJavaToken && + ((PsiJavaToken)lastElement).getTokenType() == JavaTokenType.SEMICOLON) + { + break; + } + if (lastElement instanceof PsiComment) { + break; + } + // skip to next field + LOG.debug( + "parseField:skipping to next field, i=" + + i + + ", psiClass=" + psiClass.getName() + ); + LOG.debug( + "parseField: psiClass children array length=" + + psiClass.getChildren().length + ); + while (++i < psiClass.getChildren().length) { + myChild = psiClass.getChildren()[i]; + LOG.debug("parseField: myChild=" + myChild.toString()); + if (myChild instanceof PsiField) { + done = true; + break; + } + } + } + return i; + } + + private void parseMethod(PsiElement child, MemberAttributes attributes, final PsiSearchHelper psh) { + attributes.method = (PsiMethod)child; + attributes.name = attributes.method.getName(); + if (attributes.method.getReturnTypeElement() == null) { + attributes.type = "null"; + } + else { + attributes.type = attributes.method.getReturnTypeElement().getText(); + } + attributes.modifierString = attributes.method.getModifierList().getText(); + attributes.modifiers = ModifierUtils.getModifierMask(attributes.modifierString); + attributes.nParameters = attributes.method.getParameterList().getParameters().length; + if (attributes.method.getContainingClass().isInterface()) { + // methods in an interface are always considered public + attributes.modifiers |= Modifier.PUBLIC; + } + // set any additional "modifier" flags. +// final Query sm2 = SuperMethodsSearch.search(attributes.method, +// attributes.method.getContainingClass(), false, false); +// for (MethodSignatureBackedByPsiMethod msb : sm2) { +// System.out.println(msb.getMethod().getName()); +// } // seems to be no different than method.findSuperMethods() + + attributes.modifiers |= isCanonicalOrInterface(attributes.method, attributes); + final SearchScope ss = psh.getUseScope(child); + final Query query = OverridingMethodsSearch.search(attributes.method, ss, true); + final PsiMethod method = query.findFirst(); + if (method != null) { + final Collection overridersCollection = query.findAll(); + final PsiMethod[] overriders = overridersCollection.toArray(new PsiMethod[overridersCollection.size()]); + LOG.debug( + "method " + + attributes.method.toString() + + " is overridden; has " + + overriders.length + " overriding methods:" + ); + dumpMethodNames(overriders); + if (attributes.method.getBody() == null) { + attributes.modifiers |= ModifierConstants.IMPLEMENTED; + } + else { + attributes.modifiers |= ModifierConstants.OVERRIDDEN; + } + } + // determine if this method overrides another. + final PsiMethod[] superMethods = attributes.method.findSuperMethods(false); + LOG.debug("method " + attributes.method.toString() + " has " + superMethods.length + " supermethods"); + dumpMethodNames(superMethods); + if (superMethods.length > 0) { + // determine if supermethod is abstract or interface; if so, assign IMPLEMENTING attribute. + PsiMethod superMethod = superMethods[0]; + boolean abztract = superMethod.getModifierList().hasModifierProperty(PsiModifier.ABSTRACT); + PsiClass superclass = superMethod.getContainingClass(); + if (abztract || ( + superclass != null && superclass.isInterface())) + { + attributes.modifiers |= ModifierConstants.IMPLEMENTING; + } + else { + attributes.modifiers |= ModifierConstants.OVERRIDING; + } + } + if (attributes.method.isConstructor()) { + attributes.modifiers |= ModifierConstants.CONSTRUCTOR; + } + /** getter/setter cannot be determined here because definition of what a getter/setter + * is can vary from rule to rule. Do it at the time of rule matching. + */ + else if ((attributes.modifiers & ModifierConstants.CANONICAL) == 0) { + attributes.modifiers |= ModifierConstants.OTHER_METHOD; + } + LOG.debug( + "method " + + attributes.name + + " attributes: " + + ModifierConstants.toString(attributes.modifiers) + ); + } + + private int isCanonicalOrInterface(PsiMethod method, MemberAttributes attributes) { + PsiElement methodParent = method.getParent(); + LOG.debug("checking to see if " + method.getName() + " of " + methodParent + " is canonical"); + PsiMethod[] superMethods = method.findSuperMethods(); + LOG.debug("result of findSuperMethods for " + method.getName() + ": size=" + superMethods.length); + // check to see if this method is canonical (inherited from Object). + for (PsiMethod m : superMethods) { + PsiElement parent = m.getParent(); + LOG.debug( + "supermethod " + + m.getName() + + " belongs to " + + parent + ); + if (parent instanceof PsiClass) { + final PsiClass psiClass = ((PsiClass)parent); + if (psiClass.isInterface()) { + LOG.debug("method " + method.toString() + " implements interface"); + attributes.interfaceName = psiClass.getName(); + } + PsiElement superclass = psiClass.getSuperClass(); + if (superclass == null) { + // m's class must be java.lang.Object; it's the only class with a null + // superclass. + LOG.debug("method " + method.toString() + " is canonical"); + return ModifierConstants.CANONICAL; + } + else { + int result = isCanonicalOrInterface(m, attributes); +// int result = 0; +// if (!superclass.toString().equalsIgnoreCase("psiclass:object")) +// { +// result = isCanonicalOrInterface(m, attributes); +// } + if (result > 0) { + LOG.debug("Returning result from canonical check as " + result); + return result; + } + } + } + } + return 0; + } + + private void dumpMethodNames(PsiMethod[] methods) { + for (int j = 0; j < methods.length; j++) { + LOG.debug( + j + + ":" + + methods[j].toString() + + " of class " + + methods[j].getParent().toString() + ); + } + } + + private void parseClassAttributes(PsiElement child, MemberAttributes attributes) { + attributes.childClass = (PsiClass)child; + attributes.name = attributes.childClass.getName(); + if (attributes.name == null) { + attributes.name = ""; + } + attributes.modifierString = attributes.childClass.getModifierList().getText(); + attributes.modifiers = ModifierUtils.getModifierMask(attributes.modifierString); + attributes.type = attributes.childClass.isEnum() ? "enum" : "class"; + if (attributes.childClass.isEnum()) { + attributes.modifiers |= ModifierConstants.ENUM; + } + } + + private void parseClassInitializer(PsiElement child, MemberAttributes attributes) { + attributes.classInitializer = (PsiClassInitializer)child; + attributes.classInitializer.getModifierList(); + attributes.name = ""; + attributes.modifierString = attributes.classInitializer.getModifierList().getText(); + attributes.modifiers = ModifierUtils.getModifierMask(attributes.modifierString) | + ModifierConstants.INITIALIZER; + } + + public void emit(Emitter emitter) { + // first emit the text up to and including the left brace. + super.emit(emitter); + // now emit all children. + emitter.emitRuleInstances(getResultRuleInstances()); + } + + public DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings) { + DefaultMutableTreeNode result = super.addToPopupTree(parent, settings); + // now add class contents, if any + if (getResultRuleInstances() != null) { + for (IRuleInstance instance : getResultRuleInstances()) { + instance.addRuleInstanceToPopupTree(result, settings); + } + } + return result; + } + + /** rearranges the contents of this PsiClass according to supplied rules. */ + public void rearrangeContents() { + buildMethodCallGraph(); + + LOG.debug("identifying setters and extracted (related) methods"); + for (ClassContentsEntry contentsEntry : getContents()) { + if (contentsEntry instanceof IRelatableEntry) { + ((IRelatableEntry)contentsEntry).determineSettersAndMethodCalls(settings, getContents()); + } + } + LOG.debug("relating extracted methods"); + for (ClassContentsEntry contentsEntry : getContents()) { + if (contentsEntry instanceof IRelatableEntry) { + ((IRelatableEntry)contentsEntry).determineExtractedMethod(settings.getExtractedMethodsSettings()); + } + } + /** + * remove any cycles in the related method graph. + */ + MethodEntry.eliminateCycles(getContents()); + /** + * check for overloaded extracted methods; if configured to be kept together, attach subsequent + * methods to the first and remove them from consideration for other alignment. + */ + MethodEntry.handleOverloadedMethods(getContents(), settings); + final GenericRearranger classContentsRearranger = + new GenericRearranger(settings.getItemOrderAttributeList(), + contents, + nestingLevel, + settings) + { + public void rearrangeRelatedItems(List entries, + List ruleInstanceList) + { + for (IRuleInstance ruleInstance : ruleInstanceList) { + ruleInstance.rearrangeRuleItems(entries, settings); + } + } + }; + resultRuleInstances = classContentsRearranger.rearrangeEntries(); + } + + private void buildMethodCallGraph() { + if (settings.getExtractedMethodsSettings().isMoveExtractedMethods() || + settings.isKeepGettersSettersTogether()) + { + LOG.debug("building method call & getter-setter graph"); + for (ClassContentsEntry contentsEntry : getContents()) { + if (contentsEntry instanceof IRelatableEntry) { + ((IRelatableEntry)contentsEntry).determineGetterSetterAndExtractedMethodStatus(settings); + } + } + } + } + +// End Methods of Interface IFilePopupEntry + + public final List getContents() { + return contents; + } + + public List getResultRuleInstances() { + return resultRuleInstances; + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/ClassInitializerEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassInitializerEntry.java new file mode 100644 index 000000000000..f15a3b75c5e4 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassInitializerEntry.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.PsiElement; +import com.wrq.rearranger.popup.RearrangerTreeNode; +import com.wrq.rearranger.settings.RearrangerSettings; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import java.lang.reflect.Modifier; + +/** Represents a class initializer. */ +public class ClassInitializerEntry + extends ClassContentsEntry +{ + private static final Logger LOG = Logger.getInstance("#" + ClassInitializerEntry.class.getName()); + + public ClassInitializerEntry(final PsiElement start, + final PsiElement end, + final int modifiers, + final String modifierString, + final String name) + { + super(start, end, modifiers, modifierString, name, ""); + } + + + public String getTypeIconName() { + final String name = Modifier.isStatic(getModifiers()) ? "nodes/StaticClassInitializer" : "nodes/ClassInitializer"; + return name; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return new JLabel(Modifier.isStatic(getModifiers()) ? "" : ""); + } + + public DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings) { + LOG.debug("add class initializer to popup tree"); + DefaultMutableTreeNode node = new RearrangerTreeNode(this, name); + parent.add(node); + return node; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/FieldEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/FieldEntry.java new file mode 100644 index 000000000000..92b96ab24473 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/FieldEntry.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiModifierList; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.settings.RearrangerSettings; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; + +/** Represents a member field of a class. */ +public class FieldEntry + extends ClassContentsEntry +{ + /** + * If Keep Getters/Setters With Property is true, and if this field is a property, then a reference to the + * property's getter (primary) method is stored here. That method is removed from the list of entries considered + * for rule matching. This field is responsible for emitting that method. + */ + MethodEntry getterMethod; + + public FieldEntry(final PsiElement start, + final PsiElement end, + final int modifiers, + final String modifierString, + final String name, + final String type) + { + super(start, end, modifiers, modifierString, name, type); + getterMethod = null; + } + + public String getTypeIconName() { + if (end instanceof PsiField) { + PsiField f = (PsiField)end; + return ((PsiModifierList)f.getModifierList()).hasModifierProperty(PsiModifier.STATIC) ? "nodes/staticField" : "nodes/field"; + } + return null; + } + + public String[] getAdditionalIconNames() { + if (end instanceof PsiField) { + PsiField f = (PsiField)end; + if (f.getModifierList().hasModifierProperty(PsiModifier.PUBLIC)) return new String[]{"nodes/c_public"}; + if (f.getModifierList().hasModifierProperty(PsiModifier.PROTECTED)) return new String[]{"nodes/c_protected"}; + if (f.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) return new String[]{"nodes/c_private"}; + return new String[]{"nodes/c_plocal"}; + } + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + StringBuffer name = new StringBuffer(80); + PsiField f = (PsiField)end; + name.append(f.getName()); + name.append(": "); + name.append(f.getTypeElement().getText()); + if (f.getInitializer() != null && f.getInitializer().getText().indexOf('\n') < 0) { + name.append(" = "); + name.append(f.getInitializer().getText()); + } + return new JLabel(name.toString()); + } + + public DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings) { + DefaultMutableTreeNode node = super.addToPopupTree(parent, settings); + if (node != null && getterMethod != null) { + getterMethod.addToPopupTree(node, settings); + for (MethodEntry me : getterMethod.correspondingGetterSetters) { + me.addToPopupTree(node, settings); + } + } + return node; + } + + public void emit(Emitter emitter) { + super.emit(emitter); + /** + * emit setters/getters if they are kept with the property. + */ + if (getterMethod != null) { + getterMethod.emit(emitter); + } + } + + public MethodEntry getGetterMethod() { + return getterMethod; + } + + public void setGetterMethod(MethodEntry getterMethod) { + this.getterMethod = getterMethod; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/IPopupTreeRangeEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/IPopupTreeRangeEntry.java new file mode 100644 index 000000000000..eb4e7636443f --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/IPopupTreeRangeEntry.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.wrq.rearranger.settings.RearrangerSettings; + +import javax.swing.tree.DefaultMutableTreeNode; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Feb 18, 2004 + * Time: 9:17:56 AM + * To change this template use File | Settings | File Templates. + */ +public interface IPopupTreeRangeEntry { + + /** + * Gives individual entries control over their appearance, depending on settings. + * + * @param parent DefaultMutableTreeNode to which this entry will be appended as a child. + * @param settings current Rearranger settings + * @return new DefaultMutableTreeNode + */ + DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/IRelatableEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/IRelatableEntry.java new file mode 100644 index 000000000000..317360a1a093 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/IRelatableEntry.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.RelatedMethodsSettings; + +import java.util.List; + +/** + * Defines methods implemented by entries which may be related to others, i.e. getters and setters, + * method entries which call other methods, and overloaded method entries. + */ +public interface IRelatableEntry { + /** + * Determine if the entry is a getter/setter or is excluded from extracted method consideration by an + * overriding rule. + */ + void determineGetterSetterAndExtractedMethodStatus(RearrangerSettings settings); + + /** + * Determine corresponding setters for getters and identify related methods. + * + * @param settings current settings, containing extracted/related method options. + * @param contents contents of class, containing potentially related methods. + */ + void determineSettersAndMethodCalls(RearrangerSettings settings, + List contents); + + /** + * Decide if a method is an extracted method. It is an extracted method if: + * - it is called by at least one other method, and + * - it is private, or passes the "never / 1 / >1" caller test. + */ + void determineExtractedMethod(RelatedMethodsSettings settings); + + /** @return true if the method is related to another. In this case, the method is exempt from rule matching. */ + boolean isRelatedMethod(); + + /** @return true if the method is a setter and will be emitted below a corresponding getter. */ + boolean isEmittableSetter(); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/MemberAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/entry/MemberAttributes.java new file mode 100644 index 000000000000..662c5d59e0a3 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/MemberAttributes.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiClassInitializer; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiMethod; + +/** Temporary structure to accumulate attributes during parsing, before final RangeEntry is created. */ +public class MemberAttributes { + String name = ""; + String type = ""; + String interfaceName = null; + PsiField field = null; + PsiMethod method = null; + PsiClass childClass = null; + PsiClassInitializer classInitializer = null; + int modifiers = 0; + String modifierString = ""; + int nParameters = 0; +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java new file mode 100644 index 000000000000..0c4780ef24c4 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java @@ -0,0 +1,1288 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.psi.*; +import com.wrq.rearranger.ModifierConstants; +import com.wrq.rearranger.popup.RearrangerTreeNode; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.RelatedMethodsSettings; +import com.wrq.rearranger.settings.attributeGroups.IHasGetterSetterDefinition; +import com.wrq.rearranger.settings.attributeGroups.IRestrictMethodExtraction; +import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.util.CommentUtil; +import com.wrq.rearranger.util.MethodUtil; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import java.util.*; + +/** + * Corresponds to a method in the source file. + * Contains structures and logic to handle related method rearrangement. + */ +public class MethodEntry + extends ClassContentsEntry + implements IRelatableEntry +{ +// ------------------------------ FIELDS ------------------------------ + + private static final Logger LOG = Logger.getInstance("#" + MethodEntry.class.getName()); + + /** + * Contains a list of methods called by this method. One exception: if this method is a getter, then + * the corresponding setter will be placed in calledMethods. This allows the same code to rearrange both + * types of related methods. + */ + List calledMethods = new ArrayList(); + List calledByMethods = new ArrayList(); + List overloadedMethods = new ArrayList(); + // MethodEntry correspondingSetter = null; // TODO - avoid wrong level for setters + List correspondingGetterSetters = new ArrayList(); + private boolean keptWithProperty; + private boolean relatedMethod; + + /** @return true if the method is related to another. In this case, the method is exempt from rule matching. */ + public boolean isRelatedMethod() { + return relatedMethod; + } + + /** @return true if the method is a setter and will be emitted below a corresponding getter. */ + public boolean isEmittableSetter() { + return setter && correspondingGetterSetters.size() > 0; + } + + private boolean isOverloadedMethod; + private final int nParameters; + private String customizedPrecedingComment = ""; + + public String getCustomizedPrecedingComment() { + if (customizedPrecedingComment == null) { + return ""; + } + return customizedPrecedingComment; + } + + private String customizedTrailingComment = ""; + + public String getCustomizedTrailingComment() { + if (customizedTrailingComment == null) { + return ""; + } + return customizedTrailingComment; + } + + private boolean noExtractedMethods; + + public boolean isNoExtractedMethods() { + return noExtractedMethods; + } + + public void setNoExtractedMethods(boolean noExtractedMethods) { + this.noExtractedMethods = noExtractedMethods; + } + + private boolean getter; + + public boolean isGetter() { + return getter; + } + + public void setGetter(boolean getter) { + this.getter = getter; + } + + private boolean setter; + + public boolean isSetter() { + return setter; + } + + public void setSetter(boolean setter) { + this.setter = setter; + } + + /** name of interface, if this method implements an interface method. */ + private final String interfaceName; + + public String getInterfaceName() { + return interfaceName; + } + + private List sortedMethods = new LinkedList(); + +// -------------------------- STATIC METHODS -------------------------- + + /** + * Called after top level methods (and other items) have been moved from entries to ruleInstanceList. Task now + * is to scan ruleInstanceList looking for MethodEntry objects with dependent (related, extracted) methods. Move + * these from the entries list to the correct place in the ruleInstanceList list. + * + * @param entries Remaining (unarranged) items, including all dependent (extracted) methods. + * @param ruleInstance Rule containing parents (callers) of potentially related methods + */ + public static void rearrangeRelatedItems(List entries, + IRuleInstance ruleInstance, + RelatedMethodsSettings rms) + { + List parentEntries = new ArrayList(ruleInstance.getMatches()); + for (RangeEntry o : parentEntries) { + if (o instanceof IRelatableEntry) { + MethodEntry me = (MethodEntry)o; + if (me.isGetter()) { + if (me.keptWithProperty) { + if (me.getMatchedRule() != null && me.getMatchedRule().getMatches() != null) { + // prevent the getter from appearing under a rule it matches; it will be placed under the property + me.getMatchedRule().getMatches().remove(me); + } + } + for (MethodEntry theSetter : me.correspondingGetterSetters) { + final IRuleInstance theRule = theSetter.getMatchedRule(); + LOG.debug( + "rearrangeRelatedItems: for getter method " + + me + + ", corresponding setter is " + + theSetter + ); + if (theRule != null && + theRule.getMatches() != null) + { + LOG.debug( + "remove entry " + + theSetter.end + + " from matched rule" + + theRule + + "; matches = " + + ((java.util.List)theRule.getMatches()) == null ? "null" : "" + ); + theRule.getMatches().remove(theSetter); + } + } + } + if (me.calledMethods.size() > 0) { + List parents = new LinkedList(); + parents.add(me); + moveRelatedItems( + entries, + parents, + rms, + ((PsiMethod)me.end).getName(), + ((PsiMethod)me.end).getName() + "()", + 1 + ); + if (LOG.isDebugEnabled()) { + // dump sorted children recursively + me.dumpChild(0); + } + me.assignComments(rms); + } + } + } + } + + /** + * Move methods related to this one underneath it (beginning at the index specified.) Do so in depth-first or + * breadth-first order, as configured. At each level, do alphabetical, original order, or call order sorting. + * + * @param entries list of global (all rule) unmatched items including dependent methods + * @param parents contains a list of items to be handled; order is depth or breadth-first. + */ + private static void moveRelatedItems(List entries, + List parents, + RelatedMethodsSettings rms, + String topLevelMethodName, + String allMethodNames, + int level) + { + allMethodNames = buildAllMethodNamesString(allMethodNames, parents); + /** + * First, identify all dependent methods. Move them to parents in the specified order. + */ + List children = ((MethodEntry)parents.get(parents.size() - 1)).sortedMethods; +// if (rms.isDepthFirstOrdering()) +// { + switch (rms.getOrdering()) { + case RelatedMethodsSettings.RETAIN_ORIGINAL_ORDER: { + /** + * iterate through entries looking for those that are called by method(s) in the set of parent methods. + * Add these to the list of children in order seen in entries. + */ + ListIterator li = entries.listIterator(); + while (li.hasNext()) { + Object o = li.next(); + if (o instanceof IRelatableEntry) { + MethodEntry me = (MethodEntry)o; + for (MethodEntry entry : parents) { + if (me.calledByMethods.contains(entry)) { + children.add(me); + li.remove(); + break; + } + } + } + } + } + break; + case RelatedMethodsSettings.ALPHABETICAL_ORDER: { + /** + * iterate through entries looking for those that are called by method(s) in the set of parent methods. + * Add these to the list of children alphabetically. + */ + ListIterator li = entries.listIterator(); + while (li.hasNext()) { + Object o = li.next(); + if (o instanceof IRelatableEntry) { + MethodEntry me = (MethodEntry)o; + for (MethodEntry entry : parents) { + if (me.calledByMethods.contains(entry)) { + me.insertAlphabetically(children); + li.remove(); + break; + } + } + } + } + } + break; + case RelatedMethodsSettings.INVOCATION_ORDER: + /** + * iterate through calling methods, looking for remaining unmatched methods (in 'entries' list). + * Add these to the list of children in order of invocation. + */ + for (MethodEntry me : parents) { + for (MethodEntry child : me.calledMethods) { + if (entries.contains(child)) { + children.add(child); + entries.remove(child); + } + } + } + break; + } + /** + * now children contains all the children of the parents for this level, and all these children have been + * removed from "entries". Move these to the rearranged list. Then: + * If depth-first, recurse setting the parent list to each of the children in turn. + * If breadth first, recurse setting the parent list to all of the children. + */ + if (children.size() > 0) { + if (rms.isDepthFirstOrdering()) { + for (MethodEntry entry : children) { + if (entry.calledMethods.size() == 0) { + continue; + } + List parent = new LinkedList(); + parent.add(entry); + moveRelatedItems( + entries, + parent, + rms, + topLevelMethodName, + allMethodNames + "." + ((PsiMethod)entry.end).getName() + "()", + level + 1 + ); + } + } + else { + moveRelatedItems( + entries, + children, + rms, + topLevelMethodName, + allMethodNames + ".Depth " + level, + level + 1 + ); + } + } + } + + private static String buildAllMethodNamesString(String allMethodNames, List parents) { + StringBuffer allMN = new StringBuffer(120); + allMN.append(allMethodNames); + if (allMN.length() > 0) { + allMN.append("."); + } + if (parents.size() > 1) { + allMN.append("["); + } + { + boolean first = true; + for (MethodEntry entry : parents) { + if (!first) { + allMN.append(","); + } + first = false; + allMN.append(((PsiMethod)entry.end).getName()); + } + } + if (parents.size() > 1) { + allMN.append("]"); + } + return allMN.toString(); + } + + public void insertAlphabetically(final List list) { + Comparator comparator = new Comparator() { + public int compare(MethodEntry me, MethodEntry me2) { + String s = ((PsiMethod)me.end).getName(); + if (me.isGetter()) { + s = MethodUtil.getPropertyName((PsiMethod)me.end); + } + return s.compareTo(((PsiMethod)me2.end).getName()); + } + }; + insertInList(list, comparator); + } + + void insertInList(final List list, Comparator comparator) { + boolean inserted = false; + ListIterator li = list.listIterator(); + while (li.hasNext() && !inserted) { + MethodEntry entry = ((MethodEntry)li.next()); + if (comparator.compare(this, entry) < 0) { + LOG.debug( + "insertInList dependent method: add " + end.toString() + " at index " + (li.nextIndex() - 1) + ); + list.add(li.nextIndex() - 1, this); + inserted = true; + } + } + if (!inserted) { + list.add(this); + } + } + + void dumpChild(int level) { + LOG.debug(level + ": " + ((PsiMethod)end).getName()); + for (MethodEntry methodEntry : sortedMethods) { + methodEntry.dumpChild(level + 1); + } + } + + private void assignComments(RelatedMethodsSettings rms) { + List callingMethod = new ArrayList(); + callingMethod.add(this); + assignComments(rms, callingMethod, "", 1); + } + + /** + * Eliminate cycles of method calls so that the related method tree is a tree, not a cycle (or directed graph). + * If method A calls method B, B calls C, and C calls A, eliminate the final call to prevent cycling. + * + * @param contents + */ + public static void eliminateCycles(List contents) { + for (ClassContentsEntry entry : contents) { + if (entry instanceof IRelatableEntry) { + MethodEntry current = (MethodEntry)entry; + List set = new LinkedList(); + set.add(current); + test(current, set); + } + } + } + + private static void test(MethodEntry current, List set) { + Iterator it = current.calledMethods.iterator(); + while (it.hasNext()) { + MethodEntry callee = it.next(); + if (set.contains(callee)) { + callee.calledByMethods.remove(current); + if (callee.calledByMethods.size() == 0) { + callee.relatedMethod = false; + } + it.remove(); + } + else { + set.add(callee); + test(callee, set); + } + } + } + + /** + * If setting indicates, move all overloaded methods (of the same name) + * adjacent with the first encountered. Sort in the configured order + * (original order, or by number of parameters). + */ + public static void handleOverloadedMethods(List contents, + RearrangerSettings settings) + { + if (!settings.isKeepOverloadedMethodsTogether()) return; + /** + * first, detect overloaded methods and move them to the first method's list of overloaded methods. + * Make two passes, first for extracted methods, then for non-extracted methods. This will organize any + * overloaded methods for extracted methods with them (as opposed to whichever was seen first.) + */ + cullOverloadedMethods(contents, true); + LOG.debug("entered handleOverloadedMethods(): move overloaded methods together"); + cullOverloadedMethods(contents, false); + List copy = new ArrayList(contents); + for (ClassContentsEntry rangeEntry : copy) { + if (rangeEntry instanceof IRelatableEntry) { + MethodEntry current = (MethodEntry)rangeEntry; + if (current.overloadedMethods.size() > 0) { + List newList = new ArrayList(current.overloadedMethods.size() + 1); + newList.add(current); + /** + * we are looking at the head of a list of overloaded methods. We need to sort the list + * if necessary and, if the head of the list has changed, replace it in the contents array. + */ + switch (settings.getOverloadedOrder()) { + case RearrangerSettings.OVERLOADED_ORDER_RETAIN_ORIGINAL: + // list is already in original order, except perhaps that the top-most extracted method + // comes first (if there is one). + newList.addAll(current.overloadedMethods); + break; + case RearrangerSettings.OVERLOADED_ORDER_ASCENDING_PARAMETERS: + case RearrangerSettings.OVERLOADED_ORDER_DESCENDING_PARAMETERS: + for (MethodEntry entry : current.overloadedMethods) { + boolean inserted = false; + for (int index = 0; index < newList.size(); index++) { + MethodEntry me = newList.get(index); + if (settings.getOverloadedOrder() == RearrangerSettings.OVERLOADED_ORDER_ASCENDING_PARAMETERS + ? me.getnParameters() > entry.getnParameters() + : me.getnParameters() < entry.getnParameters()) + { + newList.add(index, entry); + inserted = true; + break; + } + } + if (!inserted) { + newList.add(entry); + } + } + break; + } + current.overloadedMethods.clear(); + /** + * if the head of the arraylist is not the same as "current", then the sort operation moved + * another method to the head of the list. Replace that in the contents array. Then assign + * a new ordered list. + */ + int index = contents.indexOf(current); + if (newList.get(0) != current) { + contents.set(index, ((MethodEntry)newList.get(0))); + } + /** + * insert the remaining overloaded methods after the current entry. + */ + newList.remove(0); + for (int j = 0; j < newList.size(); j++) { + contents.add(index + j + 1, ((MethodEntry)newList.get(j))); + } + } + } + } + } + + /** + * Removes overloaded methods from the contents list and adds them to the overloadedMethods list of the first + * overloaded method encountered. + * + * @param contents + * @param doExtractedMethods + */ + private static void cullOverloadedMethods(List contents, + boolean doExtractedMethods) + { + List copy = new ArrayList(contents); + for (ClassContentsEntry o : copy) { + if (o instanceof IRelatableEntry) { + MethodEntry me = (MethodEntry)o; + if ((me.isRelatedMethod() == doExtractedMethods) && !me.isOverloadedMethod) { + String meName = me.end.toString(); + // search contents list for methods with identical name, and attach them as overloaded methods. + ListIterator contentIterator = contents.listIterator(); + while (contentIterator.hasNext()) { + Object o1 = contentIterator.next(); + if (o1 instanceof IRelatableEntry) { + MethodEntry me2 = (MethodEntry)o1; + if (me2 == me) { + continue; + } + String me2Name = me2.end.toString(); + if (meName.equals(me2Name)) { + contentIterator.remove(); + me.overloadedMethods.add(me2); + me2.isOverloadedMethod = true; // set flag so array copy will skip this entry. + } + } + } + } + } + } + } + + public int getnParameters() { + return nParameters; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public MethodEntry(final PsiElement start, + final PsiElement end, + final int modifiers, + final String modifierString, + final String name, + final String type, + int nParameters, + final String interfaceName) + { + super(start, end, modifiers, modifierString, name, type); + this.nParameters = nParameters; + this.interfaceName = interfaceName; + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public String[] getAdditionalIconNames() { + ArrayList result = new ArrayList(); + String[] sa = new String[0]; + if (end instanceof PsiMethod) { + PsiMethod m = (PsiMethod)end; + if (m.getModifierList().hasModifierProperty(PsiModifier.PUBLIC)) { + result.add("nodes/c_public"); + } + else if (m.getModifierList().hasModifierProperty(PsiModifier.PROTECTED)) { + result.add("nodes/c_protected"); + } + else if (m.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) { + result.add("nodes/c_private"); + } + else { + result.add("nodes/c_plocal"); + } + if ((getModifiers() & ModifierConstants.IMPLEMENTING) != 0) { + result.add("gutter/implementingMethod"); + } + if ((getModifiers() & ModifierConstants.IMPLEMENTED) != 0) { + result.add("gutter/implementedMethod"); + } + if ((getModifiers() & ModifierConstants.OVERRIDING) != 0) { + result.add("gutter/overridingMethod"); + } + if ((getModifiers() & ModifierConstants.OVERRIDDEN) != 0) { + result.add("gutter/overridenMethod"); + } + } + return result.toArray(sa); + } + + public String getTypeIconName() { + if (end instanceof PsiMethod) { + PsiMethod m = (PsiMethod)end; + return (((PsiModifierList)m.getModifierList()).hasModifierProperty(PsiModifier.STATIC)) ? "nodes/staticMethod" : "nodes/method"; + } + return null; + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface IFilePopupEntry --------------------- + + public JLabel getPopupEntryText(RearrangerSettings settings) { + StringBuffer name = new StringBuffer(80); + + PsiMethod m = (PsiMethod)end; + if (m.getReturnTypeElement() != null && !settings.isShowTypeAfterMethod()) { + name.append(m.getReturnTypeElement().getText()); + name.append(' '); + } + name.append(m.getName()); + PsiParameterList plist = m.getParameterList(); + if (settings.isShowParameterNames() || + settings.isShowParameterTypes()) + { + if (plist != null) { + name.append("("); + for (int i = 0; i < plist.getParameters().length; i++) { + if (i > 0) { + name.append(", "); + } + if (settings.isShowParameterTypes()) { + String modifiers = plist.getParameters()[i].getModifierList().getText(); + if (modifiers.length() > 0) { + name.append(modifiers); + name.append(' '); + } + name.append(plist.getParameters()[i].getTypeElement().getText()); + if (settings.isShowParameterNames()) { + name.append(' '); + } + } + if (settings.isShowParameterNames()) { + name.append(plist.getParameters()[i].getName()); + } + } + name.append(")"); + } + } + if (m.getReturnTypeElement() != null && settings.isShowTypeAfterMethod()) { + name.append(": "); + name.append(m.getReturnTypeElement().getText()); + } + return new JLabel(name.toString()); + } + +// --------------------- Interface IRelatableEntry --------------------- + + public void determineGetterSetterAndExtractedMethodStatus(RearrangerSettings settings) { + LOG.debug("building method call & getter-setter graph for " + getName()); + /** + * check all rules to find first that this method matches. If that rule specifies + * that matching methods are excluded from extracted method treatment, then skip this + * step. If this method is a getter (according to that rule's definition) then + * determine its setter (according to that rule's definition) at this point also. + */ + setNoExtractedMethods(false); + /** + * The following code determines whether the method is a getter/setter based on default definition. + * This is necessary in case there are no rules, but "Keep Getters/Setters Together" is set. + * If the method matches an individual rule with its own getter/setter definition, the values of + * getter and setter will be changed to match that rule's definition. + */ + setGetter( + MethodUtil.isGetter( + (PsiMethod)end, + settings.getDefaultGSDefinition() + ) + ); + setSetter( + MethodUtil.isSetter( + (PsiMethod)end, + settings.getDefaultGSDefinition() + ) + ); + for (IRule rule : settings.getItemOrderAttributeList()) { + if (rule instanceof IRestrictMethodExtraction) { + if (rule.isMatch(this)) { + if (((IRestrictMethodExtraction)rule).isNoExtractedMethods()) { + LOG.debug( + "excluding " + + end.toString() + + " from extracted method consideration" + ); + setNoExtractedMethods(true); + } + setGetter(false); + if (rule instanceof IHasGetterSetterDefinition) { + if (MethodUtil.isGetter( + (PsiMethod)getEnd(), + ((IHasGetterSetterDefinition)rule).getGetterSetterDefinition() + )) + { + if (settings.isKeepGettersSettersTogether()) { + setGetter(true); + } + } + setSetter( + MethodUtil.isSetter( + (PsiMethod)getEnd(), + ((IHasGetterSetterDefinition)rule).getGetterSetterDefinition() + ) + ); + } + break; + } + } + } + } + + public void determineSettersAndMethodCalls(RearrangerSettings settings, + List contents) + { + if (isGetter()) { + if (settings.isKeepGettersSettersTogether()) { + determineSetter(contents, settings); // link getters/setters via correspondingGetterSetter entries + } + } + if (!isNoExtractedMethods() && + settings.getExtractedMethodsSettings().isMoveExtractedMethods()) + { + determineMethodCalls(contents, settings); + } + } + + /** + * Decide if a method is an extracted method. It is an extracted method if: + * - it is called by at least one other method, and + * - it is private, or passes the "never / 1 / >1" caller test. + *

+ * (It is not considered an extracted method if it is a setter, there is a corresponding getter, and the + * option to keep getters and setters together is set. This is a special case.) + */ + public void determineExtractedMethod(RelatedMethodsSettings settings) { + relatedMethod = false; + if (!isGetter() && !isSetter()) { + if (calledByMethods.size() > 0) { + PsiMethod m = (PsiMethod)end; + if (!m.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) { + switch (settings.getNonPrivateTreatment()) { + case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_NEVER: + break; + case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ONE_CALLER: + if (calledByMethods.size() == 1) { + relatedMethod = true; + } + break; + case RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ANY_CALLERS: + relatedMethod = true; + break; + } + } + else { + relatedMethod = true; + } + } + } + else { + if (isSetter() && calledByMethods.size() > 0 && correspondingGetterSetters.size() == 0) { + relatedMethod = true; + LOG.debug(end.toString() + " is setter but has no getter, treated as extracted method"); + } + else { + LOG.debug(end.toString() + " is getter/setter, not treated as extracted method"); + } + } + LOG.debug("determined " + end.toString() + " is extracted method? " + relatedMethod); + /** + * If this is not an extracted method, remove it from any callers so that it won't be moved. + */ + if (!relatedMethod) { + ListIterator li = calledByMethods.listIterator(); + while (li.hasNext()) { + MethodEntry entry = (li.next()); + entry.calledMethods.remove(this); + li.remove(); + } + } + /** + * Remaining entries are only extracted methods at this point. Using first/last rule, keep only the call by + * the calling method that this child method will be grouped with, and discard the rest. + */ + if (calledByMethods.size() > 1) { + ListIterator li; + if (settings.isBelowFirstCaller()) { + li = calledByMethods.listIterator(1); + while (li.hasNext()) { + MethodEntry entry = (li.next()); + entry.calledMethods.remove(this); + li.remove(); + } + } + else { + li = calledByMethods.listIterator(calledByMethods.size() - 1); + while (li.hasPrevious()) { + MethodEntry entry = (li.previous()); + entry.calledMethods.remove(this); + li.remove(); + } + } + } + if (relatedMethod) { + LOG.debug( + "extracted method " + + toString() + + " will be arranged under " + + calledByMethods.get(0).toString() + ); + } + } + +// -------------------------- OTHER METHODS -------------------------- + + public DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings) { + DefaultMutableTreeNode node = new RearrangerTreeNode(this, name); + parent.add(node); + ListIterator li; + for (MethodEntry methodEntry : sortedMethods) { + if (methodEntry.isSetter() && methodEntry.calledByMethods.size() > 0) { + // setters are arranged with getters when "keep getters/setters together" option is checked. + // but setters are not really called by getters. So attach them to the upper level. + methodEntry.addToPopupTree(parent, settings); + } + else { + methodEntry.addToPopupTree(node, settings); + } + } + for (MethodEntry methodEntry : overloadedMethods) { + methodEntry.addToPopupTree(node, settings); + } + return node; + } + + /** + * Set preceding and/or trailing comments on the appropriate methods, based on the comment type. + * + * @param rms + * @param allMethodNames contains a list of methods invoked to reach this point. Top level is empty string. + * @param level current nesting level; top level is 1. + */ + private void assignComments(RelatedMethodsSettings rms, + List allCallingMethods, + String allMethodNames, + int level) + { + final String currentMethodName = ((PsiMethod)end).getName(); + String[] callingNames = new String[allCallingMethods.size()]; + for (int i = 0; i < allCallingMethods.size(); i++) { + MethodEntry me = allCallingMethods.get(i); + callingNames[i] = ((PsiMethod)me.end).getName(); + } + MethodEntry topLevel = this; + while (topLevel.calledByMethods.size() > 0) { + topLevel = (topLevel.calledByMethods.get(0)); + } + switch (rms.getCommentType()) { + case RelatedMethodsSettings.COMMENT_TYPE_TOP_LEVEL: + customizedPrecedingComment = expandComment( + rms.getPrecedingComment(), + currentMethodName, + allMethodNames, + currentMethodName, + level + ); + MethodEntry last = this; + while (last.sortedMethods.size() > 0) { + last = (last.sortedMethods.get(last.sortedMethods.size() - 1)); + } + last.customizedTrailingComment = expandComment( + rms.getTrailingComment(), + currentMethodName, + allMethodNames, + currentMethodName, + level + ); + break; + case RelatedMethodsSettings.COMMENT_TYPE_EACH_METHOD: + customizedPrecedingComment = expandComment( + rms.getPrecedingComment(), + currentMethodName, + allMethodNames, + ((PsiMethod)topLevel.end).getName(), + level + ); + customizedTrailingComment = expandComment( + rms.getTrailingComment(), + currentMethodName, + allMethodNames, + ((PsiMethod)topLevel.end).getName(), + level + ); + // recursively assign comments. + for (MethodEntry methodEntry : sortedMethods) { + String newAllMethodNames = appendMN( + allMethodNames, + callingNames, + allCallingMethods, + this, + rms + ); + methodEntry.assignComments(rms, sortedMethods, newAllMethodNames, level + 1); + } + break; + case RelatedMethodsSettings.COMMENT_TYPE_NEW_FAMILY: { + /** + * Specialized routine to assign comments to "families" of + * methods. Insert a preceding comment before every sibling + * except: when it is the first, and when the prior sibling + * had no children and this sibling has no children. + */ + MethodEntry firstEntry = null; + MethodEntry previousEntry = null; + for (MethodEntry methodEntry : allCallingMethods) { + if (firstEntry == null) { + firstEntry = methodEntry; + } + else if (methodEntry.sortedMethods.size() != 0 || + previousEntry.sortedMethods.size() != 0) + { + methodEntry.customizedPrecedingComment = + expandComment( + rms.getPrecedingComment(), + currentMethodName, + allMethodNames, + ((PsiMethod)topLevel.end).getName(), + level + ); + } + previousEntry = methodEntry; + if (methodEntry.sortedMethods.size() != 0) { + String newAllMethodNames = appendMN( + allMethodNames, + callingNames, + allCallingMethods, + methodEntry, + rms + ); + methodEntry.assignComments(rms, methodEntry.sortedMethods, newAllMethodNames, level + 1); + } + } + } + break; + case RelatedMethodsSettings.COMMENT_TYPE_EACH_LEVEL: { + MethodEntry beginLevel = allCallingMethods.get(0); + MethodEntry endLevel = allCallingMethods.get(allCallingMethods.size() - 1); + beginLevel.customizedPrecedingComment = expandComment( + rms.getPrecedingComment(), + currentMethodName, + allMethodNames, + ((PsiMethod)topLevel.end).getName(), + level + ); + // recursively assign comments for each level. + for (MethodEntry methodEntry : allCallingMethods) { + if (methodEntry.sortedMethods.size() > 0) { + String newAllMethodNames = appendMN( + allMethodNames, + callingNames, + allCallingMethods, + methodEntry, + rms + ); + methodEntry.assignComments(rms, methodEntry.sortedMethods, newAllMethodNames, level + 1); + } + } + while (endLevel.sortedMethods.size() > 0) { + endLevel = endLevel.sortedMethods.get(endLevel.sortedMethods.size() - 1); + } + if (endLevel.customizedTrailingComment.length() > 0) { + endLevel.customizedTrailingComment += "\n"; + } + endLevel.customizedTrailingComment += expandComment( + rms.getTrailingComment(), + currentMethodName, + allMethodNames, + ((PsiMethod)topLevel.end).getName(), + level + ); + } + break; + } + } + + /** + * Build a string representing a sequence of method calls needed to reach a particular child method. + * + * @param allMethods previous method call sequence + * @param newMethods names of each of the methods in callingMethods + * @param callingMethods MethodEntry objects for each method + * @param currentMethod current method being handled + * @param rms contains setting determining if depth-first or breadth-first traversal has taken place. + * @return + */ + private String appendMN(String allMethods, + String[] newMethods, + List callingMethods, + MethodEntry currentMethod, + RelatedMethodsSettings rms) + { + StringBuffer result = new StringBuffer(allMethods.length() + 80); + result.append(allMethods); + if (rms.isDepthFirstOrdering()) { + if (newMethods.length > 0) { + if (result.length() > 0) result.append('.'); + } + int index = callingMethods.indexOf(currentMethod); + result.append(newMethods[index]); + result.append("()"); + } + else { + if (newMethods.length > 0) { + if (result.length() > 0) result.append('.'); + if (newMethods.length > 1) { + result.append('['); + } + for (int i = 0; i < newMethods.length; i++) { + if (i > 0) result.append(','); + result.append(newMethods[i]); + result.append("()"); + } + if (newMethods.length > 1) { + result.append(']'); + } + } + } + return result.toString(); + } + + private static String expandComment(CommentRule comment, + String methodName, + String methodNames, + String topLevelMethodName, + int level) + { + if (comment == null) return ""; + String result = comment.getCommentText(); + if (result == null) return ""; + result = result.replaceAll("%TL%", topLevelMethodName); + result = result.replaceAll("%MN%", methodName); + result = result.replaceAll("%AM%", methodNames); + result = result.replaceAll("%LV%", String.valueOf(level)); + return result; + } + + public void checkForComment() { + if (CommentUtil.getCommentMatchers().size() == 0) { + return; + } + createAlternateValueString(); + /** + * we don't want to check for comments in the body of the method. So reduce the alternate value string + * to only that text up to and including the open brace. Temporarily remove the rest of the text; append + * it again after checking for comments. + */ + int brace = alternateValue.indexOf('{'); + String temp = ""; + if (brace >= 0) { + // every method should have an open brace -- unless it is abstract. + temp = alternateValue.substring(brace + 1, alternateValue.length()); + alternateValue = alternateValue.substring(0, brace + 1); + } + super.checkForComment(); + alternateValue += temp; + } + + /** + * Analyzes the method calls made by this method and creates a "call graph," linking caller and callee by + * references in the calledMethods and calledByMethods lists, respectively. Only method calls to methods in + * this class are entered into the call graph, because only methods in this class can be moved underneath + * their caller. + * + * @param possibleMethods list of methods in this class; call graph is limited to these methods + * @param settings current configuration + */ + public void determineMethodCalls(final List possibleMethods, + final RearrangerSettings settings) + { + /** + * recursively walk the method's code block looking for method calls. + */ + final PsiMethod thisMethod = (PsiMethod)end; + final MethodEntry thisMethodEntry = this; + + JavaRecursiveElementVisitor rev = new JavaRecursiveElementVisitor() { + public void visitMethodCallExpression(PsiMethodCallExpression psiMethodCallExpression) { +// logger.debug("visitMethodCallExpression:" + psiMethodCallExpression.toString()); + PsiElement c = psiMethodCallExpression.getMethodExpression().getReference().resolve(); + /** + * if the called method is already in our list, don't add it again. + */ + if (c != null && !calledMethods.contains(c)) { + for (ClassContentsEntry o : possibleMethods) { + if (o instanceof IRelatableEntry) { + MethodEntry me = (MethodEntry)o; + PsiMethod m = (PsiMethod)me.end; + if (c == m) { + if (settings.isKeepOverloadedMethodsTogether() && + m.getName().equals(thisMethod.getName())) + { + LOG.debug("method " + me + " is overload, not inserted in call graph"); + } + else { + LOG.debug("method " + thisMethod.toString() + " calls " + m.toString()); + calledMethods.add(me); + me.calledByMethods.add(thisMethodEntry); + } + break; + } + } + } + } + // now parse the expression list; it also may contain method calls. + super.visitExpressionList(psiMethodCallExpression.getArgumentList()); + } + }; + + thisMethod.accept(rev); + } + + /** + * Called when getters and setters are to be kept together in pairs. Searches the list of entries for + * any getter/setter methods that matches this getter method. Normally there is only one setter per getter, + * but one could have a "getXXX", "isXXX" and "setXXX" trio which need to be related. In this case, the first + * getter encountered finds the other getter and setter and the three will be emitted in that order. + * + * @param possibleMethods entry list, possibly containing the corresponding setter for this getter. + * @param settings + */ + public void determineSetter(final List possibleMethods, RearrangerSettings settings) { + if (!isGetter()) // wasted assertion, already checked before calling + { + return; + } + final PsiMethod thisMethod = (PsiMethod)end; + String thisProperty = MethodUtil.getPropertyName(thisMethod); + if (isGetter() && !keptWithProperty) { + if (settings.isKeepGettersSettersWithProperty()) { + hookGetterToProperty(possibleMethods); + } + } + for (ClassContentsEntry o : possibleMethods) { + if (o instanceof IRelatableEntry) { + MethodEntry me = (MethodEntry)o; + // don't use a setter twice (could be two methods which both look like getters; assign the setter + // to only one of them.) Also, associate all getter/setter methods for the same property with the + // first one encountered. + if ((me.isSetter() || + me.isGetter()) && + me.correspondingGetterSetters.size() == 0 && + me != this) + { + PsiMethod m = (PsiMethod)me.end; + String otherProperty = MethodUtil.getPropertyName(m); + if (thisProperty.equals(otherProperty)) { + LOG.debug("method " + thisMethod.toString() + " is getter; its setter is " + m.toString()); + // place getters ahead of setters + if (me.isGetter()) { + correspondingGetterSetters.add(0, me); + // clear the getter flag and set the setter flag; this causes the method to be emitted + // under the first getter encountered. + me.setGetter(false); + me.setSetter(true); + } + else { + correspondingGetterSetters.add(me); + } + me.correspondingGetterSetters.add(this); + } + } + } + } + } + + /** + * Getters/Setters are supposed to be kept with their associated property. Search the list of entries to find + * the property and attach the setter. + * + * @param entries list of all items (methods, fields) in the class. + */ + private void hookGetterToProperty(List entries) { + ListIterator li = entries.listIterator(); + String property = MethodUtil.getPropertyName((PsiMethod)end); + while (li.hasNext()) { + Object o = li.next(); + if (o instanceof FieldEntry) { + FieldEntry fe = (FieldEntry)o; + StringBuffer sb = new StringBuffer(fe.getName()); + sb.setCharAt(0, Character.toUpperCase(sb.charAt(0))); + if (fe.getGetterMethod() == null && property.equals(sb.toString())) { + fe.setGetterMethod(this); + keptWithProperty = true; + break; + } + } + } + } + + public void emit(Emitter emitter) { + StringBuffer sb = emitter.getStringBuffer(); + if (getCustomizedPrecedingComment().length() > 0) { + sb.append("\n"); + sb.append(getCustomizedPrecedingComment()); + } + emitAllElements(sb, emitter.getDocument()); + if (getCustomizedTrailingComment().length() > 0) { + sb.append("\n"); + sb.append(getCustomizedTrailingComment()); + } + /** + * emit corresponding setter, overloaded methods, and related methods, if any. + */ + ListIterator li; + if (isGetter()) { + for (MethodEntry entry : correspondingGetterSetters) { + entry.emit(emitter); + } + } + for (MethodEntry me : overloadedMethods) { + me.emit(emitter); + } + for (MethodEntry me : sortedMethods) { + me.emit(emitter); + } + } + + protected void emitAllElements(StringBuffer sb, Document document) { + if (alternateValue != null) { + /** + * protect body of method from removing newlines. + */ + int brace = alternateValue.indexOf('{'); + String temp = ""; + if (brace >= 0) { + // every method should have an open brace -- unless it is abstract. + temp = alternateValue.substring(brace + 1, alternateValue.length()); + alternateValue = alternateValue.substring(0, brace + 1); + } + super.emitAllElements(sb, document); + sb.append(temp); + } + else { + super.emitAllElements(sb, document); + } + } + + public void insertInterfaceOrder(List list) { + Comparator comparator = new Comparator() { + public int compare(MethodEntry o1, MethodEntry o2) { + final int offset1 = getMethodOffsetInInterface((PsiMethod)o1.end); + final int offset2 = getMethodOffsetInInterface((PsiMethod)o2.end); + if (offset1 < offset2) return -1; + if (offset1 == offset2) return 0; + return 1; + } + }; + insertInList(list, comparator); + } + + private int getMethodOffsetInInterface(PsiMethod method) { + final PsiMethod[] superMethods = method.findSuperMethods(); +// final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); // todo - for IDEA 5.0 + if (superMethods.length == 0) return 0; + PsiMethod m = superMethods[0]; + PsiElement parent = m.getParent(); + if (parent instanceof PsiClass && ((PsiClass)parent).isInterface()) { + return m.getTextOffset(); + } + return getMethodOffsetInInterface(m); + } + + public String toString() { + return "MethodEntry " + + end.toString() + + "; calls " + + calledMethods.size() + + ", called by " + + calledByMethods.size() + + ", nParameters=" + nParameters; + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/MiscellaneousTextEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/MiscellaneousTextEntry.java new file mode 100644 index 000000000000..4d3da310a052 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/MiscellaneousTextEntry.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.psi.PsiElement; +import com.wrq.rearranger.settings.RearrangerSettings; + +import javax.swing.*; + +/** Corresponds to comments and whitespace that surround Java syntactic items like classes and methods. */ +public class MiscellaneousTextEntry + extends ClassContentsEntry +{ + public MiscellaneousTextEntry(final PsiElement start, + final PsiElement end, + final boolean fixedHeader, + final boolean fixedTrailer) + { + super(start, end, fixedHeader, fixedTrailer); + } + + public String getTypeIconName() { + // do not show headers and trailers in the file structure popup. + return null; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return null; + } + + public String toString() { + String result; + if (isFixedHeader()) { + result = "Header"; + } + else { + result = "Trailer"; + } + if (alternateValue != null) { + result += "; comments removed"; + } + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/PsiFileEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/PsiFileEntry.java new file mode 100644 index 000000000000..11ac5ba48afe --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/PsiFileEntry.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.wrq.rearranger.settings.RearrangerSettings; + +import java.util.List; + +/** + * Dummy "outer class" which actually corresponds to the PsiFile. Since classes contain + * header text (text from the beginning of the class until the first recognized member), one or more + * members, and trailing text, we can create a dummy "class" which will parse the file. Header text + * will include the package and import statements, and outer classes will be its members. + */ +public class PsiFileEntry + extends ClassEntry +{ + public PsiFileEntry(RearrangerSettings settings) { + super(null, null, 0, "", null, 0, settings); + } + + /** + * Strip off leading elements which do not belong to the first class, and place them in + * a MiscellaneousText entry. + * + * @param project + * @param psiFile + * @param commentList + * @return + */ + public List parseFile(Project project, + PsiElement psiFile, + List commentList) + { + int startingIndex = 0; + for (int i = 0; i < psiFile.getChildren().length; i++) { + PsiElement child = psiFile.getChildren()[i]; + if (child instanceof PsiClass) { + do { + startingIndex = i; + i--; + if (i >= 0) { + child = psiFile.getChildren()[i]; + } + else { + break; + } + } + while (child instanceof PsiWhiteSpace || + child instanceof PsiComment || + child.getText().length() == 0); + break; + } + } + MiscellaneousTextEntry miscellaneousTextEntry = null; + if (startingIndex > 0) { + miscellaneousTextEntry = new MiscellaneousTextEntry( + psiFile.getChildren()[0], + psiFile.getChildren()[startingIndex - 1], + true, false + ); + } + parseRemainingClassContents(project, startingIndex, psiFile); + if (miscellaneousTextEntry != null) { + contents.add(0, miscellaneousTextEntry); + } + return contents; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java new file mode 100644 index 000000000000..5f41b963e9d2 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.entry; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.psi.PsiElement; +import com.wrq.rearranger.popup.RearrangerTreeNode; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.CommentUtil; + +import javax.swing.tree.DefaultMutableTreeNode; +import java.util.regex.Matcher; + +/** + * Corresponds to Java syntactic items ("entries") like classes, fields, and methods. A range entry + * contains start and end Psi elements for each item (which could be identical), as well as modifier + * flags and special flags to mark any miscellaneous text or comments that precede or follow the item. + */ +abstract public class RangeEntry implements IPopupTreeRangeEntry { +// ------------------------------ FIELDS ------------------------------ + + private static final Logger LOG = Logger.getInstance("#" + RangeEntry.class.getName()); + String alternateValue; + final String name; + protected final PsiElement start; + protected final PsiElement end; + private final int modifiers; + private final String modifierString; + private final boolean fixedHeader; + private final boolean fixedTrailer; + private final String type; + private IRuleInstance matchedRule; + private boolean separatorCommentPrecedes; + +// --------------------------- CONSTRUCTORS --------------------------- + + public RangeEntry(final PsiElement start, + final PsiElement end, + final boolean fixedHeader, + final boolean fixedTrailer) + { + this(start, end, 0, "", "", "", fixedHeader, fixedTrailer); + } + + RangeEntry(final PsiElement start, + final PsiElement end, + final int modifiers, + final String modifierString, + final String name, + final String type) + { + this(start, end, modifiers, modifierString, name, type, false, false); + } + + private RangeEntry(final PsiElement start, + final PsiElement end, + final int modifiers, + final String modifierString, + final String name, + final String type, + final boolean fixedHeader, + final boolean fixedTrailer) + { + this.start = start; + this.end = end; + this.modifiers = modifiers; + this.modifierString = modifierString; + this.fixedHeader = fixedHeader; + this.fixedTrailer = fixedTrailer; + this.name = name; + this.type = type; + alternateValue = null; + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public PsiElement getEnd() { + return end; + } + + public IRuleInstance getMatchedRule() { + return matchedRule; + } + + public void setMatchedRule(IRuleInstance matchedRule) { + this.matchedRule = matchedRule; + } + + public int getModifiers() { + return modifiers; + } + + public String getModifierString() { + return modifierString; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public PsiElement getStart() { + return start; + } + + public boolean isFixedHeader() { + return fixedHeader; + } + + public boolean isFixedTrailer() { + return fixedTrailer; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public String toString() { + String result = (name == null ? "" : name); + if (start != null && end != null) { + result += "; range from " + + start.toString() + + " [" + + start.getTextRange().getStartOffset() + + "] to " + + end.toString() + + " [" + + end.getTextRange().getEndOffset() + + "]; modifiers=0x" + + Integer.toHexString(modifiers); + } + else { + result += "; no start/end specified"; + } + if (fixedHeader) { + result = "Header: " + result; + } + if (fixedTrailer) { + result = "Trailer: " + result; + } + if (alternateValue != null) { + result += "; comments removed"; + } + return result; + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface IPopupTreeRangeEntry --------------------- + + public DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings) { + DefaultMutableTreeNode myNode = new RearrangerTreeNode(this, name); + parent.add(myNode); + return myNode; + } + +// -------------------------- OTHER METHODS -------------------------- + + public void checkForComment() { + if (CommentUtil.getCommentMatchers().size() == 0) { + return; + } + createAlternateValueString(); + /** + * for each separator comment specified by the user, check to see if this comment matches. + */ + for (Matcher matcher : CommentUtil.getCommentMatchers()) { + matcher.reset(alternateValue); + boolean foundMatch = matcher.find(); + if (foundMatch) { + LOG.debug("found comment pattern '" + + matcher.pattern().pattern().replaceAll("\n", "#") + + "' in '" + + alternateValue.replaceAll("\n", "#") + + "'"); + StringBuffer sb = new StringBuffer(alternateValue.length()); + do { + boolean leadingNewlines = start.getTextRange().getStartOffset() > 0; + matcher.appendReplacement(sb, + leadingNewlines ? "\n" : ""); + foundMatch = matcher.find(); + } + while (foundMatch); + matcher.appendTail(sb); + alternateValue = sb.toString(); + LOG.debug("RangeEntry alternateValue=" + alternateValue.replaceAll("\n", "#")); + } + } + } + + protected void createAlternateValueString() { + if (alternateValue != null) { + return; + } + final StringBuffer sb = new StringBuffer( + end.getTextRange().getEndOffset() - + start.getTextRange().getStartOffset() + ); + PsiElement e = start; + while (e != null && e != end) { + if (e == end.getParent()) { + e = e.getFirstChild(); + } + else { + sb.append(e.getText()); + e = e.getNextSibling(); + } + } + if (e == end) { + sb.append(end.getText()); + } + alternateValue = sb.toString(); + } + + public void emit(Emitter emitter) { + emitAllElements(emitter.getStringBuffer(), emitter.getDocument()); + } + + protected void emitAllElements(StringBuffer sb, Document document) { + if (alternateValue != null) { + String result = alternateValue; + if (separatorCommentPrecedes) { + // remove all leading blank lines. The only blank lines we want are the ones explicitly appended + // to the preceding separator comment. + LOG.debug("emitAllElements: separator comment precedes " + + name + "; original value=" + + alternateValue.replaceAll("\n", "#")); + result = alternateValue.replaceFirst("\n[ \t\n]*\n", "\n"); + LOG.debug("emitAllElements: resulting value=" + + alternateValue.replaceAll("\n", "#")); + } + sb.append(result); + } + else { + PsiElement curr = start; + while (curr != null && curr != end) { + if (curr == end.getParent()) { + curr = curr.getFirstChild(); + } + else { + emitElement(curr, sb, document); + curr = curr.getNextSibling(); + } + } + if (curr == end) { + emitElement(end, sb, document); + } + } + } + + private void emitElement(final PsiElement curr, + final StringBuffer sb, + final Document document) + { + try { + sb.append( + document.getCharsSequence().toString().toCharArray(), // for Irida (builds 3185 etc). + curr.getTextRange().getStartOffset(), + curr.getTextRange().getEndOffset() - curr.getTextRange().getStartOffset() + ); + } + catch (ArrayIndexOutOfBoundsException oob) { + LOG.error("internal error attempting to append text to document"); + LOG.error("document.getCharsSequence.length=" + document.getCharsSequence().length()); + LOG.error("document.getCharsSequence.toString().length=" + document.getCharsSequence().toString().length()); + LOG.error("document...toCharArray.length=" + document.getCharsSequence().toString().toCharArray().length); + LOG.error("current PSI element=" + curr.toString()); + LOG.error("current PSI element text=" + curr.getText()); + LOG.error("current PSI element text range, start offset=" + curr.getTextRange().getStartOffset()); + LOG.error("current PSI element text range, end offset=" + curr.getTextRange().getEndOffset()); + LOG.error("current PSI element text range, length=" + curr.getTextRange().getLength()); + LOG.error(oob); + throw oob; + } + } + + public void setSeparatorCommentPrecedes(boolean precedes) { + this.separatorCommentPrecedes = precedes; + LOG.debug("emitAllElements: set separator comment precedes " + name); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java b/plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java new file mode 100644 index 000000000000..5b6b4cad46e5 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.intellij.psi.PsiFile; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import com.wrq.rearranger.util.IconUtil; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.ArrayList; +import java.util.List; + +/** Contains code to pop up a file structure dialog, showing proposed rearrangement. */ +public class FileStructurePopup + implements IHasScrollPane +{ + final RearrangerSettings settings; + final PopupTreeComponent treeComponent; + + public FileStructurePopup(RearrangerSettings settings, + List resultRuleInstances, + final IFilePopupEntry psiFileEntry) + { + this.settings = settings; + treeComponent = new PopupTreeComponent(settings, resultRuleInstances, psiFileEntry); + } + + public FileStructurePopup(RearrangerSettings settings, + List resultRuleInstances, + final PsiFile psiFile) + { + this.settings = settings; + IFilePopupEntry psiFileEntry = new IFilePopupEntry() { + public String getTypeIconName() { + return "ppFile"; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return new JLabel(psiFile.getName()); + } + }; + treeComponent = new PopupTreeComponent(settings, resultRuleInstances, psiFileEntry); + } + + /** + * Display a pane showing the rearrangement. + * + * @return true if rearrangement should take place + */ + public boolean displayRearrangement() { + JPanel containerPanel = getContainerPanel(); + JOptionPane pane = new JOptionPane( + containerPanel, + JOptionPane.PLAIN_MESSAGE, + JOptionPane.OK_CANCEL_OPTION + ); + JDialog dialog = pane.createDialog(null, "Rearrangement Results"); + dialog.setResizable(true); + dialog.setVisible(true); + Object selectedValue = pane.getValue(); + return ((Integer)selectedValue) == JOptionPane.OK_OPTION; + } + +// Level 2 methods + + private JPanel getContainerPanel() { + final JPanel containerPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints scrollPaneConstraints = new GridBagConstraints(); + Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + + final JScrollPane treeView = getScrollPane(); + final JComponent showTypesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowParameterTypes(); + } + + void setSetting(boolean value) { + settings.setShowParameterTypes(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowParamTypes"); + } + + String getToolTipText() { + return "Show parameter types"; + } + + int getShortcut() { + return KeyEvent.VK_T; + } + }.getIconBox(); + final JComponent showNamesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowParameterNames(); + } + + void setSetting(boolean value) { + settings.setShowParameterNames(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowParamNames"); + } + + String getToolTipText() { + return "Show parameter names"; + } + + int getShortcut() { + return KeyEvent.VK_N; + } + }.getIconBox(); + + final JComponent showFieldsBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowFields(); + } + + void setSetting(boolean value) { + settings.setShowFields(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowFields"); + } + + String getToolTipText() { + return "Show fields"; + } + + int getShortcut() { + return KeyEvent.VK_F; + } + }.getIconBox(); + final JComponent showTypeAfterMethodBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowTypeAfterMethod(); + } + + void setSetting(boolean value) { + settings.setShowTypeAfterMethod(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowTypeAfterMethod"); + } + + String getToolTipText() { + return "Show type after method"; + } + + int getShortcut() { + return KeyEvent.VK_A; + } + }.getIconBox(); + final JComponent showRulesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowRules(); + } + + void setSetting(boolean value) { + settings.setShowRules(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowRules"); + } + + String getToolTipText() { + return "Show rules"; + } + + int getShortcut() { + return KeyEvent.VK_R; + } + }.getIconBox(); + final JComponent showMatchedRulesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowMatchedRules(); + } + + void setSetting(boolean value) { + settings.setShowMatchedRules(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowMatchedRules"); + } + + String getToolTipText() { + return "Show matched rules only"; + } + + int getShortcut() { + return KeyEvent.VK_M; + } + }.getIconBox(); + final JComponent showCommentsBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowComments(); + } + + void setSetting(boolean value) { + settings.setShowComments(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowComments"); + } + + String getToolTipText() { + return "Show generated separator comments"; + } + + int getShortcut() { + return KeyEvent.VK_C; + } + }.getIconBox(); + ((JCheckBox)showRulesBox.getComponent(0)).addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + showMatchedRulesBox.setEnabled(((JCheckBox)showRulesBox.getComponent(0)).isSelected()); + } + } + ); + showMatchedRulesBox.setEnabled(((JCheckBox)showRulesBox.getComponent(0)).isSelected()); + scrollPaneConstraints.insets = new Insets(3, 3, 3, 3); + scrollPaneConstraints.fill = GridBagConstraints.BOTH; + scrollPaneConstraints.gridwidth = GridBagConstraints.REMAINDER; + scrollPaneConstraints.gridheight = GridBagConstraints.REMAINDER; + scrollPaneConstraints.weightx = 1; + scrollPaneConstraints.weighty = 1; + scrollPaneConstraints.gridx = 0; + scrollPaneConstraints.gridy = 1; + + constraints.insets = new Insets(5, 5, 5, 5); + + containerPanel.add(showTypesBox, constraints.firstCol()); + containerPanel.add(showNamesBox, constraints.nextCol()); + containerPanel.add(showFieldsBox, constraints.nextCol()); + containerPanel.add(showTypeAfterMethodBox, constraints.nextCol()); + containerPanel.add(showCommentsBox, constraints.nextCol()); + containerPanel.add(showRulesBox, constraints.nextCol()); + containerPanel.add(showMatchedRulesBox, constraints.lastCol()); + containerPanel.add(treeView, scrollPaneConstraints); + return containerPanel; + } + + /** + * build a JTree containing classes, fields and methods, in accordance with settings. + * + * @return + */ + public JScrollPane getScrollPane() { + // Create the nodes. + JTree tree = treeComponent.createTree(); + /** expand all nodes. */ + for (int i = 0; i < tree.getRowCount(); i++) { + tree.expandRow(i); + } + JScrollPane treeView = new JScrollPane(tree); + treeView.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + treeView.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + Dimension d = treeView.getPreferredSize(); + if (d.width < 400) d.width = 400; + if (d.height < 300) d.height = 300; + treeView.setPreferredSize(d); + return treeView; + } + + public static void main(String[] args) { + final RearrangerSettings settings = new RearrangerSettings(); + IFilePopupEntry pf = new IFilePopupEntry() { + public String getTypeIconName() { + return "nodes/ppFile"; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return new JLabel("FileName.java"); + } + }; + FileStructurePopup fsp = new FileStructurePopup(settings, new ArrayList(), pf); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + + final JFrame frame = new JFrame("SwingApplication"); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1.0d; + constraints.weighty = 1.0d; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 0; + constraints.gridy = 0; + final JPanel object = fsp.getContainerPanel(); + frame.getContentPane().setLayout(new GridBagLayout()); + frame.getContentPane().add(object, constraints); + + //Finish setting up the frame, and show it. + frame.addWindowListener( + new WindowAdapter() { + public void windowClosing(final WindowEvent e) { + System.exit(0); + } + } + ); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/IFilePopupEntry.java b/plugins/rearranger/src/com/wrq/rearranger/popup/IFilePopupEntry.java new file mode 100644 index 000000000000..bd0550870935 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/IFilePopupEntry.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.wrq.rearranger.settings.RearrangerSettings; + +import javax.swing.*; + +/** Interface implemented by objects which can appear as entries in the file structure popup. */ +public interface IFilePopupEntry { + /** @return the name of the icon representing the popup entry's type of Java object (method, class, etc.) */ + String getTypeIconName(); + + /** + * @return the names of the icon representing the protection level of the popup entry, and any other + * icons (overrides/overriding/implements/implmenting). + */ + String[] getAdditionalIconNames(); + + /** @return a JLabel containing the text of the popup tree entry. */ + JLabel getPopupEntryText(RearrangerSettings settings); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/IHasScrollPane.java b/plugins/rearranger/src/com/wrq/rearranger/popup/IHasScrollPane.java new file mode 100644 index 000000000000..b352fbb39a49 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/IHasScrollPane.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import javax.swing.*; + +/** + * Interface implemented by popups (LiveRearrangerPopup, FileStructurePopup) to (re)create the scrollpane when + * the underlying tree changes. + */ +public interface IHasScrollPane { + public JScrollPane getScrollPane(); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java b/plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java new file mode 100644 index 000000000000..dc1543023256 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.wrq.rearranger.ruleinstance.IRuleInstance; + +import java.util.List; + +public interface ILiveRearranger { + void setRearrangementOccurred(boolean rearrangementOccurred); + + void setResultRuleInstances(List resultRuleInstances); + + void liveRearranger(); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/IconBox.java b/plugins/rearranger/src/com/wrq/rearranger/popup/IconBox.java new file mode 100644 index 000000000000..cc0ff8c03c3b --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/IconBox.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import com.wrq.rearranger.util.IconUtil; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; +import java.awt.event.*; + +/** + * Contains enough information to construct a checkbox with the given icon and tooltip + * text, related to a setting. + */ +abstract class IconBox { + + static final Color mouseoverColor = new Color(181, 190, 214); + static final Color selectedColor = new Color(132, 146, 189); + static final Color outlineColor = new Color(8, 36, 107); + + final JPanel containerPanel; + final GridBagConstraints constraints; + final IHasScrollPane scrollPaneComponent; + + protected IconBox(JPanel containerPanel, + GridBagConstraints constraints, + IHasScrollPane scrollPaneComponent) + { + this.containerPanel = containerPanel; + this.constraints = constraints; + this.scrollPaneComponent = scrollPaneComponent; + } + + abstract boolean getSetting(); + + abstract void setSetting(boolean value); + + abstract Icon getIcon(); + + abstract String getToolTipText(); + + abstract int getShortcut(); + + class MouseBox + extends JCheckBox + { + boolean mouseOver; + + public MouseBox(Icon icon) { + super(icon); + } + } + + class MyAction + extends AbstractAction + { + final MouseBox box; + + public MyAction(String name, MouseBox box) { + super(name); + this.box = box; + } + + public void actionPerformed(ActionEvent e) { + //To change body of implemented methods use File | Settings | File Templates. + box.getActionMap().get("pressed").actionPerformed(e); + box.getActionMap().get("released").actionPerformed(e); + } + } + + public JPanel getIconBox() { + final JPanel result = new JPanel(new GridBagLayout()); + + final Icon icon = getIcon(); + final MouseBox box = new MouseBox(icon); + box.setToolTipText(getToolTipText()); + box.setSelected(getSetting()); + box.setBackground(box.isSelected() ? selectedColor : null); + setOutline(result, box.isSelected()); + final MyAction myAction = new MyAction("toggleButton", box); + box.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + setAction(box, (JPanel)box.getParent()); + } + } + ); + box.setFocusable(false); + box.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( + KeyStroke.getKeyStroke( + getShortcut(), + InputEvent.ALT_DOWN_MASK + ), + "toggleButton" + ); + + box.getActionMap().put("toggleButton", myAction); + box.addMouseListener( + new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + box.mouseOver = true; + if (!box.isSelected()) { + box.setBackground(mouseoverColor); + setOutline(result, true); + } + } + + public void mouseExited(MouseEvent e) { + box.mouseOver = false; + if (!box.isSelected()) { + box.setBackground(null); + setOutline(result, false); + } + } + } + ); + result.add(box); + return result; + } + + private void setAction(final MouseBox box, final JPanel result) { + setSetting(box.isSelected()); + box.setBackground(box.isSelected() ? selectedColor : box.mouseOver ? mouseoverColor : null); + setOutline(result, box.mouseOver); + int lastIndex = containerPanel.getComponentCount() - 1; + containerPanel.remove(lastIndex); + final JScrollPane scrollPane = scrollPaneComponent.getScrollPane(); + containerPanel.add(scrollPane, constraints, lastIndex); + scrollPane.invalidate(); + containerPanel.validate(); + } + + /** + * draws a nearly-black outline border around the button (or removes such border). + * + * @param panel JPanel which contains the button. + * @param outline if true, draw the outline. + */ + private void setOutline(JPanel panel, boolean outline) { + Color borderColor = outline ? outlineColor : ((java.awt.Color)panel.getBackground()); + Border b = BorderFactory.createLineBorder(borderColor); + panel.setBorder(b); + } + + public static void main(String[] args) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + + final JFrame frame = new JFrame("IconBox test"); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + frame.getContentPane().setLayout(new GridBagLayout()); + JPanel panel = new JPanel(new GridBagLayout()); + frame.getContentPane().add(panel, constraints.weightedLastCol()); + constraints.fill = GridBagConstraints.NONE; + constraints.gridheight = 1; + constraints.weighty = 0; + IHasScrollPane scroll = new IHasScrollPane() { + public JScrollPane getScrollPane() { + return new JScrollPane(new JLabel("scroll pane contents")); + } + }; + final RearrangerSettings settings = new RearrangerSettings(); + IconBox box = new IconBox(panel, constraints, scroll) { + boolean getSetting() { + return settings.isShowComments(); + } + + void setSetting(boolean value) { + settings.setShowComments(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowComments"); + } + + String getToolTipText() { + return "Show comments (Alt+C)"; + } + + int getShortcut() { + return KeyEvent.VK_C; + } + }; + panel.add(box.getIconBox(), constraints); + constraints.weightedLastRow(); + constraints.fill = GridBagConstraints.BOTH; + JScrollPane firstPane = new JScrollPane(new JLabel("first scrollpane")); + panel.add(firstPane, constraints); + + //Finish setting up the frame, and show it. + frame.addWindowListener( + new WindowAdapter() { + public void windowClosing(final WindowEvent e) { + System.exit(0); + } + } + ); + frame.pack(); + frame.setVisible(true); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java new file mode 100644 index 000000000000..33204f9f285e --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.psi.PsiFile; +import com.wrq.rearranger.LiveRearrangerActionHandler; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import com.wrq.rearranger.util.IconUtil; + +import javax.swing.*; +import java.awt.*; +import java.awt.dnd.DnDConstants; +import java.awt.event.KeyEvent; +import java.util.List; + +/** + * Contains logic to display a rearrangement dialog, allow user to perform drag&drop rearrangement, and + * rearrange the code accordingly. + */ +public class LiveRearrangerDialog + implements IHasScrollPane, + ILiveRearranger +{ + private static final Logger LOG = Logger.getInstance("#" + LiveRearrangerDialog.class.getName()); + final RearrangerSettings settings; + PopupTreeComponent treeComponent; + List resultRuleInstances; + final Window outerPanel; + final Document document; + final PsiFile psiFile; + IFilePopupEntry psiFileEntry; + TreeDragSource tds; + TreeDropTarget tdt; + boolean rearrangementOccurred = false; + private JPanel containerPanel; + int cursorOffset; + private PopupTree popupTree; + + private void createFilePopupEntry(final PsiFile psiFile) { + psiFileEntry = new IFilePopupEntry() { + public String getTypeIconName() { + return "nodes/ppFile"; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return new JLabel(psiFile.getName()); + } + }; + } + + public LiveRearrangerDialog(RearrangerSettings settings, PsiFile psiFile, Document document, + final Window outerPanel, int cursorOffset) + { + this.settings = settings; + this.document = document; + this.psiFile = psiFile; + createFilePopupEntry(psiFile); + this.outerPanel = outerPanel; + this.cursorOffset = cursorOffset; + } + + public void setRearrangementOccurred(boolean rearrangementOccurred) { + this.rearrangementOccurred = rearrangementOccurred; + } + + public void setResultRuleInstances(List resultRuleInstances) { + this.resultRuleInstances = resultRuleInstances; + treeComponent = new PopupTreeComponent(settings, resultRuleInstances, psiFileEntry); + } + + /** Display a live rearrangement window. */ + public void liveRearranger() { + containerPanel = getContainerPanel(); + JOptionPane pane = new JOptionPane( + containerPanel, + JOptionPane.PLAIN_MESSAGE, + JOptionPane.OK_CANCEL_OPTION + ); + JDialog dialog = pane.createDialog(null, "Live Rearranger"); + dialog.setResizable(true); + dialog.setVisible(true); + Object selectedValue = pane.getValue(); + rearrangementOccurred = + treeComponent.isRearrangementOccurred() && + (popupTree.isExitedWithEnterKey() || + (selectedValue != null && + (((Integer)selectedValue) == JOptionPane.OK_OPTION))); + finish(); + LOG.debug("exit liveRearranger"); + } + + public void finish() { + LOG.debug("entered finish() on thread " + Thread.currentThread().getName()); + if (!rearrangementOccurred) { + LOG.debug("no rearrangement occurred, not rearranging document"); + return; + } + LOG.debug("rearranging document"); + if (document != null) { + final Emitter e = new Emitter(psiFile, resultRuleInstances, document); + e.emitRearrangedDocument(); + } + + LiveRearrangerActionHandler.setInProgress(false); + LOG.debug("exit finish() on thread " + Thread.currentThread().getName()); + } + + private JPanel getContainerPanel() { + final JPanel containerPanel = new JPanel(new GridBagLayout()); + + final GridBagConstraints scrollPaneConstraints = new GridBagConstraints(); + scrollPaneConstraints.insets = new Insets(3, 3, 3, 3); + scrollPaneConstraints.fill = GridBagConstraints.BOTH; + scrollPaneConstraints.gridwidth = GridBagConstraints.REMAINDER; + scrollPaneConstraints.gridheight = GridBagConstraints.REMAINDER; + scrollPaneConstraints.weightx = 1; + scrollPaneConstraints.weighty = 1; + scrollPaneConstraints.gridx = 0; + scrollPaneConstraints.gridy = 1; + + final JScrollPane treeView = getScrollPane(); + final JComponent showTypesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowParameterTypes(); + } + + void setSetting(boolean value) { + settings.setShowParameterTypes(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowParamTypes"); + } + + String getToolTipText() { + return "Show parameter types"; + } + + int getShortcut() { + return KeyEvent.VK_T; + } + }.getIconBox(); + final JComponent showNamesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowParameterNames(); + } + + void setSetting(boolean value) { + settings.setShowParameterNames(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowParamNames"); + } + + String getToolTipText() { + return "Show parameter names"; + } + + int getShortcut() { + return KeyEvent.VK_N; + } + }.getIconBox(); + final JComponent showFieldsBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowFields(); + } + + void setSetting(boolean value) { + settings.setShowFields(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowFields"); + } + + String getToolTipText() { + return "Show fields"; + } + + int getShortcut() { + return KeyEvent.VK_F; + } + }.getIconBox(); + final JComponent showTypeAfterMethodBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowTypeAfterMethod(); + } + + void setSetting(boolean value) { + settings.setShowTypeAfterMethod(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowTypeAfterMethod"); + } + + String getToolTipText() { + return "Show type after method"; + } + + int getShortcut() { + return KeyEvent.VK_A; + } + }.getIconBox(); + Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.insets = new Insets(5, 5, 5, 5); + containerPanel.add(showTypesBox, constraints.firstCol()); + containerPanel.add(showNamesBox, constraints.nextCol()); + containerPanel.add(showFieldsBox, constraints.nextCol()); + containerPanel.add(showTypeAfterMethodBox, constraints.lastCol()); + containerPanel.add(treeView, scrollPaneConstraints); + return containerPanel; + } + + /** + * build a JTree containing classes, fields and methods, in accordance with settings. + * + * @return + */ + public JScrollPane getScrollPane() { + // Create the nodes. + popupTree = treeComponent.createLiveRearrangerTree(); + +// /** only expand node where cursor is located. Inspect all rows; deepest node that covers +// * cursor location is the best to expand. (Parent node like a class contains a method where +// * the cursor is; we want to expand the method, not just the class. +// */ +// int expandRow = -1; +// for (int i = 0; i < tree.getRowCount(); i++) +// { +// DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getPathForRow(i).getLastPathComponent(); +// if (node.getUserObject() instanceof RangeEntry) +// { +// RangeEntry re = (RangeEntry) node.getUserObject(); +// if (re.getStart().getTextRange().getStartOffset() <= cursorOffset && +// re.getEnd().getTextRange().getEndOffset() >= cursorOffset) +// { +// logger.debug( +// "node " + +// i + +// " contained cursor (offset=" + +// cursorOffset + +// "): " + re +// ); +// expandRow = i; +// } +// } +// else +// { +// logger.debug("expand node candidate not RangeEntry; node=" + node); +// } +// } +// if (expandRow >= 0) +// { +// logger.debug("expand row " + expandRow); +// tree.expandRow(expandRow); +// } + /** simply expand all nodes. */ + for (int i = 0; i < popupTree.getRowCount(); i++) { + popupTree.expandRow(i); + } + JScrollPane treeView = new JScrollPane(popupTree); + treeView.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + treeView.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + treeView.getVerticalScrollBar().setFocusable(false); + treeView.getHorizontalScrollBar().setFocusable(false); + Dimension d = treeView.getPreferredSize(); + if (d.width < 400) d.width = 400; + if (d.height < 300) d.height = 300; + treeView.setPreferredSize(d); + tdt = new TreeDropTarget(popupTree, this); + tds = new TreeDragSource(popupTree, DnDConstants.ACTION_MOVE, tdt); + return treeView; + } + +// class RearrangerTest +// extends LightCodeInsightTestCase +// { +// private RearrangerSettings rs; +// +// protected final void setUp() throws Exception +// { +// super.setUp(); +// } +// +// +// +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java new file mode 100644 index 000000000000..700ee7527917 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.wrq.rearranger.LiveRearrangerActionHandler; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.IconUtil; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.TitledBorder; +import javax.swing.tree.DefaultMutableTreeNode; +import java.awt.*; +import java.awt.dnd.DnDConstants; +import java.awt.event.*; +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +/** + * Contains logic to display a rearrangement popup, allow user to perform drag&drop rearrangement, and (when + * a keystroke is seen or a mouse click outside the popup occurs) rearrange the code accordingly. + */ +public class LiveRearrangerPopup + implements IHasScrollPane, ILiveRearranger +{ + private static final Logger LOG = Logger.getInstance("#" + LiveRearrangerPopup.class.getName()); + final RearrangerSettings settings; + PopupTreeComponent treeComponent; + List resultRuleInstances; + final Window outerPanel; + final Document document; + final PsiFile psiFile; + IFilePopupEntry psiFileEntry; + private WindowFocusListener windowFocusListener; + private WindowAdapter windowAdapter; + private MouseAdapter mouseAdapter; + private KeyEventDispatcher keyEventDispatcher; + private Popup popup; + // private JWindow popup; + TreeDragSource tds; + TreeDropTarget tdt; + boolean rearrangementOccurred = false; + private FocusAdapter focusAdapter; + private JPanel containerPanel; + private final Project project; + private Cursor oldCursor; + private MouseAdapter ma2; + int cursorOffset; + private Component outerPanelFocusOwner; + boolean sawKeyPressed = false; + + public LiveRearrangerPopup(RearrangerSettings settings, + final IFilePopupEntry psiFileEntry, + Window outerPanel, + Document document, + Project project) + { + LOG.debug("entered LiveRearrangerPopup constructor"); + this.settings = settings; + this.outerPanel = outerPanel; + this.psiFileEntry = psiFileEntry; + this.document = document; + this.psiFile = null; + this.project = project; + } + + private void createFilePopupEntry(final PsiFile psiFile) { + psiFileEntry = new IFilePopupEntry() { + public String getTypeIconName() { + return "nodes/ppFile"; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return new JLabel(psiFile.getName()); + } + }; + } + + public LiveRearrangerPopup(RearrangerSettings settings, PsiFile psiFile, Document document, Project project, + final Window outerPanel, int cursorOffset) + { + this.settings = settings; + this.document = document; + this.psiFile = psiFile; + createFilePopupEntry(psiFile); + this.project = project; + this.outerPanel = outerPanel; + this.cursorOffset = cursorOffset; + try { + SwingUtilities.invokeAndWait( + new Runnable() { + public void run() { +// popup = new JWindow(); + JPanel tempPanel = new JPanel(new GridBagLayout()); + JLabel label = new JLabel("Live Rearranger parsing file..."); + Border b = BorderFactory.createRaisedBevelBorder(); + tempPanel.setBorder(b); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.insets = new Insets(5, 5, 5, 5); + tempPanel.add(label, constraints); + Dimension d = outerPanel.getSize(); + Dimension c = tempPanel.getPreferredSize(); + int x = (d.width - c.width) / 2; + int y = (d.height - c.height) / 2; + if (x < 0) x = 0; + if (y < 0) y = 0; + popup = PopupFactory.getSharedInstance().getPopup(outerPanel, tempPanel, x, y); +// popup.getContentPane().add(tempPanel); +// popup.setLocation(x, y); + LOG.debug("initial outerPanel size=" + d + ", tempPanel preferred size=" + c); + LOG.debug("Constructing initial Popup at x,y=" + x + "," + y); +// popup.pack(); +// popup.setVisible(true); +// popup.requestFocusInWindow(); + popup.show(); + Cursor cu = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); + oldCursor = outerPanel.getCursor(); + LOG.debug("setCursor (WAIT)" + cu + " on " + outerPanel); + outerPanel.setCursor(cu); + } + } + ); + } + catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + catch (InvocationTargetException ite) { + throw new RuntimeException(ite); + } + } + + public void setRearrangementOccurred(boolean rearrangementOccurred) { + this.rearrangementOccurred = rearrangementOccurred; + } + + public void setResultRuleInstances(List resultRuleInstances) { + this.resultRuleInstances = resultRuleInstances; + treeComponent = new PopupTreeComponent(settings, resultRuleInstances, psiFileEntry); + } + + /** Display a live rearrangement window. */ + public void liveRearranger() { + try { + SwingUtilities.invokeAndWait( + new Runnable() { + public void run() { + containerPanel = getContainerPanel(); + LOG.debug("containerPanel.isFocusable=" + containerPanel.isFocusable()); + Border b = BorderFactory.createRaisedBevelBorder(); + containerPanel.setBorder(b); + Dimension d = outerPanel.getSize(); + Dimension c = containerPanel.getPreferredSize(); + int x = (d.width - c.width) / 2; + int y = (d.height - c.height) / 2; + if (x < 0) x = 0; + if (y < 0) y = 0; + popup.hide(); // destroy initial (interim) popup + popup = PopupFactory.getSharedInstance().getPopup(outerPanel, containerPanel, x, y); +// popup = new JFrame(); +// final Container contentPane = popup.getContentPane(); +// contentPane.remove(0); +// contentPane.add(containerPanel); +// contentPane.validate(); +// popup.setLocation(x, y); + LOG.debug("setCursor (original)" + oldCursor + " on " + outerPanel); + outerPanel.setCursor(oldCursor); +// logger.debug("set default cursor on " + popup); +// popup.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); +// popup.repaint(); + LOG.debug("outerPanel size=" + d + ", containerPanel preferred size=" + c); + LOG.debug("Constructing Popup at x,y=" + x + "," + y); + LiveRearrangerActionHandler.setInProgress(true); + +// popup.addWindowFocusListener(windowFocusListener); +// popup.addWindowListener(windowAdapter); +// popup.addMouseListener(mouseAdapter); +// popup.addFocusListener(focusAdapter); +// contentPane.addFocusListener(focusAdapter); + outerPanel.addWindowFocusListener( + windowFocusListener = getWindowFocusListener("outerPanel") + ); + outerPanel.addWindowListener(windowAdapter = getWindowAdapter("outerPanel")); + outerPanel.addMouseListener(mouseAdapter = getMouseAdapter("outerPanel")); + ma2 = getMouseAdapter("focus owner"); + outerPanelFocusOwner = outerPanel.getFocusOwner(); + if (outerPanelFocusOwner != null) { + outerPanelFocusOwner.addMouseListener(ma2); + } + outerPanel.addFocusListener(focusAdapter = getFocusAdapter("outerPanel")); + containerPanel.addFocusListener(getFocusAdapter("containerPanel")); + + keyEventDispatcher = new KeyEventDispatcher() { + public boolean dispatchKeyEvent(KeyEvent e) { + LOG.debug( + "key event dispatcher: outerPanel isFocused=" + + outerPanel.isFocused() + + ", rearrangementOccurred=" + + rearrangementOccurred + + " keyEvent=" + + e + ); + if (e.getID() == KeyEvent.KEY_RELEASED && + (rearrangementOccurred || sawKeyPressed)) + { + LOG.debug("key event dispatcher: disposing popup, saw keyEvent " + e); + finish(); + } + if (e.getID() == KeyEvent.KEY_PRESSED) { + sawKeyPressed = true; + } + return true; + } + }; + KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher( + keyEventDispatcher + ); +// wasLightWeight = ToolTipManager.sharedInstance().isLightWeightPopupEnabled(); +// ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); + popup.show(); +// popup.setVisible(true); + } + } + ); + } + catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + catch (InvocationTargetException ite) { + throw new RuntimeException(ite); + } + LOG.debug("exit liveRearranger"); + } + + private MouseAdapter getMouseAdapter(final String component) { + return new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + LOG.debug( + component + + ": mouse clicked at " + + e.getX() + + "," + + e.getY() + + "; window size/position is " + + outerPanel.getBounds() + ); + LOG.debug("close popup and finish"); + finish(); + super.mouseClicked(e); + } + }; + } + + private FocusAdapter getFocusAdapter(final String component) { + return new FocusAdapter() { + public void focusGained(FocusEvent e) { + LOG.debug(component + ": focus gained"); + } + + public void focusLost(FocusEvent e) { + LOG.debug(component + ": focus lost, close popup & finish"); + finish(); + } + }; + } + + private WindowAdapter getWindowAdapter(final String component) { + return new WindowAdapter() { + public void windowLostFocus(WindowEvent e) { + LOG.debug(component + ": lost focus"); + LOG.debug("close popup and finish"); + finish(); + } + + public void windowClosing(WindowEvent e) { + LOG.debug(component + ": window closing"); + } + }; + } + + private WindowFocusListener getWindowFocusListener(final String component) { + return new WindowFocusListener() { + public void windowGainedFocus(WindowEvent e) { + LOG.debug(component + ": gained window focus"); + } + + public void windowLostFocus(WindowEvent e) { + LOG.debug(component + ": lost window focus"); + LOG.debug("close popup and finish"); + finish(); + } + }; + } + + public void finish() { + LOG.debug("entered finish() on thread " + Thread.currentThread().getName()); +// popup.setVisible(false); +// popup.dispose(); +// popup.removeWindowFocusListener(windowFocusListener); +// popup.removeWindowListener(windowAdapter); +// popup.removeMouseListener(mouseAdapter); +// popup.removeFocusListener(focusAdapter); +// popup.getContentPane().removeFocusListener(focusAdapter); + outerPanel.removeWindowFocusListener(windowFocusListener); + if (outerPanelFocusOwner != null) { + outerPanelFocusOwner.removeMouseListener(ma2); + } + outerPanel.removeWindowListener(windowAdapter); + outerPanel.removeMouseListener(mouseAdapter); + outerPanel.removeFocusListener(focusAdapter); +// containerPanel.removeFocusListener(containerPanel.getFocusListeners()[0]); + popup.hide(); +// popup.dispose(); + + KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(keyEventDispatcher); +// ToolTipManager.sharedInstance().setLightWeightPopupEnabled(wasLightWeight); + if (!rearrangementOccurred) { + LOG.debug("no rearrangement occurred, not rearranging document"); + LiveRearrangerActionHandler.setInProgress(false); + return; + } + LOG.debug("rearranging document"); + final Runnable task = new Runnable() { + public void run() { + if (document != null) { + final Emitter e = new Emitter(psiFile, resultRuleInstances, document); + e.emitRearrangedDocument(); + } + } + }; + final Application application = ApplicationManager.getApplication(); + + application.runWriteAction( + new Runnable() { + public void run() { + CommandProcessor.getInstance().executeCommand(project, task, "Rearrange", null); + } + } + ); + + LiveRearrangerActionHandler.setInProgress(false); + LOG.debug("exit finish() on thread " + Thread.currentThread().getName()); + } + + private JPanel getContainerPanel() { + final JPanel containerPanel = new JPanel(new GridBagLayout()); + Border etched = BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), "Live Rearranger", TitledBorder.CENTER, + TitledBorder.TOP + ); + containerPanel.setBorder(etched); + final GridBagConstraints scrollPaneConstraints = new GridBagConstraints(); + scrollPaneConstraints.insets = new Insets(3, 3, 3, 3); + scrollPaneConstraints.fill = GridBagConstraints.BOTH; + scrollPaneConstraints.gridwidth = GridBagConstraints.REMAINDER; + scrollPaneConstraints.gridheight = GridBagConstraints.REMAINDER; + scrollPaneConstraints.weightx = 1; + scrollPaneConstraints.weighty = 1; + scrollPaneConstraints.gridx = 0; + scrollPaneConstraints.gridy = 1; + + final JScrollPane treeView = getScrollPane(); + final JComponent showTypesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowParameterTypes(); + } + + void setSetting(boolean value) { + settings.setShowParameterTypes(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowParamTypes"); + } + + String getToolTipText() { + return "Show parameter types"; + } + + int getShortcut() { + return KeyEvent.VK_T; + } + }.getIconBox(); + final JComponent showNamesBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowParameterNames(); + } + + void setSetting(boolean value) { + settings.setShowParameterNames(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowParamNames"); + } + + String getToolTipText() { + return "Show parameter names"; + } + + int getShortcut() { + return KeyEvent.VK_N; + } + }.getIconBox(); + final JComponent showFieldsBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowFields(); + } + + void setSetting(boolean value) { + settings.setShowFields(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowFields"); + } + + String getToolTipText() { + return "Show fields"; + } + + int getShortcut() { + return KeyEvent.VK_F; + } + }.getIconBox(); + final JComponent showTypeAfterMethodBox = + new IconBox(containerPanel, scrollPaneConstraints, this) { + boolean getSetting() { + return settings.isShowTypeAfterMethod(); + } + + void setSetting(boolean value) { + settings.setShowTypeAfterMethod(value); + } + + Icon getIcon() { + return IconUtil.getIcon("ShowTypeAfterMethod"); + } + + String getToolTipText() { + return "Show type after method"; + } + + int getShortcut() { + return KeyEvent.VK_A; + } + }.getIconBox(); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 0; + constraints.weighty = 0; + constraints.insets = new Insets(5, 5, 5, 5); + containerPanel.add(showTypesBox, constraints); + constraints.gridx++; + containerPanel.add(showNamesBox, constraints); + constraints.gridx++; + containerPanel.add(showFieldsBox, constraints); + constraints.gridx++; + constraints.gridwidth = GridBagConstraints.REMAINDER; + containerPanel.add(showTypeAfterMethodBox, constraints); + containerPanel.add(treeView, scrollPaneConstraints); + return containerPanel; + } + + /** + * build a JTree containing classes, fields and methods, in accordance with settings. + * + * @return + */ + public JScrollPane getScrollPane() { + // Create the nodes. + PopupTree tree = treeComponent.createLiveRearrangerTree(); + + /** only expand node where cursor is located. Inspect all rows; deepest node that covers + * cursor location is the best to expand. (Parent node like a class contains a method where + * the cursor is; we want to expand the method, not just the class. + */ + int expandRow = -1; + for (int i = 0; i < tree.getRowCount(); i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getPathForRow(i).getLastPathComponent(); + if (node.getUserObject() instanceof RangeEntry) { + RangeEntry re = (RangeEntry)node.getUserObject(); + if (re.getStart().getTextRange().getStartOffset() <= cursorOffset && + re.getEnd().getTextRange().getEndOffset() >= cursorOffset) + { + LOG.debug( + "node " + + i + + " contained cursor (offset=" + + cursorOffset + + "): " + re + ); + expandRow = i; + } + } + else { + LOG.debug("expand node candidate not RangeEntry; node=" + node); + } + } + if (expandRow >= 0) { + LOG.debug("expand row " + expandRow); + tree.expandRow(expandRow); + } + JScrollPane treeView = new JScrollPane(tree); + treeView.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + treeView.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + Dimension d = treeView.getPreferredSize(); + if (d.width < 400) d.width = 400; + if (d.height < 300) d.height = 300; + treeView.setPreferredSize(d); + tdt = new TreeDropTarget(tree, this); + tds = new TreeDragSource(tree, DnDConstants.ACTION_MOVE, tdt); + return treeView; + } + + // class RearrangerTest +// extends LightCodeInsightTestCase +// { +// private RearrangerSettings rs; +// +// protected final void setUp() throws Exception +// { +// super.setUp(); +// } +// +// +// + public static void main(String[] args) { +// RearrangerTest t = new RearrangerTest(); +// t.testIt(); +// void testIt() +// { + final RearrangerSettings settings = new RearrangerSettings(); + IFilePopupEntry pf = new IFilePopupEntry() { + public String getTypeIconName() { + return "nodes/ppFile"; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + return new JLabel("FileName.java"); + } + }; + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + +// logger.setAdditivity(false); +// logger.addAppender(new ConsoleAppender(new PatternLayout("[%7r] %6p - %30.30c - %m \n"))); +// logger.setLevel(Level.DEBUG); +// logger.debug("Testing LiveRearrangerPopup"); + + final JFrame frame = new JFrame("SwingApplication"); +// Window window = new Window(frame); + JPanel panel = new JPanel(); + panel.setSize(800, 600); + frame.setSize(800, 600); + frame.getRootPane().add(panel); +// window.setSize(800, 600); +// window.getRootPane().add(panel); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1.0d; + constraints.weighty = 1.0d; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 0; + constraints.gridy = 0; + LiveRearrangerPopup lrp = new LiveRearrangerPopup( + // getProject(), + settings, pf, frame, null, + null + ); +// final JPanel object = lrp.getContainerPanel(); +// frame.getContentPane().setLayout(new GridBagLayout()); +// frame.getContentPane().add(object, constraints); + + //Finish setting up the frame, and show it. + frame.addWindowListener( + new WindowAdapter() { + public void windowClosing(final WindowEvent e) { + System.exit(0); + } + } + ); +// frame.pack(); + frame.setVisible(true); + lrp.liveRearranger(); + } +} + +// +//} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java new file mode 100644 index 000000000000..de925315e1fa --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.intellij.openapi.diagnostic.Logger; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.IRuleInstance; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.awt.dnd.Autoscroll; +import java.util.LinkedList; + +/** Handles vertical autoscrolling of the tree inside the live rearranger popup/dialog. */ +public class PopupTree + extends JTree + implements Autoscroll +{ + private static final Logger LOG = Logger.getInstance("#" + PopupTree.class.getName()); + private static final int margin = 12; + private TreeDropTarget treeDropTarget; + private boolean exitedWithEnterKey; + private final PopupTreeComponent owner; + + public PopupTree(TreeNode root, PopupTreeComponent owner) { + super(root); + this.owner = owner; + } + + public void setTreeDropTarget(TreeDropTarget dropTarget) { + treeDropTarget = dropTarget; + } + + public boolean isExitedWithEnterKey() { + return exitedWithEnterKey; + } + + public void setExitedWithEnterKey(boolean exitedWithEnterKey) { + this.exitedWithEnterKey = exitedWithEnterKey; + } + + // scroll because mouse cursor is in the scroll zone. + public void autoscroll(Point p) { + // determine row. Set y value to that of current row left edge; this allows scrolling to occur + int realrow = getRowForLocation(p.x, p.y); + if (treeDropTarget != null) { + treeDropTarget.clearInsertionPoint(); + // Set y value to that of current row left edge; this allows scrolling to occur even when cursor is + // to the right or left of the smallest rectangle enclosing the row. + int row = treeDropTarget.getSrcRow(); + Rectangle r = getRowBounds(row); + if (realrow < 0) { + LOG.debug("autscroll: realrow < 0 for [" + p.x + "," + p.y + "], trying x=" + r.x); + p.x = r.x; + realrow = getRowForLocation(p.x, p.y); + } + } + if (realrow < 0) { + LOG.debug("autoscroll point=[" + p.x + "," + p.y + "] realrow=" + realrow); + return; + } + Rectangle outer = getBounds(); + + // now determine if the row is at the top or bottom of the screen. + // Make the previous or next row visible accordingly. + int newRow = + p.y + outer.y <= margin + ? realrow < 1 ? 0 : realrow - 1 + : realrow < getRowCount() - 1 + ? realrow + 1 + : realrow; +// logger.setLevel(Level.DEBUG); -- following code doesn't work for horizontal scrolling; something interferes +// int newCol = p.x; +// if (this.getParent() instanceof JViewport) +// { +// JViewport parent = (JViewport) getParent(); +// logger.debug( +// "autoscroll horizontal TEST: p.x=" + +// p.x + +// ", bounds.x=" + +// outer.x + +// ", viewport x=" + +// parent.getBounds().x + +// ", width=" + parent.getBounds().width); +// if (p.x + outer.x <= margin) +// { +// newCol = p.x - margin; +// logger.debug( +// "autoscroll horizontal LEFT: new x=" + newCol +// ); +// logger.debug("this=" + this.toString()); +// logger.debug("this.parent=" + this.getParent().toString()); +// Rectangle r = parent.getViewRect(); +// r.x -= margin; +// parent.scrollRectToVisible(r); +// } +// else +// { +// if (p.x + outer.x + margin >= parent.getBounds().x + parent.getBounds().width) +// { +// newCol = p.x + margin; +// logger.debug( +// "autoscroll horizontal RIGHT: new x=" + newCol +// ); +//// logger.debug("this=" + this.toString()); +//// logger.debug("this.parent=" + parent.toString()); +// Rectangle r = parent.getViewRect(); +// r.x += margin; +// parent.scrollRectToVisible(r); +// } +// } +// } + LOG.debug("autoscroll point=[" + p.x + "," + p.y + "] realrow=" + realrow + ", newRow=" + newRow); + scrollRowToVisible(newRow); + if (treeDropTarget != null) { + treeDropTarget.computeInsertionPoint(); + treeDropTarget.drawInsertionPoint(); + } + } + + /** + * Calculate insets for the JTree, not the viewport the tree is in. + * this makes it a bit messy. + * + * @return + */ + public Insets getAutoscrollInsets() { + Rectangle outer = getBounds(); + Rectangle inner = getParent().getBounds(); + return new Insets( + inner.y - outer.y + margin, + inner.x - outer.x + margin, + outer.height - inner.height - inner.y + outer.y + margin, + outer.width - inner.width - inner.x + outer.x + margin + ); + } + + // Use this method to see the boundaries of the autoscroll active region. +// public void paintComponent(Graphics g) +// { +// super.paintComponent(g); +// Rectangle outer = getBounds(); +// Rectangle inner = getParent().getBounds(); +// g.setColor(Color.RED); +// g.drawRect(-outer.x + margin, -outer.y + margin, +// inner.width - 2*margin, inner.height - 2*margin); +// } + + /** + * Move the tree's selection to the destination row indicated. The selection may contain multiple + * discontiguous rows, but all rows must have the same parent node. + * + * @param dstIndex child index of common parent before which selection is to be inserted. If null, insert at end of parent. + */ + public void moveSelection(int dstIndex, boolean before) { + /** + * First, remove all mutable tree nodes from the tree's model and the rule instance. Place them in a list. + * If any are removed before the destination row, decrement the dstIndex so that the insertion still + * happens in the correct place. + */ + TreePath[] paths = getSelectionPaths(); + LinkedList nodeList = new LinkedList(); + LinkedList ruleList = new LinkedList(); + if (paths == null || paths.length == 0) { + return; // nothing selected + } + owner.setRearrangementOccurred(true); + final DefaultMutableTreeNode peerNode = (DefaultMutableTreeNode)paths[0].getLastPathComponent(); + RangeEntry entry = (RangeEntry)peerNode.getUserObject(); + DefaultMutableTreeNode peerParent = (DefaultMutableTreeNode)peerNode.getParent(); + DefaultMutableTreeNode dstNode = (DefaultMutableTreeNode)peerParent.getChildAt(dstIndex); + if (!before && dstIndex < peerParent.getChildCount()) { + dstIndex++; + } + IRuleInstance ruleInstance = entry.getMatchedRule(); + DefaultTreeModel model = (DefaultTreeModel)getModel(); + + for (TreePath path : paths) { + DefaultMutableTreeNode srcNode = (DefaultMutableTreeNode)path.getLastPathComponent(); + DefaultMutableTreeNode srcParent = (DefaultMutableTreeNode)srcNode.getParent(); + int srcRow = srcParent.getIndex(srcNode); + if (srcRow < dstIndex) { + dstIndex--; + } + nodeList.add(srcNode); + model.removeNodeFromParent(srcNode); + RangeEntry match = (RangeEntry)srcNode.getUserObject(); + ruleInstance.getMatches().remove(match); + ruleList.add(match); + } + /** + * now insert all the nodes in the list at the appropriate spots in the model and rule instance. + */ + clearSelection(); + TreePath visiblePath = null; + /** + * calculate the offset between the destination row in the model and its location in the ruleInstance's + * list of matching items. This is non-zero when fields exist but are not shown in the tree. + */ + int dstOffset = (ruleInstance.getMatches().indexOf(dstNode.getUserObject())) - peerParent.getIndex(dstNode); + while (!nodeList.isEmpty()) { + DefaultMutableTreeNode srcNode = nodeList.removeFirst(); + model.insertNodeInto(srcNode, peerParent, dstIndex); + final TreePath treePath = new TreePath(srcNode.getPath()); + addSelectionPath(treePath); + if (before) { + if (visiblePath == null) visiblePath = treePath; + } + else { + visiblePath = treePath; + } + final RangeEntry match = ruleList.removeFirst(); + ruleInstance.getMatches().add(dstIndex + dstOffset, match); + dstIndex++; + } + if (visiblePath != null) { + scrollPathToVisible(visiblePath); + } + } + + /** + * returns true if src and dst have common parent. Since src has been created from serialized data, + * the actual parents are different objects. So compare by name up to the root. Ignore any plain + * DefaultMutableTreeNodes in the path (these correspond to rules) -- just compare names of + * RearrangerTreeNodes. + * + * @param src RearrangerTreeNode reconstituted from serialized data + * @param dst RearrangerTreeNode next to which src is to be dropped + * @return -1 if src and dst do not have common parent; >= 0 to indicate position of src in children list + */ + int haveCommonAncestors(DefaultMutableTreeNode src, DefaultMutableTreeNode dst) { + if (src == null || dst == null) { + return -1; + } + DefaultMutableTreeNode p = (DefaultMutableTreeNode)src.getParent(); + int result = p.getIndex(src); + src = (DefaultMutableTreeNode)src.getParent(); + dst = (DefaultMutableTreeNode)dst.getParent(); + while (src != null && dst != null) { + if (src instanceof RearrangerTreeNode) { + if (dst instanceof RearrangerTreeNode) { + RearrangerTreeNode s = (RearrangerTreeNode)src; + RearrangerTreeNode d = (RearrangerTreeNode)dst; + if (!s.name.equals(d.name)) { + return -1; + } + } + else { + return -1; + } + } + else if (dst instanceof RearrangerTreeNode) { + return -1; + } + src = (DefaultMutableTreeNode)src.getParent(); + dst = (DefaultMutableTreeNode)dst.getParent(); + } + return src == null && dst == null ? result : -1; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java new file mode 100644 index 000000000000..fa825b548a75 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.intellij.openapi.diagnostic.Logger; +import com.wrq.rearranger.Rearranger; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import com.wrq.rearranger.util.IconUtil; + +import javax.swing.*; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.net.URL; +import java.util.List; + +/** Builds a JTree that can be used in a file structure popup or live rearranger popup. */ +public class PopupTreeComponent { + private static final Logger LOG = Logger.getInstance("#" + PopupTreeComponent.class.getName()); + private final IFilePopupEntry psiFileEntry; + private final List resultRuleInstances; + private final RearrangerSettings settings; + private boolean rearrangementOccurred; + + public PopupTreeComponent(RearrangerSettings settings, + List resultRuleInstances, + final IFilePopupEntry psiFileEntry) + { + this.settings = settings; + this.resultRuleInstances = resultRuleInstances; + this.psiFileEntry = psiFileEntry; + } + + public boolean isRearrangementOccurred() { + return rearrangementOccurred; + } + + public void setRearrangementOccurred(boolean rearrangementOccurred) { + this.rearrangementOccurred = rearrangementOccurred; + } + + public JTree createTree() { + DefaultMutableTreeNode top = createAllNodes(); + final JTree tree = new JTree(top); + tree.putClientProperty("JTree.lineStyle", "Angled"); + tree.setRootVisible(true); + tree.setShowsRootHandles(true); + tree.setRowHeight(0); + tree.setCellRenderer(new JavaObjectRenderer()); + tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + tree.setEditable(false); + return tree; + } + + public PopupTree createLiveRearrangerTree() { + DefaultMutableTreeNode top = createAllNodes(); + // discard top nodes if only one child +// while (top.getChildCount() == 1) { // TODO - enable +// // remove that child, make its child(ren) top's child(ren). +// DefaultMutableTreeNode child = (DefaultMutableTreeNode) top.getChildAt(0); +// child.removeFromParent(); +// for (int i = 0; i < child.getChildCount(); i++) { +// DefaultMutableTreeNode grandchild = (DefaultMutableTreeNode) child.getChildAt(i); +// top.add(grandchild); +// } +// } + final PopupTree tree = new PopupTree(top, this); + tree.putClientProperty("JTree.lineStyle", "Angled"); + tree.setRootVisible(true); + tree.setShowsRootHandles(true); + tree.setRowHeight(0); + tree.setCellRenderer(new JavaObjectRenderer()); + tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); + tree.setEditable(false); + tree.getSelectionModel().addTreeSelectionListener( + new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + LOG.debug("selection changed as follows (" + e.getPaths().length + " path(s)):"); + TreePath lastPathAdded = null; + int i = 0; + + for (TreePath path : e.getPaths()) { + if (e.isAddedPath(path)) { + lastPathAdded = path; + } + LOG.debug( + "path " + + i + + (e.isAddedPath(path) ? " added:" : " removed:") + + path + ); + i++; + } + if (lastPathAdded == null) { + // nothing added, so all selected paths still have same parent. + return; + } + /** + * ensure that all selection rows have the same parent. If not, take the last added + * path, and remove any rows with a different parent. (So simply start with the last + * added path and remove any rows with a different parent.) + */ + DefaultMutableTreeNode lastNodeAdded = null; + lastNodeAdded = (DefaultMutableTreeNode)lastPathAdded.getLastPathComponent(); + boolean haveSameParent = true; + for (TreePath path : tree.getSelectionPaths()) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); + if (lastNodeAdded == null) { + lastNodeAdded = node; + } + if (node != lastNodeAdded) { + if (tree.haveCommonAncestors(lastNodeAdded, node) < 0) { + // parents not identical, so remove node from selection. + haveSameParent = false; + break; + } + } + } + if (!haveSameParent) { + // to avoid reentry into this listener, temporarily remove it + tree.getSelectionModel().removeTreeSelectionListener(this); + tree.clearSelection(); + tree.addSelectionPath(lastPathAdded); + tree.getSelectionModel().addTreeSelectionListener(this); + } + } + } + ); + + AbstractAction moveUpAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + LOG.debug("moveUpAction, " + tree.getSelectionPaths().length + " paths in selection"); + if (tree.getSelectionPaths().length == 0) { + return; + } + /** + * find first selection row. + */ + int selectionRow = Integer.MAX_VALUE; + for (TreePath path : tree.getSelectionPaths()) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); + int nodeIndex = node.getParent().getIndex(node); + if (selectionRow > nodeIndex) { + selectionRow = nodeIndex; + } + } + if (selectionRow > 0) { + selectionRow--; + } + tree.moveSelection(selectionRow, true); + } + }; + AbstractAction moveDownAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + LOG.debug("moveDownAction, " + tree.getSelectionPaths().length + " paths in selection"); + if (tree.getSelectionPaths().length == 0) { + return; + } + /** + * find last selection row. + */ + int selectionRow = -1; + for (TreePath path : tree.getSelectionPaths()) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); + final DefaultMutableTreeNode parent = ((DefaultMutableTreeNode)node.getParent()); + int nodeIndex = parent.getIndex(node); + if (selectionRow < nodeIndex) { + selectionRow = nodeIndex; + } + } + selectionRow++; + tree.moveSelection(selectionRow, false); + } + }; + AbstractAction enterKeyAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + LOG.debug("exit with enter key"); + tree.setExitedWithEnterKey(true); + for (Container p = tree.getParent(); p != null; p = p.getParent()) { + if (p instanceof JDialog) { + p.setVisible(false); + } + } + } + }; + tree.getInputMap().put( + KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), + "enterKeyAction" + ); + tree.getActionMap().put("enterKeyAction", enterKeyAction); + tree.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( + KeyStroke.getKeyStroke( + KeyEvent.VK_UP, + InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK + ), + "moveUpAction" + ); + + tree.getActionMap().put("moveUpAction", moveUpAction); + tree.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( + KeyStroke.getKeyStroke( + KeyEvent.VK_DOWN, + InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK + ), + "moveDownAction" + ); + + tree.getActionMap().put("moveDownAction", moveDownAction); + tree.setSelectionPath(tree.getPathForRow(0)); + return tree; + } + + public DefaultMutableTreeNode createAllNodes() { + DefaultMutableTreeNode top = new RearrangerTreeNode(psiFileEntry, "root"); + createNodes(top); + return top; + } + + private void createNodes(DefaultMutableTreeNode top) { + for (IRuleInstance ruleInstance : resultRuleInstances) { + ruleInstance.addRuleInstanceToPopupTree(top, settings); + } + } + + class JavaObjectRenderer + extends DefaultTreeCellRenderer + { + Icon findIcon(String iconName) { + if (iconName == null) { + return null; + } + URL iconURL = this.getClass().getClassLoader().getResource(iconName + ".png"); + if (iconURL == null) { + return IconUtil.getIcon(iconName); + } + else { + return new ImageIcon(iconURL, Rearranger.COMPONENT_NAME); + } + } + + public Component getTreeCellRendererComponent(final JTree tree, + final Object value, + final boolean sel, + final boolean expanded, + final boolean leaf, + final int row, + final boolean hasFocus) + { + Object userObject = null; + if (value instanceof DefaultMutableTreeNode) { + userObject = ((DefaultMutableTreeNode)value).getUserObject(); + } + // obtain a component that will render the appropriate item. + if (userObject instanceof IFilePopupEntry) { + IFilePopupEntry entry = (IFilePopupEntry)userObject; + final String iconTypeName = entry.getTypeIconName(); + final String[] iconNames = entry.getAdditionalIconNames(); + final JLabel textLabel = entry.getPopupEntryText(settings); + JPanel panel = new JPanel(new GridBagLayout()) { + public void paint(Graphics g) { +// System.out.println("paint " + textLabel.getText() + ", sel=" + sel + +// ", hasFocus=" + hasFocus + +// ", selected=" + selected + +// ", bg=" + getBackground().toString().replaceFirst(".*\\[", "[") + +// ", bg sel=" + getBackgroundSelectionColor().toString().replaceFirst(".*\\[", "[") + +// ", border=" + getBorderSelectionColor().toString().replaceFirst(".*\\[", "[") +// ); + if (sel && !hasFocus) { + Color bgColor = getBackground(); + setBackground(Color.WHITE); + super.paint(g); + setBackground(bgColor); + Color bsColor = getBorderSelectionColor(); + + if (bsColor != null) { + g.setColor(bsColor); + if (getComponentOrientation().isLeftToRight()) { + g.drawRect( + 0, 0, getWidth() - 1, + getHeight() - 1 + ); + } + else { + g.drawRect( + 0, 0, getWidth() - 1, + getHeight() - 1 + ); + } + } + } + else { + super.paint(g); + } + } + }; + Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.weightedLastRow(); + Icon typeIcon = findIcon(iconTypeName == null ? "fileTypes/unknown" : iconTypeName); + panel.setBackground(Color.WHITE); + if (sel) { +// Color fg = textLabel.getForeground(); +// Color bg = textLabel.getBackground(); +// textLabel.setForeground(bg); +// textLabel.setBackground(new Color(181, 190, 214)); +// Color fg = panel.getForeground(); +// Color bg = panel.getBackground(); +// panel.setForeground(bg); + panel.setBackground(new Color(181, 190, 214)); + } + else { + textLabel.setBackground(Color.WHITE); + } + if (typeIcon != null) { + JLabel typeLabel = new JLabel(typeIcon); + panel.add(typeLabel, constraints.nextCol()); + } + if (iconNames != null) { + for (String iconName : iconNames) { + Icon addlIcon = findIcon(iconName); + JLabel plLabel = new JLabel(addlIcon); + panel.add(plLabel, constraints.nextCol()); + } + } + constraints.insets = new Insets(0, 3, 0, 0); + panel.add(textLabel, constraints.lastCol()); + panel.repaint(); + return panel; + } + LOG.debug("getTreeCellRendererComponent: userObject not IFilePopupEntry;" + userObject); + return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/RearrangerTreeNode.java b/plugins/rearranger/src/com/wrq/rearranger/popup/RearrangerTreeNode.java new file mode 100644 index 000000000000..0a5b1afb09a5 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/RearrangerTreeNode.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import javax.swing.tree.DefaultMutableTreeNode; + +public class RearrangerTreeNode + extends DefaultMutableTreeNode +{ + String name; + + public RearrangerTreeNode(Object userObject, String name) { + super(userObject); + this.name = name; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/TransferableTreeNode.java b/plugins/rearranger/src/com/wrq/rearranger/popup/TransferableTreeNode.java new file mode 100644 index 000000000000..4f9b3660f836 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/TransferableTreeNode.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import javax.swing.tree.TreePath; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; + +public class TransferableTreeNode + implements Transferable +{ + public static DataFlavor treePathFlavor = new DataFlavor(TreePath.class, "Tree Path Flavor"); + DataFlavor[] flavors = {treePathFlavor}; + TreePath[] paths; + + public TransferableTreeNode(TreePath[] paths) { + this.paths = paths; + } + + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + return (flavor.getRepresentationClass() == TreePath.class); + } + + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (isDataFlavorSupported(flavor)) { + return paths; + } + else { + throw new UnsupportedFlavorException(flavor); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/TreeDragSource.java b/plugins/rearranger/src/com/wrq/rearranger/popup/TreeDragSource.java new file mode 100644 index 000000000000..77aa88279732 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/TreeDragSource.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.intellij.openapi.diagnostic.Logger; + +import javax.swing.*; +import java.awt.*; +import java.awt.dnd.*; + +/** Contains logic to start a drag from the popup file structure tree. */ +public class TreeDragSource + implements DragSourceListener, + DragGestureListener +{ + private static final Logger LOG = Logger.getInstance("#" + TreeDragSource.class.getName()); + DragSource source; + DragGestureRecognizer recognizer; + TransferableTreeNode transferable; + JTree sourceTree; + TreeDropTarget tdt; + + public TreeDragSource(JTree sourceTree, int actions, TreeDropTarget tdt) { + LOG.debug("construct TreeDragSource, actions=" + actions); + this.sourceTree = sourceTree; + this.tdt = tdt; + source = DragSource.getDefaultDragSource(); + recognizer = source.createDefaultDragGestureRecognizer( + sourceTree, actions, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + LOG.debug("src dragEnter, calling dragOver"); + dragOver(dsde); + } + + public void dragOver(DragSourceDragEvent dsde) { +// logger.debug("src dragOver; drop action=" + dsde.getDropAction() + +// ", target actions=" + dsde.getTargetActions()); +// dsde.getDragSourceContext().setCursor(dsde.getDropAction() > 0 +// ? DragSource.DefaultMoveDrop +// : DragSource.DefaultMoveNoDrop); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + LOG.debug("src dropActionChanged: action=" + dsde.getDropAction()); + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + LOG.debug("src dragDropEnd, success=" + dsde.getDropSuccess()); + } + + public void dragExit(DragSourceEvent dse) { +// logger.debug("src dragExit"); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + LOG.debug("src dragGestureRecognized, action=" + dge.getDragAction() + + ", n paths in selection=" + sourceTree.getSelectionPaths().length); + final Point point = dge.getDragOrigin(); +// TreePath path = sourceTree.getSelectionPath(); +// if (path == null || +// path.getPathCount() <= 1) +// { +// // can't move the root node or an empty selection +// System.out.println("can't drag root node or empty selection"); +// return; +// } + // Make a version of the node that we can use for DnD. + tdt.setSrcRow(sourceTree.getClosestRowForLocation(point.x, point.y)); + transferable = new TransferableTreeNode(sourceTree.getSelectionPaths()); + dge.startDrag(null, transferable, this); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/TreeDropTarget.java b/plugins/rearranger/src/com/wrq/rearranger/popup/TreeDropTarget.java new file mode 100644 index 000000000000..08be5c72ab6d --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/TreeDropTarget.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.popup; + +import com.intellij.openapi.diagnostic.Logger; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.*; +import java.io.IOException; + +/** Handles drop actions associated with manual rearrangement. */ +public class TreeDropTarget + implements DropTargetListener +{ + private static final Logger LOG = Logger.getInstance("#" + TreeDropTarget.class.getName()); + private static final Color xorBackgroundColor = new Color(255 - 8, 255 - 36, 255 - 107); + DropTarget target; + PopupTree targetTree; + ILiveRearranger lrp; + /** Cached information about the location of the last insertion row to be drawn. */ + private transient Rectangle lastRowRect; + + /** cached value of last row to be drawn. */ + private int lastRow; + /** + * Cached information about whether insertion was possible at the last + * insertion point. + */ + private transient boolean canInsert; + + /** true if rectangle has been drawn. */ + private boolean rectangleDrawn; + /** row being dragged. */ + private int srcRow; + + public TreeDropTarget(PopupTree tree, + ILiveRearranger lrp) + { + this.lrp = lrp; + this.targetTree = tree; + target = new DropTarget(targetTree, DnDConstants.ACTION_MOVE, this); + this.lastRowRect = new Rectangle(); + this.canInsert = false; + rectangleDrawn = false; + srcRow = -1; + tree.setTreeDropTarget(this); + } + + public void dragEnter(DropTargetDragEvent dtde) { +// logger.debug("tgt dragEnter calling dragOver logic"); + dragOver(dtde); + } + + public int getSrcRow() { + return srcRow; + } + + public void setSrcRow(int srcRow) { + this.srcRow = srcRow; + } + + public void dragOver(DropTargetDragEvent dtde) { +// logger.debug("target dragOver: src drop actions=" + dtde.getSourceActions() + +// ", src drop action=" + dtde.getDropAction()); + clearInsertionPoint(); + Point pt = dtde.getLocation(); + lastRow = targetTree.getClosestRowForLocation(pt.x, pt.y); + + computeInsertionPoint(lastRow); + TreePath path = targetTree.getClosestPathForLocation(pt.x, pt.y); + final DefaultMutableTreeNode tgtNode; + tgtNode = (DefaultMutableTreeNode)path.getLastPathComponent(); +// logger.debug("tgt dragOver, closest node=" + tgtNode); + // compare selected node(s) to see if it has same parent as tgtNode. + final DefaultMutableTreeNode srcNode; + final TreePath srcPath = targetTree.getSelectionPath(); + if (srcPath != null) { + srcNode = (DefaultMutableTreeNode)srcPath.getLastPathComponent(); +// logger.debug("tgt dragOver, selected node=" + srcNode); + if (srcNode.getParent() == tgtNode.getParent() && + srcNode != tgtNode) + { +// logger.debug("tgt dragOver: accept drag"); + canInsert = true; + drawInsertionPoint(); + dtde.acceptDrag(DnDConstants.ACTION_MOVE); + return; + } + } +// logger.debug("tgt dragOver: reject drag"); + canInsert = false; + dtde.rejectDrag(); + } + + public void dropActionChanged(DropTargetDragEvent dtde) { +// logger.debug("tgt:dropActionChanged, action=" + dtde.getDropAction()); + } + + public void drop(DropTargetDropEvent dtde) { + clearInsertionPoint(); + canInsert = false; + // figure out where the drop occurred. + Point pt = dtde.getLocation(); + TreePath path = targetTree.getClosestPathForLocation(pt.x, pt.y); + Transferable t = dtde.getTransferable(); + DataFlavor[] flavors = t.getTransferDataFlavors(); + for (DataFlavor flavor : flavors) { + if (t.isDataFlavorSupported(flavor)) { + DefaultMutableTreeNode dstNode = (DefaultMutableTreeNode)path.getLastPathComponent(); + Transferable tx = dtde.getTransferable(); + TreePath[] tr = null; + try { + Object o = tx.getTransferData(TransferableTreeNode.treePathFlavor); + tr = (TreePath[])o; + } + catch (UnsupportedFlavorException e) { + e.printStackTrace(); + dtde.rejectDrop(); + return; + } + catch (IOException e) { + e.printStackTrace(); + dtde.rejectDrop(); + return; + } + if (tr == null) { + dtde.rejectDrop(); + return; + } + final DefaultMutableTreeNode srcNode = (DefaultMutableTreeNode)tr[0].getLastPathComponent(); + int srcIndex = targetTree.haveCommonAncestors(srcNode, dstNode); + if (srcIndex < 0) { + LOG.debug( + "reject drop onto " + + dstNode + + "; parent of " + + srcNode + " is different" + ); + dtde.rejectDrop(); + return; + } + else { + DefaultMutableTreeNode parent = (DefaultMutableTreeNode)dstNode.getParent(); + DefaultMutableTreeNode srcInCurrentTree = (DefaultMutableTreeNode)parent.getChildAt(srcIndex); + int dstRow = parent.getIndex(dstNode); + boolean before = true; + if (srcIndex < dstRow) { + LOG.debug( + "drop: move " + + srcIndex + + ":" + + srcInCurrentTree + + " after " + dstRow + ":" + dstNode + ); + before = false; + } + else if (srcIndex == dstRow) { + LOG.debug("reject drop: item onto itself"); + dtde.rejectDrop(); + return; + } + else { + LOG.debug( + "drop: move " + + srcIndex + + ":" + + srcInCurrentTree + + " before " + dstRow + ":" + dstNode + ); + } + targetTree.moveSelection(dstRow, before); + lrp.setRearrangementOccurred(true); + dtde.acceptDrop(dtde.getDropAction()); + dtde.dropComplete(true); + return; + } + } + } + dtde.rejectDrop(); + } + + public void dragExit(DropTargetEvent dte) { + LOG.debug("tgt dragExit"); + clearInsertionPoint(); + canInsert = false; + } + + public void clearInsertionPoint() { + if (rectangleDrawn) { + // Erase the old insertion point by drawing over it. + drawInsertionPoint(); + } + } + + /** + * Draw or erase the current insertion point indicator. This draws in XOR + * mode, so drawing the indicator once will display it and drawing it again + * in the same location will erase it. + */ + public void drawInsertionPoint() { + if (canInsert) { + Graphics g = this.targetTree.getGraphics(); + g.setXORMode(xorBackgroundColor); + g.drawRect( + this.lastRowRect.x, this.lastRowRect.y, + this.lastRowRect.width, this.lastRowRect.height + ); + rectangleDrawn = !rectangleDrawn; + } + } + + public void computeInsertionPoint() { + computeInsertionPoint(lastRow); + } + + /** + * Given a particular point over the associated tree component, determine + * the corresponding insertion point in the tree for dropped data. The tree + * path that the insertion will be relative to can be found using the + * JTree method getClosestPathForLocation. The + * insertion itself will either be before, after, or in the node at the end + * of the path. This method also calculates the rectangle which can be used + * to draw the appropriate indicator for the insertion point. + * + * @param row the row number of the tree corresponding to the drop target. + */ + public void computeInsertionPoint(int row) { + JTree tree = targetTree; + + Rectangle rowBounds = tree.getRowBounds(row); + if (row < srcRow) { + // Insertion point is immediately before the node. + this.lastRowRect.setBounds(rowBounds.x, rowBounds.y, rowBounds.width, 0); + } + else if (row > srcRow) { + // Insertion point is immediately after the node. + this.lastRowRect.setBounds( + rowBounds.x, rowBounds.y + rowBounds.height - 1, + rowBounds.width, 0 + ); + } + else { + // Insertion point is on the node - dropped data will be appended to the + // nodes child list. Draw nothing in this case. + this.lastRowRect.setBounds(rowBounds.x, rowBounds.y, 0, 0); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java new file mode 100644 index 000000000000..20e750b47ec9 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.rearrangement; + +import com.intellij.openapi.editor.Document; +import com.intellij.psi.PsiFile; +import com.wrq.rearranger.ruleinstance.IRuleInstance; + +import java.util.List; + +/** Emits a new document from the rearranged entries. */ +public final class Emitter { + private final PsiFile psiFile; + private final List resultRuleInstances; + private final Document document; + private StringBuffer stringBuffer; + + public Emitter(final PsiFile psiFile, final List resultRuleInstances, final Document document) { + this.psiFile = psiFile; + this.resultRuleInstances = resultRuleInstances; + this.document = document; + stringBuffer = new StringBuffer(psiFile.getText().length() + 100); // room for inserted blank lines + } + + public Document getDocument() { + return document; + } + + public StringBuffer getStringBuffer() { + return stringBuffer; + } + + public void emitRearrangedDocument() { + emitRuleInstances(resultRuleInstances); + document.replaceString( + psiFile.getTextRange().getStartOffset(), + psiFile.getTextRange().getEndOffset(), + stringBuffer.toString() + ); + } + + public void emitRuleInstances(List resultRuleInstances) { + if (resultRuleInstances == null) { + return; + } + for (IRuleInstance ruleInstance : resultRuleInstances) { + ruleInstance.emit(this); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java new file mode 100644 index 000000000000..4289bba83c51 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.rearrangement; + +import com.intellij.openapi.diagnostic.Logger; +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.entry.ClassEntry; +import com.wrq.rearranger.entry.IRelatableEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.CommentRuleInstance; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +/** Template for generic rearrangement of items in a class or in a Java file. */ +public abstract class GenericRearranger { + private static final Logger LOG = Logger.getInstance("#" + GenericRearranger.class.getName()); + private final List rules; + private final List entries; + private final List resultRuleInstances; + private final int nestingLevel; + private final RearrangerSettings settings; + + @SuppressWarnings({"AssignmentToCollectionOrArrayFieldFromParameter"}) + protected GenericRearranger(final List rules, + final List outerClasses, + final int nestingLevel, + final RearrangerSettings settings) + { + this.rules = rules; + entries = outerClasses; + this.nestingLevel = nestingLevel; + this.settings = settings; + resultRuleInstances = new ArrayList(rules.size() + 4); + } + + /** + * Rearranges the RangeEntry objects contained in entries according to rules specified by the user. + * Inserts comments as directed. + * + * @return rearranged list of RangeEntry and CommentRuleInstance objects. + */ + public final List rearrangeEntries() { + final List prioritizedRuleInstances = new ArrayList(); + buildRuleInstanceLists(prioritizedRuleInstances); + /** + * recursively reorder contents of every nested ClassEntry. + */ + for (ClassContentsEntry entry : entries) { + if (entry instanceof ClassEntry) { + ((ClassEntry)entry).rearrangeContents(); + } + } + matchPrioritizedRules(prioritizedRuleInstances); + + /** + * Move related methods together. Extracted methods and setters (emitted with getters) + * were not moved by the rearrangement code ("MatchPrioritizedRules()") just above. + */ + rearrangeRelatedItems(entries, resultRuleInstances); + /** + * Now go back and determine which comments are going to be emitted, based on their criteria and the + * state of the immediately surrounding rules. Ignore inner classes if no rearrangement of inner + * classes is taking place. + */ + if (nestingLevel <= 1 || settings.isRearrangeInnerClasses()) { + determineEmittedComments(); + } + return resultRuleInstances; + } + + /** For each comment rule instance, test its "emit" condition and set its emit flag appropriately. */ + private void determineEmittedComments() { + for (int i = 0; i < resultRuleInstances.size(); i++) { + if (resultRuleInstances.get(i) instanceof CommentRuleInstance) { + final CommentRuleInstance ce = (CommentRuleInstance)resultRuleInstances.get(i); + ce.determineEmit(resultRuleInstances, i); + if (ce.isEmit()) { + // set the "separator comment preceding" flag on the next matching RangeEntry. + for (int j = i + 1; j < resultRuleInstances.size(); j++) { + IRuleInstance instance = resultRuleInstances.get(j); + if (instance.hasMatches()) { + RangeEntry entry = (instance.getMatches().get(0)); + entry.setSeparatorCommentPrecedes(true); + break; + } + } + } + } + } + } + + /** + * For each rule (in prioritized order), test all remaining entries to identify those that match. + * Exclude any extracted (i.e. related) methods and any setter methods that will be emitted with + * a corresponding getter. If an entry matches the rule, add it to the list of entries matching the + * rule and remove it from the list of remaining entries. + * + * @param prioritizedRules prioritized list of rules + */ + @SuppressWarnings({"StringContatenationInLoop"}) + private void matchPrioritizedRules(List prioritizedRules) { + for (IRuleInstance ruleInstance : prioritizedRules) { + final IRule rule = ruleInstance.getRule(); + final ListIterator entryIterator = entries.listIterator(); + while (entryIterator.hasNext()) { + final RangeEntry entry = (RangeEntry)entryIterator.next(); + if (entry instanceof IRelatableEntry) { + // if this is an extracted (i.e. related) method, or + // if this is a setter that will be emitted under the corresponding getter, + // don't test it for match against the rule. + final IRelatableEntry relatableEntry = ((IRelatableEntry)entry); + if (relatableEntry.isRelatedMethod() || relatableEntry.isEmittableSetter()) { + continue; + } + } + if (rule.isMatch(entry)) { + LOG.debug("rule:" + rule.toString() + "; entry matched:" + entry.getEnd().toString()); + ruleInstance.addEntry(entry); + entry.setMatchedRule(ruleInstance); + entryIterator.remove(); + } + } + } + } + + /** + * Build two rule instance lists, one in order of emission ("resultRuleInstances") and one + * in order of matching ("prioritizedRuleInstances"). + * + * @param prioritizedRuleInstances + */ + private void buildRuleInstanceLists(final List prioritizedRuleInstances) { + /** + * add a HeaderTrailerRuleInstance to pick up any headers that might exist. + */ + IRuleInstance hri = new HeaderRule().createRuleInstance(); + resultRuleInstances.add(hri); + prioritizedRuleInstances.add(hri); + for (IRule rule : rules) { + IRuleInstance instance = rule.createRuleInstance(); + resultRuleInstances.add(instance); + /** + * now insert the rule instance into the prioritized list; highest priority first; stable insertion. + */ + boolean inserted = false; + for (int i = prioritizedRuleInstances.size() - 1; i >= 0; i--) { + IRuleInstance entry = (prioritizedRuleInstances.get(i)); + if (rule.getPriority() <= entry.getRule().getPriority()) { + prioritizedRuleInstances.add(i + 1, instance); + inserted = true; + break; + } + } + if (!inserted) { + prioritizedRuleInstances.add(0, instance); + } + } + // now add a default rule to pick up all unmatched items. + IRuleInstance defaultRuleInstance = new DefaultRule().createRuleInstance(); + resultRuleInstances.add(defaultRuleInstance); + prioritizedRuleInstances.add(defaultRuleInstance); + // finally, add a TrailerRuleInstance to pick up any leftover text. + IRuleInstance tri = new TrailerRule().createRuleInstance(); + resultRuleInstances.add(tri); + prioritizedRuleInstances.add(tri); + } + + /** + * Move any related items (e.g., extracted methods) remaining in 'entries' into the correct position in + * rearrangedEntries. + * + * @param entries + * @param rearrangedEntries + */ + public abstract void rearrangeRelatedItems(List entries, + List rearrangedEntries); +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java new file mode 100644 index 000000000000..745099c43398 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.rearrangement; + +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; + +import java.util.ArrayList; +import java.util.List; + +/** Moves (rearranges) classes and class members according to rules specified by the user. */ +public final class Mover { + private final List outerClasses; + private final RearrangerSettings settings; + + public Mover(final List outerClasses, + final RearrangerSettings settings) + { + this.outerClasses = new ArrayList(outerClasses); + this.settings = settings; + } + + public List rearrangeOuterClasses() { + final GenericRearranger outerClassRearranger = new GenericRearranger( + settings.getClassOrderAttributeList(), + outerClasses, + 0, + settings) + { + /** + * There are no items related to outer classes -- outer classes are completely disjoint + * and independent. Hence this routine does nothing. + * @param entries + + + @param rearrangedEntries + */ + public void rearrangeRelatedItems(List entries, + List rearrangedEntries) + { + } + }; + + return outerClassRearranger.rearrangeEntries(); + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Parser.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Parser.java new file mode 100644 index 000000000000..53033b2d264f --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Parser.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.rearrangement; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.entry.ClassEntry; +import com.wrq.rearranger.entry.PsiFileEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.settings.RearrangerSettings; + +import java.util.List; + +/** Creates a list of entries for classes and class members by parsing the Java file. */ +public final class Parser { + private static final Logger LOG = Logger.getInstance("#" + Parser.class.getName()); + private final Project project; + private final RearrangerSettings settings; + private final PsiFile psiFile; + + public Parser(final Project project, + final RearrangerSettings settings, + final PsiFile psiFile) + { + this.project = project; + this.settings = settings; + this.psiFile = psiFile; + } + + public List parseOuterLevel() { + /** + * Parse the top level contents of the PsiFile here. + */ + PsiFileEntry fileEntry = new PsiFileEntry(settings); + return fileEntry.parseFile(project, psiFile, settings.getClassOrderAttributeList()); + } + + private void dumpOuterClasses(final List outerClasses) { + LOG.debug("Outer class entries:"); + for (ClassEntry classEntry : outerClasses) { + LOG.debug(classEntry.toString()); + if (classEntry.getContents() == null) { + // this is a header or trailer, and isn't really a class. + continue; + } + LOG.debug(" === class contents:"); + for (RangeEntry rangeEntry : classEntry.getContents()) { + LOG.debug(rangeEntry.toString()); + } + LOG.debug(" === end class contents:"); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java new file mode 100644 index 000000000000..b8d5c0f11872 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.rearrangement; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.wrq.rearranger.settings.ForceBlankLineSetting; +import com.wrq.rearranger.settings.RearrangerSettings; + +import javax.swing.*; +import java.util.HashMap; +import java.util.Map; + +/** Responsible for adjusting the number of blank lines at strategic places in the source file. */ +public class Spacer { + private static final Logger LOG = Logger.getInstance("#" + Spacer.class.getName()); + private final Project project; + private final PsiFile psiFile; + private final Document document; + private final PsiElementFactory factory; + private final RearrangerSettings settings; + private final char[] newlineChars; + private boolean changesMade; + private StringBuffer sb; + private Map virtualElements = new HashMap(); + + public Spacer(Project project, PsiFile psiFile, Document document, RearrangerSettings settings) { + this.project = project; + this.psiFile = psiFile; + this.document = document; + this.settings = settings; + changesMade = false; + factory = JavaPsiFacade.getInstance(project).getElementFactory(); + int size = 0; + size += settings.getAfterClassLBrace().getnBlankLines() + 1; + size += settings.getBeforeMethodLBrace().getnBlankLines() + 1; + size += settings.getAfterMethodLBrace().getnBlankLines() + 1; + size += settings.getBeforeMethodRBrace().getnBlankLines() + 1; + size += settings.getAfterMethodRBrace().getnBlankLines() + 1; + size += settings.getBeforeClassRBrace().getnBlankLines() + 1; + size += settings.getAfterClassRBrace().getnBlankLines() + 1; + LOG.debug("constructor allocating " + size + " newline chars for max insertion"); + newlineChars = new char[size]; + while (size > 0) { + newlineChars[--size] = '\n'; + } + LOG.debug(settings.getAfterClassLBrace().toString()); + LOG.debug(settings.getBeforeMethodLBrace().toString()); + LOG.debug(settings.getAfterMethodLBrace().toString()); + LOG.debug(settings.getBeforeMethodRBrace().toString()); + LOG.debug(settings.getAfterMethodRBrace().toString()); + LOG.debug(settings.getBeforeClassRBrace().toString()); + LOG.debug(settings.getAfterClassRBrace().toString()); + final int ROOM_FOR_EXPANSION = 100; + int maxSize = document.getTextLength() + ROOM_FOR_EXPANSION; + sb = new StringBuffer(maxSize); + } + + private class AbortRespacing extends RuntimeException { + } + + private class BadPsiElement extends Exception { + BadPsiElement(String string) { + super(string); + } + } + + private void handleBadPsiElementException(BadPsiElement bpe, String desc, PsiElement element) + throws AbortRespacing + { + JOptionPane.showMessageDialog(null, + "Spacing could not be performed due to a syntax error:\n" + + desc + element.getText(), "Spacing Error", JOptionPane.ERROR_MESSAGE); + throw new AbortRespacing(); + } + + public boolean respace() { + sb.append(document.getText()); + + JavaElementVisitor visitor = new JavaRecursiveElementVisitor() { + private int bias = 0; + + public void visitReferenceExpression(PsiReferenceExpression referenceExpression) { + } + + public void visitFile(PsiFile psiFile) { + super.visitFile(psiFile); + if (settings.getNewlinesAtEOF().isForce()) { + // remove all newlines at end of file, then append as many as are declared in configuration. + while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '\n') { + sb.setLength(sb.length() - 1); + } + for (int count = 0; count < settings.getNewlinesAtEOF().getnBlankLines(); count++) { + sb.append('\n'); + } + } + } + + public void visitAnonymousClass(PsiAnonymousClass psiAnonymousClass) { + super.visitAnonymousClass(psiAnonymousClass); + } + + public void visitClass(PsiClass psiClass) { + if (psiClass instanceof PsiTypeParameter) { + return; + } + boolean anonymous = psiClass.getName() == null; + int oldbias = bias; + try { + bias += adjustSpacing( + psiClass.getLBrace(), + psiClass.getRBrace(), + settings.getAfterClassLBrace(), + bias + ); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "class " + psiClass.getName() + " missing left brace. Body follows:", + psiClass); + } + log(settings.getAfterClassLBrace(), psiClass.getName(), oldbias, bias); + super.visitClass(psiClass); + oldbias = bias; + try { + bias += adjustSpacing( + psiClass.getRBrace(), + psiClass.getLBrace(), + settings.getBeforeClassRBrace(), + bias + ); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "class " + psiClass.getName() + " missing right brace. Body follows:", + psiClass); + } + log(settings.getBeforeClassRBrace(), psiClass.getName(), oldbias, bias); + + if (anonymous) { + return; + } + + /** + * if this is the last class in a file, don't adjust spacing after right brace. + * The setting for number of newline characters at end of file overrides it. + */ + boolean lastClass = false; + if (psiClass.getParent() instanceof PsiJavaFile) { + lastClass = isLastMeaningfulElement(psiClass.getParent(), psiClass); + } + if (!lastClass) { + oldbias = bias; + try { + bias += adjustSpacing( + psiClass.getRBrace(), + psiClass.getLBrace(), + settings.getAfterClassRBrace(), + bias + ); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "class " + psiClass.getName() + " missing left brace. Body follows:", + psiClass); + } + log(settings.getAfterClassRBrace(), psiClass.getName(), oldbias, bias); + } + else { + LOG.debug( + "class " + + psiClass.getName() + + " is last in file, no 'after right brace' adjustment" + ); + } + } + + public void visitMethod(PsiMethod psiMethod) { + int oldbias; + /** + * if method has no body, make no spacing adjustments - there are no braces. It must be an interface + * or abstract method declaration. + */ + if (psiMethod.getBody() == null) { + LOG.debug("skipping interface or abstract method " + psiMethod.getName()); + super.visitMethod(psiMethod); + return; + } + /** + * if method has an empty body, do only the spacing before the opening brace and after the closing + * brace. + */ + boolean methodIsEmpty = true; + { + PsiElement element = psiMethod.getBody().getLBrace().getNextSibling(); + while (element != null) { + if (!(element instanceof PsiWhiteSpace) && + element != psiMethod.getBody().getRBrace()) + { + methodIsEmpty = false; + break; + } + element = element.getNextSibling(); + } + } + if (!methodIsEmpty) { + oldbias = bias; + try { + bias += adjustSpacing( + psiMethod.getBody().getLBrace(), + psiMethod.getBody().getRBrace(), + settings.getBeforeMethodLBrace(), + bias + ); + bias += adjustSpacing( + psiMethod.getBody().getLBrace(), + psiMethod.getBody().getRBrace(), + settings.getAfterMethodLBrace(), + bias + ); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "body of method " + psiMethod.getName() + " missing left brace. Body follows:", + psiMethod); + } + log(settings.getAfterMethodLBrace(), psiMethod.getName(), oldbias, bias); + super.visitMethod(psiMethod); + oldbias = bias; + try { + bias += adjustSpacing( + psiMethod.getBody().getRBrace(), + psiMethod.getBody().getLBrace(), + settings.getBeforeMethodRBrace(), + bias + ); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "body of method " + psiMethod.getName() + " missing right brace. Body follows:", + psiMethod); + } + log(settings.getBeforeMethodRBrace(), psiMethod.getName(), oldbias, bias); + } + else { + LOG.debug("method " + psiMethod.getName() + " is empty, no internal spacing changes"); + } + /** + * if this is the last method in a class, don't adjust spacing after right brace. + * The class setting for number of spaces before closing right brace overrides it. + * Normally this would make no difference, as the 2nd would cancel out the first; + * but in the case where the method ends with "}});" (anonymous inner class as + * parameter), an inserted blank line actually causes two newline characters to be + * inserted; but the class rule only removes one of those. + */ + boolean lastMethod = false; + PsiClass owner = psiMethod.getContainingClass(); + if (owner == psiMethod.getParent()) { + lastMethod = isLastMeaningfulElement(owner, psiMethod); + } + if (!lastMethod) { + oldbias = bias; + try { + bias += adjustSpacing( + psiMethod.getBody().getRBrace(), + psiMethod.getBody().getLBrace(), + settings.getAfterMethodRBrace(), + bias + ); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "body of method " + psiMethod.getName() + " missing right brace. Body follows:", + psiMethod); + } + log(settings.getAfterMethodRBrace(), psiMethod.getName(), oldbias, bias); + } + else { + LOG.debug( + "method " + + psiMethod.getName() + + " is last in class, no 'after right brace' adjustment" + ); + } + } + + public void visitCodeBlock(PsiCodeBlock psiCodeBlock) { + int oldbias; + if (!(psiCodeBlock.getParent() instanceof PsiMethod) && + settings.isRemoveBlanksInsideCodeBlocks()) + { + oldbias = bias; + try { + bias += adjustSpacing(psiCodeBlock.getLBrace(), + psiCodeBlock.getRBrace(), false, 0, bias); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "code block missing left brace. Content follows:\n", psiCodeBlock); + } + log("code block left brace", oldbias, bias); + } + super.visitCodeBlock(psiCodeBlock); + if (!(psiCodeBlock.getParent() instanceof PsiMethod) && + settings.isRemoveBlanksInsideCodeBlocks()) + { + oldbias = bias; + try { + bias += adjustSpacing(psiCodeBlock.getRBrace(), psiCodeBlock.getLBrace(), true, 0, bias); + } + catch (BadPsiElement badPsiElement) { + handleBadPsiElementException(badPsiElement, + "code block missing right brace. Content follows:\n", psiCodeBlock); + } + log("code block right brace", oldbias, bias); + } + } + }; + try { + psiFile.accept(visitor); + } + catch (AbortRespacing ar) { + return false; + } + if (changesMade) { + LOG.debug( + "changes made to document; old length=" + + document.getTextLength() + ", new=" + sb.length() + ); + LOG.debug("old document is:\n" + document.getText()); + LOG.debug("new document is:\n" + sb.toString()); + document.replaceString(0, document.getTextLength(), sb.toString()); + } + return changesMade; + } + + /** + * Determines if the psiElement (method or class) is last syntactic item in the owner class. + * If so, we don't want to change spacing after right brace of psiElement; this spacing is + * overridden by the parent class's spacing before right brace. + * + * @param owner class element to which psiElement belongs. + * @param psiElement method or inner class to be tested. + * @return true if the psiElement is the last syntactic item (i.e., not including comments and whitespace) + * of the owner. + */ + private boolean isLastMeaningfulElement(PsiElement owner, PsiElement psiElement) { + boolean lastMethod; + // class is immediate parent + PsiElement[] elements = owner.getChildren(); + boolean sawThisMethod = false; + boolean sawSomethingElseLater = false; + for (PsiElement element : elements) { + if (!sawThisMethod && element == psiElement) { + sawThisMethod = true; + } + else if (sawThisMethod && + !(element instanceof PsiWhiteSpace) && + !(element instanceof PsiJavaToken && + element.getText().equals("}"))) +// ((PsiJavaToken) elements[i]).getTokenType() == PsiJavaToken.RBRACE)) + { + sawSomethingElseLater = true; + break; + } + } + lastMethod = sawThisMethod && !sawSomethingElseLater; + return lastMethod; + } + + private void log(ForceBlankLineSetting fbls, String name, int oldbias, int bias) { + if (oldbias != bias) { + LOG.debug( + fbls.getObjectName() + + " " + + name + + (fbls.isBefore() ? " before" : " after") + + (fbls.isOpenBrace() ? " left brace:" : " right brace:") + + (oldbias < bias ? " inserted " + (bias - oldbias) + : " removed " + (oldbias - bias)) + " newlines" + ); + } + } + + private void log(String name, int oldbias, int bias) { + if (oldbias != bias) { + LOG.debug( + name + + (oldbias < bias ? " inserted " + (bias - oldbias) + : " removed " + (oldbias - bias)) + " newlines" + ); + } + } + + private int adjustSpacing(PsiElement brace, PsiElement matchingBrace, ForceBlankLineSetting fbls, int bias) + throws BadPsiElement + { + if (fbls.isForce()) { + return adjustSpacing(brace, matchingBrace, fbls.isBefore(), fbls.getnBlankLines(), bias); + } + else { + return 0; + } + } + + /** + * When whiteSpace is changed based on contents of a PsiWhiteSpace element, we need to keep track of that + * so that if a subsequent adjustment in spacing is based on that same element, we use the new whitespace value. + */ + private class VirtualElement { + private String textValue; + private final int textOffset; + + VirtualElement(PsiWhiteSpace whiteSpace, int bias) { + textValue = whiteSpace.getText(); + textOffset = whiteSpace.getTextOffset() + bias; + virtualElements.put(whiteSpace, this); + } + + String getText() { + return textValue; + } + + public void setTextValue(String textValue) { + this.textValue = textValue; + } + + public int getTextOffset() { + return textOffset; + } + } + + /** + * Determine the number of blank lines actually occurring before or after the brace. If this is not + * the desired number, alter the whitespace before or after the brace to contain the desired number + * of blank lines. + * + * @param brace + * @param before + * @param nBlankLines + * @param bias + * @return bias adjustment corresponding to number of newlines inserted or deleted + */ + private int adjustSpacing(PsiElement brace, PsiElement matchingBrace, boolean before, int nBlankLines, int bias) + throws BadPsiElement + { + int result = 0; + if (brace == null) { + throw new BadPsiElement( + "adjustSpacing: illegal syntax (mismatched braces); PsiElement for brace is null" + ); + } + /* + * ensure that character at offset indicated by brace element is in fact a brace. + */ + int offset = brace.getTextRange().getStartOffset() + bias; + int direction = before ? -1 : +1; + int count = 0; + { + char braceChar = sb.charAt(offset); + if (braceChar != '{' && braceChar != '}') { + int L = offset - 50; + int R = offset + 50; + if (L < 0) { + L = 0; + } + if (R > sb.length()) { + R = sb.length(); + } + String context = sb.toString().substring(L, R); + throw new RuntimeException( + "adjustSpacing: char at offset " + + offset + + " is not a brace, ='" + + braceChar + "'" + "; context is " + context + ); + } + } + /* + * Locate the whitespace that precedes or follows this brace and which contains newline characters. + * Intervening text, such as comments and other syntactic items, could be skipped. + */ + PsiElement whiteSpace = brace; + do { + whiteSpace = getNextElement(whiteSpace, before); + if (whiteSpace == matchingBrace) { + /** + * Don't parse past the matching brace. This could occur if a class or method body is empty and + * the left and right braces are on the same line with no intervening whitespace. + */ + return result; + } + } + while (whiteSpace != null && + (!(whiteSpace instanceof PsiWhiteSpace) || + whiteSpace.getText().indexOf('\n') < 0)); + + VirtualElement virtualWhiteSpace = null; + if (whiteSpace != null) { + virtualWhiteSpace = (virtualElements.get(whiteSpace)); + if (virtualWhiteSpace == null) { + virtualWhiteSpace = new VirtualElement((PsiWhiteSpace)whiteSpace, bias); + } + else { + LOG.debug("reusing virtualWhiteSpace, offset=" + virtualWhiteSpace.textOffset); + } + /* + * now count the number of newlines. + */ + String s = virtualWhiteSpace.getText(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '\n') { + count++; + } + } + } + + /** + * first count the number of existing blank lines. + */ + if (offset + direction >= sb.length()) { + LOG.debug("at EOF, don't append any extra blank lines"); + // we're at end of file. Don't append any extra blank lines. + nBlankLines = 0; + } + /** + * Count of one means there was a single newline character next to the brace. + * This can be counted as the one that belongs on the brace's line. So the real number + * of consecutive newline characters desired is nBlankLines + 1. + */ + int desiredNewlineChars = nBlankLines + 1; + if (desiredNewlineChars == 1 && count == 0 && before) { + // no blank lines to precede this text; in fact, there's prior text and no newline character at all. + // this is acceptable. + desiredNewlineChars = 0; + } + { + PsiElement element = brace.getParent(); + if (element instanceof PsiCodeBlock && + element.getParent() instanceof PsiMethod) + { + element = element.getParent(); + } + LOG.debug( + "adjustSpacing: " + + (before ? "before " : "after ") + + element.toString() + + " " + + brace.getText() + + ", desire " + desiredNewlineChars + " newlines, have " + count + ); + } + if (desiredNewlineChars == count) { + return 0; + } + /* + * determine end index of whitespace to be replaced. + * keep trailing spaces/tabs. + */ + int endIndex; +// if (whiteSpace != null) // todo - try modifying the PSI tree +// { +// try +// { +// StringBuilder sbr = new StringBuilder(whiteSpace.getText()); +// if (desiredNewlineChars > count) sbr.append(newlineChars, 0, desiredNewlineChars - count); +// else sbr.setLength(sbr.length() + desiredNewlineChars - count); +// PsiElement codeblk = factory.createCodeBlockFromText(sbr.toString(), element); +// whiteSpace.replace(codeblk.getFirstChild()); +// } +// catch (IncorrectOperationException e) +// { +// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. +// } +// } + if (virtualWhiteSpace != null) { + String s = virtualWhiteSpace.getText(); + for (endIndex = s.length() - 1; endIndex >= 0; endIndex--) { + if (s.charAt(endIndex) != ' ' && + s.charAt(endIndex) != '\t') + { + break; + } + } // now endIndex points to the last newline character in the whitespace. + offset = virtualWhiteSpace.getTextOffset(); + endIndex += offset + 1; + } + else { + offset = endIndex = sb.length(); + } + try { + changesMade = true; + LOG.debug( + "sb.replace(" + + offset + + "," + + endIndex + ") with " + desiredNewlineChars + " newline characters" + ); + sb.replace(offset, endIndex, new String(newlineChars, 0, desiredNewlineChars)); + result = desiredNewlineChars - (endIndex - offset); + // now update virtualWhiteSpace accordingly. + if (virtualWhiteSpace != null) { + offset -= virtualWhiteSpace.getTextOffset(); + endIndex -= virtualWhiteSpace.getTextOffset(); + StringBuffer vsb = new StringBuffer(virtualWhiteSpace.getText()); + vsb.replace(offset, endIndex, new String(newlineChars, 0, desiredNewlineChars)); + virtualWhiteSpace.setTextValue(vsb.toString()); + } + } + catch (StringIndexOutOfBoundsException si) { + throw new RuntimeException( + "sb.length()=" + + sb.length() + + ", offset=" + + offset + + ", before=" + + before + + ", count=" + + count + + ", desiredNewlineChars=" + + desiredNewlineChars + + ", charAt offset=" + (offset < sb.length() ? "" + sb.charAt(offset) : "OOB"), si + ); + } + return result; + } + + /** + * Returns the leaf psiElement before or after the given element. + * + * @param element original element. + * @param before if true, return prior leaf element; else return next left element. + * @return adjacent leaf element. + */ + private PsiElement getNextElement(PsiElement element, boolean before) { + PsiElement result; + while (true) { + result = before ? element.getPrevSibling() : element.getNextSibling(); + if (result == null) { + // first/last sibling; go to parent's previous/next item. + result = element.getParent(); + if (result instanceof PsiFile) { + // don't go beyond this document! + result = null; + } + // if we started at the first/last leaf node, we run out of parents; there is no previous/next leaf element. + if (result == null) { + break; + } + else { + element = result; + } + } + else { + break; + } + } + while (result != null && result.getChildren().length != 0) { + // previous/next sibling is parent of others; find last/first leaf node. + result = result.getChildren()[before ? result.getChildren().length - 1 : 0]; + } + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java new file mode 100644 index 000000000000..2e30b45d3161 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.IRule; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** Used to store a generated comment, and to determine if it should be emitted. */ +public abstract class CommentRuleInstance + implements IRuleInstance, + IFilePopupEntry +{ + protected final CommentRule commentRule; + protected boolean emit; + + public CommentRuleInstance(final CommentRule commentRule) { + this.commentRule = commentRule; + emit = false; + } + + public boolean isEmit() { + return emit; + } + + public void setEmit(final boolean emit) { + this.emit = emit; + } + + public IRule getRule() { + return commentRule; + } + + /** Determine if this comment, in this instance, should be emitted. */ + public abstract void determineEmit(List resultRuleInstances, int startIndex); + + public boolean hasMatches() { + return false; // a generated comment never matches any object + } + + public void emit(Emitter emitter) { + StringBuffer sb = emitter.getStringBuffer(); + if (emit) { + // emit a comment. Precede with a newline unless this is the first line of the file. + if (sb.length() > 0) { + sb.append('\n'); + sb.append(commentRule.getExpandedCommentText()); + } + else { + sb.append(commentRule.getExpandedCommentText()); + sb.append('\n'); + } + } + } + + public void addEntry(RangeEntry entry) // adds entry to list of matching entries, in correct order + { + // comment rules don't match anything in the existing file; they conditionally generate comments. + // So this method will never be called. + throw new RuntimeException("cannot add entry to comment rule instance"); + } + + public List getMatches() { + return new ArrayList(); + } + + public void rearrangeRuleItems(List entries, + RearrangerSettings settings) + { + } + + public void addRuleInstanceToPopupTree(DefaultMutableTreeNode node, RearrangerSettings settings) { + /** + * if we are supposed to show comment rules, create a node for the rule and put its contents below. + * Otherwise, just add comments. + */ + if (!settings.isShowComments()) return; + DefaultMutableTreeNode top = node; + if (settings.isShowRules()) { + // if "show matched rules only" is set, only display if comment will be emitted + if ((!settings.isShowMatchedRules()) || isEmit()) { + top = new DefaultMutableTreeNode(this); + node.add(top); + } + } + /** + * append the comment if generated and if showComments is set. + */ + if (isEmit()) { + commentRule.addToPopupTree(top, settings); + } + } + + public String getTypeIconName() { + return null; + } + + @Nullable + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + JLabel label = new JLabel(commentRule.toString()); + Font font = label.getFont().deriveFont(Font.ITALIC); + label.setFont(font); + return label; + } + + public String toString() { + return "instance of:" + commentRule.toString(); + } + + /** + * beginning at the index of ruleStatistics (which is a comment entry), find nRules in the direction indicated, + * and test to see if all or any of them had entries that matched. + * + * @param nRules number of rules to consider for matching algorithm. + * @param direction 1 = subsequent, -1 = previous. + * @param startIndex comment entry index, sandwiched between rules. + * @param ANDing if true, all rules must be matched; if false, any rule that matches returns a result of true. + * @return true if the match condition is met. + */ + @SuppressWarnings({"MethodParameterNamingConvention"}) + protected boolean match(final List resultRuleInstances, + final int nRules, + final int direction, + final int startIndex, + final boolean ANDing) + { + int index = startIndex + direction; + int nRulesSeen = 0; + while (index >= 0 && + index < resultRuleInstances.size() && + nRulesSeen < nRules) + { + if (!(resultRuleInstances.get(index) instanceof CommentRuleInstance)) { + // this is a rule entry, not a comment. + nRulesSeen++; + final IRuleInstance ruleInstance = resultRuleInstances.get(index); + if (ruleInstance.hasMatches()) { + if (!ANDing) { + return true; // OR condition (any matching rule) met + } + } + else { + if (ANDing) { + return false; // AND condition not met + } + } + } + index += direction; + } + return ANDing; + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstanceFactory.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstanceFactory.java new file mode 100644 index 000000000000..0c2f3a49cd01 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstanceFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.settings.CommentRule; + +/** Creates appropriate subtype of CommentRuleInstance from a CommentRule. */ +@SuppressWarnings({"UtilityClass"}) +public class CommentRuleInstanceFactory { + private CommentRuleInstanceFactory() { + } + + @SuppressWarnings({"MethodWithMultipleReturnPoints"}) + public static CommentRuleInstance buildCommentRuleInstance(CommentRule rule) { + switch (rule.getEmitCondition()) { + case CommentRule.EMIT_ALWAYS: + return new EmitAlwaysCommentRuleInstance(rule); + case CommentRule.EMIT_IF_ITEMS_MATCH_SURROUNDING_RULES: + return new SurroundingCommentRuleInstance(rule); + case CommentRule.EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE: + return new SubsequentCommentRuleInstance(rule); + case CommentRule.EMIT_IF_ITEMS_MATCH_PRECEDING_RULE: + return new PrecedingCommentRuleInstance(rule); + default: + throw new IllegalStateException("unknown emit condition type=" + rule.getEmitCondition()); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java new file mode 100644 index 000000000000..4fa75c6bc511 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.intellij.openapi.diagnostic.Logger; +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.entry.IPopupTreeRangeEntry; +import com.wrq.rearranger.entry.MethodEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.atomicAttributes.SortOptions; +import com.wrq.rearranger.settings.attributeGroups.CommonAttributes; +import com.wrq.rearranger.settings.attributeGroups.IRule; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** Handles basic Rule functions. */ +public abstract class CommonRuleInstance + implements IRuleInstance, + IFilePopupEntry +{ + private static final Logger LOG = Logger.getInstance("#" + CommonRuleInstance.class.getName()); + protected final IRule rule; + protected final List matchedItems; + + public CommonRuleInstance(IRule rule) { + this.rule = rule; + matchedItems = new ArrayList(); + } + + public IRule getRule() { + return rule; + } + + /** + * adds entry to list of matching entries, in correct order (order encountered, or alphabetically) + * + * @param entry + */ + public void addEntry(RangeEntry entry) { + if (rule instanceof CommonAttributes) { + SortOptions sortOptions = ((CommonAttributes)rule).getSortAttr(); + insertionSort(entry, sortOptions); + } + else { + matchedItems.add(entry); + } + } + + public List getMatches() { + return matchedItems; + } + + private void insertionSort(final RangeEntry newEntry, final SortOptions sortOptions) { + boolean inserted = false; + final String s = sortOptions.generateSortString(newEntry); + LOG.debug("insertionSort: new entry=" + s); + int index = 0; + while (index < matchedItems.size()) { + final RangeEntry re = matchedItems.get(index); + final String res = sortOptions.generateSortString(re); + LOG.debug("insertionSort: compare to " + res); + if (s.compareTo(res) < 0) { + LOG.debug("insertionSort: insert at " + index); + matchedItems.add(index, newEntry); + inserted = true; + break; + } + index++; + } + if (!inserted) { + LOG.debug("insertionSort: add " + s + " to end"); + matchedItems.add(newEntry); + } + } + + public boolean hasMatches() { + return matchedItems.size() > 0; + } + + public void emit(Emitter emitter) { + for (RangeEntry rangeEntry : matchedItems) { + rangeEntry.emit(emitter); + } + } + + public void rearrangeRuleItems(List entries, + RearrangerSettings settings) + { + MethodEntry.rearrangeRelatedItems( + entries, + this, + settings.getExtractedMethodsSettings() + ); + } + + public void addRuleInstanceToPopupTree(DefaultMutableTreeNode node, RearrangerSettings settings) { + /** + * if we are supposed to show rules, create a node for the rule and put its contents below. + * Otherwise, delegate to each of the matches. + */ + DefaultMutableTreeNode top = node; + if (settings.isShowRules() && + (!settings.isShowMatchedRules() || hasMatches())) + { + top = new DefaultMutableTreeNode(this); + node.add(top); + } + /** + * append each of the matches to the top level. + */ + for (IPopupTreeRangeEntry entry : getMatches()) { + entry.addToPopupTree(top, settings); + } + } + + public String getTypeIconName() { + return "general/templateGroup"; + } + + public String[] getAdditionalIconNames() { + return null; + } + + public JLabel getPopupEntryText(RearrangerSettings settings) { + JLabel label = new JLabel(toString()); + Font font = label.getFont().deriveFont(Font.ITALIC); + label.setFont(font); + return label; + } + + public String toString() { + return getRule().toString(); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java new file mode 100644 index 000000000000..deda68b4c640 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.settings.attributeGroups.IRule; + +/** Collects any remaining RangeEntries after all explicit rule matching is done. */ +public class DefaultRuleInstance extends CommonRuleInstance { + public DefaultRuleInstance(IRule defaultRule) { + super(defaultRule); + } + + public String toString() { + return getRule().toString(); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java new file mode 100644 index 000000000000..77f53e911e07 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.settings.CommentRule; + +import java.util.List; + +/** Used to store a generated comment which is always emitted. */ +public class EmitAlwaysCommentRuleInstance + extends CommentRuleInstance +{ + public EmitAlwaysCommentRuleInstance(final CommentRule commentRule) { + super(commentRule); + } + + /** + * Determine if this comment, in this instance, should be emitted. + * For an "Emit Always" type of comment, it should always be emitted. + */ + public void determineEmit(List resultRuleInstances, int startIndex) { + setEmit(true); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java new file mode 100644 index 000000000000..098215166840 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.IRule; + +import javax.swing.tree.DefaultMutableTreeNode; +import java.util.ArrayList; +import java.util.List; + +/** Instance to pick up header text. */ +public class HeaderTrailerRuleInstance + implements IRuleInstance +{ + private final IRule rule; + private RangeEntry entry; + + public HeaderTrailerRuleInstance(IRule rule) { + this.rule = rule; + } + + public boolean hasMatches() { + return false; // comments are never emitted based on whether header text is emitted, so false is fine. + } + + public List getMatches() { + List list = null; + if (entry != null) { + list = new ArrayList(); + list.add(entry); + } + return list; + } + + public IRule getRule() { + return rule; + } + + public void addEntry(RangeEntry entry) { + this.entry = entry; // a header only has one entry + } + + public void emit(Emitter emitter) { + if (entry != null) { + entry.emit(emitter); + } + } + + public void rearrangeRuleItems(List entries, + RearrangerSettings settings) + { + return; + } + + public void addRuleInstanceToPopupTree(DefaultMutableTreeNode node, RearrangerSettings settings) { + return; // don't show header/trailer junk in popup tree + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/IRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/IRuleInstance.java new file mode 100644 index 000000000000..fd681e3cb13f --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/IRuleInstance.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.IRule; + +import javax.swing.tree.DefaultMutableTreeNode; +import java.util.List; + +/** + * One RuleInstance exists for every execution of every rule. An execution of a rule is the process by which + * items are matched to a rule. + */ +public interface IRuleInstance { + /** @return true if one or more items matched the rule in this instance. */ + boolean hasMatches(); + + /** @return list of items matching the rule in this instance. */ + List getMatches(); + + /** + * Causes the text representation of this item to be emitted to a buffer, and from there into the final Document. + * + * @param emitter Emitter target object with buffer and Document. + */ + void emit(Emitter emitter); + + /** @return the rule associated with this instance. */ + IRule getRule(); + + /** + * Adds an item to the list of items matching the rule in this instance. Order is preserved. + * + * @param entry matching item + */ + void addEntry(RangeEntry entry); + + /** + * Perform any rearranging based on rule or item relationships indicated by the settings. + * + * @param entries list of items (fields, methods, etc.) + * @param settings + */ + void rearrangeRuleItems(List entries, RearrangerSettings settings); + + /** add the contents of this rule to the file structure popup tree. */ + void addRuleInstanceToPopupTree(DefaultMutableTreeNode node, RearrangerSettings settings); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java new file mode 100644 index 000000000000..c227c5829fcd --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.entry.MethodEntry; +import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.InterfaceAttributes; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** Corresponds to a single interface with one or more implementing methods. */ +public class InterfaceInstance + implements IFilePopupEntry +{ +// ------------------------------------------------------- FIELDS ------------------------------------------------------ + + private String interfaceName; + + public String getInterfaceName() { + return interfaceName; + } + + private List methods; + private InterfaceAttributes rule; + +// ---------------------------------------------------- CONSTRUCTORS --------------------------------------------------- + + public InterfaceInstance(String interfaceName, InterfaceAttributes rule) { + this.interfaceName = interfaceName; + methods = new ArrayList(); + this.rule = rule; + } + +// ---------------------------------------------- GETTER / SETTER METHODS ---------------------------------------------- + + public String[] getAdditionalIconNames() { + return null; + } + + public String getTypeIconName() { + return null; + } + +// ------------------------------------------------- INTERFACE METHODS ------------------------------------------------- + +// --------------------------------------------- Interface IFilePopupEntry --------------------------------------------- + + public JLabel getPopupEntryText(RearrangerSettings settings) { + JLabel label = new JLabel("methods of interface " + interfaceName); + Font font = label.getFont().deriveFont(Font.ITALIC); + label.setFont(font); + return label; + } + +// --------------------------------------------------- OTHER METHODS --------------------------------------------------- + + /** + * add the method to the list of methods, in the order specified by the configuration settings (alphabetical, + * in order declared in the interface, or in order encountered). + * + * @param entry method to add. + */ + void addMethod(MethodEntry entry) { + switch (rule.getMethodOrder()) { + case InterfaceAttributes.METHOD_ORDER_ALPHABETICAL: + entry.insertAlphabetically(methods); + break; + case InterfaceAttributes.METHOD_ORDER_ENCOUNTERED: + methods.add(entry); + break; + case InterfaceAttributes.METHOD_ORDER_INTERFACE_ORDER: + entry.insertInterfaceOrder(methods); + break; + } + } + + public void addToPopupTree(DefaultMutableTreeNode node, RearrangerSettings settings) { + /** + * if we are supposed to show rules, create a node for the rule and put its contents below. + * Otherwise, delegate to each of the matches. + */ + DefaultMutableTreeNode top = node; + if (settings.isShowRules()) { + top = new DefaultMutableTreeNode(this); + node.add(top); + } + /** + * append each of the matches to the top level. + */ + for (MethodEntry entry : methods) { + entry.addToPopupTree(top, settings); + } + } + + void emit(Emitter emitter) { + StringBuffer sb = emitter.getStringBuffer(); + String commentString = expandComment(rule.getPrecedingComment()); + if (commentString.length() > 0) { + sb.append("\n"); + sb.append(commentString); + } + for (MethodEntry rangeEntry : methods) { + rangeEntry.emit(emitter); + } + commentString = expandComment(rule.getTrailingComment()); + if (commentString.length() > 0) { + sb.append("\n"); + sb.append(commentString); + } + } + + private String expandComment(CommentRule comment) { + if (comment == null || comment.getCommentText() == null) return ""; + comment.setCommentFillString(rule.getCommentFillString()); + String result = comment.getCommentText().replaceAll("%IF%", interfaceName); + result = rule.getCommentFillString().getExpandedCommentText(result); + return result; + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java new file mode 100644 index 000000000000..db5ee379cdd2 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.entry.ClassContentsEntry; +import com.wrq.rearranger.entry.MethodEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.rearrangement.Emitter; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.InterfaceAttributes; + +import javax.swing.tree.DefaultMutableTreeNode; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +/** Handles interface rule processing. */ +public class InterfaceRuleInstance + extends CommonRuleInstance +{ +// ------------------------------ FIELDS ------------------------------ + + List interfaceInstances; + +// --------------------------- CONSTRUCTORS --------------------------- + + public InterfaceRuleInstance(IRule rule) { + super(rule); + interfaceInstances = new ArrayList(); + } + +// -------------------------- OTHER METHODS -------------------------- + + /** + * override the supermethod because we never want to alphabetize methods based on the "alphabetize" flag; that + * flag controls whether interfaces are alphabetized or not. Just add the methods to the list in order encountered. + * + * @param entry + */ + public void addEntry(RangeEntry entry) { + matchedItems.add((MethodEntry)entry); + } + + public void addRuleInstanceToPopupTree(DefaultMutableTreeNode node, RearrangerSettings settings) { + /** + * if we are supposed to show rules, create a node for the rule and put its contents below. + * Otherwise, delegate to each of the matches. + */ + DefaultMutableTreeNode top = node; + if (settings.isShowRules()) { + top = new DefaultMutableTreeNode(this); + node.add(top); + } + /** + * An InterfaceRuleInstance has a list of InterfaceInstances, which in turn list the methods which matched + * the name of the interface. Build the tree accordingly. + */ + for (InterfaceInstance instance : interfaceInstances) { + instance.addToPopupTree(top, settings); + } + } + + public void emit(Emitter emitter) { + for (Object interfaceInstance : interfaceInstances) { + InterfaceInstance instance = (InterfaceInstance)interfaceInstance; + instance.emit(emitter); + } + } + + public void rearrangeRuleItems(List entries, + RearrangerSettings settings) + { + /** + * create a list of interface instances, one for each interface specified by any of the matched methods. + * Alphabetize this list if specified. + */ + for (RangeEntry re : matchedItems) { + MethodEntry me = (MethodEntry)re; + InterfaceInstance instance = null; + for (InterfaceInstance interfaceInstance : interfaceInstances) { + if (interfaceInstance.getInterfaceName().equals(me.getInterfaceName())) { + instance = interfaceInstance; + } + } + if (instance == null) { + final InterfaceAttributes interfaceRule = (InterfaceAttributes)getRule(); + instance = new InterfaceInstance(me.getInterfaceName(), interfaceRule); + if (interfaceRule.isAlphabetize()) { + boolean inserted = false; + String s = instance.getInterfaceName(); + ListIterator lii = interfaceInstances.listIterator(); + while (lii.hasNext()) { + InterfaceInstance entry = (lii.next()); + final String ename = entry.getInterfaceName(); + if (s.compareTo(ename) < 0) { + interfaceInstances.add(lii.nextIndex() - 1, instance); + inserted = true; + break; + } + } + if (!inserted) { + interfaceInstances.add(instance); + } + } + else { + interfaceInstances.add(instance); + } + } + instance.addMethod(me); + } + MethodEntry.rearrangeRelatedItems(entries, + this, + settings.getExtractedMethodsSettings()); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java new file mode 100644 index 000000000000..ba31eaf0c85a --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.settings.CommentRule; + +import java.util.List; + +/** Used to store a generated comment which is emitted based on whether it matches preceding rules. */ +public class PrecedingCommentRuleInstance + extends CommentRuleInstance +{ + + public PrecedingCommentRuleInstance(final CommentRule commentRule) { + super(commentRule); + } + + /** Determine if this comment, in this instance, should be emitted. */ + public void determineEmit(List resultRuleInstances, int startIndex) { + if (match( + resultRuleInstances, + commentRule.getnPrecedingRulesToMatch(), + -1, + startIndex, + commentRule.isAllPrecedingRules())) + { + setEmit(true); + } + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java new file mode 100644 index 000000000000..89ddb0e99e3a --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.settings.CommentRule; + +import java.util.List; + +/** Used to store a generated comment which is emitted based on whether it matches subsequent rules. */ +public class SubsequentCommentRuleInstance + extends CommentRuleInstance +{ + + public SubsequentCommentRuleInstance(final CommentRule commentRule) { + super(commentRule); + } + + /** Determine if this comment, in this instance, should be emitted. */ + public void determineEmit(List resultRuleInstances, int startIndex) { + if (match( + resultRuleInstances, + commentRule.getnSubsequentRulesToMatch(), + +1, + startIndex, + commentRule.isAllSubsequentRules() + )) + { + setEmit(true); + } + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java new file mode 100644 index 000000000000..b5e379b9a3f6 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.ruleinstance; + +import com.wrq.rearranger.settings.CommentRule; + +import java.util.List; + +/** Used to store a generated comment which is emitted based on whether it matches surrounding rules. */ +public class SurroundingCommentRuleInstance + extends CommentRuleInstance +{ + + public SurroundingCommentRuleInstance(final CommentRule commentRule) { + super(commentRule); + } + + /** Determine if this comment, in this instance, should be emitted. */ + public void determineEmit(List resultRuleInstances, int startIndex) { + if (match( + resultRuleInstances, + commentRule.getnPrecedingRulesToMatch(), + -1, + startIndex, + commentRule.isAllPrecedingRules() + ) && + match( + resultRuleInstances, + commentRule.getnSubsequentRulesToMatch(), + +1, + startIndex, + commentRule.isAllSubsequentRules() + )) + { + setEmit(true); + } + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/CommentFillString.java b/plugins/rearranger/src/com/wrq/rearranger/settings/CommentFillString.java new file mode 100644 index 000000000000..f1992695517a --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/CommentFillString.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import com.wrq.rearranger.RearrangerActionHandler; +import com.wrq.rearranger.configuration.IntTextField; +import com.wrq.rearranger.settings.attributeGroups.RegexUtil; +import com.wrq.rearranger.util.CommentUtil; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Attribute; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** Implements routines for handling comment fill string expansion. */ +public class CommentFillString { + private String fillString; // replicate in place of %FS% + private boolean useProjectWidthForFill; + private int fillWidth; + + public CommentFillString() { + fillString = ""; + useProjectWidthForFill = true; + fillWidth = 0; + } + + public final String getExpandedCommentText(String commentText) { + int width = useProjectWidthForFill ? RearrangerActionHandler.getRightMargin() : fillWidth; + int tabSize = RearrangerActionHandler.getTabSize(); + return CommentUtil.expandFill(commentText, width, tabSize, fillString); + } + + public String getFillString() { + return fillString; + } + + public void setFillString(String fillString) { + this.fillString = fillString; + } + + public boolean isUseProjectWidthForFill() { + return useProjectWidthForFill; + } + + public void setUseProjectWidthForFill(boolean useProjectWidthForFill) { + this.useProjectWidthForFill = useProjectWidthForFill; + } + + public int getFillWidth() { + return fillWidth; + } + + public void setFillWidth(int fillWidth) { + this.fillWidth = fillWidth; + } + + public final boolean equals(final Object object) { + if (!(object instanceof CommentFillString)) return false; + final CommentFillString c = (CommentFillString)object; + return fillString.equals(c.fillString) && + useProjectWidthForFill == c.useProjectWidthForFill && + fillWidth == c.fillWidth; + } + + public final CommentFillString deepCopy() { + final CommentFillString comment = new CommentFillString(); + comment.fillString = fillString; + comment.useProjectWidthForFill = useProjectWidthForFill; + comment.fillWidth = fillWidth; + return comment; + } + + public static CommentFillString readExternal(final Element item) { + final CommentFillString result = new CommentFillString(); + Attribute fillAttr = RearrangerSettings.getAttribute(item, "fillString"); + if (fillAttr == null) { + result.fillString = ""; + } + else { + String fill = fillAttr.getValue(); + result.fillString = CommentRule.unescape(fill); + } + result.useProjectWidthForFill = RearrangerSettings.getBooleanAttribute(item, "useProjectWidthForFill", true); + result.fillWidth = RearrangerSettings.getIntAttribute(item, "fillWidth", 0); + return result; + } + + public final void writeExternal(final Element me) { + me.setAttribute("fillString", CommentRule.escape(fillString)); + me.setAttribute("useProjectWidthForFill", "" + useProjectWidthForFill); + me.setAttribute("fillWidth", "" + fillWidth); + } + + public final JPanel getCommentFillStringPanel() { + final JPanel cfsPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.insets = new Insets(4, 4, 4, 0); + constraints.newRow(); + final JLabel fillStringLabel = new JLabel("Fill string:"); + fillStringLabel.setToolTipText("Occurrences of %FS% in the comment separator text will be replaced with equal \n" + + "amounts of the fill string, replicated to make the comment end at the specified column"); + cfsPanel.add(fillStringLabel, constraints.firstCol()); + final JTextField fillString = new JTextField(this.fillString); + cfsPanel.add(fillString, constraints.weightedLastCol()); + constraints.newRow(); + final JCheckBox useProjectWidthBox = new JCheckBox("Use project right margin as fill width"); + useProjectWidthBox.setSelected(useProjectWidthForFill); + cfsPanel.add(useProjectWidthBox, constraints.weightedLastCol()); + constraints.lastRow(); + constraints.insets = new Insets(4, 15, 4, 4); + final JLabel fillWidthLabel = new JLabel("Fill width:"); + cfsPanel.add(fillWidthLabel, constraints.firstCol()); + final IntTextField fillWidthField = new IntTextField( + new IntTextField.IGetSet() { + public int get() { + return fillWidth; + } + + public void set(int value) { + fillWidth = value; + } + }, + 0, + 999 + ); + cfsPanel.add(fillWidthField, constraints.nextCol()); + cfsPanel.add(new JLabel(), constraints.weightedLastCol()); + fillWidthLabel.setEnabled(!useProjectWidthForFill); + fillWidthField.setEnabled(!useProjectWidthForFill); + fillString.getDocument().addDocumentListener(new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + setFillString(fillString.getText()); + } + + public void removeUpdate(DocumentEvent e) { + setFillString(fillString.getText()); + } + + public void changedUpdate(DocumentEvent e) { + setFillString(fillString.getText()); + } + }); + useProjectWidthBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + useProjectWidthForFill = useProjectWidthBox.isSelected(); + fillWidthLabel.setEnabled(!useProjectWidthForFill); + fillWidthField.setEnabled(!useProjectWidthForFill); + } + }); + return cfsPanel; + } + + /** Returns a regular expression that will match the fill string. */ + public String getFillStringPattern() { + String fs = fillString; + if (fs.length() == 0) fs = " "; + final int length = fs.length(); + StringBuffer sb = new StringBuffer(length * (length + 1) / 2 + length * 3); + sb.append('('); + sb.append(RegexUtil.escape(fs)); + sb.append(")*"); + if (length > 1) { + sb.append('('); + for (int i = length - 1; i > 0; i--) { + sb.append(RegexUtil.escape(fs.substring(0, i))); + sb.append(i <= 1 ? ")?" : "|"); + } + } + return sb.toString(); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java new file mode 100644 index 000000000000..dd871c0c69b7 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import com.wrq.rearranger.entry.IPopupTreeRangeEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.RearrangerTreeNode; +import com.wrq.rearranger.ruleinstance.CommentRuleInstanceFactory; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; +import com.wrq.rearranger.settings.attributeGroups.RegexUtil; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Attribute; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.tree.DefaultMutableTreeNode; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; + +/** Handles insertion of comment separators between sections of the rearranged file. */ +public final class CommentRule + implements AttributeGroup, + IPopupTreeRangeEntry, + IFilePopupEntry +{ +// ------------------------------------------------------- FIELDS ------------------------------------------------------ + + public static final int EMIT_ALWAYS = 0; + public static final int EMIT_IF_ITEMS_MATCH_PRECEDING_RULE = 1; + public static final int EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE = 2; + public static final int EMIT_IF_ITEMS_MATCH_SURROUNDING_RULES = 3; + + private String commentText; + + public final String getCommentText() { + return commentText; + } + + public final void setCommentText(final String commentText) { + StringBuffer sb = new StringBuffer(commentText); + while (sb.length() > 0 && + Character.isWhitespace(sb.charAt(sb.length() - 1)) && + sb.charAt(sb.length() - 1) != '\n') + { + sb.setLength(sb.length() - 1); + } + this.commentText = sb.toString(); + } + + private int emitCondition; + + public final int getEmitCondition() { + return emitCondition; + } + + public final void setEmitCondition(final int emitCondition) { + this.emitCondition = emitCondition; + } + + private int nPrecedingRulesToMatch; // default 1 + private int nSubsequentRulesToMatch; // default 1 + private boolean allPrecedingRules; // if false, ANY preceding rules + + public final boolean isAllPrecedingRules() { + return allPrecedingRules; + } + + public final void setAllPrecedingRules(final boolean allPrecedingRules) { + this.allPrecedingRules = allPrecedingRules; + } + + private boolean allSubsequentRules; // if false, ANY subsequent rules + + public final boolean isAllSubsequentRules() { + return allSubsequentRules; + } + + public final void setAllSubsequentRules(final boolean allSubsequentRules) { + this.allSubsequentRules = allSubsequentRules; + } + + private CommentFillString commentFillString; + + public CommentFillString getCommentFillString() { + return commentFillString; + } + + public void setCommentFillString(CommentFillString commentFillString) { + this.commentFillString = commentFillString; + } + +// --------------------------------------------------- STATIC METHODS -------------------------------------------------- + + public static CommentRule readExternal(final Element item) { + final CommentRule result = new CommentRule(); + + final Attribute attr = RearrangerSettings.getAttribute(item, "commentText"); + // backward compatibility. Comment text was formerly saved as an attribute. + // Newline characters were lost this way. Now comment text is saved as element text. + // If there's no text but there is an attribute, load the old format. It will be + // saved as element text next time IDEA is exited. + // Turns out that IDEA strips newlines in the element text. Maybe it's due to document + // formatting options. In any case, we have to escape newline characters. + String text = item.getText(); + if (text == null || text.length() == 0) { + result.commentText = (attr == null ? "" : ((java.lang.String)attr.getValue())); + } + else { + result.commentText = unescape(text); + } + result.emitCondition = RearrangerSettings.getIntAttribute(item, "condition", 0); + result.nPrecedingRulesToMatch = RearrangerSettings.getIntAttribute(item, "nPrecedingRulesToMatch", 1); + result.nSubsequentRulesToMatch = RearrangerSettings.getIntAttribute(item, "nSubsequentRulesToMatch", 1); + result.allPrecedingRules = RearrangerSettings.getBooleanAttribute(item, "allPrecedingRules", true); + result.allSubsequentRules = RearrangerSettings.getBooleanAttribute(item, "allSubsequentRules", true); + result.commentFillString = CommentFillString.readExternal(item); + return result; + } + + public static String unescape(String text) { + StringBuffer s = new StringBuffer(text); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '\\' && (i + 1 < s.length())) { + switch (s.charAt(i + 1)) { + case 'n': + s.setCharAt(i, '\n'); + s.deleteCharAt(i + 1); + break; + case '\\': + s.deleteCharAt(i + 1); + break; + case 't': + s.setCharAt(i, '\t'); + s.deleteCharAt(i + 1); + break; + case ' ': + s.deleteCharAt(i); + break; + } + } + } + return s.toString(); + } + + public static String escape(String s) { + StringBuffer sb = new StringBuffer(s); + // for reasons given in readExternal(), escape certain characters in the comment text. + for (int i = 0; i < sb.length(); i++) { + switch (sb.charAt(i)) { + case '\\': + case ' ': + sb.insert(i, '\\'); + i++; + break; + case '\n': + sb.replace(i, i + 1, "\\n"); + i++; + break; + case '\t': + sb.replace(i, i + 1, "\\t"); + i++; + break; + } + } + return sb.toString(); + } + +// ---------------------------------------------------- CONSTRUCTORS --------------------------------------------------- + + public CommentRule() { + commentText = ""; + emitCondition = EMIT_ALWAYS; + nPrecedingRulesToMatch = 1; + nSubsequentRulesToMatch = 1; + allPrecedingRules = true; + allSubsequentRules = true; + commentFillString = new CommentFillString(); + } + +// ---------------------------------------------- GETTER / SETTER METHODS ---------------------------------------------- + + public String[] getAdditionalIconNames() { + return null; + } + + public int getCommentCount() { + return (commentText != null && commentText.length() > 0) ? 1 : 0; + } + + public final JPanel getCommentPanel() { + final JPanel commentPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + commentPanel.setBorder(border); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.insets = new Insets(4, 4, 4, 0); + final JLabel emitLabel = new JLabel("Emit comment:"); + final JRadioButton alwaysButton = new JRadioButton("Always"), + whenButton = new JRadioButton("When"); + final ButtonGroup group = new ButtonGroup(); + group.add(alwaysButton); + group.add(whenButton); + if (emitCondition == 0) { + alwaysButton.setSelected(true); + } + else { + whenButton.setSelected(true); + } + commentPanel.add(emitLabel, constraints.weightedLastCol()); + constraints.newRow(); + constraints.insets = new Insets(0, 14, 0, 0); + commentPanel.add(alwaysButton, constraints.weightedLastCol()); + constraints.newRow(); + commentPanel.add(whenButton, constraints.weightedLastCol()); + constraints.insets = new Insets(0, 24, 0, 4); + constraints.newRow(); + final JPanel anyAllPreviousPanel = new AnyAllPanel(true); + commentPanel.add(anyAllPreviousPanel, constraints.weightedLastCol()); + constraints.newRow(); + constraints.insets = new Insets(0, 24, 10, 4); + final JPanel anyAllSubsequentPanel = new AnyAllPanel(false); + commentPanel.add(anyAllSubsequentPanel, constraints.weightedLastCol()); + anyAllPreviousPanel.setEnabled(emitCondition > 0); + anyAllSubsequentPanel.setEnabled(emitCondition > 0); + final JLabel commentLabel = new JLabel("Comment separator text:"); + constraints.insets = new Insets(4, 4, 4, 4); + constraints.newRow(); + commentPanel.add(commentLabel, constraints.weightedLastCol()); + final JTextArea commentArea = new JTextArea(4, 40); + commentArea.setText(getCommentText()); + constraints.weightedNewRow(); + final JScrollPane scrollPane = new JScrollPane(commentArea); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + commentPanel.add(scrollPane, constraints.weightedLastCol()); + constraints.newRow(); + final JPanel cfsPanel = commentFillString.getCommentFillStringPanel(); + final JLabel fillStringLabel = new JLabel("Fill string:"); + fillStringLabel.setToolTipText("Occurrences of %FS% in the comment separator text will be replaced with equal \n" + + "amounts of the fill string, replicated to make the comment end at the specified column"); + commentPanel.add(cfsPanel, constraints.weightedLastCol()); + + alwaysButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + if (alwaysButton.isSelected()) { + emitCondition = EMIT_ALWAYS; + anyAllPreviousPanel.setEnabled(false); + anyAllSubsequentPanel.setEnabled(false); + } + } + }); + whenButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + if (whenButton.isSelected()) { + anyAllPreviousPanel.setEnabled(true); + anyAllSubsequentPanel.setEnabled(true); + } + } + }); + commentArea.getDocument().addDocumentListener(new DocumentListener() { + public void changedUpdate(final DocumentEvent e) { + setCommentText(commentArea.getText()); + } + + public void insertUpdate(final DocumentEvent e) { + setCommentText(commentArea.getText()); + } + + public void removeUpdate(final DocumentEvent e) { + setCommentText(commentArea.getText()); + } + }); + return commentPanel; + } + + public String getDescriptiveString() { + final StringBuffer sb = new StringBuffer(commentText.trim()); + if (sb.length() > 60) { + // attempt to shorten by removing duplicate (well, quadruplicate) characters. + for (int i = 0; i < sb.length() - 4; i++) { + if (sb.charAt(i) == sb.charAt(i + 1) && + sb.charAt(i + 1) == sb.charAt(i + 2) && + sb.charAt(i + 2) == sb.charAt(i + 3)) + { + // we have at least 4 characters in a row. Shorten the entire sequence to + // a length of 4 characters and append the length. + int j = 0; + while (i + 4 < sb.length() && sb.charAt(i) == sb.charAt(i + 4)) { + j++; + sb.deleteCharAt(i + 4); + } + if (j > 3) { + sb.insert(i + 4, "<" + j + ">"); + } + else { + // compression is quite small, so just output the actual characters. + while (j-- > 0) { + sb.insert(i + 4, sb.charAt(i)); + } + } + } + } + } + if (sb.length() > 60) { + sb.delete(60, sb.length()); + sb.append("..."); + } + String condition = ""; + switch (emitCondition) { + case EMIT_ALWAYS: + break; + case EMIT_IF_ITEMS_MATCH_PRECEDING_RULE: + condition = " when " + precedingRuleString(); + break; + case EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE: + condition = " when " + subsequentRuleString(); + break; + case EMIT_IF_ITEMS_MATCH_SURROUNDING_RULES: + condition = " when " + precedingRuleString() + ", and " + subsequentRuleString(); + } + return ("Comment (" + sb.toString() + ")" + condition); + } + + private String precedingRuleString() { + return (nPrecedingRulesToMatch == 1) ? "preceding rule is matched" : + (allPrecedingRules ? "all" : "any") + + " of preceding " + (nPrecedingRulesToMatch) + " rules are matched"; + } + + private String subsequentRuleString() { + return (nSubsequentRulesToMatch == 1) ? "subsequent rule is matched" : + (allSubsequentRules ? "all" : "any") + + " of subsequent " + (nSubsequentRulesToMatch) + " rules are matched"; + } + + public final String getExpandedCommentText() { + return commentFillString.getExpandedCommentText(commentText); + } + + private String getName() { + return commentText.trim(); + } + + public int getPriority() { + return -1; // Comments never match anything, so any priority will do. + } + + public void setPriority(int priority) { + // does nothing + } + + public String getTypeIconName() { + return "nodes/J2eeParameter"; + } + + public final boolean isAlphabetize() { + throw new UnsupportedOperationException("CommentRule.isAlphabetize() not implemented"); + } + + public final void setnPrecedingRulesToMatch(final int nPrecedingRulesToMatch) { + this.nPrecedingRulesToMatch = nPrecedingRulesToMatch; + } + + public final void setnSubsequentRulesToMatch(final int nSubsequentRulesToMatch) { + this.nSubsequentRulesToMatch = nSubsequentRulesToMatch; + } + +// ------------------------------------------------- CANONICAL METHODS ------------------------------------------------- + + public final boolean equals(final Object object) { + if (!(object instanceof CommentRule)) return false; + final CommentRule c = (CommentRule)object; + return commentText.equals(c.commentText) && + emitCondition == c.emitCondition && + nPrecedingRulesToMatch == c.nPrecedingRulesToMatch && + nSubsequentRulesToMatch == c.nSubsequentRulesToMatch && + allPrecedingRules == c.allPrecedingRules && + allSubsequentRules == c.allSubsequentRules && + commentFillString.equals(c.commentFillString); + } + + public final String toString() { + return getDescriptiveString(); + } + +// ================================================= INTERFACE METHODS ================================================= + +// ---------------------------------------------- Interface AttributeGroup --------------------------------------------- + + public final /*CommentRule*/AttributeGroup deepCopy() { + final CommentRule comment = new CommentRule(); + comment.commentText = commentText; + comment.emitCondition = emitCondition; + comment.nPrecedingRulesToMatch = nPrecedingRulesToMatch; + comment.nSubsequentRulesToMatch = nSubsequentRulesToMatch; + comment.allPrecedingRules = allPrecedingRules; + comment.allSubsequentRules = allSubsequentRules; + comment.commentFillString = commentFillString.deepCopy(); + return comment; + } + + public final void writeExternal(final Element parent) { + final Element me = new Element("Comment"); + me.setText(escape(commentText)); + me.setAttribute("condition", "" + emitCondition); + me.setAttribute("nPrecedingRulesToMatch", "" + nPrecedingRulesToMatch); + me.setAttribute("nSubsequentRulesToMatch", "" + nSubsequentRulesToMatch); + me.setAttribute("allPrecedingRules", "" + allPrecedingRules); + me.setAttribute("allSubsequentRules", "" + allSubsequentRules); + commentFillString.writeExternal(me); + parent.getChildren().add(me); + } + +// --------------------------------------------- Interface IFilePopupEntry --------------------------------------------- + + + public JLabel getPopupEntryText(RearrangerSettings settings) { + String s = commentText.trim(); + if (commentFillString != null && commentFillString.getFillString().length() > 0) { + s = commentFillString.getExpandedCommentText(s); + } + return new JLabel(s); + } + +// ------------------------------------------- Interface IPopupTreeRangeEntry ------------------------------------------ + + + public DefaultMutableTreeNode addToPopupTree(DefaultMutableTreeNode parent, RearrangerSettings settings) { + DefaultMutableTreeNode myNode = new RearrangerTreeNode(this, getName()); + parent.add(myNode); + return myNode; + } + +// -------------------------------------------------- Interface IRule -------------------------------------------------- + + + public IRuleInstance createRuleInstance() { + return CommentRuleInstanceFactory.buildCommentRuleInstance(this); + } + + public boolean isMatch(RangeEntry rangeEntry) { + return false; // comment rules match no entries -- they're just placeholders to generate comments. + } + + public boolean commentsMatchGlobalPattern(String pattern) { + return commentText.matches(pattern); + } + + public List getOffendingPatterns(String pattern) { + List result = new ArrayList(1); + result.add(commentText); + return result; + } + + public void addCommentPatternsToList(List list) { + if (commentText != null && commentText.length() > 0) { + String esc = RegexUtil.escape(commentText); + String fsp = commentFillString.getFillStringPattern(); + esc = esc.replaceAll("%FS%", fsp); + list.add(esc); + } + } + +// --------------------------------------------------- OTHER METHODS --------------------------------------------------- + + public int getnPrecedingRulesToMatch() { + return nPrecedingRulesToMatch; + } + + public final int getnSubsequentRulesToMatch() { + return nSubsequentRulesToMatch; + } + +// --------------------------------------------------- INNER CLASSES --------------------------------------------------- + + final class AnyAllPanel extends JPanel { + final JCheckBox anyAllCheckbox; + final JComboBox anyAllComboBox; + final JLabel anyAllLabel; + final JFormattedTextField anyAllPrevNumber; + final JLabel rulesLabel; + + /** + * Return a JPanel that allows user to specify checkbox (enable rule), Any/All combo box, "of the " + * "preceding"/"subsequent", text field for integer >= 1, "rules" + * + * @param preceding true if handling "preceding" rules, otherwise "subsequent" rules + */ + AnyAllPanel(final boolean preceding) { + super(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.lastRow(); + constraints.fill = GridBagConstraints.BOTH; + anyAllCheckbox = new JCheckBox("items match"); + anyAllCheckbox.setSelected((emitCondition & (preceding ? 1 : 2)) > 0); + anyAllComboBox = new JComboBox(new String[]{"any", "all"}); + anyAllComboBox.setSelectedIndex(preceding ? (allPrecedingRules ? 1 : 0) + : (allSubsequentRules ? 1 : 0)); + Dimension d = anyAllComboBox.getPreferredSize(); + d.width += 3; // make room for "any", if "all" is narrower and is first selection. + anyAllComboBox.setPreferredSize(d); + anyAllLabel = new JLabel(); + anyAllLabel.setText("of the subsequent"); // calculate max size + d = anyAllLabel.getPreferredSize(); + anyAllLabel.setText(preceding ? "of the preceding" : "of the subsequent"); + anyAllLabel.setMinimumSize(d); + anyAllLabel.setPreferredSize(d); + final NumberFormat integerInstance = NumberFormat.getIntegerInstance(); + integerInstance.setMaximumIntegerDigits(2); + integerInstance.setMinimumIntegerDigits(1); + anyAllPrevNumber = new JFormattedTextField(integerInstance); + anyAllPrevNumber.setValue(new Integer("88")); + d = anyAllPrevNumber.getPreferredSize(); + d.width += 3; + anyAllPrevNumber.setPreferredSize(d); + anyAllPrevNumber.setValue(preceding ? nPrecedingRulesToMatch : nSubsequentRulesToMatch); + anyAllPrevNumber.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT); + rulesLabel = new JLabel("rules"); + constraints.insets = new Insets(0, 10, 0, 0); + add(anyAllCheckbox, constraints.nextCol()); + constraints.insets = new Insets(0, 0, 0, 0); + add(anyAllComboBox, constraints.nextCol()); + constraints.insets = new Insets(0, 4, 0, 0); + add(anyAllLabel, constraints.nextCol()); + constraints.insets = new Insets(0, 4, 0, 0); + add(anyAllPrevNumber, constraints.nextCol()); + add(rulesLabel, constraints.weightedLastCol()); + anyAllComboBox.setEnabled(anyAllCheckbox.isSelected()); + anyAllLabel.setEnabled(anyAllCheckbox.isSelected()); + anyAllPrevNumber.setEnabled(anyAllCheckbox.isSelected()); + rulesLabel.setEnabled(anyAllCheckbox.isSelected()); + anyAllCheckbox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + if (anyAllCheckbox.isSelected()) { + emitCondition |= (preceding ? 1 : 2); + } + else { + emitCondition &= (preceding ? ~1 : ~2); + } + anyAllComboBox.setEnabled(anyAllCheckbox.isSelected()); + anyAllLabel.setEnabled(anyAllCheckbox.isSelected()); + anyAllPrevNumber.setEnabled(anyAllCheckbox.isSelected()); + rulesLabel.setEnabled(anyAllCheckbox.isSelected()); + } + }); + anyAllComboBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + final int s = anyAllComboBox.getSelectedIndex(); + if (preceding) { + allPrecedingRules = (s == 1); + } + else { + allSubsequentRules = (s == 1); + } + } + }); + anyAllPrevNumber.addPropertyChangeListener("value", new PropertyChangeListener() { + public void propertyChange(final PropertyChangeEvent evt) { + int n = ((Number)anyAllPrevNumber.getValue()).intValue(); + if (n <= 0) { + n = 1; + anyAllPrevNumber.setValue(n); + } + if (preceding) { + nPrecedingRulesToMatch = n; + } + else { + nSubsequentRulesToMatch = n; + } + } + }); + } + + public final void setEnabled(final boolean enable) { + anyAllCheckbox.setEnabled(enable); + anyAllComboBox.setEnabled(anyAllCheckbox.isSelected() && enable); + anyAllLabel.setEnabled(anyAllCheckbox.isSelected() && enable); + anyAllPrevNumber.setEnabled(anyAllCheckbox.isSelected() && enable); + rulesLabel.setEnabled(anyAllCheckbox.isSelected() && enable); + } + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/ForceBlankLineSetting.java b/plugins/rearranger/src/com/wrq/rearranger/settings/ForceBlankLineSetting.java new file mode 100644 index 000000000000..ab0485c14b5a --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/ForceBlankLineSetting.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import org.jdom.Element; + +/** Contains a single "force N blank lines before/after" some brace. */ +public class ForceBlankLineSetting { + public static final int CLASS_OBJECT = 0; + public static final int METHOD_OBJECT = 1; + public static final int EOF_OBJECT = 2; + + boolean force; + int nBlankLines; + final boolean before; // false => after + final boolean openBrace; // false => close brace + final int object; + final String name; + + public ForceBlankLineSetting(boolean before, boolean openBrace, int object, String name) { + this.before = before; + this.openBrace = openBrace; + this.object = object; + this.name = name; + } + + public boolean isForce() { + return force; + } + + public void setForce(boolean force) { + this.force = force; + } + + public int getnBlankLines() { + return nBlankLines; + } + + public void setnBlankLines(int nBlankLines) { + this.nBlankLines = nBlankLines; + } + + public boolean isBefore() { + return before; + } + + public boolean isOpenBrace() { + return openBrace; + } + + public int getObject() { + return object; + } + + + public boolean equals(final Object obj) { + if (!(obj instanceof ForceBlankLineSetting)) return false; + final ForceBlankLineSetting fbls = (ForceBlankLineSetting)obj; + if (fbls.force != force) return false; + if (fbls.nBlankLines != nBlankLines) return false; + if (fbls.before != before) return false; + if (fbls.openBrace != openBrace) return false; + if (fbls.object != object) return false; + return true; + } + + public final ForceBlankLineSetting deepCopy() { + final ForceBlankLineSetting result = new ForceBlankLineSetting(before, openBrace, object, name); + result.force = force; + result.nBlankLines = nBlankLines; + return result; + } + + /** + * Read the contents of this object from the JDOM element. + * + * @param entry JDOM element which contains setting values as attributes. + */ + public static ForceBlankLineSetting readExternal(final Element entry, + boolean before, + boolean openBrace, + int object, + String name) + { + ForceBlankLineSetting fbls; + Element fblsElement = entry.getChild(name); + boolean force = RearrangerSettings.getBooleanAttribute(fblsElement, "Force", false); + int nBlankLines = RearrangerSettings.getIntAttribute(fblsElement, "nBlankLines", 1); + fbls = new ForceBlankLineSetting(before, openBrace, object, name); + fbls.setForce(force); + fbls.setnBlankLines(nBlankLines); + return fbls; + } + + public final void writeExternal(final Element entry) { + final Element fblsElement = new Element(name); + entry.getChildren().add(fblsElement); + fblsElement.setAttribute("Force", Boolean.valueOf(force).toString()); + fblsElement.setAttribute("nBlankLines", "" + nBlankLines); + } + + public String toString() { + return name + ": " + (before ? "before " : "after ") + + getObjectName() + + (openBrace ? " open brace" : " close brace") + + (force ? ", force " + nBlankLines + " lines" : ", leave intact"); + } + + public String getObjectName() { + return (object == CLASS_OBJECT ? "class" : "method"); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/PrimaryMethodSetting.java b/plugins/rearranger/src/com/wrq/rearranger/settings/PrimaryMethodSetting.java new file mode 100644 index 000000000000..3ddd181a4f70 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/PrimaryMethodSetting.java @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import com.wrq.rearranger.configuration.*; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains settings pertinent to a single related-by-name method setting. A primary field is + * specified + */ +public class PrimaryMethodSetting + implements IListManagerObject +{ + /** Description for a single related-by-name method setting. */ + String description; + /** + * Regular expression which method name must match. If the method is to be matched to a field, there must be + * at least one capture group (parenthesized subexpression) which will be treated as the field. + * In the case of a traditional getter method, this pattern is "get(\w+)". + */ + String methodNamePattern; + /** + * The number of the capture group in methodNamePattern which corresponds to the field name. If the + * methodNamePattern is "get(\w+)", then the fieldCaptureGroupNumber is 1. + */ + int fieldCaptureGroupNumber; + /** number of parameters the primary method must have. In the case of a traditional getter method, this is zero. */ + int numParameters; + /** + * regular expression pattern of the type which primary method must return. + * In the case of a traditional getter method, this is the field type. One substitution is available: + *

+   * %FT%  field type
+   * 
+ */ + String methodTypePattern; + /** + * regular expression pattern of the attributes of the method. + * In the case of a traditional getter method, this is ".*public.*" (i.e., any public method). + */ + String methodAttributePattern; + /** + * pattern of method body (excluding comments and newline characters). Substitutions are available as follows: + *
+   * %FN%  field name
+   * %FT%  field type (if field is valid field, else empty string)
+   * %MT%  method return type
+   * %P1%  parameter 1 name (%P2%, %P3% etc for additional parameters)
+   * %T1%  parameter 1 type name
+   * 
+ */ + String body; + /** list of secondary method configurations, e.g. for "set" and "is". */ + ArrayList secondaryMethodList = new ArrayList(); + + public PrimaryMethodSetting() { + methodNamePattern = "get(\\w+)"; + fieldCaptureGroupNumber = 1; + numParameters = 0; + methodTypePattern = "%FT%"; + methodAttributePattern = ".*public.*"; + body = "{\\s*return\\s*%fn%;\\s*}"; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getMethodNamePattern() { + return methodNamePattern; + } + + public void setMethodNamePattern(String methodNamePattern) { + this.methodNamePattern = methodNamePattern; + } + + public int getFieldCaptureGroupNumber() { + return fieldCaptureGroupNumber; + } + + public void setFieldCaptureGroupNumber(int fieldCaptureGroupNumber) { + this.fieldCaptureGroupNumber = fieldCaptureGroupNumber; + } + + public int getNumParameters() { + return numParameters; + } + + public void setNumParameters(int numParameters) { + this.numParameters = numParameters; + } + + public String getMethodTypePattern() { + return methodTypePattern; + } + + public void setMethodTypePattern(String methodTypePattern) { + this.methodTypePattern = methodTypePattern; + } + + public String getMethodAttributePattern() { + return methodAttributePattern; + } + + public void setMethodAttributePattern(String methodAttributePattern) { + this.methodAttributePattern = methodAttributePattern; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public ArrayList getSecondaryMethodList() { + return secondaryMethodList; + } + + public String toString() { + return description; + } + + public boolean equals(Object obj) { + if (!(obj instanceof PrimaryMethodSetting)) return false; + PrimaryMethodSetting pms = (PrimaryMethodSetting)obj; + if (!pms.description.equals(description)) return false; + if (!pms.methodNamePattern.equals(methodNamePattern)) return false; + if (pms.fieldCaptureGroupNumber != fieldCaptureGroupNumber) return false; + if (pms.numParameters != numParameters) return false; + if (!pms.methodTypePattern.equals(methodTypePattern)) return false; + if (!pms.methodAttributePattern.equals(methodAttributePattern)) return false; + if (!pms.body.equals(body)) return false; + return true; + } + + public JPanel getPanel() { + IListManagerObjectFactory lmof = new IListManagerObjectFactory() { + public IListManagerObject create(String name) { + SecondaryMethodSetting sms = new SecondaryMethodSetting(); + sms.setDescription(name); + return sms; + } + + public List/**/ getObjectList() { + return secondaryMethodList; + } + }; + ListManager Lmgr = new ListManager(lmof, "Description:"); + JPanel pmsPanel = new JPanel(new GridBagLayout()); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0.0d; + constraints.weighty = 0.0d; + constraints.gridy = constraints.gridx = 0; + constraints.insets = new Insets(3, 3, 3, 3); + pmsPanel.setBorder(BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "Primary (\"Getter\") Method Criteria")); + constraints.gridwidth = 1; + constraints.gridy++; + JLabel methodNamePatternLabel = new JLabel("Method name:"); + methodNamePatternLabel.setToolTipText( + "Regular expression which method name must match. " + + "If the method is to be matched to a field, there must be\n" + + " at least one capture group (parenthesized subexpression) which will be treated as the field.\n" + + " In the case of a traditional getter method, this pattern is \"get(\\w+)\"."); + pmsPanel.add(methodNamePatternLabel, constraints); + constraints.gridx++; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.weightx = .5; + StringTextField primaryPrefixText = new StringTextField() { + public void setValue(String value) { + setMethodNamePattern(value); + } + + public String getValue() { + return getMethodNamePattern(); + } + }; + pmsPanel.add(primaryPrefixText, constraints); + constraints.fill = GridBagConstraints.NONE; + constraints.weightx = 0; + constraints.gridx++; + JLabel fieldCaptureGroupLabel = new JLabel("Field capture group:"); + fieldCaptureGroupLabel.setToolTipText( + "The number of the capture group in methodNamePattern which corresponds to the field name. If the\n" + + " methodNamePattern is \"get(\\w+)\", then the fieldCaptureGroupNumber is 1." + ); + pmsPanel.add(fieldCaptureGroupLabel, constraints); + IntTextField itf = new IntTextField( + new IntTextField.IGetSet() { + public void set(int value) { + fieldCaptureGroupNumber = value; + } + + public int get() { + return fieldCaptureGroupNumber; + } + }, + null, null + ); + + constraints.gridx++; + pmsPanel.add(itf, constraints); + constraints.gridx++; + JLabel nParamLabel = new JLabel("Number of parameters:"); + nParamLabel.setToolTipText( + "number of parameters the primary method must have.\n" + + "In the case of a traditional getter method, this is zero."); + pmsPanel.add(nParamLabel, constraints); + constraints.gridx++; + IntTextField nParamText = new IntTextField( + new IntTextField.IGetSet() { + public void set(int value) { + numParameters = value; + } + + public int get() { + return numParameters; + } + }, null, null); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridwidth = GridBagConstraints.REMAINDER; + pmsPanel.add(nParamText, constraints); + + constraints.gridx = 0; + constraints.gridy++; + constraints.gridwidth = 1; + constraints.weightx = 0; + constraints.fill = GridBagConstraints.NONE; + JLabel returnTypeLabel = new JLabel("Return type:"); + returnTypeLabel.setToolTipText( + "regular expression pattern of the type which primary method must return.\n" + + " In the case of a traditional getter method, this is the field type. One substitution is available:\n" + + " * %FT% field type"); + pmsPanel.add(returnTypeLabel, constraints); + constraints.gridx++; + constraints.weightx = .5; + constraints.fill = GridBagConstraints.HORIZONTAL; + StringTextField returnTypeField = new StringTextField() { + public void setValue(String value) { + methodTypePattern = value; + } + + public String getValue() { + return methodTypePattern; + } + }; + pmsPanel.add(returnTypeField, constraints); + constraints.fill = GridBagConstraints.NONE; + constraints.gridx++; + constraints.weightx = 0; + JLabel methodAttributeLabel = new JLabel("Method attributes:"); + methodAttributeLabel.setToolTipText("Protection level or other attributes for the method.\n" + + "In the case of a getter method, this is usually \".*public.*\"."); + pmsPanel.add(methodAttributeLabel, constraints); + StringTextField methodAttributeField = new StringTextField() { + public void setValue(String value) { + methodAttributePattern = value; + } + + public String getValue() { + return methodAttributePattern; + } + }; + constraints.gridx++; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = .5; + constraints.fill = GridBagConstraints.HORIZONTAL; + pmsPanel.add(methodAttributeField, constraints); + constraints.gridx++; + constraints.weightx = 0; + constraints.fill = GridBagConstraints.NONE; + constraints.gridy++; + constraints.gridx = 0; + JLabel bodyLabel = new JLabel("Body:"); + bodyLabel.setToolTipText("regular expression pattern of method body (excluding comments and newline characters).\n" + + "Substitutions are available as follows:\n" + + " %FN% field name\n" + + " %FT% field type (if field is valid field, else empty string)\n" + + " %MT% method return type\n" + + " %P1% parameter 1 name (%P2%, %P3% etc for additional parameters)\n" + + " %T1% parameter 1 type name"); + constraints.gridwidth = 1; + constraints.weightx = 0; + constraints.fill = GridBagConstraints.NONE; + pmsPanel.add(bodyLabel, constraints); + constraints.gridx++; + StringTextArea bodyField = new StringTextArea() { + public void setValue(String value) { + body = value; + } + + public String getValue() { + return body; + } + }; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1; + constraints.weighty = .35; + constraints.fill = GridBagConstraints.BOTH; + JScrollPane sp = new JScrollPane(bodyField); + pmsPanel.add(sp, constraints); + constraints.gridx = 0; + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.fill = GridBagConstraints.NONE; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1; + constraints.weighty = .65; + final JPanel pane = Lmgr.getPane(); + pane.setBorder(BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), "Related Methods")); + pmsPanel.add(pane, constraints); + return pmsPanel; + } + + public IListManagerObject deepcopy() { + PrimaryMethodSetting pms = new PrimaryMethodSetting(); + pms.description = getDescription(); + pms.methodNamePattern = getMethodNamePattern(); + pms.fieldCaptureGroupNumber = getFieldCaptureGroupNumber(); + pms.numParameters = getNumParameters(); + pms.methodTypePattern = getMethodTypePattern(); + pms.methodAttributePattern = getMethodAttributePattern(); + pms.body = getBody(); + pms.secondaryMethodList = new ArrayList(); + for (SecondaryMethodSetting sms : secondaryMethodList) { + pms.secondaryMethodList.add((SecondaryMethodSetting)sms.deepcopy()); + } + return pms; + } + + public static void main(String[] args) { + PrimaryMethodSetting ms = new PrimaryMethodSetting(); + final JDialog frame = new JDialog((Frame)null, "SwingApplication"); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1.0d; + constraints.weighty = 1.0d; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 0; + constraints.gridy = 0; + frame.getContentPane().setLayout(new GridBagLayout()); + frame.getContentPane().add(ms.getPanel(), constraints); + //Finish setting up the frame, and show it. + frame.pack(); + frame.setResizable(true); + frame.setModal(true); + frame.setVisible(true); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java b/plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java new file mode 100644 index 000000000000..e302e62076c2 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import com.intellij.openapi.diagnostic.Logger; +import com.wrq.rearranger.Rearranger; +import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; +import com.wrq.rearranger.settings.attributeGroups.ClassAttributes; +import com.wrq.rearranger.settings.attributeGroups.GetterSetterDefinition; +import com.wrq.rearranger.settings.attributeGroups.ItemAttributes; +import org.jdom.Attribute; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; +import org.jdom.output.Format; +import org.jdom.output.XMLOutputter; + +import java.io.*; +import java.net.URL; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +/** + * Holds two lists of rearrangement settings, one for the outer level classes, the other for class members. Each + * list contains objects of type CommonAttributes. + */ +public final class RearrangerSettings { + +// ------------------------------ FIELDS ------------------------------ + + // BEGINNING OF FIELDS + private static final Logger logger = Logger.getInstance("#" + RearrangerSettings.class.getName()); + public static final int OVERLOADED_ORDER_RETAIN_ORIGINAL = 0; + public static final int OVERLOADED_ORDER_ASCENDING_PARAMETERS = 1; + public static final int OVERLOADED_ORDER_DESCENDING_PARAMETERS = 2; + private final List itemOrderAttributeList; + private final List classOrderAttributeList; + private RelatedMethodsSettings relatedMethodsSettings; + private boolean keepGettersSettersTogether; + private boolean keepGettersSettersWithProperty; + private boolean keepOverloadedMethodsTogether; + private String globalCommentPattern; + private boolean askBeforeRearranging; + private boolean rearrangeInnerClasses; + private boolean showParameterTypes; + private boolean showParameterNames; + private boolean showFields; + private boolean showTypeAfterMethod; + private boolean showRules; + private boolean showMatchedRules; + private boolean showComments; + private ForceBlankLineSetting afterClassLBrace; + private ForceBlankLineSetting afterClassRBrace; + private ForceBlankLineSetting beforeClassRBrace; + private ForceBlankLineSetting beforeMethodLBrace; + private ForceBlankLineSetting afterMethodLBrace; + private ForceBlankLineSetting afterMethodRBrace; + private ForceBlankLineSetting beforeMethodRBrace; + private boolean removeBlanksInsideCodeBlocks; + private ForceBlankLineSetting newlinesAtEOF; + + private int overloadedOrder; + private GetterSetterDefinition defaultGSDefinition; + private List primaryMethodList; + +// -------------------------- STATIC METHODS -------------------------- + + static public int getIntAttribute(final Element me, final String attr) { + return getIntAttribute(me, attr, 0); + } + + static public boolean getBooleanAttribute(final Element me, final String attr) { + return getBooleanAttribute(me, attr, false); + } + + public static RearrangerSettings getDefaultSettings() { + logger.debug("enter loadDefaultSettings"); + URL settingsURL = Rearranger.class.getClassLoader().getResource("com/wrq/rearranger/defaultConfiguration.xml"); + logger.debug("settings URL=" + settingsURL.getFile()); + try { + InputStream is = settingsURL.openStream(); + return getSettingsFromStream(is); + } + catch (IOException e) { + logger.debug("getDefaultSettings:" + e); + return null; + } + } + + public static RearrangerSettings getSettingsFromStream(InputStream is) { + Document document = null; + try { + SAXBuilder builder = new SAXBuilder(); + document = builder.build(is); + } + catch (JDOMException jde) { + logger.debug("JDOM exception building document:" + jde); + return null; + } + catch (IOException e) { + logger.debug("I/O exception building document:" + e); + return null; + } + finally { + if (is != null) { + try { + is.close(); + } + catch (IOException e) { + } + } + } + Element app = document.getRootElement(); + Element component = null; + if (app.getName().equals("application")) { + ListIterator li = app.getChildren().listIterator(); + while (li.hasNext()) +// for (Element child : (List)((java.util.List)app.getChildren())) + { + Element child = (Element)li.next(); + if (child.getName().equals("component") && + child.getAttribute("name") != null && + child.getAttribute("name").getValue().equals(Rearranger.COMPONENT_NAME)) + { + component = child; + break; + } + } + } + else { + if (app.getName().equals("component") && + app.getAttribute("name") != null && + app.getAttribute("name").getValue().equals(Rearranger.COMPONENT_NAME)) + { + component = app; + } + } + if (component != null) { + Element rearranger = component.getChild(Rearranger.COMPONENT_NAME); + if (rearranger != null) { + RearrangerSettings rs = new RearrangerSettings(); + rs.readExternal(rearranger); + return rs; + } + } + return null; + } + +// Level 1 methods + + /** @param entry JDOM element named "Rearranger" which contains setting values as attributes. */ + public final void readExternal(final Element entry) { + final Element items = entry.getChild("Items"); + final Element classes = entry.getChild("Classes"); + + final List itemList = items.getChildren(); + final List classList = classes.getChildren(); + + ListIterator li; + li = itemList.listIterator(); + while (li.hasNext()) +// for (Element element : itemList) + { + Element element = (Element)li.next(); + itemOrderAttributeList.add(((com.wrq.rearranger.settings.attributeGroups.AttributeGroup)ItemAttributes.readExternal(element))); + } + li = classList.listIterator(); +// for (Element element : classList) + while (li.hasNext()) { + Element element = (Element)li.next(); + classOrderAttributeList.add(((com.wrq.rearranger.settings.attributeGroups.AttributeGroup)ClassAttributes.readExternal(element))); + } + final Element gsd = entry.getChild("DefaultGetterSetterDefinition"); + defaultGSDefinition = GetterSetterDefinition.readExternal(gsd); + final Element relatedItems = entry.getChild("RelatedMethods"); + relatedMethodsSettings = RelatedMethodsSettings.readExternal(relatedItems); + keepGettersSettersTogether = getBooleanAttribute(entry, "KeepGettersSettersTogether", true); + keepGettersSettersWithProperty = getBooleanAttribute(entry, "KeepGettersSettersWithProperty", false); + keepOverloadedMethodsTogether = getBooleanAttribute(entry, "KeepOverloadedMethodsTogether", true); + final Attribute attr = RearrangerSettings.getAttribute(entry, "globalCommentPattern"); + askBeforeRearranging = getBooleanAttribute(entry, "ConfirmBeforeRearranging", false); + rearrangeInnerClasses = getBooleanAttribute(entry, "RearrangeInnerClasses", false); + globalCommentPattern = (attr == null ? "" : ((java.lang.String)attr.getValue())); + overloadedOrder = getIntAttribute(entry, "overloadedOrder", OVERLOADED_ORDER_RETAIN_ORIGINAL); + showParameterTypes = getBooleanAttribute(entry, "ShowParameterTypes", true); + showParameterNames = getBooleanAttribute(entry, "ShowParameterNames", true); + showFields = getBooleanAttribute(entry, "ShowFields", true); + showRules = getBooleanAttribute(entry, "ShowRules", false); + showMatchedRules = getBooleanAttribute(entry, "ShowMatchedRules", false); + showComments = getBooleanAttribute(entry, "ShowComments", false); + showTypeAfterMethod = getBooleanAttribute(entry, "ShowTypeAfterMethod", true); + removeBlanksInsideCodeBlocks = getBooleanAttribute(entry, "RemoveBlanksInsideCodeBlocks", false); + afterClassLBrace = ForceBlankLineSetting.readExternal(entry, false, true, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassLBrace"); + afterClassRBrace = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassRBrace"); + beforeClassRBrace = ForceBlankLineSetting.readExternal(entry, true, false, ForceBlankLineSetting.CLASS_OBJECT, "BeforeClassRBrace"); + beforeMethodLBrace = ForceBlankLineSetting.readExternal(entry, true, true, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodLBrace"); + afterMethodLBrace = ForceBlankLineSetting.readExternal(entry, false, true, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodLBrace"); + afterMethodRBrace = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodRBrace"); + beforeMethodRBrace = ForceBlankLineSetting.readExternal(entry, true, false, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodRBrace"); + newlinesAtEOF = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.EOF_OBJECT, "NewlinesAtEOF"); + } + +// Level 2 methods + + static public Attribute getAttribute(Element element, String attributeName) { + if (element == null) return null; + return element.getAttribute(attributeName); + } + + static public int getIntAttribute(final Element item, final String attributeName, int defaultValue) { + if (item == null) return defaultValue; + final Attribute a = item.getAttribute(attributeName); + if (a == null) return defaultValue; + final String r = a.getValue(); + if (r == null) return defaultValue; + if (r.length() == 0) return defaultValue; + return Integer.parseInt(r); + } + + static public boolean getBooleanAttribute(final Element me, final String attr, boolean defaultValue) { + if (me == null) return defaultValue; + final Attribute a = me.getAttribute(attr); + if (a == null) return defaultValue; + final String r = a.getValue(); + if (r == null) return defaultValue; + return (r.equalsIgnoreCase("true")); + } + + public static RearrangerSettings getSettingsFromFile(File f) { + try { + return getSettingsFromStream(new FileInputStream(f)); + } + catch (FileNotFoundException e) { + logger.debug("getSettingsFromFile:" + e); + } + return null; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + // END OF ALL FIELDS + public RearrangerSettings() { + itemOrderAttributeList = new ArrayList(); + classOrderAttributeList = new ArrayList(); + relatedMethodsSettings = new RelatedMethodsSettings(); + keepGettersSettersTogether = false; + keepGettersSettersWithProperty = false; + keepOverloadedMethodsTogether = false; + globalCommentPattern = ""; + overloadedOrder = OVERLOADED_ORDER_RETAIN_ORIGINAL; + askBeforeRearranging = false; + rearrangeInnerClasses = false; + showParameterTypes = true; + showParameterNames = false; + showFields = true; + showTypeAfterMethod = true; + showRules = false; + showMatchedRules = false; + showComments = false; + removeBlanksInsideCodeBlocks = false; + afterClassLBrace = new ForceBlankLineSetting(false, true, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassLBrace"); + afterClassRBrace = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassRBrace"); + beforeClassRBrace = new ForceBlankLineSetting(true, false, ForceBlankLineSetting.CLASS_OBJECT, "BeforeClassRBrace"); + beforeMethodLBrace = new ForceBlankLineSetting(true, true, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodLBrace"); + afterMethodLBrace = new ForceBlankLineSetting(false, true, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodLBrace"); + beforeMethodRBrace = new ForceBlankLineSetting(true, false, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodRBrace"); + afterMethodRBrace = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodRBrace"); + newlinesAtEOF = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.EOF_OBJECT, "NewlinesAtEOF"); + defaultGSDefinition = new GetterSetterDefinition(); + primaryMethodList = new LinkedList(); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public ForceBlankLineSetting getAfterClassLBrace() { + return afterClassLBrace; + } + + public ForceBlankLineSetting getAfterClassRBrace() { + return afterClassRBrace; + } + + public ForceBlankLineSetting getBeforeMethodLBrace() { + return beforeMethodLBrace; + } + + public ForceBlankLineSetting getAfterMethodLBrace() { + return afterMethodLBrace; + } + + public ForceBlankLineSetting getAfterMethodRBrace() { + return afterMethodRBrace; + } + + public ForceBlankLineSetting getBeforeClassRBrace() { + return beforeClassRBrace; + } + + public ForceBlankLineSetting getBeforeMethodRBrace() { + return beforeMethodRBrace; + } + + public final List getClassOrderAttributeList() { + return classOrderAttributeList; + } + + public GetterSetterDefinition getDefaultGSDefinition() { + return defaultGSDefinition; + } + +// Level 1 methods + + public String getGlobalCommentPattern() { + return globalCommentPattern; + } + +// Level 2 methods + + public void setGlobalCommentPattern(String globalCommentPattern) { + this.globalCommentPattern = globalCommentPattern; + } + +// end of Level 2 methods +// end of Level 1 methods + + public final List getItemOrderAttributeList() { + return itemOrderAttributeList; + } + + public ForceBlankLineSetting getNewlinesAtEOF() { + return newlinesAtEOF; + } + +// Level 1 methods + + public int getOverloadedOrder() { + return overloadedOrder; + } + +// Level 2 methods + + public void setOverloadedOrder(int overloadedOrder) { + this.overloadedOrder = overloadedOrder; + } + +// end of Level 2 methods +// end of Level 1 methods + + public RelatedMethodsSettings getExtractedMethodsSettings() { + return relatedMethodsSettings; + } + +// Level 1 methods + + public boolean isAskBeforeRearranging() { + return askBeforeRearranging; + } + +// Level 2 methods + + public void setAskBeforeRearranging(boolean askBeforeRearranging) { + this.askBeforeRearranging = askBeforeRearranging; + } + + public boolean isKeepGettersSettersTogether() { + return keepGettersSettersTogether; + } + +// Level 2 methods + + public void setKeepGettersSettersTogether(boolean keepGettersSettersTogether) { + this.keepGettersSettersTogether = keepGettersSettersTogether; + } + + public boolean isKeepGettersSettersWithProperty() { + return keepGettersSettersWithProperty; + } + + public void setKeepGettersSettersWithProperty(boolean keepGettersSettersWithProperty) { + this.keepGettersSettersWithProperty = keepGettersSettersWithProperty; + } +// end of Level 2 methods +// end of Level 1 methods +// Level 1 methods + + public boolean isKeepOverloadedMethodsTogether() { + return keepOverloadedMethodsTogether; + } + +// Level 2 methods + + public void setKeepOverloadedMethodsTogether(boolean keepOverloadedMethodsTogether) { + this.keepOverloadedMethodsTogether = keepOverloadedMethodsTogether; + } + + // end of Level 2 methods +// end of Level 1 methods +// Level 1 methods + public boolean isRearrangeInnerClasses() { + return rearrangeInnerClasses; + } + + public void setRearrangeInnerClasses(boolean rearrangeInnerClasses) { + this.rearrangeInnerClasses = rearrangeInnerClasses; + } + +// end of Level 2 methods +// end of Level 1 methods +// Level 1 methods + + public boolean isRemoveBlanksInsideCodeBlocks() { + return removeBlanksInsideCodeBlocks; + } + +// Level 2 methods + + public void setRemoveBlanksInsideCodeBlocks(boolean removeBlanksInsideCodeBlocks) { + this.removeBlanksInsideCodeBlocks = removeBlanksInsideCodeBlocks; + } + + public boolean isShowComments() { + return showComments; + } + + public void setShowComments(boolean showComments) { + this.showComments = showComments; + } + +// end of Level 2 methods +// end of Level 1 methods +// Level 1 methods + + public boolean isShowFields() { + return showFields; + } + +// Level 2 methods + + public void setShowFields(boolean showFields) { + this.showFields = showFields; + } + + public boolean isShowMatchedRules() { + return showMatchedRules; + } + + public void setShowMatchedRules(boolean showMatchedRules) { + this.showMatchedRules = showMatchedRules; + } + + public boolean isShowParameterNames() { + return showParameterNames; + } + +// Level 2 methods + + public void setShowParameterNames(boolean showParameterNames) { + this.showParameterNames = showParameterNames; + } + +// end of Level 2 methods +// end of Level 1 methods +// Level 1 methods + + public boolean isShowParameterTypes() { + return showParameterTypes; + } + +// Level 2 methods + + public void setShowParameterTypes(boolean showParameterTypes) { + this.showParameterTypes = showParameterTypes; + } + + // end of Level 2 methods +// end of Level 1 methods +// Level 1 methods + public boolean isShowRules() { + return showRules; + } + + public void setShowRules(boolean showRules) { + this.showRules = showRules; + } + + // end of Level 2 methods +// end of Level 1 methods + public boolean isShowTypeAfterMethod() { + return showTypeAfterMethod; + } + + public void setShowTypeAfterMethod(boolean showTypeAfterMethod) { + this.showTypeAfterMethod = showTypeAfterMethod; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public boolean equals(final Object object) { + if (!(object instanceof RearrangerSettings)) return false; + final RearrangerSettings rs = (RearrangerSettings)object; + if (rs.getClassOrderAttributeList().size() != getClassOrderAttributeList().size()) return false; + if (rs.getItemOrderAttributeList().size() != getItemOrderAttributeList().size()) return false; + for (int i = 0; i < getClassOrderAttributeList().size(); i++) { + if (!getClassOrderAttributeList().get(i).equals(rs.getClassOrderAttributeList().get(i))) return false; + } + for (int i = 0; i < getItemOrderAttributeList().size(); i++) { + if (!getItemOrderAttributeList().get(i).equals(rs.getItemOrderAttributeList().get(i))) return false; + } + if (!rs.getExtractedMethodsSettings().equals(getExtractedMethodsSettings())) return false; + if (rs.isKeepGettersSettersTogether() != isKeepGettersSettersTogether()) return false; + if (rs.isKeepGettersSettersWithProperty() != isKeepGettersSettersWithProperty()) return false; + if (rs.isKeepOverloadedMethodsTogether() != isKeepOverloadedMethodsTogether()) return false; + if (rs.overloadedOrder != overloadedOrder) return false; + if (!rs.globalCommentPattern.equals(globalCommentPattern)) return false; + if (rs.askBeforeRearranging != askBeforeRearranging) return false; + if (rs.rearrangeInnerClasses != rearrangeInnerClasses) return false; + if (rs.showParameterTypes != showParameterTypes) return false; + if (rs.showParameterNames != showParameterNames) return false; + if (rs.showFields != showFields) return false; + if (rs.showTypeAfterMethod != showTypeAfterMethod) return false; + if (rs.showRules != showRules) return false; + if (rs.showMatchedRules != showMatchedRules) return false; + if (rs.showComments != showComments) return false; + if (rs.removeBlanksInsideCodeBlocks != removeBlanksInsideCodeBlocks) return false; + if (!rs.afterClassLBrace.equals(afterClassLBrace)) return false; + if (!rs.afterClassRBrace.equals(afterClassRBrace)) return false; + if (!rs.beforeClassRBrace.equals(beforeClassRBrace)) return false; + if (!rs.beforeMethodLBrace.equals(beforeMethodLBrace)) return false; + if (!rs.afterMethodLBrace.equals(afterMethodLBrace)) return false; + if (!rs.afterMethodRBrace.equals(afterMethodRBrace)) return false; + if (!rs.beforeMethodRBrace.equals(beforeMethodRBrace)) return false; + if (!rs.newlinesAtEOF.equals(newlinesAtEOF)) return false; + if (!rs.defaultGSDefinition.equals(defaultGSDefinition)) return false; + if (primaryMethodList.size() != rs.primaryMethodList.size()) return false; + for (int i = 0; i < primaryMethodList.size(); i++) { + PrimaryMethodSetting pms = primaryMethodList.get(i); + PrimaryMethodSetting rspms = rs.primaryMethodList.get(i); + if (!rspms.equals(pms)) return false; + } + return true; + } + +// -------------------------- OTHER METHODS -------------------------- + + public final void addClass(final AttributeGroup ca, final int index) { + if (classOrderAttributeList.size() < index) { + classOrderAttributeList.add(ca); + } + else { + classOrderAttributeList.add(index, ca); + } + } + + public final void addItem(final AttributeGroup ia, final int index) { + if (itemOrderAttributeList.size() < index) { + itemOrderAttributeList.add(ia); + } + else { + itemOrderAttributeList.add(index, ia); + } + } + + public final RearrangerSettings deepCopy() { + final RearrangerSettings result = new RearrangerSettings(); + for (AttributeGroup itemAttributes : itemOrderAttributeList) { + result.itemOrderAttributeList.add(itemAttributes.deepCopy()); + } + for (AttributeGroup classAttributes : classOrderAttributeList) { + result.classOrderAttributeList.add(classAttributes.deepCopy()); + } + result.relatedMethodsSettings = relatedMethodsSettings.deepCopy(); + result.keepGettersSettersTogether = keepGettersSettersTogether; + result.keepGettersSettersWithProperty = keepGettersSettersWithProperty; + result.keepOverloadedMethodsTogether = keepOverloadedMethodsTogether; + result.globalCommentPattern = globalCommentPattern; + result.overloadedOrder = overloadedOrder; + result.askBeforeRearranging = askBeforeRearranging; + result.rearrangeInnerClasses = rearrangeInnerClasses; + result.showParameterNames = showParameterNames; + result.showParameterTypes = showParameterTypes; + result.showFields = showFields; + result.showTypeAfterMethod = showTypeAfterMethod; + result.showRules = showRules; + result.showMatchedRules = showMatchedRules; + result.showComments = showComments; + result.removeBlanksInsideCodeBlocks = removeBlanksInsideCodeBlocks; + result.afterClassLBrace = afterClassLBrace.deepCopy(); + result.afterClassRBrace = afterClassRBrace.deepCopy(); + result.beforeClassRBrace = beforeClassRBrace.deepCopy(); + result.beforeMethodLBrace = beforeMethodLBrace.deepCopy(); + result.afterMethodLBrace = afterMethodLBrace.deepCopy(); + result.afterMethodRBrace = afterMethodRBrace.deepCopy(); + result.beforeMethodRBrace = beforeMethodRBrace.deepCopy(); + result.newlinesAtEOF = newlinesAtEOF.deepCopy(); + result.defaultGSDefinition = defaultGSDefinition.deepCopy(); + return result; + } + + public void writeSettingsToFile(File f) { + Element component = new Element("component"); + component.setAttribute("name", Rearranger.COMPONENT_NAME); + Element r = new Element(Rearranger.COMPONENT_NAME); + component.getChildren().add(r); + writeExternal(r); + Format format = Format.getPrettyFormat(); + XMLOutputter outputter = new XMLOutputter(format); + try { + final FileOutputStream fileOutputStream = new FileOutputStream(f); + outputter.output(component, fileOutputStream); + fileOutputStream.close(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + +// end of Level 2 methods +// end of Level 1 methods + + public final void writeExternal(final Element entry) { + final Element items = new Element("Items"); + final Element classes = new Element("Classes"); + entry.getChildren().add(items); + entry.getChildren().add(classes); + for (AttributeGroup item : itemOrderAttributeList) { + item.writeExternal(items); + } + for (AttributeGroup attributes : classOrderAttributeList) { + attributes.writeExternal(classes); + } + final Element gsd = new Element("DefaultGetterSetterDefinition"); + entry.getChildren().add(gsd); + defaultGSDefinition.writeExternal(gsd); + final Element relatedItems = new Element("RelatedMethods"); + entry.getChildren().add(relatedItems); + entry.setAttribute("KeepGettersSettersTogether", Boolean.valueOf(keepGettersSettersTogether).toString()); + entry.setAttribute("KeepGettersSettersWithProperty", Boolean.valueOf(keepGettersSettersWithProperty).toString()); + entry.setAttribute("KeepOverloadedMethodsTogether", Boolean.valueOf(keepOverloadedMethodsTogether).toString()); + entry.setAttribute("ConfirmBeforeRearranging", Boolean.valueOf(askBeforeRearranging).toString()); + entry.setAttribute("RearrangeInnerClasses", Boolean.valueOf(rearrangeInnerClasses).toString()); + entry.setAttribute("globalCommentPattern", globalCommentPattern); + entry.setAttribute("overloadedOrder", "" + overloadedOrder); + entry.setAttribute("ShowParameterTypes", Boolean.valueOf(showParameterTypes).toString()); + entry.setAttribute("ShowParameterNames", Boolean.valueOf(showParameterNames).toString()); + entry.setAttribute("ShowFields", Boolean.valueOf(showFields).toString()); + entry.setAttribute("ShowTypeAfterMethod", Boolean.valueOf(showTypeAfterMethod).toString()); + entry.setAttribute("ShowRules", Boolean.valueOf(showRules).toString()); + entry.setAttribute("ShowMatchedRules", Boolean.valueOf(showMatchedRules).toString()); + entry.setAttribute("ShowComments", Boolean.valueOf(showComments).toString()); + entry.setAttribute("RemoveBlanksInsideCodeBlocks", Boolean.valueOf(removeBlanksInsideCodeBlocks).toString()); + relatedMethodsSettings.writeExternal(relatedItems); + afterClassLBrace.writeExternal(entry); + afterClassRBrace.writeExternal(entry); + beforeClassRBrace.writeExternal(entry); + beforeMethodLBrace.writeExternal(entry); + afterMethodLBrace.writeExternal(entry); + afterMethodRBrace.writeExternal(entry); + beforeMethodRBrace.writeExternal(entry); + newlinesAtEOF.writeExternal(entry); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/RelatedByNameMethodsSettings.java b/plugins/rearranger/src/com/wrq/rearranger/settings/RelatedByNameMethodsSettings.java new file mode 100644 index 000000000000..481b6820150f --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/RelatedByNameMethodsSettings.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import java.util.ArrayList; + +/** Contains settings pertaining to methods related by name, e.g. getter/setters. */ +public class RelatedByNameMethodsSettings { + ArrayList methodList; + + public RelatedByNameMethodsSettings() { + methodList = new ArrayList(); + } + + public ArrayList/**/ getMethodList() { + return methodList; + } + + public void addMethod(PrimaryMethodSetting pms) { + methodList.add(pms); + } + + public void removeMethod(PrimaryMethodSetting pms) { + methodList.remove(pms); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/RelatedMethodsSettings.java b/plugins/rearranger/src/com/wrq/rearranger/settings/RelatedMethodsSettings.java new file mode 100644 index 000000000000..d4b2ec30a89f --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/RelatedMethodsSettings.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import com.wrq.rearranger.settings.attributeGroups.RegexUtil; +import org.jdom.Element; + +import java.util.List; + +/** Contains settings regarding placement of related methods. */ +public class RelatedMethodsSettings { + private boolean moveExtractedMethods; + private boolean belowFirstCaller; // false means below last caller + private boolean depthFirstOrdering; // false means breadth first ordering + + public static final int INVOCATION_ORDER = 0; + public static final int RETAIN_ORIGINAL_ORDER = 1; + public static final int ALPHABETICAL_ORDER = 2; + private int ordering; + + public static final int NON_PRIVATE_EXTRACTED_NEVER = 0; + public static final int NON_PRIVATE_EXTRACTED_ONE_CALLER = 1; + public static final int NON_PRIVATE_EXTRACTED_ANY_CALLERS = 2; + + private int nonPrivateTreatment; + + public static final int COMMENT_TYPE_TOP_LEVEL = 0; + public static final int COMMENT_TYPE_EACH_LEVEL = 1; + public static final int COMMENT_TYPE_EACH_METHOD = 2; + public static final int COMMENT_TYPE_NEW_FAMILY = 3; + + private int commentType; + private CommentRule precedingComment; + private CommentRule trailingComment; + private CommentFillString commentFillString; + + private RelatedByNameMethodsSettings rbnms; + + public RelatedByNameMethodsSettings getRbnms() { + return rbnms; + } + + public RelatedMethodsSettings() { + belowFirstCaller = true; + depthFirstOrdering = true; + ordering = INVOCATION_ORDER; + nonPrivateTreatment = NON_PRIVATE_EXTRACTED_ANY_CALLERS; + commentType = COMMENT_TYPE_TOP_LEVEL; + precedingComment = new CommentRule(); + trailingComment = new CommentRule(); + rbnms = new RelatedByNameMethodsSettings(); + commentFillString = new CommentFillString(); + } + + public boolean isMoveExtractedMethods() { + return moveExtractedMethods; + } + + public void setMoveExtractedMethods(boolean moveExtractedMethods) { + this.moveExtractedMethods = moveExtractedMethods; + } + + public boolean isBelowFirstCaller() { + return belowFirstCaller; + } + + public void setBelowFirstCaller(boolean belowFirstCaller) { + this.belowFirstCaller = belowFirstCaller; + } + + public boolean isDepthFirstOrdering() { + return depthFirstOrdering; + } + + public void setDepthFirstOrdering(boolean depthFirstOrdering) { + this.depthFirstOrdering = depthFirstOrdering; + } + + public int getOrdering() { + return ordering; + } + + public void setOrdering(int ordering) { + this.ordering = ordering; + } + + public int getNonPrivateTreatment() { + return nonPrivateTreatment; + } + + public void setNonPrivateTreatment(int nonPrivateTreatment) { + this.nonPrivateTreatment = nonPrivateTreatment; + } + + public int getCommentType() { + return commentType; + } + + public void setCommentType(int commentType) { + this.commentType = commentType; + } + + public CommentRule getPrecedingComment() { + return precedingComment; + } + + public void setPrecedingComment(CommentRule precedingComment) { + this.precedingComment = precedingComment; + } + + public CommentRule getTrailingComment() { + return trailingComment; + } + + public void setTrailingComment(CommentRule trailingComment) { + this.trailingComment = trailingComment; + } + + public CommentFillString getCommentFillString() { + return commentFillString; + } + + public boolean equals(Object object) { + if (object instanceof RelatedMethodsSettings) { + RelatedMethodsSettings rms = (RelatedMethodsSettings)object; + return (rms.moveExtractedMethods == moveExtractedMethods && + rms.belowFirstCaller == belowFirstCaller && + rms.depthFirstOrdering == depthFirstOrdering && + rms.ordering == ordering && + rms.nonPrivateTreatment == nonPrivateTreatment && + rms.commentType == commentType && + rms.precedingComment.equals(precedingComment) && + rms.trailingComment.equals(trailingComment) && + rms.commentFillString.equals(commentFillString)); + } + return false; + } + + public RelatedMethodsSettings deepCopy() { + RelatedMethodsSettings result = new RelatedMethodsSettings(); + result.moveExtractedMethods = moveExtractedMethods; + result.belowFirstCaller = belowFirstCaller; + result.depthFirstOrdering = depthFirstOrdering; + result.ordering = ordering; + result.nonPrivateTreatment = nonPrivateTreatment; + result.commentType = commentType; + result.precedingComment = (CommentRule)precedingComment.deepCopy(); + result.trailingComment = (CommentRule)trailingComment.deepCopy(); + result.commentFillString = commentFillString.deepCopy(); + return result; + } + + public String toString() { + return "moveExtractedMethods=" + moveExtractedMethods + + ", belowFirstCaller=" + belowFirstCaller + + ", depthFirstOrdering=" + depthFirstOrdering + + ", ordering=" + ordering + + ", non-private treatment=" + nonPrivateTreatment + + ", comment type=" + commentType; + } + + public void loadAttributes(final Element me) { + moveExtractedMethods = RearrangerSettings.getBooleanAttribute(me, "moveExtractedMethods"); + belowFirstCaller = RearrangerSettings.getBooleanAttribute(me, "belowFirstCaller", true); + depthFirstOrdering = RearrangerSettings.getBooleanAttribute(me, "depthFirstOrdering", true); + ordering = RearrangerSettings.getIntAttribute(me, + "ordering", + INVOCATION_ORDER); + nonPrivateTreatment = RearrangerSettings.getIntAttribute(me, + "nonPrivateTreatment", + NON_PRIVATE_EXTRACTED_ANY_CALLERS); + commentType = RearrangerSettings.getIntAttribute(me, + "commentType", + COMMENT_TYPE_TOP_LEVEL); + Element prc = me.getChild("PrecedingComment"); + if (prc != null) prc = prc.getChild("Comment"); + precedingComment = CommentRule.readExternal(prc); + Element trc = me.getChild("TrailingComment"); + if (trc != null) trc = trc.getChild("Comment"); + trailingComment = CommentRule.readExternal(trc); + commentFillString = CommentFillString.readExternal(me); + } + + public static RelatedMethodsSettings readExternal(final Element item) { + final RelatedMethodsSettings result = new RelatedMethodsSettings(); + result.loadAttributes(item); + return result; + } + + public final void writeExternal(final Element me) { + me.setAttribute("moveExtractedMethods", Boolean.valueOf(moveExtractedMethods).toString()); + me.setAttribute("belowFirstCaller", Boolean.valueOf(belowFirstCaller).toString()); + me.setAttribute("depthFirstOrdering", Boolean.valueOf(depthFirstOrdering).toString()); + me.setAttribute("ordering", "" + ordering); + me.setAttribute("nonPrivateTreatment", "" + nonPrivateTreatment); + me.setAttribute("commentType", "" + commentType); + Element prc = new Element("PrecedingComment"); + Element trc = new Element("TrailingComment"); + me.getChildren().add(prc); + me.getChildren().add(trc); + precedingComment.writeExternal(prc); + trailingComment.writeExternal(trc); + commentFillString.writeExternal(me); + } + + public void addCommentPatternsToList(List list) { + addCommentPatternToList(precedingComment, list); + addCommentPatternToList(trailingComment, list); + } + + private void addCommentPatternToList(CommentRule comment, List list) { + String s = null; + if (comment != null) { + s = comment.getCommentText(); + } + if (s != null && s.length() > 0) { + String esc = RegexUtil.escape(s); + String fsp = commentFillString.getFillStringPattern(); + + s = RegexUtil.replaceAllFS(esc, fsp); + s = s.replaceAll("%TL%", "[A-Za-z0-9_()]+"); + s = s.replaceAll("%MN%", "[A-Za-z0-9_()]+"); + s = s.replaceAll("%AM%", "[A-Za-z0-9_\\\\[\\\\],.]+"); + s = s.replaceAll("%LV%", "[0-9]+"); + list.add(s); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/SecondaryMethodSetting.java b/plugins/rearranger/src/com/wrq/rearranger/settings/SecondaryMethodSetting.java new file mode 100644 index 000000000000..9547a75e941d --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/SecondaryMethodSetting.java @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings; + +import com.wrq.rearranger.configuration.IListManagerObject; +import com.wrq.rearranger.configuration.IntTextField; +import com.wrq.rearranger.configuration.StringTextArea; +import com.wrq.rearranger.configuration.StringTextField; + +import javax.swing.*; +import java.awt.*; + + +/** + * Contains settings for each secondary method (e.g., "set", "is"). Any number of secondary method definitions + * may be associated with a primary method definition. + */ +public class SecondaryMethodSetting + implements IListManagerObject +{ + /** Description of the related method. */ + String description; + /** + * Regular expression which method name must match. If the method is to be matched to a field, there must be + * at least one capture group (parenthesized subexpression) which will be treated as the field. + * In the case of a traditional setter method, this pattern is "set%FN%". One substitution is available: + *
+   * %FN%  field name
+   * 
+ */ + String methodNamePattern; + /** number of parameters the secondary method must have. In the case of a traditional setter method, this is one. */ + int numParameters; + /** + * regular expression pattern of the type which the secondary method must return. + * In the case of a traditional getter method, this is the field type. One substitution is available: + *
+   * %FT%  field type
+   * 
+ */ + String methodTypePattern; + /** + * regular expression pattern of the attributes of the method. + * In the case of a traditional getter method, this is ".*public.*" (i.e., any public method). + */ + String methodAttributePattern; + /** + * pattern of method body (excluding comments and newline characters). Substitutions are available as follows: + *
+   * %FN%  field name
+   * %FT%  field type (if field is valid field, else empty string)
+   * %MT%  method return type
+   * %P1%  parameter 1 name (%P2%, %P3% etc for additional parameters)
+   * %T1%  parameter 1 type name
+   * 
+ */ + String body; + + public SecondaryMethodSetting() { + methodNamePattern = "set%FN%"; + numParameters = 1; + methodTypePattern = "void"; + methodAttributePattern = ".*public.*"; + body = "{\\s*return\\s*%FN%;\\s*}"; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getMethodNamePattern() { + return methodNamePattern; + } + + public void setMethodNamePattern(String methodNamePattern) { + this.methodNamePattern = methodNamePattern; + } + + public int getNumParameters() { + return numParameters; + } + + public void setNumParameters(int numParameters) { + this.numParameters = numParameters; + } + + public String getMethodTypePattern() { + return methodTypePattern; + } + + public void setMethodTypePattern(String methodTypePattern) { + this.methodTypePattern = methodTypePattern; + } + + public String getMethodAttributePattern() { + return methodAttributePattern; + } + + public void setMethodAttributePattern(String methodAttributePattern) { + this.methodAttributePattern = methodAttributePattern; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String toString() { + return description; + } + + public com.wrq.rearranger.configuration.IListManagerObject deepcopy() { + SecondaryMethodSetting pms = new SecondaryMethodSetting(); + pms.description = getDescription(); + pms.methodNamePattern = getMethodNamePattern(); + pms.numParameters = getNumParameters(); + pms.methodTypePattern = getMethodTypePattern(); + pms.methodAttributePattern = getMethodAttributePattern(); + pms.body = getBody(); + return pms; + } + + public boolean equals(Object obj) { + if (!(obj instanceof PrimaryMethodSetting)) return false; + PrimaryMethodSetting pms = (PrimaryMethodSetting)obj; + if (!pms.description.equals(description)) return false; + if (!pms.methodNamePattern.equals(methodNamePattern)) return false; + if (pms.numParameters != numParameters) return false; + if (!pms.methodTypePattern.equals(methodTypePattern)) return false; + if (!pms.methodAttributePattern.equals(methodAttributePattern)) return false; + if (!pms.body.equals(body)) return false; + return true; + } + + public JPanel getPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), + "Matching Method (\"Setter\") Criteria")); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0.0d; + constraints.weighty = 0.0d; + constraints.gridy = constraints.gridx = 0; + constraints.insets = new Insets(3, 3, 3, 3); + JLabel methodNamePatternLabel = new JLabel("Method name:"); + methodNamePatternLabel.setToolTipText( + "Regular expression which method name must match. " + + "If the method is to be matched to a field, there must be\n" + + " at least one capture group (parenthesized subexpression) which will be treated as the field.\n" + + " In the case of a traditional setter method, this pattern is \"set%FN%\".\n" + + " One substitution is available:\n" + + " %FN% field name"); + panel.add(methodNamePatternLabel, constraints); + constraints.gridx++; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.weightx = .5; + StringTextField primaryPrefixText = new StringTextField() { + public void setValue(String value) { + setMethodNamePattern(value); + } + + public String getValue() { + return getMethodNamePattern(); + } + }; + panel.add(primaryPrefixText, constraints); + constraints.fill = GridBagConstraints.NONE; + constraints.weightx = 0; + constraints.gridx++; + JLabel nParamLabel = new JLabel("Number of parameters:"); + nParamLabel.setToolTipText( + "number of parameters the secondary method must have.\n" + + "In the case of a traditional setter method, this is 1."); + panel.add(nParamLabel, constraints); + constraints.gridx++; + IntTextField nParamText = new IntTextField( + new IntTextField.IGetSet() { + public int get() { + return numParameters; + } + + public void set(int value) { + numParameters = value; + } + }, null, null + ); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridwidth = GridBagConstraints.REMAINDER; + panel.add(nParamText, constraints); + + constraints.gridx = 0; + constraints.gridy++; + constraints.gridwidth = 1; + constraints.weightx = 0; + constraints.fill = GridBagConstraints.NONE; + JLabel returnTypeLabel = new JLabel("Return type:"); + returnTypeLabel.setToolTipText( + "regular expression pattern of the type which the secondary method must return.\n" + + " In the case of a traditional setter method, this is void. One substitution is available:\n" + + " * %FT% field type"); + panel.add(returnTypeLabel, constraints); + constraints.gridx++; + constraints.weightx = .5; + constraints.fill = GridBagConstraints.HORIZONTAL; + StringTextField returnTypeField = new StringTextField() { + public void setValue(String value) { + methodTypePattern = value; + } + + public String getValue() { + return methodTypePattern; + } + }; + panel.add(returnTypeField, constraints); + constraints.fill = GridBagConstraints.NONE; + constraints.gridx++; + constraints.weightx = 0; + JLabel methodAttributeLabel = new JLabel("Method attributes:"); + methodAttributeLabel.setToolTipText("Protection level or other attributes for the method.\n" + + "In the case of a getter method, this is usually \".*public.*\"."); + panel.add(methodAttributeLabel, constraints); + StringTextField methodAttributeField = new StringTextField() { + public void setValue(String value) { + methodAttributePattern = value; + } + + public String getValue() { + return methodAttributePattern; + } + }; + constraints.gridx++; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = .5; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(methodAttributeField, constraints); + constraints.gridx++; + constraints.weightx = 0; + constraints.fill = GridBagConstraints.NONE; + constraints.gridy++; + constraints.gridx = 0; + JLabel bodyLabel = new JLabel("Body:"); + bodyLabel.setToolTipText("regular expression pattern of method body (excluding comments and newline characters).\n" + + "Substitutions are available as follows:\n" + + " %FN% field name\n" + + " %FT% field type (if field is valid field, else empty string)\n" + + " %MT% method return type\n" + + " %P1% parameter 1 name (%P2%, %P3% etc for additional parameters)\n" + + " %T1% parameter 1 type name"); + constraints.gridwidth = 1; + constraints.weightx = 0; + constraints.fill = GridBagConstraints.NONE; + panel.add(bodyLabel, constraints); + constraints.gridx++; + StringTextArea bodyField = new StringTextArea() { + public void setValue(String value) { + body = value; + } + + public String getValue() { + return body; + } + }; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1; + constraints.weighty = .35; + constraints.fill = GridBagConstraints.BOTH; + JScrollPane sp = new JScrollPane(bodyField); + panel.add(sp, constraints); + constraints.gridx = 0; + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.fill = GridBagConstraints.NONE; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1; + constraints.weighty = .65; + return panel; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AbstractAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AbstractAttribute.java new file mode 100644 index 000000000000..82f3608a656b --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AbstractAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +import java.lang.reflect.Modifier; + +/** Common routines for 'abstract' modifier. */ +public final class AbstractAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static AbstractAttribute readExternal(final Element item) { + final AbstractAttribute result = new AbstractAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public AbstractAttribute() { + super("abstract", Modifier.ABSTRACT); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*AbstractAttribute*/AtomicAttribute deepCopy() { + final AbstractAttribute aba = new AbstractAttribute(); + aba.value = value; + aba.invert = invert; + return aba; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AndNotAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AndNotAttribute.java new file mode 100644 index 000000000000..f3180b76f6a9 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AndNotAttribute.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Element; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** Base class for all boolean attributes. */ +abstract public class AndNotAttribute + extends AtomicAttribute +{ +// ------------------------------ FIELDS ------------------------------ + + boolean value; + boolean invert; + private final String valueName; + private final int modifierBit; + +// --------------------------- CONSTRUCTORS --------------------------- + + AndNotAttribute(final String s, final int modifierBit) { + valueName = s; + this.modifierBit = modifierBit; + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public final JPanel getAndNotPanel() { + final JPanel andNotPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.WEST); + final JCheckBox andBox = new JCheckBox("And"); + andBox.setSelected(isValue()); + final JCheckBox notBox = new JCheckBox("not"); + notBox.setSelected(isInvert()); + notBox.setEnabled(andBox.isSelected()); + notBox.setForeground(notBox.isSelected() ? Color.BLACK : Color.GRAY); + final JLabel nameLabel = new JLabel(getName()); + nameLabel.setEnabled(andBox.isSelected()); + andNotPanel.add(andBox, constraints.firstCol()); + andNotPanel.add(notBox, constraints.nextCol()); + constraints.insets = new Insets(0, 0, 0, 4); + andNotPanel.add(nameLabel, constraints.weightedLastCol()); + andBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setValue(andBox.isSelected()); + notBox.setEnabled(andBox.isSelected()); + nameLabel.setEnabled(andBox.isSelected()); + } + }); + notBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setInvert(notBox.isSelected()); + notBox.setForeground(notBox.isSelected() ? Color.BLACK : Color.GRAY); + } + }); + return andNotPanel; + } + + private String getName() { + return valueName; + } + + public final boolean isInvert() { + return invert; + } + + public final void setInvert(final boolean invert) { + this.invert = invert; + } + + public final boolean isValue() { + return value; + } + + public final void setValue(final boolean value) { + this.value = value; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public final boolean equals(final Object obj) { + if (!(obj instanceof AndNotAttribute)) return false; + final AndNotAttribute ana = (AndNotAttribute)obj; + return (value == ana.value && + invert == ana.invert && + valueName.equals(ana.valueName) && + modifierBit == ana.modifierBit); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final void appendAttributes(final Element me) { + final Element stElement = new Element(getElementName()); + me.getChildren().add(stElement); + stElement.setAttribute("value", Boolean.valueOf(value).toString()); + stElement.setAttribute("invert", Boolean.valueOf(invert).toString()); + } + + final String getElementName() { + final StringBuffer sb = new StringBuffer(valueName.length()); + sb.append(valueName); + sb.replace(0, 1, new String("" + sb.charAt(0)).toUpperCase()); + for (int i = 1; i < sb.length(); i++) { + if (sb.charAt(i) == ' ') { + sb.deleteCharAt(i); + sb.replace(i, i + 1, new String("" + sb.charAt(i)).toUpperCase()); + } + } + return sb.toString(); + } + + public final String getDescriptiveString() { + return (isValue() ? + isInvert() ? "non-" + valueName + " " : valueName + " " + : ""); + } + + public final boolean isMatch(final int modifiers) { + return (!isValue()) ? true : ((modifiers & modifierBit) > 0) ^ isInvert(); + } + + public final void loadAttributes(final Element item) { + value = RearrangerSettings.getBooleanAttribute(item, "value"); + invert = RearrangerSettings.getBooleanAttribute(item, "invert"); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AtomicAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AtomicAttribute.java new file mode 100644 index 000000000000..994fc492cda2 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/AtomicAttribute.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + + +/** base class for all individual attributes that a field, method or class may have. */ +abstract public class AtomicAttribute { + + /** + * All subclasses will implement a static public AtomicAttribute readExternal(final Element item) method. + * However, because it is static, the interface can't contain it. + */ +// abstract public AtomicAttribute readExternal(final Element item); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/EnumAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/EnumAttribute.java new file mode 100644 index 000000000000..a58bdc2aa8c0 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/EnumAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.ModifierConstants; +import org.jdom.Element; + +/** Routines to handle 'enum' class attribute. */ +public class EnumAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static EnumAttribute readExternal(final Element item) { + final EnumAttribute result = new EnumAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public EnumAttribute() { + super("enum", ModifierConstants.ENUM); + } + +// -------------------------- OTHER METHODS -------------------------- + + /** final attribute. */ + public final /*EnumAttribute*/AtomicAttribute deepCopy() { + final EnumAttribute result = new EnumAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/FinalAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/FinalAttribute.java new file mode 100644 index 000000000000..acf75802d0de --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/FinalAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +import java.lang.reflect.Modifier; + +/** Routines to handle the 'final' modifier. */ +public final class FinalAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static FinalAttribute readExternal(final Element item) { + final FinalAttribute result = new FinalAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public FinalAttribute() { + super("final", Modifier.FINAL); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*FinalAttribute*/AtomicAttribute deepCopy() { + final FinalAttribute result = new FinalAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementedAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementedAttribute.java new file mode 100644 index 000000000000..92b48ae79f48 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementedAttribute.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.ModifierConstants; +import org.jdom.Element; + + +public final class ImplementedAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static ImplementedAttribute readExternal(final Element item) { + final ImplementedAttribute result = new ImplementedAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public ImplementedAttribute() { + super("implemented", ModifierConstants.IMPLEMENTED); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*ImplementedAttribute*/AtomicAttribute deepCopy() { + final ImplementedAttribute result = new ImplementedAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementingAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementingAttribute.java new file mode 100644 index 000000000000..77059d784ba9 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ImplementingAttribute.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.ModifierConstants; +import org.jdom.Element; + +public final class ImplementingAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static ImplementingAttribute readExternal(final Element item) { + final ImplementingAttribute result = new ImplementingAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public ImplementingAttribute() { + super("implementing", ModifierConstants.IMPLEMENTING); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*ImplementingAttribute*/AtomicAttribute deepCopy() { + final ImplementingAttribute result = new ImplementingAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitToAnonClassAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitToAnonClassAttribute.java new file mode 100644 index 000000000000..e3cbef25990b --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitToAnonClassAttribute.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.ModifierConstants; +import org.jdom.Element; + +public final class InitToAnonClassAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static InitToAnonClassAttribute readExternal(final Element item) { + final InitToAnonClassAttribute result = new InitToAnonClassAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public InitToAnonClassAttribute() { + super("initialized to anonymous class", ModifierConstants.INIT_TO_ANON_CLASS); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*InitToAnonClassAttribute*/AtomicAttribute deepCopy() { + final InitToAnonClassAttribute result = new InitToAnonClassAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitializerAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitializerAttribute.java new file mode 100644 index 000000000000..8b18576538b1 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/InitializerAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.ModifierConstants; +import org.jdom.Element; + +/** Routines to handle a static initializer method. */ +public final class InitializerAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static InitializerAttribute readExternal(final Element item) { + final InitializerAttribute result = new InitializerAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public InitializerAttribute() { + super("initializer", ModifierConstants.INITIALIZER); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*InitializerAttribute*/AtomicAttribute deepCopy() { + final InitializerAttribute result = new InitializerAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/IntegerAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/IntegerAttribute.java new file mode 100644 index 000000000000..ddbc7361f745 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/IntegerAttribute.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.wrq.rearranger.configuration.IntTextField; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import com.wrq.rearranger.util.MethodUtil; +import org.jdom.Element; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** Allow item selection by comparison with an integer attribute. */ +abstract public class IntegerAttribute extends AtomicAttribute { + public static final int OP_GE = 0; + public static final int OP_LE = 1; + + // ------------------------------ FIELDS ------------------------------ + protected int value; + protected int opType; + protected boolean match; // when true, condition applies + private final String attributeDisplayName; // should be plural + private final String storageName; + +// --------------------------- CONSTRUCTORS --------------------------- + + IntegerAttribute(final String attributeDisplayName, + final String storageName, + final int opType) + { + this.attributeDisplayName = attributeDisplayName; + this.storageName = storageName; + this.opType = opType; + } + + // --------------------- GETTER / SETTER METHODS --------------------- + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public int getOpType() { + return opType; + } + + public final boolean isMatch() { + return match; + } + + public final void setMatch(final boolean match) { + this.match = match; + } + + public final JPanel getIntegerPanel() { + final JPanel intPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(); + constraints.weightedLastRow(); + final JCheckBox enableBox = new JCheckBox(opType == OP_GE ? "with at least" : "with at most"); + intPanel.add(enableBox, constraints.firstCol()); + final IntTextField intField = new IntTextField( + new IntTextField.IGetSet() { + public int get() { + return value; + } + + public void set(int v) { + value = v; + } + }, + 0, 99); + + constraints.insets = new Insets(0, 3, 0, 0); + intPanel.add(intField, constraints.nextCol()); + final JLabel attribLabel = new JLabel(attributeDisplayName + "s"); + intPanel.add(attribLabel, constraints.weightedLastCol()); + enableBox.setSelected(match); + enableBox.setForeground(enableBox.isSelected() ? Color.BLACK : Color.GRAY); + intField.setEnabled(match); + attribLabel.setEnabled(match); + enableBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setMatch(enableBox.isSelected()); + intPanel.setEnabled(enableBox.isSelected()); + enableBox.setSelected(match); + enableBox.setForeground(enableBox.isSelected() ? Color.BLACK : Color.GRAY); + intField.setEnabled(match); + attribLabel.setEnabled(match); + } + }); + return intPanel; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public boolean equals(final Object obj) { + if (!(obj instanceof IntegerAttribute)) return false; + final IntegerAttribute na = (IntegerAttribute)obj; + return match == na.match && + opType == na.opType && + value == na.value; + } + +// -------------------------- OTHER METHODS -------------------------- + + public final void appendAttributes(final Element me) { + final Element stElement = new Element(storageName); + + me.getChildren().add(stElement); + stElement.setAttribute("match", Boolean.valueOf(match).toString()); + stElement.setAttribute("opType", "" + opType); + stElement.setAttribute("value", "" + value); + } + + protected final void deepCopy(IntegerAttribute result) { + result.match = match; + result.opType = opType; + result.value = value; + } + + public final String getDescriptiveString() { + return (match ? + (opType == OP_GE ? "with at least " : "with at most ") + + value + " " + attributeDisplayName + (value != 1 ? "s" : "") + : ""); + } + + public final boolean isMatch(PsiElement value) { + if (!match) return true; + if (!(value instanceof PsiMethod)) return false; + PsiMethod method = (PsiMethod)value; + int n = MethodUtil.nofParameters(method); + if (opType == OP_GE) { + return n >= this.value; + } + else { + return n <= this.value; + } + } + + public final void loadAttributes(final Element item) { + match = RearrangerSettings.getBooleanAttribute(item, "match", false); + // opType = RearrangerSettings.getIntAttribute(item, "opType", opType); -- never load opType, it is immutable + value = RearrangerSettings.getIntAttribute(item, "value", 0); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MaxParamsAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MaxParamsAttribute.java new file mode 100644 index 000000000000..e6c1194557bb --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MaxParamsAttribute.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +/** Common routines for 'maximum number of params' modifier. */ +public class MaxParamsAttribute + extends IntegerAttribute +{ + private static final String PROPNAME = "MAX_PARAMS"; + // -------------------------- STATIC METHODS -------------------------- + + public static MaxParamsAttribute readExternal(final Element item) { + final MaxParamsAttribute result = new MaxParamsAttribute(); + result.loadAttributes(item.getChild(PROPNAME)); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public MaxParamsAttribute() { + super("parameter", PROPNAME, IntegerAttribute.OP_LE); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*AbstractAttribute*/AtomicAttribute deepCopy() { + final MaxParamsAttribute mpa = new MaxParamsAttribute(); + mpa.value = value; + mpa.match = match; + return mpa; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MinParamsAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MinParamsAttribute.java new file mode 100644 index 000000000000..4d3f301007f1 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/MinParamsAttribute.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +/** Common routines for 'minimum number of params' modifier. */ +public class MinParamsAttribute + extends IntegerAttribute +{ + private static final String PROPNAME = "MIN_PARAMS"; + // -------------------------- STATIC METHODS -------------------------- + + public static MinParamsAttribute readExternal(final Element item) { + final MinParamsAttribute result = new MinParamsAttribute(); + result.loadAttributes(item.getChild(PROPNAME)); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public MinParamsAttribute() { + super("parameter", PROPNAME, IntegerAttribute.OP_GE); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*AbstractAttribute*/AtomicAttribute deepCopy() { + final MinParamsAttribute mpa = new MinParamsAttribute(); + mpa.value = value; + mpa.match = match; + return mpa; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NameAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NameAttribute.java new file mode 100644 index 000000000000..d77f755ab4a8 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NameAttribute.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +/** Allows item selection by matching its name to a regular expression. */ +public final class NameAttribute extends StringAttribute { + +// -------------------------- STATIC METHODS -------------------------- + + public static NameAttribute readExternal(final Element item) { + final NameAttribute result = new NameAttribute(); + result.loadAttributes(item.getChild("NameMatch")); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public NameAttribute() { + super("names", "NameMatch"); + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public final boolean equals(final Object object) { + if (!(object instanceof NameAttribute)) return false; + return super.equals(object); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*NameAttribute*/AtomicAttribute deepCopy() { + final NameAttribute result = new NameAttribute(); + super.deepCopy(result); + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NativeAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NativeAttribute.java new file mode 100644 index 000000000000..e36af5c7fe3b --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/NativeAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +import java.lang.reflect.Modifier; + +/** Handles the 'native' modifier. */ +public final class NativeAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static NativeAttribute readExternal(final Element item) { + final NativeAttribute result = new NativeAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public NativeAttribute() { + super("native", Modifier.NATIVE); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*NativeAttribute*/AtomicAttribute deepCopy() { + final NativeAttribute result = new NativeAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverriddenAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverriddenAttribute.java new file mode 100644 index 000000000000..e922cc316a34 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverriddenAttribute.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.ModifierConstants; +import org.jdom.Element; + + +public final class OverriddenAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static OverriddenAttribute readExternal(final Element item) { + final OverriddenAttribute result = new OverriddenAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public OverriddenAttribute() { + super("overridden", ModifierConstants.OVERRIDDEN); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*OverriddenAttribute*/AtomicAttribute deepCopy() { + final OverriddenAttribute result = new OverriddenAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverridingAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverridingAttribute.java new file mode 100644 index 000000000000..3e3af6a95909 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/OverridingAttribute.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.ModifierConstants; +import org.jdom.Element; + +public final class OverridingAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static OverridingAttribute readExternal(final Element item) { + final OverridingAttribute result = new OverridingAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public OverridingAttribute() { + super("overriding", ModifierConstants.OVERRIDING); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*OverridingAttribute*/AtomicAttribute deepCopy() { + final OverridingAttribute result = new OverridingAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ProtectionLevelAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ProtectionLevelAttributes.java new file mode 100644 index 000000000000..9ff8cfc8b3c8 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ProtectionLevelAttributes.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Element; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.Modifier; + +/** Routines to handle the four protection level modifiers. */ +public final class ProtectionLevelAttributes + extends AtomicAttribute +{ + +// ------------------------------ FIELDS ------------------------------ + + /** protection levels. */ + private boolean plPublic; + private boolean plPrivate; + private boolean plProtected; + private boolean plPackage; + private boolean invertProtectionLevel; + +// -------------------------- STATIC METHODS -------------------------- + + public static ProtectionLevelAttributes readExternal(final Element item) { + final ProtectionLevelAttributes result = new ProtectionLevelAttributes(); + final Element me = item.getChild("ProtectionLevel"); + result.loadAttributes(me); + return result; + } + + private void loadAttributes(final Element me) { + plPublic = RearrangerSettings.getBooleanAttribute(me, "public"); + plPrivate = RearrangerSettings.getBooleanAttribute(me, "private"); + plProtected = RearrangerSettings.getBooleanAttribute(me, "protected"); + plPackage = RearrangerSettings.getBooleanAttribute(me, "package"); + invertProtectionLevel = RearrangerSettings.getBooleanAttribute(me, "invert"); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + private boolean isInvertProtectionLevel() { + return invertProtectionLevel; + } + + public final void setInvertProtectionLevel(final boolean invertProtectionLevel) { + this.invertProtectionLevel = invertProtectionLevel; + } + + private boolean isPlPackage() { + return plPackage; + } + + public final void setPlPackage(final boolean plPackage) { + this.plPackage = plPackage; + } + + private boolean isPlPrivate() { + return plPrivate; + } + + public void setPlPrivate(final boolean plPrivate) { + this.plPrivate = plPrivate; + } + + private boolean isPlProtected() { + return plProtected; + } + + public final void setPlProtected(final boolean plProtected) { + this.plProtected = plProtected; + } + + private boolean isPlPublic() { + return plPublic; + } + + public final void setPlPublic(final boolean plPublic) { + this.plPublic = plPublic; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public boolean equals(final Object obj) { + if (!(obj instanceof ProtectionLevelAttributes)) return false; + final ProtectionLevelAttributes pla = (ProtectionLevelAttributes)obj; + return plPublic == pla.plPublic && + plPrivate == pla.plPrivate && + plProtected == pla.plProtected && + plPackage == pla.plPackage && + invertProtectionLevel == pla.invertProtectionLevel; + } + +// -------------------------- OTHER METHODS -------------------------- + + public final void appendAttributes(final Element me) { + final Element plElement = new Element("ProtectionLevel"); + me.getChildren().add(plElement); + plElement.setAttribute("public", Boolean.valueOf(plPublic).toString()); + plElement.setAttribute("private", Boolean.valueOf(plPrivate).toString()); + plElement.setAttribute("protected", Boolean.valueOf(plProtected).toString()); + plElement.setAttribute("package", Boolean.valueOf(plPackage).toString()); + plElement.setAttribute("invert", Boolean.valueOf(invertProtectionLevel).toString()); + } + + public final /*ProtectionLevelAttributes*/AtomicAttribute deepCopy() { + final ProtectionLevelAttributes pla = new ProtectionLevelAttributes(); + pla.plPublic = plPublic; + pla.plPrivate = plPrivate; + pla.plProtected = plProtected; + pla.plPackage = plPackage; + pla.invertProtectionLevel = invertProtectionLevel; + return pla; + } + + public final JPanel getProtectionLevelPanel() { + final JPanel plPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(); + constraints.weightedLastRow(); + constraints.fill = GridBagConstraints.BOTH; + final JCheckBox notBox = new JCheckBox("not"); + notBox.setSelected(isInvertProtectionLevel()); + notBox.setForeground(notBox.isSelected() ? Color.BLACK : Color.GRAY); + plPanel.add(notBox, constraints.firstCol()); + final JPanel plLevels = getProtLevels(); + plPanel.add(plLevels, constraints.weightedLastCol()); + notBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setInvertProtectionLevel(notBox.isSelected()); + notBox.setForeground(notBox.isSelected() ? Color.BLACK : Color.GRAY); + } + }); + + return plPanel; + } + + private JPanel getProtLevels() { + final JPanel plPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(); + final JCheckBox publicBox = new JCheckBox("public or"); + publicBox.setSelected(isPlPublic()); + final JCheckBox privateBox = new JCheckBox("private or"); + privateBox.setSelected(isPlPrivate()); + final JCheckBox protectedBox = new JCheckBox("protected or"); + protectedBox.setSelected(isPlProtected()); + final JCheckBox packageBox = new JCheckBox("package"); + packageBox.setSelected(isPlPackage()); + plPanel.add(publicBox, constraints.weightedLastCol()); + constraints.newRow(); + plPanel.add(privateBox, constraints.weightedLastCol()); + constraints.newRow(); + plPanel.add(protectedBox, constraints.weightedLastCol()); + constraints.weightedLastRow(); + plPanel.add(packageBox, constraints.weightedLastCol()); + publicBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setPlPublic(publicBox.isSelected()); + } + }); + privateBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setPlPrivate(privateBox.isSelected()); + } + }); + protectedBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setPlProtected(protectedBox.isSelected()); + } + }); + packageBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setPlPackage(packageBox.isSelected()); + } + }); + return plPanel; + } + + public final String getProtectionLevelString() { + final StringBuffer sb = new StringBuffer(60); + final int nProtLevels = (isPlPublic() ? 1 : 0) + + (isPlPrivate() ? 1 : 0) + + (isPlProtected() ? 1 : 0) + + (isPlPackage() ? 1 : 0); + + int nProtLevelsSeen = 0; + if (isPlPublic()) { + sb.append(isInvertProtectionLevel() ? "non-public" : "public"); + nProtLevelsSeen++; + if (nProtLevelsSeen < nProtLevels) { + sb.append("/"); + } + } + if (isPlPrivate()) { + sb.append(isInvertProtectionLevel() ? "non-private" : "private"); + nProtLevelsSeen++; + if (nProtLevelsSeen < nProtLevels) { + sb.append("/"); + } + } + if (isPlProtected()) { + sb.append(isInvertProtectionLevel() ? "non-protected" : "protected"); + nProtLevelsSeen++; + if (nProtLevelsSeen < nProtLevels) { + sb.append("/"); + } + } + if (isPlPackage()) { + sb.append(isInvertProtectionLevel() ? "non-package" : "package"); + nProtLevelsSeen++; + if (nProtLevelsSeen < nProtLevels) { + sb.append("/"); + } + } + if (nProtLevels > 0) { + sb.append(' '); + } + return sb.toString(); + } + + /** + * @param modifiers Java modifiers for the field, method or class. + * @return true if the supplied protection level modifiers match this object's modifier requirements. + */ + public final boolean isMatch(final int modifiers) { + boolean result; + if (!plPublic && !plPrivate && !plProtected && !plPackage) { + return true; // nothing selected, so don't take protection level into account. + } + result = + (plPublic && Modifier.isPublic(modifiers)) || + (plPrivate && Modifier.isPrivate(modifiers)) || + (plProtected && Modifier.isProtected(modifiers)) || + (plPackage && !(Modifier.isPublic(modifiers) || + Modifier.isPrivate(modifiers) || + Modifier.isProtected(modifiers))); + result ^= invertProtectionLevel; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ReturnTypeAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ReturnTypeAttribute.java new file mode 100644 index 000000000000..645d5e422d33 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/ReturnTypeAttribute.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +/** Allows method selection by matching its return type to a regular expression. */ +public final class ReturnTypeAttribute extends StringAttribute { + +// -------------------------- STATIC METHODS -------------------------- + + public static ReturnTypeAttribute readExternal(final Element item) { + final ReturnTypeAttribute result = new ReturnTypeAttribute(); + result.loadAttributes(item.getChild("ReturnTypeMatch")); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public ReturnTypeAttribute() { + super("return types", "ReturnTypeMatch"); + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public final boolean equals(final Object object) { + if (!(object instanceof ReturnTypeAttribute)) return false; + return super.equals(object); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*ReturnTypeAttribute*/AtomicAttribute deepCopy() { + final ReturnTypeAttribute result = new ReturnTypeAttribute(); + super.deepCopy(result); + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SortOptions.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SortOptions.java new file mode 100644 index 000000000000..1b1f43b26ce9 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SortOptions.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Element; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Contains sorting attributes (part of common attributes; applies to fields, methods, inner and outer classes). + *

+ * Originally, methods and classes could only be sorted alphabetically by name (case sensitive). Fields could be + * sorted by type (optionally ignoring case), by name (case sensitive), or both. + *

+ * Beginning with release 4.4, all of these types (fields, methods and classes) can be sorted optionally by + * modifiers, optionally by type (optionally ignoring case), and by name (optionally ignoring case). This covers + * all permutations. Modifiers are always lower case so no need to ask about whether to ignore case. + */ +public class SortOptions + extends AtomicAttribute +{ + private boolean byModifiers; + private boolean byType; + private boolean isTypeCaseInsensitive; + private boolean byName; + private boolean isNameCaseInsensitive; + + public SortOptions() { + byModifiers = false; + byType = false; + isTypeCaseInsensitive = false; + byName = false; + isNameCaseInsensitive = false; + } + + public boolean isByModifiers() { + return byModifiers; + } + + public void setByModifiers(boolean byModifiers) { + this.byModifiers = byModifiers; + } + + public boolean isByName() { + return byName; + } + + public void setByName(boolean byName) { + this.byName = byName; + } + + public boolean isByType() { + return byType; + } + + public void setByType(boolean byType) { + this.byType = byType; + } + + public boolean isNameCaseInsensitive() { + return isNameCaseInsensitive; + } + + public void setNameCaseInsensitive(boolean nameCaseInsensitive) { + isNameCaseInsensitive = nameCaseInsensitive; + } + + public boolean isTypeCaseInsensitive() { + return isTypeCaseInsensitive; + } + + public void setTypeCaseInsensitive(boolean typeCaseInsensitive) { + isTypeCaseInsensitive = typeCaseInsensitive; + } + + public final boolean equals(final Object obj) { + if (!(obj instanceof SortOptions)) return false; + SortOptions so = (SortOptions)obj; + return byModifiers == so.byModifiers && + byType == so.byType && + isTypeCaseInsensitive == so.isTypeCaseInsensitive && + byName == so.byName && + isNameCaseInsensitive == so.isNameCaseInsensitive; + } + + public static SortOptions readExternal(final Element item) { + SortOptions result = new SortOptions(); + final Element me = item.getChild("SortOptions"); + result.loadAttributes(me); + // support old settings + result.byName |= RearrangerSettings.getBooleanAttribute(item, "alphabetize"); + result.byType |= RearrangerSettings.getBooleanAttribute(item, "sortByType", false); + result.isTypeCaseInsensitive |= RearrangerSettings.getBooleanAttribute(item, "ignoreTypeCase", false); + return result; + } + + private void loadAttributes(final Element me) { + byModifiers = RearrangerSettings.getBooleanAttribute(me, "byModifiers"); + byType = RearrangerSettings.getBooleanAttribute(me, "byType"); + isTypeCaseInsensitive = RearrangerSettings.getBooleanAttribute(me, "isTypeCaseInsensitive"); + byName = RearrangerSettings.getBooleanAttribute(me, "byName"); + isNameCaseInsensitive = RearrangerSettings.getBooleanAttribute(me, "isNameCaseInsensitive"); + } + + public final /*SortOptions*/ AtomicAttribute deepCopy() { + final SortOptions result = new SortOptions(); + result.byModifiers = byModifiers; + result.byType = byType; + result.isTypeCaseInsensitive = isTypeCaseInsensitive; + result.byName = byName; + result.isNameCaseInsensitive = isNameCaseInsensitive; + return result; + } + + public final void appendAttributes(final Element me) { + final Element plElement = new Element("SortOptions"); + me.getChildren().add(plElement); + plElement.setAttribute("byModifiers", Boolean.valueOf(byModifiers).toString()); + plElement.setAttribute("byType", Boolean.valueOf(byType).toString()); + plElement.setAttribute("isTypeCaseInsensitive", Boolean.valueOf(isTypeCaseInsensitive).toString()); + plElement.setAttribute("byName", Boolean.valueOf(byName).toString()); + plElement.setAttribute("isNameCaseInsensitive", Boolean.valueOf(isNameCaseInsensitive).toString()); + } + + public final String getDescriptiveString() { + StringBuilder sb = new StringBuilder(80); + if (byName && !isNameCaseInsensitive && !byModifiers && !byType) { + return " (alphabetized)"; + } + if (byModifiers || byType || byName) { + sb.append(" (sorted by"); + boolean needComma = false; + if (byModifiers) { + sb.append(" modifiers"); + needComma = true; + } + if (byType) { + if (needComma) { + sb.append(','); + } + sb.append(" type"); + if (isTypeCaseInsensitive) { + sb.append("(CI)"); + } + needComma = true; + } + if (byName) { + if (needComma) { + sb.append(','); + } + sb.append(" name"); + if (isNameCaseInsensitive) { + sb.append("(CI)"); + } + } + sb.append(")"); + } + return sb.toString(); + } + + public final JPanel getSortOptionsPanel() { + final JPanel abPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(); + final JLabel sortLabel = new JLabel("Sort"); + constraints.insets = new Insets(0, 5, 0, 5); + abPanel.add(sortLabel, constraints.firstCol()); + final JCheckBox byModifiersBox = new JCheckBox("by modifiers"); + final JCheckBox byTypeBox = new JCheckBox("by type"); + final JCheckBox typeCIBox = new JCheckBox("case insensitive"); + final JCheckBox byNameBox = new JCheckBox("by name"); + final JCheckBox nameCIBox = new JCheckBox("case insensitive"); + constraints.insets = new Insets(0, 0, 0, 0); + abPanel.add(byModifiersBox, constraints.weightedLastCol()); + constraints.newRow(); + constraints.nextCol(); + abPanel.add(byTypeBox, constraints.nextCol()); + abPanel.add(typeCIBox, constraints.weightedLastCol()); + constraints.weightedLastRow(); + constraints.nextCol(); + abPanel.add(byNameBox, constraints.nextCol()); + abPanel.add(nameCIBox, constraints.weightedLastCol()); + + byModifiersBox.setSelected(isByModifiers()); + byTypeBox.setSelected(isByType()); + typeCIBox.setSelected(isTypeCaseInsensitive()); + byNameBox.setSelected(isByName()); + nameCIBox.setSelected(isNameCaseInsensitive()); + + byModifiersBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setByModifiers(byModifiersBox.isSelected()); + } + }); + byTypeBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setByType(byTypeBox.isSelected()); + } + }); + typeCIBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setTypeCaseInsensitive(typeCIBox.isSelected()); + } + }); + byNameBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setByName(byNameBox.isSelected()); + } + }); + nameCIBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setNameCaseInsensitive(nameCIBox.isSelected()); + } + }); + + return abPanel; + } + + public String generateSortString(RangeEntry entry) { + String modifiers = entry.getModifierString(); + String type = entry.getType(); + String name = entry.getName(); + StringBuilder sb = new StringBuilder(modifiers.length() + type.length() + name.length()); + if (byModifiers) { + sb.append(modifiers); + } + if (byType) { + sb.append(isTypeCaseInsensitive ? type.toLowerCase() : type); + } + if (byName) { + sb.append(isNameCaseInsensitive ? name.toLowerCase() : name); + } + return sb.toString(); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StaticAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StaticAttribute.java new file mode 100644 index 000000000000..5c4b5f883f64 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StaticAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +import java.lang.reflect.Modifier; + +/** Routines to handle the 'static' modifier. */ +public final class StaticAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static StaticAttribute readExternal(final Element item) { + final StaticAttribute result = new StaticAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public StaticAttribute() { + super("static", Modifier.STATIC); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*StaticAttribute*/AtomicAttribute deepCopy() { + final StaticAttribute result = new StaticAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StringAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StringAttribute.java new file mode 100644 index 000000000000..147c9b75b5f7 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/StringAttribute.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Attribute; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** Allows item selection by matching a string attribute to a regular expression. */ +abstract public class StringAttribute extends AtomicAttribute { + +// ------------------------------ FIELDS ------------------------------ + + private String expression; + private boolean match; + private boolean invert; + private final String attributeDisplayName; // should be plural + private final String storageName; + +// --------------------------- CONSTRUCTORS --------------------------- + + StringAttribute(String attributeDisplayName, String storageName) { + this.attributeDisplayName = attributeDisplayName; + this.storageName = storageName; + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public final String getExpression() { + return expression; + } + + public final void setExpression(final String expression) { + this.expression = expression; + } + + public final JPanel getStringPanel() { + final JPanel stringPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(); + constraints.weightedLastRow(); + final JCheckBox enableBox = new JCheckBox("whose " + attributeDisplayName); + stringPanel.add(enableBox, constraints.firstCol()); + final JComboBox invertBox = new JComboBox(new Object[]{"match", "do not match"}); + invertBox.setSelectedIndex(isInvert() ? 1 : 0); + final JTextField patternField = new JTextField(20); + stringPanel.add(invertBox, constraints.nextCol()); + stringPanel.add(patternField, constraints.weightedLastCol()); + enableBox.setSelected(isMatch()); + invertBox.setEnabled(isMatch()); + patternField.setEnabled(isMatch()); + patternField.setText(getExpression()); + enableBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setMatch(enableBox.isSelected()); + invertBox.setEnabled(enableBox.isSelected()); + patternField.setEnabled(enableBox.isSelected()); + } + }); + invertBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setInvert(invertBox.getSelectedIndex() == 1); + } + }); + patternField.getDocument().addDocumentListener(new DocumentListener() { + public void changedUpdate(final DocumentEvent e) { + setExpression(patternField.getText()); + } + + public void insertUpdate(final DocumentEvent e) { + setExpression(patternField.getText()); + } + + public void removeUpdate(final DocumentEvent e) { + setExpression(patternField.getText()); + } + }); + return stringPanel; + } + + public final boolean isInvert() { + return invert; + } + + private void setInvert(final boolean invert) { + this.invert = invert; + } + + public final boolean isMatch() { + return match; + } + + public final void setMatch(final boolean match) { + this.match = match; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public boolean equals(final Object object) { + if (!(object instanceof StringAttribute)) return false; + final StringAttribute na = (StringAttribute)object; + return match == na.match && + (expression == null || na.expression == null ? + expression == null && na.expression == null : expression.equals(na.expression)) && + invert == na.invert; + } + +// -------------------------- OTHER METHODS -------------------------- + + public final void appendAttributes(final Element me) { + final Element stElement = new Element(storageName); + if (expression == null) { + expression = ""; + } + me.getChildren().add(stElement); + stElement.setAttribute("match", Boolean.valueOf(match).toString()); + stElement.setAttribute("invert", Boolean.valueOf(invert).toString()); + stElement.setAttribute("pattern", expression); + } + + protected final void deepCopy(StringAttribute result) { + result.match = match; + result.expression = expression; + result.invert = invert; + } + + public final String getDescriptiveString() { + return (match ? "whose " + + attributeDisplayName + + (invert ? " do not match '" : " match '") + + expression + "'" + : ""); + } + + public final boolean isMatch(final String string) { + return !match || string.matches(expression) ^ invert; + } + + public final void loadAttributes(final Element item) { + match = RearrangerSettings.getBooleanAttribute(item, "match", false); + invert = RearrangerSettings.getBooleanAttribute(item, "invert", false); + final Attribute attr = RearrangerSettings.getAttribute(item, "pattern"); + expression = (attr == null ? "" : ((java.lang.String)attr.getValue())); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SynchronizedAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SynchronizedAttribute.java new file mode 100644 index 000000000000..8e166fc6ae63 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/SynchronizedAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +import java.lang.reflect.Modifier; + +/** Handles the 'synchronized' modifier. */ +public final class SynchronizedAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static SynchronizedAttribute readExternal(final Element item) { + final SynchronizedAttribute result = new SynchronizedAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public SynchronizedAttribute() { + super("synchronized", Modifier.SYNCHRONIZED); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*SynchronizedAttribute*/AtomicAttribute deepCopy() { + final SynchronizedAttribute result = new SynchronizedAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TransientAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TransientAttribute.java new file mode 100644 index 000000000000..2f48fb93cdc4 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TransientAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +import java.lang.reflect.Modifier; + +/** Handles the 'transient' modifier. */ +public final class TransientAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static TransientAttribute readExternal(final Element item) { + final TransientAttribute result = new TransientAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public TransientAttribute() { + super("transient", Modifier.TRANSIENT); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*TransientAttribute*/AtomicAttribute deepCopy() { + final TransientAttribute result = new TransientAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TypeAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TypeAttribute.java new file mode 100644 index 000000000000..0627b20ff8ea --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/TypeAttribute.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +/** Allows field selection by matching its type to a regular expression. */ + +public class TypeAttribute extends StringAttribute { + +// -------------------------- STATIC METHODS -------------------------- + + public static TypeAttribute readExternal(final Element item) { + final TypeAttribute result = new TypeAttribute(); + result.loadAttributes(item.getChild("TypeMatch")); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public TypeAttribute() { + super("types", "TypeMatch"); + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public final boolean equals(final Object object) { + if (!(object instanceof TypeAttribute)) return false; + return super.equals(object); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*TypeAttribute*/AtomicAttribute deepCopy() { + final TypeAttribute result = new TypeAttribute(); + super.deepCopy(result); + return result; + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/VolatileAttribute.java b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/VolatileAttribute.java new file mode 100644 index 000000000000..6bc6a05c17d9 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/atomicAttributes/VolatileAttribute.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.atomicAttributes; + +import org.jdom.Element; + +import java.lang.reflect.Modifier; + +/** Handles the 'volatile' modifier. */ +public final class VolatileAttribute + extends AndNotAttribute +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static VolatileAttribute readExternal(final Element item) { + final VolatileAttribute result = new VolatileAttribute(); + result.loadAttributes(item.getChild(result.getElementName())); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public VolatileAttribute() { + super("volatile", Modifier.VOLATILE); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final /*VolatileAttribute*/AtomicAttribute deepCopy() { + final VolatileAttribute result = new VolatileAttribute(); + result.value = value; + result.invert = invert; + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java new file mode 100644 index 000000000000..dc1bd8e3d3c9 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import org.jdom.Element; + +/** Methods implemented by rule objects, which are saved in configuration. */ +public interface AttributeGroup + extends IRule +{ + +// -------------------------- OTHER METHODS -------------------------- + + public AttributeGroup deepCopy(); + + public void writeExternal(final Element parent); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ClassAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ClassAttributes.java new file mode 100644 index 000000000000..0af457a9d854 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ClassAttributes.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiJavaToken; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.atomicAttributes.AbstractAttribute; +import com.wrq.rearranger.settings.atomicAttributes.EnumAttribute; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; + +/** Routines to handle class modifiers other than those already handled by CommonAttributes. */ +public final class ClassAttributes + extends CommonAttributes + implements AttributeGroup +{ + +// ------------------------------ FIELDS ------------------------------ + + private AbstractAttribute abAttr; + private EnumAttribute enumAttr; + +// -------------------------- STATIC METHODS -------------------------- + + public static AttributeGroup readExternal(final Element element) { + if (element.getName().equals("Class")) { + final ClassAttributes result = new ClassAttributes(); + CommonAttributes.readExternal(result, element); + result.abAttr = AbstractAttribute.readExternal(element); + result.enumAttr = EnumAttribute.readExternal(element); + return result; + } + else if (element.getName().equals("Comment")) { + return CommentRule.readExternal(element); + } + else { + return null; + } + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public ClassAttributes() { + abAttr = new AbstractAttribute(); + enumAttr = new EnumAttribute(); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + private AbstractAttribute getAbAttr() { + return abAttr; + } + + public EnumAttribute getEnumAttr() { + return enumAttr; + } +// ------------------------ CANONICAL METHODS ------------------------ + + public final String toString() { + final StringBuffer sb = new StringBuffer(70); + sb.append(abAttr.getDescriptiveString()); + sb.append(plAttr.getProtectionLevelString()); + sb.append(stAttr.getDescriptiveString()); + sb.append(fAttr.getDescriptiveString()); + sb.append(enumAttr.getDescriptiveString()); + if (sb.length() == 0) { + sb.append("all classes"); + } + else { + sb.append("classes"); + } + if (nameAttr.isMatch()) { + sb.append(' '); + sb.append(nameAttr.getDescriptiveString()); + } + sb.append(sortAttr.getDescriptiveString()); + return sb.toString(); + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface AttributeGroup --------------------- + + public final /*ClassAttributes*/AttributeGroup deepCopy() { + final ClassAttributes result = new ClassAttributes(); + deepCopyCommonItems(result); + result.abAttr = (AbstractAttribute)abAttr.deepCopy(); + result.enumAttr = (EnumAttribute)enumAttr.deepCopy(); + return result; + } + + public final void writeExternal(final Element parent) { + final Element me = new Element("Class"); + writeExternalCommonAttributes(me); + abAttr.appendAttributes(me); + enumAttr.appendAttributes(me); + parent.getChildren().add(me); + } + +// -------------------------- OTHER METHODS -------------------------- + + public boolean equals(final Object obj) { + if (!(obj instanceof ClassAttributes)) { + return false; + } + final ClassAttributes ca = (ClassAttributes)obj; + return super.equals(ca) && + abAttr.equals(ca.abAttr) && + enumAttr.equals(ca.enumAttr); + } + + public final JPanel getClassAttributesPanel() { + final JPanel caPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + caPanel.setBorder(border); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 4; + constraints.weightx = 1.0d; + constraints.weighty = 0.0d; + constraints.insets = new Insets(0, 0, 10, 0); + caPanel.add(getPlAttr().getProtectionLevelPanel(), constraints); + constraints.gridy = 4; + constraints.gridheight = 1; + caPanel.add(getStAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getAbAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getfAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getEnumAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getNameAttr().getStringPanel(), constraints); + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.weighty = 1.0d; + constraints.insets = new Insets(0, 0, 0, 0); + caPanel.add(sortAttr.getSortOptionsPanel(), constraints); + return caPanel; + } + + public final boolean isMatch(RangeEntry entry) + // final int modifiers, final String name, final String returnType) + { + return entry.getEnd().getParent() instanceof PsiClass && + entry.getEnd() instanceof PsiJavaToken && +// ((PsiJavaToken)entry.getEnd()).getTokenType() == PsiJavaToken.LBRACE && + entry.getEnd().getText().equals("{") && + super.isMatch(entry) && + abAttr.isMatch(entry.getModifiers()) && + enumAttr.isMatch(entry.getModifiers()); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java new file mode 100644 index 000000000000..d0f14db787e1 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.DefaultRuleInstance; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.atomicAttributes.*; +import org.jdom.Element; + +import java.util.ArrayList; +import java.util.List; + +/** + * Routines for Java modifiers common to fields, methods and classes, namely: protection levels (public, private, + * protected, package), final modifier, and static modifier. Ability to match the name to a regular + * expression is also supported. + */ +public abstract class CommonAttributes + implements AttributeGroup, IPrioritizableRule +{ +// ------------------------------ FIELDS ------------------------------ + + ProtectionLevelAttributes plAttr; + FinalAttribute fAttr; + StaticAttribute stAttr; + NameAttribute nameAttr; + SortOptions sortAttr; + int priority; // 1 = low priority, > 1 is higher priority + +// -------------------------- STATIC METHODS -------------------------- + + static void readExternal(final CommonAttributes result, final Element item) { + result.plAttr = ProtectionLevelAttributes.readExternal(item); + result.stAttr = StaticAttribute.readExternal(item); + result.fAttr = FinalAttribute.readExternal(item); + result.nameAttr = NameAttribute.readExternal(item); + result.sortAttr = SortOptions.readExternal(item); + result.priority = RearrangerSettings.getIntAttribute(item, "priority", 1); + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public CommonAttributes() { + plAttr = new ProtectionLevelAttributes(); + fAttr = new FinalAttribute(); + stAttr = new StaticAttribute(); + nameAttr = new NameAttribute(); + sortAttr = new SortOptions(); + priority = 1; + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public final NameAttribute getNameAttr() { + return nameAttr; + } + + final public ProtectionLevelAttributes getPlAttr() { + return plAttr; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + final public StaticAttribute getStAttr() { + return stAttr; + } + + public SortOptions getSortAttr() { + return sortAttr; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public boolean equals(final Object obj) { + if (!(obj instanceof CommonAttributes)) { + return false; + } + final CommonAttributes ca = (CommonAttributes)obj; + return plAttr.equals(ca.plAttr) && + stAttr.equals(ca.stAttr) && + fAttr.equals(ca.fAttr) && + nameAttr.equals(ca.nameAttr) && + sortAttr.equals(ca.sortAttr) && + priority == ca.priority; + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface IRule --------------------- + + public IRuleInstance createRuleInstance() { + return new DefaultRuleInstance(this); + } + + public boolean isMatch(RangeEntry rangeEntry) { + final boolean result = plAttr.isMatch(rangeEntry.getModifiers()) && + stAttr.isMatch(rangeEntry.getModifiers()) && + fAttr.isMatch(rangeEntry.getModifiers()) && + nameAttr.isMatch(rangeEntry.getName()); + return result; + } + + /** + * Returns a boolean indicating if the comments associated with this rule match a global comment pattern. + * Most rules don't have comments, so by default it returns true. + * + * @param pattern global pattern to which all comments should conform + * @return true if comments conform to pattern + */ + public boolean commentsMatchGlobalPattern(String pattern) { + return true; + } + + public List getOffendingPatterns(String pattern) { + return new ArrayList(1); + } + + public int getCommentCount() { + return 0; + } + + /** + * Calculates a list of regular expression patterns, one for each comment that the rule might create, which will + * match any comment that the rule might generate. These can be combined to form a global comment pattern which + * will match all possible generated comments from all rules. These patterns will be appended to the supplied + * list. + */ + public void addCommentPatternsToList(List list) { + return; + } + +// -------------------------- OTHER METHODS -------------------------- + + final void deepCopyCommonItems(final CommonAttributes result) { + result.plAttr = (ProtectionLevelAttributes)plAttr.deepCopy(); + result.fAttr = (FinalAttribute)fAttr.deepCopy(); + result.stAttr = (StaticAttribute)stAttr.deepCopy(); + result.nameAttr = (NameAttribute)nameAttr.deepCopy(); + result.sortAttr = (SortOptions)sortAttr.deepCopy(); + result.priority = priority; + } + + final public FinalAttribute getfAttr() { + return fAttr; + } + + final void writeExternalCommonAttributes(final Element child) { + plAttr.appendAttributes(child); + stAttr.appendAttributes(child); + fAttr.appendAttributes(child); + nameAttr.appendAttributes(child); + sortAttr.appendAttributes(child); + child.setAttribute("priority", "" + priority); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java new file mode 100644 index 000000000000..b33bbd6157e5 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.DefaultRuleInstance; +import com.wrq.rearranger.ruleinstance.IRuleInstance; + +import java.util.ArrayList; +import java.util.List; + +/** + * A rule to match whatever is not matched by other rules. Always the last rule emitted except for any trailing + * constant (unparsed) text. + */ +public class DefaultRule + implements IRule +{ + public IRuleInstance createRuleInstance() { + return new DefaultRuleInstance(this); + } + + public int getPriority() { + return -1; // this rule matches every remaining entry, so must go last. + } + + public void setPriority(int priority) { + // does nothing + } + + public boolean isMatch(RangeEntry entry) { + return !(entry.isFixedHeader() || entry.isFixedTrailer()); + } + + public boolean commentsMatchGlobalPattern(String pattern) { + return true; + } + + public List getOffendingPatterns(String pattern) { + return new ArrayList(1); + } + + public int getCommentCount() { + return 0; + } + + public void addCommentPatternsToList(List list) { + } + + public String toString() { + return ""; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/FieldAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/FieldAttributes.java new file mode 100644 index 000000000000..6706b7fae11e --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/FieldAttributes.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.intellij.psi.PsiField; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.settings.atomicAttributes.InitToAnonClassAttribute; +import com.wrq.rearranger.settings.atomicAttributes.TransientAttribute; +import com.wrq.rearranger.settings.atomicAttributes.TypeAttribute; +import com.wrq.rearranger.settings.atomicAttributes.VolatileAttribute; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; + +/** Routines to handle field attributes not covered by CommonAttributes. */ +public final class FieldAttributes + extends ItemAttributes +{ + +// ------------------------------ FIELDS ------------------------------ + + private InitToAnonClassAttribute initToAnonClassAttr; + private TransientAttribute transientAttr; + private VolatileAttribute volatileAttr; + private TypeAttribute typeAttr; + +// -------------------------- STATIC METHODS -------------------------- + + public static /*FieldAttributes*/AttributeGroup readExternal(final Element item) { + final FieldAttributes result = new FieldAttributes(); + CommonAttributes.readExternal(result, item); + result.initToAnonClassAttr = InitToAnonClassAttribute.readExternal(item); + result.transientAttr = TransientAttribute.readExternal(item); + result.volatileAttr = VolatileAttribute.readExternal(item); + result.typeAttr = TypeAttribute.readExternal(item); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public FieldAttributes() { + initToAnonClassAttr = new InitToAnonClassAttribute(); + transientAttr = new TransientAttribute(); + volatileAttr = new VolatileAttribute(); + typeAttr = new TypeAttribute(); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public InitToAnonClassAttribute getInitToAnonClassAttr() { + return initToAnonClassAttr; + } + + private TransientAttribute getTransientAttr() { + return transientAttr; + } + + public TypeAttribute getTypeAttr() { + return typeAttr; + } + + private VolatileAttribute getVolatileAttr() { + return volatileAttr; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public final String toString() { + final StringBuffer sb = new StringBuffer(70); + sb.append(plAttr.getProtectionLevelString()); + sb.append(stAttr.getDescriptiveString()); + sb.append(fAttr.getDescriptiveString()); + sb.append(transientAttr.getDescriptiveString()); + sb.append(volatileAttr.getDescriptiveString()); + + if (sb.length() == 0) { + sb.append("all fields"); + } + else { + sb.append("fields"); + } + if (initToAnonClassAttr.isValue()) { + if (!initToAnonClassAttr.isInvert()) { + sb.append(" which are initialized to an anonymous class"); + } + else { + sb.append(" which are not initialized to an anonymous class"); + } + } + if (nameAttr.isMatch()) { + if (initToAnonClassAttr.isValue()) { + sb.append(" and"); + } + sb.append(' '); + sb.append(nameAttr.getDescriptiveString()); + } + if (typeAttr.isMatch()) { + if (nameAttr.isMatch() || initToAnonClassAttr.isValue()) { + sb.append(" and"); + } + sb.append(' '); + sb.append(typeAttr.getDescriptiveString()); + } + sb.append(sortAttr.getDescriptiveString()); + return sb.toString(); + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface AttributeGroup --------------------- + + public final /*FieldAttributes*/AttributeGroup deepCopy() { + final FieldAttributes result = new FieldAttributes(); + deepCopyCommonItems(result); + result.initToAnonClassAttr = (InitToAnonClassAttribute)initToAnonClassAttr.deepCopy(); + result.transientAttr = (TransientAttribute)transientAttr.deepCopy(); + result.volatileAttr = (VolatileAttribute)volatileAttr.deepCopy(); + result.typeAttr = (TypeAttribute)typeAttr.deepCopy(); + return result; + } + + public final void writeExternal(final Element parent) { + final Element child = new Element("Field"); + writeExternalCommonAttributes(child); + initToAnonClassAttr.appendAttributes(child); + transientAttr.appendAttributes(child); + volatileAttr.appendAttributes(child); + typeAttr.appendAttributes(child); + parent.getChildren().add(child); + } + +// -------------------------- OTHER METHODS -------------------------- + + public boolean equals(final Object object) { + if (!(object instanceof FieldAttributes)) return false; + final FieldAttributes fa = (FieldAttributes)object; + return super.equals(fa) && + transientAttr.equals(fa.transientAttr) && + volatileAttr.equals(fa.volatileAttr) && + initToAnonClassAttr.equals(fa.initToAnonClassAttr) && + typeAttr.equals(fa.typeAttr); + } + + public JPanel getFieldAttributes() { + final JPanel plPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + plPanel.setBorder(border); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.gridwidth = 1; + constraints.gridheight = 4; + constraints.weightx = 1.0d; + plPanel.add(getPlAttr().getProtectionLevelPanel(), constraints); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridy = 0; + constraints.gridx = 1; + constraints.gridheight = 1; + constraints.weighty = 0; + plPanel.add(getStAttr().getAndNotPanel(), constraints); + constraints.gridy++; + plPanel.add(getfAttr().getAndNotPanel(), constraints); + constraints.gridy++; + plPanel.add(getTransientAttr().getAndNotPanel(), constraints); + constraints.gridy++; + plPanel.add(getVolatileAttr().getAndNotPanel(), constraints); + constraints.insets = new Insets(5, 0, 0, 0); + constraints.gridx = 0; + constraints.gridy++; + plPanel.add(getInitToAnonClassAttr().getAndNotPanel(), constraints); + constraints.gridy++; + plPanel.add(getNameAttr().getStringPanel(), constraints); + constraints.gridy++; + plPanel.add(getTypeAttr().getStringPanel(), constraints); + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.weighty = 1.0d; + constraints.insets = new Insets(0, 0, 0, 0); + plPanel.add(sortAttr.getSortOptionsPanel(), constraints); + return plPanel; + } + + public boolean isMatch(RangeEntry rangeEntry) { + return rangeEntry.getEnd() instanceof PsiField && + initToAnonClassAttr.isMatch(rangeEntry.getModifiers()) && + transientAttr.isMatch(rangeEntry.getModifiers()) && + volatileAttr.isMatch(rangeEntry.getModifiers()) && + typeAttr.isMatch(rangeEntry.getType()) && + super.isMatch(rangeEntry); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/GetterSetterDefinition.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/GetterSetterDefinition.java new file mode 100644 index 000000000000..8a7b7ca1ebf3 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/GetterSetterDefinition.java @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.settings.RearrangerSettings; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.TitledBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** Specifies criteria defining what constitutes a getter or setter method. */ +public class GetterSetterDefinition { + +// ------------------------------ FIELDS ------------------------------ + + public static final int GETTER_BODY_RETURNS_FIELD = 0; + public static final int GETTER_BODY_RETURNS = 1; + public static final int GETTER_BODY_IMMATERIAL = 2; + + public static final int GETTER_NAME_MATCHES_FIELD = 0; + public static final int GETTER_NAME_CORRECT_PREFIX = 1; + + public static final int SETTER_BODY_SETS_FIELD = 0; + public static final int SETTER_BODY_IMMATERIAL = 1; + + public static final int SETTER_NAME_MATCHES_FIELD = 0; + public static final int SETTER_NAME_CORRECT_PREFIX = 1; + + private int getterBodyCriterion; + private int getterNameCriterion; + private int setterBodyCriterion; + private int setterNameCriterion; + +// -------------------------- STATIC METHODS -------------------------- + + public static GetterSetterDefinition readExternal(Element item) { + final GetterSetterDefinition result = new GetterSetterDefinition(); + if (item != null) { + Element child = item.getChild("GetterSetterDefinition"); + if (child != null) { + result.loadAttributes(child); + } + } + return result; + } + + public void loadAttributes(Element me) { + getterBodyCriterion = RearrangerSettings.getIntAttribute(me, "getterBody"); + getterNameCriterion = RearrangerSettings.getIntAttribute(me, "getterName"); + setterBodyCriterion = RearrangerSettings.getIntAttribute(me, "setterBody"); + setterNameCriterion = RearrangerSettings.getIntAttribute(me, "setterName"); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public int getGetterBodyCriterion() { + return getterBodyCriterion; + } + + public void setGetterBodyCriterion(int getterBodyCriterion) { + this.getterBodyCriterion = getterBodyCriterion; + } + + public int getGetterNameCriterion() { + return getterNameCriterion; + } + + public void setGetterNameCriterion(int getterNameCriterion) { + this.getterNameCriterion = getterNameCriterion; + } + + public int getSetterBodyCriterion() { + return setterBodyCriterion; + } + + public void setSetterBodyCriterion(int setterBodyCriterion) { + this.setterBodyCriterion = setterBodyCriterion; + } + + public int getSetterNameCriterion() { + return setterNameCriterion; + } + + public void setSetterNameCriterion(int setterNameCriterion) { + this.setterNameCriterion = setterNameCriterion; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public boolean equals(Object obj) { + if (obj instanceof GetterSetterDefinition) { + GetterSetterDefinition gsd = (GetterSetterDefinition)obj; + if (gsd.getterBodyCriterion == getterBodyCriterion && + gsd.getterNameCriterion == getterNameCriterion && + gsd.setterBodyCriterion == setterBodyCriterion && + gsd.setterNameCriterion == setterNameCriterion) + { + return true; + } + } + return false; + } + +// -------------------------- OTHER METHODS -------------------------- + + public final GetterSetterDefinition deepCopy() { + final GetterSetterDefinition result = new GetterSetterDefinition(); + result.getterBodyCriterion = getterBodyCriterion; + result.getterNameCriterion = getterNameCriterion; + result.setterBodyCriterion = setterBodyCriterion; + result.setterNameCriterion = setterNameCriterion; + return result; + } + + public JPanel getGSDefinitionPanel() { + final JPanel gsdPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1.0d; + constraints.weighty = 0.0d; + constraints.gridx = constraints.gridy = 0; + constraints.insets = new Insets(5, 5, 0, 5); + { + JPanel getterPanel = new JPanel(new GridBagLayout()); + final Border getterBorder = BorderFactory.createEtchedBorder(); + final TitledBorder titledBorder = BorderFactory.createTitledBorder(getterBorder, "Getter definition"); + getterPanel.setBorder(titledBorder); + final GridBagConstraints gc = new GridBagConstraints(); + gc.gridwidth = 1; + gc.gridheight = 1; + gc.anchor = GridBagConstraints.WEST; + gc.fill = GridBagConstraints.BOTH; + gc.weightx = 0; + gc.weighty = 0; + gc.gridx = gc.gridy = 0; + JLabel methodBodyLabel = new JLabel("Method body:"); + getterPanel.add(methodBodyLabel, gc); + gc.gridx++; + gc.gridwidth = GridBagConstraints.REMAINDER; + gc.weightx = 1.0; + final JComboBox getterBodyBox = new JComboBox( + new Object[]{ + "Contains \"return ;\" only", + "Contains one return statement only", + "Ignore body" + } + ); + JLabel methodNameLabel = new JLabel("Method name:"); + final JComboBox getterNameBox = new JComboBox( + new Object[]{ + "Has prefix plus correct field name", + "Has \"get/is/has\" prefix", + } + ); + getterPanel.add(getterBodyBox, gc); + gc.gridy++; + getterBodyBox.setSelectedIndex(getterBodyCriterion); + getterBodyBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + getterBodyCriterion = getterBodyBox.getSelectedIndex(); + if (getterBodyCriterion == GETTER_BODY_RETURNS_FIELD && + getterNameCriterion != GETTER_NAME_MATCHES_FIELD) + { + getterNameBox.setSelectedIndex(getterNameCriterion = GETTER_NAME_MATCHES_FIELD); + } + if (getterBodyCriterion != GETTER_BODY_RETURNS_FIELD && + getterNameCriterion != GETTER_NAME_CORRECT_PREFIX) + { + getterNameBox.setSelectedIndex(getterNameCriterion = GETTER_NAME_CORRECT_PREFIX); + } + } + } + ); + gc.weightx = 0; + gc.gridx = 0; + gc.gridwidth = 1; + getterPanel.add(methodNameLabel, gc); + gc.gridx++; + gc.gridwidth = GridBagConstraints.REMAINDER; + gc.weightx = 1.0; + getterNameBox.setSelectedIndex(getterNameCriterion); + getterPanel.add(getterNameBox, gc); + gc.gridy++; + getterNameBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + getterNameCriterion = getterNameBox.getSelectedIndex(); + if (getterNameCriterion == GETTER_NAME_MATCHES_FIELD && + getterBodyCriterion != GETTER_BODY_RETURNS_FIELD) + { + getterBodyBox.setSelectedIndex(getterBodyCriterion = GETTER_BODY_RETURNS_FIELD); + } + if (getterNameCriterion == GETTER_NAME_CORRECT_PREFIX && + getterBodyCriterion == GETTER_BODY_RETURNS_FIELD) + { + getterBodyBox.setSelectedIndex(getterBodyCriterion = GETTER_BODY_RETURNS); + } + } + } + ); + gsdPanel.add(getterPanel, constraints); + } + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.weighty = 1; + { + JPanel setterPanel = new JPanel(new GridBagLayout()); + final Border setterBorder = BorderFactory.createEtchedBorder(); + final TitledBorder titledBorder = BorderFactory.createTitledBorder(setterBorder, "Setter definition"); + setterPanel.setBorder(titledBorder); + final GridBagConstraints gc = new GridBagConstraints(); + gc.gridwidth = 1; + gc.gridheight = 1; + gc.anchor = GridBagConstraints.WEST; + gc.fill = GridBagConstraints.BOTH; + gc.weightx = 0; + gc.weighty = 0; + gc.gridx = gc.gridy = 0; + JLabel methodBodyLabel = new JLabel("Method body:"); + setterPanel.add(methodBodyLabel, gc); + gc.gridx++; + gc.gridwidth = GridBagConstraints.REMAINDER; + gc.weightx = 1.0; + final JComboBox setterBodyBox = new JComboBox( + new Object[]{ + "Contains one assignment statement \" = ;\" only", + "Ignore body"} + ); + final JComboBox setterNameBox = new JComboBox( + new Object[]{ + "Has prefix plus correct field name", + "Has \"set\" prefix", + } + ); + setterPanel.add(setterBodyBox, gc); + gc.gridy++; + setterBodyBox.setSelectedIndex(setterBodyCriterion); + setterBodyBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + setterBodyCriterion = setterBodyBox.getSelectedIndex(); + if (setterBodyCriterion == SETTER_BODY_IMMATERIAL && + setterNameCriterion != SETTER_NAME_CORRECT_PREFIX) + { + setterNameBox.setSelectedIndex(setterNameCriterion = SETTER_NAME_CORRECT_PREFIX); + } + if (setterBodyCriterion == SETTER_BODY_SETS_FIELD && + setterNameCriterion != SETTER_NAME_MATCHES_FIELD) + { + setterNameBox.setSelectedIndex(setterNameCriterion = SETTER_NAME_MATCHES_FIELD); + } + } + } + ); + gc.weightx = 0; + gc.gridx = 0; + gc.gridwidth = 1; + JLabel methodNameLabel = new JLabel("Method name:"); + setterPanel.add(methodNameLabel, gc); + gc.gridx++; + gc.gridwidth = GridBagConstraints.REMAINDER; + gc.weightx = 1.0; + setterPanel.add(setterNameBox, gc); + setterNameBox.setSelectedIndex(setterNameCriterion); + gsdPanel.add(setterPanel, constraints); + setterNameBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + setterNameCriterion = setterNameBox.getSelectedIndex(); + if (setterNameCriterion == SETTER_NAME_CORRECT_PREFIX && + setterBodyCriterion != SETTER_BODY_IMMATERIAL) + { + setterBodyBox.setSelectedIndex(setterBodyCriterion = SETTER_BODY_IMMATERIAL); + } + if (setterNameCriterion == SETTER_NAME_MATCHES_FIELD && + setterBodyCriterion != SETTER_BODY_SETS_FIELD) + { + setterBodyBox.setSelectedIndex(setterBodyCriterion = SETTER_BODY_SETS_FIELD); + } + } + } + ); + } + return gsdPanel; + } + + public final void writeExternal(final Element items) { + appendAttributes(items); + } + + public final void appendAttributes(final Element me) { + final Element stElement = new Element("GetterSetterDefinition"); + me.getChildren().add(stElement); + stElement.setAttribute("getterBody", "" + getterBodyCriterion); + stElement.setAttribute("getterName", "" + getterNameCriterion); + stElement.setAttribute("setterBody", "" + setterBodyCriterion); + stElement.setAttribute("setterName", "" + setterNameCriterion); + } +} \ No newline at end of file diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java new file mode 100644 index 000000000000..0d6f759ea2de --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.HeaderTrailerRuleInstance; +import com.wrq.rearranger.ruleinstance.IRuleInstance; + +import java.util.ArrayList; +import java.util.List; + +/** A rule to match header text (text which does not constitute a matchable item such as a field or method.) */ +public class HeaderRule + implements IRule +{ + public IRuleInstance createRuleInstance() { + return new HeaderTrailerRuleInstance(this); + } + + public int getPriority() { + return -1; // priority doesn't matter since header rules only match the one header entry (if it exists), and + // the header entry is never matched by another rule. + } + + public void setPriority(int priority) { + // does nothing + } + + public boolean isMatch(RangeEntry rangeEntry) { + return rangeEntry.isFixedHeader(); + } + + public boolean commentsMatchGlobalPattern(String pattern) { + return true; + } + + public List getOffendingPatterns(String pattern) { + return new ArrayList(1); + } + + public int getCommentCount() { + return 0; + } + + public void addCommentPatternsToList(List list) { + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IHasGetterSetterDefinition.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IHasGetterSetterDefinition.java new file mode 100644 index 000000000000..b6a70f0f0f15 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IHasGetterSetterDefinition.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +/** + * Marker interface for rules that have unique getter/setter definitions. Currently this is only the MethodAttributes + * rule. + */ +public interface IHasGetterSetterDefinition { + public GetterSetterDefinition getGetterSetterDefinition(); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IPrioritizableRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IPrioritizableRule.java new file mode 100644 index 000000000000..29668d76448f --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IPrioritizableRule.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +/** + * Marker interface for rules which have a user-assignable priority. This excludes comment rules, and invisible + * header and trailer rules. + */ +public interface IPrioritizableRule { +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRestrictMethodExtraction.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRestrictMethodExtraction.java new file mode 100644 index 000000000000..32f4016a3245 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRestrictMethodExtraction.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +/** + * Interface implemented by rules which can prevent extracted methods being grouped with the + * calling method, in spite of the global setting. + */ +public interface IRestrictMethodExtraction { + public boolean isNoExtractedMethods(); + + public void setNoExtractedMethods(boolean noExtractedMethods); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRule.java new file mode 100644 index 000000000000..c6ff7952e6b8 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRule.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.IRuleInstance; + +import java.util.List; + +/** Interface which all rules implement. */ +public interface IRule { + IRuleInstance createRuleInstance(); + + // all rules have a priority; but some are not settable by the user. Those that are user settable implement + // the marker interface IPrioritizableRule. + int getPriority(); + + void setPriority(int priority); + + boolean isMatch(RangeEntry rangeEntry); + + /** + * @param pattern global pattern to which all comments should conform. + * @return true if all comments associated with this rule match the pattern. + */ + boolean commentsMatchGlobalPattern(String pattern); + + /** + * @param pattern global pattern to which all comments should conform. + * @return list of comments which fail to match the pattern. + */ + List getOffendingPatterns(String pattern); + + /** @return the number of comments associated with this rule. */ + int getCommentCount(); + + /** + * Calculates a list of regular expression patterns, one for each comment that the rule might create, which + * will match any comment that the rule might generate. These can be combined to form a global comment pattern + * which will match all possible generated comments from all rules. These patterns will be appended + * to the supplied list. + */ + void addCommentPatternsToList(List list); +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InnerClassAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InnerClassAttributes.java new file mode 100644 index 000000000000..80ebd47b7766 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InnerClassAttributes.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiJavaToken; +import com.wrq.rearranger.ModifierConstants; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.settings.atomicAttributes.AbstractAttribute; +import com.wrq.rearranger.settings.atomicAttributes.EnumAttribute; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; + +/** Routines to handle inner class modifiers not already covered by ItemAttributes. */ +public final class InnerClassAttributes + extends ItemAttributes +{ + +// ------------------------------ FIELDS ------------------------------ + + private AbstractAttribute abAttr; + private EnumAttribute enumAttr; + +// -------------------------- STATIC METHODS -------------------------- + + public static /*InnerClassAttributes*/AttributeGroup readExternal(final Element item) { + final InnerClassAttributes result = new InnerClassAttributes(); + CommonAttributes.readExternal(result, item); + result.abAttr = AbstractAttribute.readExternal(item); + result.enumAttr = EnumAttribute.readExternal(item); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public InnerClassAttributes() { + abAttr = new AbstractAttribute(); + enumAttr = new EnumAttribute(); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + private AbstractAttribute getAbAttr() { + return abAttr; + } + + public EnumAttribute getEnumAttr() { + return enumAttr; + } +// ------------------------ CANONICAL METHODS ------------------------ + + public final String toString() { + final StringBuffer sb = new StringBuffer(70); + sb.append(abAttr.getDescriptiveString()); + sb.append(plAttr.getProtectionLevelString()); + sb.append(stAttr.getDescriptiveString()); + sb.append(fAttr.getDescriptiveString()); + sb.append(enumAttr.getDescriptiveString()); + if (sb.length() == 0) { + sb.append("all inner classes"); + } + else { + sb.append("inner classes"); + } + if (nameAttr.isMatch()) { + sb.append(' '); + sb.append(nameAttr.getDescriptiveString()); + } + sb.append(sortAttr.getDescriptiveString()); + return sb.toString(); + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface AttributeGroup --------------------- + + public final /*InnerClassAttributes*/AttributeGroup deepCopy() { + final InnerClassAttributes result = new InnerClassAttributes(); + deepCopyCommonItems(result); + result.abAttr = (AbstractAttribute)abAttr.deepCopy(); + result.enumAttr = (EnumAttribute)enumAttr.deepCopy(); + return result; + } + + public final void writeExternal(final Element parent) { + final Element me = new Element("InnerClass"); + writeExternalCommonAttributes(me); + abAttr.appendAttributes(me); + enumAttr.appendAttributes(me); + parent.getChildren().add(me); + } + +// -------------------------- OTHER METHODS -------------------------- + + public boolean equals(final Object obj) { + if (!(obj instanceof InnerClassAttributes)) { + return false; + } + final InnerClassAttributes ica = (InnerClassAttributes)obj; + return super.equals(ica) && + abAttr.equals(ica.abAttr) && + enumAttr.equals(ica.enumAttr); + } + + public JPanel getInnerClassAttributes() { + final JPanel caPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + caPanel.setBorder(border); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.weightx = 1.0d; + constraints.weighty = 0.0d; + constraints.gridx = constraints.gridy = 0; + constraints.insets = new Insets(0, 0, 5, 0); + caPanel.add(getPlAttr().getProtectionLevelPanel(), constraints); + constraints.gridy = 1; + constraints.gridheight = 1; + caPanel.add(getStAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getAbAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getfAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getEnumAttr().getAndNotPanel(), constraints); + constraints.gridy++; + caPanel.add(getNameAttr().getStringPanel(), constraints); + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.weighty = 1.0d; + constraints.insets = new Insets(0, 0, 0, 0); + caPanel.add(sortAttr.getSortOptionsPanel(), constraints); + return caPanel; + } + + public final boolean isMatch(RangeEntry entry) { +// return entry.getEnd() instanceof PsiClass && + // entry.getEnd() should be the LBrace of a class. + return entry.getEnd().getParent() instanceof PsiClass && + ((entry.getModifiers() & ModifierConstants.ENUM) != 0) || + (entry.getEnd() instanceof PsiJavaToken && + // ((PsiJavaToken)entry.getEnd()).getTokenType() == PsiJavaToken.LBRACE && + entry.getEnd().getText().equals("{")) && + super.isMatch(entry) && + abAttr.isMatch(entry.getModifiers()) && + enumAttr.isMatch(entry.getModifiers()); + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java new file mode 100644 index 000000000000..78eb7e4ca1bd --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.entry.MethodEntry; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.InterfaceRuleInstance; +import com.wrq.rearranger.settings.CommentFillString; +import com.wrq.rearranger.settings.CommentRule; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.atomicAttributes.NameAttribute; +import com.wrq.rearranger.util.Constraints; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.TitledBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +/** Rule and attributes to support grouping of methods that implement interface methods. */ +public class InterfaceAttributes + implements AttributeGroup, IRestrictMethodExtraction, IPrioritizableRule +{ + private boolean noExtractedMethods; + NameAttribute nameAttr; + boolean alphabetizeInterfaces; + private int priority; + + public static final int METHOD_ORDER_ALPHABETICAL = 0; + public static final int METHOD_ORDER_INTERFACE_ORDER = 1; + public static final int METHOD_ORDER_ENCOUNTERED = 2; + private int methodOrder; + + CommentRule precedingComment; + CommentRule trailingComment; + private CommentFillString commentFillString; + + public InterfaceAttributes() { + nameAttr = new NameAttribute(); + noExtractedMethods = false; + alphabetizeInterfaces = false; + methodOrder = METHOD_ORDER_ENCOUNTERED; + precedingComment = new CommentRule(); + trailingComment = new CommentRule(); + commentFillString = new CommentFillString(); + priority = 1; + } + + public NameAttribute getNameAttr() { + return nameAttr; + } + + public boolean isNoExtractedMethods() { + return noExtractedMethods; + } + + public void setNoExtractedMethods(boolean noExtractedMethods) { + this.noExtractedMethods = noExtractedMethods; + } + + public boolean isAlphabetize() { + return alphabetizeInterfaces; + } + + public void setAlphabetizeInterfaces(boolean alphabetizeInterfaces) { + this.alphabetizeInterfaces = alphabetizeInterfaces; + } + + public CommentRule getTrailingComment() { + return trailingComment; + } + + public void setTrailingComment(CommentRule trailingComment) { + this.trailingComment = trailingComment; + } + + public final String getExpandedTrailingCommentText() { + return commentFillString.getExpandedCommentText(trailingComment.getCommentText()); + } + + public CommentRule getPrecedingComment() { + return precedingComment; + } + + public void setPrecedingComment(CommentRule precedingComment) { + this.precedingComment = precedingComment; + } + + public final String getExpandedPrecedingCommentText() { + return commentFillString.getExpandedCommentText(precedingComment.getCommentText()); + } + + public CommentFillString getCommentFillString() { + return commentFillString; + } + + public int getMethodOrder() { + return methodOrder; + } + + public void setMethodOrder(int methodOrder) { + this.methodOrder = methodOrder; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public int getPriority() { + return priority; + } + + public IRuleInstance createRuleInstance() { + return new InterfaceRuleInstance(this); + } + + public final boolean isMatch(RangeEntry rangeEntry) { + if (rangeEntry instanceof MethodEntry) { + MethodEntry me = (MethodEntry)rangeEntry; + if (me.getInterfaceName() != null) { + return nameAttr.isMatch(me.getInterfaceName()); + } + } + return false; + } + + public boolean equals(final Object obj) { + if (!(obj instanceof InterfaceAttributes)) return false; + final InterfaceAttributes ia = (InterfaceAttributes)obj; + return nameAttr.equals(ia.getNameAttr()) && + alphabetizeInterfaces == ia.alphabetizeInterfaces && + methodOrder == ia.methodOrder && + noExtractedMethods == ia.noExtractedMethods && + precedingComment.equals(ia.precedingComment) && + trailingComment.equals(ia.trailingComment) && + commentFillString.equals(ia.commentFillString); + } + + public final String toString() { + // convert settings to readable English description of the method. + // + final StringBuffer sb = new StringBuffer(80); + + sb.append("Methods implementing interfaces"); + + if (nameAttr.isMatch()) { + sb.append(' '); + sb.append(nameAttr.getDescriptiveString()); + } + + if (alphabetizeInterfaces) { + sb.append(" (interfaces alphabetized)"); + } + if (noExtractedMethods) { + sb.append(" (no extracted methods)"); + } + if (precedingComment.getCommentText().length() != 0) { + sb.append(" Preceding "); + sb.append(precedingComment.getDescriptiveString()); + } + if (trailingComment.getCommentText().length() != 0) { + sb.append(" Trailing "); + sb.append(trailingComment.getDescriptiveString()); + } + return sb.toString(); + } + + public final /*InterfaceAttributes*/AttributeGroup deepCopy() { + final InterfaceAttributes result = new InterfaceAttributes(); + result.nameAttr = (NameAttribute)nameAttr.deepCopy(); + result.alphabetizeInterfaces = alphabetizeInterfaces; + result.noExtractedMethods = noExtractedMethods; + result.methodOrder = methodOrder; + result.precedingComment = (CommentRule)precedingComment.deepCopy(); + result.trailingComment = (CommentRule)trailingComment.deepCopy(); + result.commentFillString = commentFillString.deepCopy(); + result.priority = priority; + return result; + } + + public static /*InterfaceAttributes*/AttributeGroup readExternal(final Element item) { + final InterfaceAttributes result = new InterfaceAttributes(); + result.loadAttributes(item); + return result; + } + + public void loadAttributes(final Element item) { + nameAttr = NameAttribute.readExternal(item); + alphabetizeInterfaces = RearrangerSettings.getBooleanAttribute(item, "alphabetizeInterfaces"); + noExtractedMethods = RearrangerSettings.getBooleanAttribute(item, "noExtractedMethods"); + methodOrder = RearrangerSettings.getIntAttribute(item, "methodOrder", METHOD_ORDER_ENCOUNTERED); + Element prc = item.getChild("PrecedingComment"); + if (prc != null) prc = prc.getChild("Comment"); + precedingComment = CommentRule.readExternal(prc); + Element trc = item.getChild("TrailingComment"); + if (trc != null) trc = trc.getChild("Comment"); + trailingComment = CommentRule.readExternal(trc); + commentFillString = CommentFillString.readExternal(item); + priority = RearrangerSettings.getIntAttribute(item, "priority", 1); + } + + public final void writeExternal(final Element parent) { + final Element me = new Element("Interface"); + parent.getChildren().add(me); + nameAttr.appendAttributes(me); + me.setAttribute("alphabetizeInterfaces", Boolean.valueOf(alphabetizeInterfaces).toString()); + me.setAttribute("noExtractedMethods", Boolean.valueOf(noExtractedMethods).toString()); + me.setAttribute("methodOrder", "" + methodOrder); + me.setAttribute("priority", "" + priority); + Element prc = new Element("PrecedingComment"); + Element trc = new Element("TrailingComment"); + me.getChildren().add(prc); + me.getChildren().add(trc); + precedingComment.writeExternal(prc); + trailingComment.writeExternal(trc); + commentFillString.writeExternal(me); + } + + public JPanel getInterfaceAttributes() { + final JPanel interfacePanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + Border titleBorder = BorderFactory.createTitledBorder(border, "Match methods implementing interfaces"); + interfacePanel.setBorder(titleBorder); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.insets = new Insets(5, 0, 0, 0); + interfacePanel.add(getNameAttr().getStringPanel(), constraints.weightedLastCol()); + constraints.newRow(); + interfacePanel.add(getAlphabetizePanel(), constraints.weightedLastCol()); + constraints.weightedNewRow(); + interfacePanel.add(getCommentPanel(), constraints.weightedLastCol()); + constraints.newRow(); + interfacePanel.add(getExcludePanel(), constraints.weightedLastCol()); + constraints.lastRow(); + interfacePanel.add(getMethodOrderPanel(), constraints.weightedLastCol()); + return interfacePanel; + } + + public final JPanel getExcludePanel() { + final JPanel excludePanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.lastRow(); + final JCheckBox excludeBox = new JCheckBox("Exclude from extracted method processing"); + excludeBox.setSelected(noExtractedMethods); + excludeBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + noExtractedMethods = excludeBox.isSelected(); + } + } + ); + excludePanel.add(excludeBox, constraints.weightedLastCol()); + return excludePanel; + } + + private final JPanel getAlphabetizePanel() { + final JPanel abPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(); + constraints.weightedLastRow(); + final JCheckBox alphabetizeBox = new JCheckBox("Alphabetize Interfaces"); + abPanel.add(alphabetizeBox, constraints.weightedLastCol()); + alphabetizeBox.setSelected(isAlphabetize()); + alphabetizeBox.addActionListener( + new ActionListener() { + public void actionPerformed(final ActionEvent e) { + alphabetizeInterfaces = alphabetizeBox.isSelected(); + } + } + ); + return abPanel; + } + + private JPanel getMethodOrderPanel() { + JPanel orderPanel = new JPanel(new GridBagLayout()); + Constraints constraints = new Constraints(); + constraints.weightedLastRow(); + constraints.fill = GridBagConstraints.BOTH; + constraints.insets = new Insets(0, 5, 0, 0); + JLabel orderLabel = new JLabel("Order methods"); + orderPanel.add(orderLabel, constraints.firstCol()); + final JComboBox orderBox = new JComboBox( + new String[]{ + "Alphabetically", + "In order declared in interface", + "In order encountered" + } + ); + orderBox.setSelectedIndex(methodOrder); + orderPanel.add(orderBox, constraints.weightedLastCol()); + orderBox.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + methodOrder = orderBox.getSelectedIndex(); + } + } + ); + return orderPanel; + } + + private JPanel getCommentPanel() { + JPanel commentPanel = new JPanel(new GridBagLayout()); + Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + Border b = BorderFactory.createEtchedBorder(); + TitledBorder t = BorderFactory.createTitledBorder(b, "Comments"); + commentPanel.setBorder(t); + constraints.fill = GridBagConstraints.BOTH; + + JLabel legendLabel = new JLabel("Comment Substitutions: use %IF% for interface name"); + JLabel precedingCommentLabel = new JLabel("Preceding Comment:"); + JLabel trailingCommentLabel = new JLabel("Trailing Comment:"); + JPanel precedingCommentPanel = getCommentAreaPanel(getPrecedingComment()); + JPanel trailingCommentPanel = getCommentAreaPanel(getTrailingComment()); + JPanel legendPanel = new JPanel(new GridBagLayout()); + Border border = BorderFactory.createEtchedBorder(); + legendPanel.setBorder(border); + constraints.insets = new Insets(5, 5, 5, 5); + constraints.gridwidth = GridBagConstraints.REMAINDER; + legendPanel.add(legendLabel, constraints.lastCol()); + constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.insets = new Insets(5, 5, 0, 5); + commentPanel.add(legendPanel, constraints.weightedLastCol()); + constraints.newRow(); + commentPanel.add(precedingCommentLabel, constraints.weightedLastCol()); + constraints.weightedNewRow(0.50d); + commentPanel.add(precedingCommentPanel, constraints.weightedLastCol()); + constraints.newRow(); + commentPanel.add(trailingCommentLabel, constraints.weightedLastCol()); + constraints.weightedNewRow(0.50d); + constraints.insets = new Insets(5, 5, 5, 5); + commentPanel.add(trailingCommentPanel, constraints.weightedLastCol()); + constraints.lastRow(); + constraints.insets = new Insets(5, 5, 0, 5); + commentPanel.add(commentFillString.getCommentFillStringPanel(), constraints.weightedLastCol()); + return commentPanel; + } + + private JPanel getCommentAreaPanel(final CommentRule comment) { + JPanel commentPanel = new JPanel(new GridBagLayout()); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + final JTextArea commentArea = new JTextArea(4, 40); + commentArea.setText(comment.getCommentText()); + final JScrollPane scrollPane = new JScrollPane(commentArea); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + commentPanel.add(scrollPane, constraints.weightedLastCol()); + commentArea.getDocument().addDocumentListener( + new DocumentListener() { + public void changedUpdate(final DocumentEvent e) { + comment.setCommentText(commentArea.getText()); + } + + public void insertUpdate(final DocumentEvent e) { + comment.setCommentText(commentArea.getText()); + } + + public void removeUpdate(final DocumentEvent e) { + comment.setCommentText(commentArea.getText()); + } + } + ); + return commentPanel; + } + + public boolean commentsMatchGlobalPattern(String pattern) { + return getOffendingPatterns(pattern).size() == 0; + } + + public List getOffendingPatterns(String pattern) { + List result = new ArrayList(2); + if (precedingComment != null && + precedingComment.getCommentText() != null && + precedingComment.getCommentText().length() > 0) + { + final String expandedComment = precedingComment.getCommentText().replaceAll( + "%IF%", "Interface_ExampleName0" + ); + if (!expandedComment.matches(pattern)) { + result.add(((java.lang.String)precedingComment.getCommentText())); + } + } + if (trailingComment != null && + trailingComment.getCommentText() != null && + trailingComment.getCommentText().length() > 0) + { + final String expandedComment = trailingComment.getCommentText().replaceAll( + "%IF%", "Interface_ExampleName0" + ); + if (!expandedComment.matches(pattern)) { + result.add(((java.lang.String)trailingComment.getCommentText())); + } + } + return result; + } + + public int getCommentCount() { + int count = 0; + if (precedingComment != null && + precedingComment.getCommentText() != null && + precedingComment.getCommentText().length() > 0) + { + count++; + } + if (trailingComment != null && + trailingComment.getCommentText() != null && + trailingComment.getCommentText().length() > 0) + { + count++; + } + return count; + } + + public void addCommentPatternsToList(List list) { + if (precedingComment != null) { + addInterfaceCommentPatternToList(list, precedingComment.getCommentText()); + } + if (trailingComment != null) { + addInterfaceCommentPatternToList(list, trailingComment.getCommentText()); + } + } + + private void addInterfaceCommentPatternToList(List list, String commentText) { + if (commentText != null && commentText.length() > 0) { + String esc = RegexUtil.escape(commentText); + String fsp = commentFillString.getFillStringPattern(); + esc = esc.replaceAll("%IF%", "[A-Za-z0-9_]+"); + esc = esc.replaceAll("%FS%", fsp); + list.add(esc); + } + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ItemAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ItemAttributes.java new file mode 100644 index 000000000000..369c97c14cea --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/ItemAttributes.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.settings.CommentRule; +import org.jdom.Element; + +/** Routines to handle attributes common to class members (fields, methods, and inner classes.) */ +abstract public class ItemAttributes + extends CommonAttributes +{ + +// -------------------------- STATIC METHODS -------------------------- + + public static AttributeGroup readExternal(final Element element) { + if (element.getName().equals("Field")) { + return FieldAttributes.readExternal(element); + } + else if (element.getName().equals("Method")) { + return MethodAttributes.readExternal(element); + } + else if (element.getName().equals("InnerClass")) { + return InnerClassAttributes.readExternal(element); + } + else if (element.getName().equals("Interface")) { + return InterfaceAttributes.readExternal(element); + } + else if (element.getName().equals("Comment")) { + return CommentRule.readExternal(element); + } + else { + return null; + } + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface AttributeGroup --------------------- + + abstract public /*ItemAttributes*/AttributeGroup deepCopy(); +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributes.java new file mode 100644 index 000000000000..79161877cbf8 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributes.java @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.intellij.psi.PsiClassInitializer; +import com.intellij.psi.PsiMethod; +import com.wrq.rearranger.ModifierConstants; +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.atomicAttributes.*; +import com.wrq.rearranger.util.MethodUtil; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Routines to handle method modifiers other than those supported by CommonAttributes. These are the 'abstract' + * modifier, a type discriminator (constructor, getter/setter, other), and a boolean flag indicating whether the + * method is overridden or not. + */ +public final class MethodAttributes + extends ItemAttributes + implements IRestrictMethodExtraction, + IHasGetterSetterDefinition +{ + +// ------------------------------ FIELDS ------------------------------ + + private AbstractAttribute abstractAttr; + private OverriddenAttribute overriddenAttr; + private OverridingAttribute overridingAttr; + private InitializerAttribute staticInitAttr; + private NativeAttribute nativeAttr; + private SynchronizedAttribute syncAttr; + private ReturnTypeAttribute returnTypeAttr; + private ImplementedAttribute implementedAttr; + private ImplementingAttribute implementingAttr; + private MinParamsAttribute minParamsAttr; + private MaxParamsAttribute maxParamsAttr; + + private boolean constructorMethodType; + private boolean getterSetterMethodType; + private boolean canonicalMethodType; + private boolean otherMethodType; + private boolean invertMethodType; + private boolean noExtractedMethods; + private GetterSetterDefinition getterSetterDefinition; + +// -------------------------- STATIC METHODS -------------------------- + + public static /*MethodAttributes*/AttributeGroup readExternal(final Element item) { + final MethodAttributes result = new MethodAttributes(); + CommonAttributes.readExternal(result, item); + result.abstractAttr = AbstractAttribute.readExternal(item); + result.syncAttr = SynchronizedAttribute.readExternal(item); + result.overriddenAttr = OverriddenAttribute.readExternal(item); + result.overridingAttr = OverridingAttribute.readExternal(item); + result.staticInitAttr = InitializerAttribute.readExternal(item); + result.nativeAttr = NativeAttribute.readExternal(item); + result.returnTypeAttr = ReturnTypeAttribute.readExternal(item); + result.implementedAttr = ImplementedAttribute.readExternal(item); + result.implementingAttr = ImplementingAttribute.readExternal(item); + result.minParamsAttr = MinParamsAttribute.readExternal(item); + result.maxParamsAttr = MaxParamsAttribute.readExternal(item); + final Element me = item.getChild("Misc"); + + result.constructorMethodType = RearrangerSettings.getBooleanAttribute(me, "constructorMethod"); + result.getterSetterMethodType = RearrangerSettings.getBooleanAttribute(me, "getterSetter"); + result.canonicalMethodType = RearrangerSettings.getBooleanAttribute(me, "canonicalMethod"); + result.otherMethodType = RearrangerSettings.getBooleanAttribute(me, "otherMethod"); + result.invertMethodType = RearrangerSettings.getBooleanAttribute(me, "invertMethod"); + result.noExtractedMethods = RearrangerSettings.getBooleanAttribute(me, "noExtractedMethods"); + result.getterSetterDefinition = GetterSetterDefinition.readExternal(item); + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public MethodAttributes() { + init(); + getterSetterDefinition = new GetterSetterDefinition(); + } + + private void init() { + abstractAttr = new AbstractAttribute(); + overriddenAttr = new OverriddenAttribute(); + overridingAttr = new OverridingAttribute(); + staticInitAttr = new InitializerAttribute(); + nativeAttr = new NativeAttribute(); + syncAttr = new SynchronizedAttribute(); + returnTypeAttr = new ReturnTypeAttribute(); + implementedAttr = new ImplementedAttribute(); + implementingAttr = new ImplementingAttribute(); + minParamsAttr = new MinParamsAttribute(); + maxParamsAttr = new MaxParamsAttribute(); + } + + public MethodAttributes(GetterSetterDefinition defaultGetterSetterDefinition) { + init(); + getterSetterDefinition = defaultGetterSetterDefinition.deepCopy(); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public AbstractAttribute getAbstractAttr() { + return abstractAttr; + } + + public final JPanel getExcludePanel() { + final JPanel excludePanel = new JPanel(new GridBagLayout()); +// final Border border = BorderFactory.createEtchedBorder(); +// excludePanel.setBorder(border); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.weightx = 1.0d; + constraints.weighty = 0.0d; + constraints.gridx = constraints.gridy = 0; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = GridBagConstraints.REMAINDER; + final JCheckBox excludeBox = new JCheckBox("Exclude from extracted method processing"); + excludeBox.setSelected(noExtractedMethods); + excludeBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + noExtractedMethods = excludeBox.isSelected(); + } + }); + excludePanel.add(excludeBox, constraints); + return excludePanel; + } + + public GetterSetterDefinition getGetterSetterDefinition() { + return getterSetterDefinition; + } + + private NativeAttribute getNativeAttr() { + return nativeAttr; + } + + private OverriddenAttribute getOverriddenAttr() { + return overriddenAttr; + } + + private OverridingAttribute getOverridingAttr() { + return overridingAttr; + } + + public ReturnTypeAttribute getReturnTypeAttr() { + return returnTypeAttr; + } + + public InitializerAttribute getStaticInitAttr() { + return staticInitAttr; + } + + private SynchronizedAttribute getSyncAttr() { + return syncAttr; + } + + public ImplementedAttribute getImplementedAttr() { + return implementedAttr; + } + + public ImplementingAttribute getImplementingAttr() { + return implementingAttr; + } + + public MinParamsAttribute getMinParamsAttr() { + return minParamsAttr; + } + + public MaxParamsAttribute getMaxParamsAttr() { + return maxParamsAttr; + } + + public boolean isCanonicalMethodType() { + return canonicalMethodType; + } + + public void setCanonicalMethodType(boolean canonicalMethodType) { + this.canonicalMethodType = canonicalMethodType; + } + + private boolean isConstructorMethodType() { + return constructorMethodType; + } + + public final void setConstructorMethodType(final boolean constructorMethodType) { + this.constructorMethodType = constructorMethodType; + } + + private boolean isGetterSetterMethodType() { + return getterSetterMethodType; + } + + public final void setGetterSetterMethodType(final boolean getterSetterMethodType) { + this.getterSetterMethodType = getterSetterMethodType; + } + + private boolean isInvertMethodType() { + return invertMethodType; + } + + public void setInvertMethodType(boolean invertMethodType) { + this.invertMethodType = invertMethodType; + } + + public boolean isNoExtractedMethods() { + return noExtractedMethods; + } + + public void setNoExtractedMethods(boolean noExtractedMethods) { + this.noExtractedMethods = noExtractedMethods; + } + + private boolean isOtherMethodType() { + return otherMethodType; + } + + public final void setOtherMethodType(final boolean otherMethodType) { + this.otherMethodType = otherMethodType; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + private boolean predicateAdded = false; + private String nextPredicate = null; + + public final String toString() { + // convert settings to readable English description of the method. + // + final StringBuffer sb = new StringBuffer(80); + + sb.append(plAttr.getProtectionLevelString()); + sb.append(stAttr.getDescriptiveString()); + sb.append(fAttr.getDescriptiveString()); + sb.append(staticInitAttr.getDescriptiveString()); + sb.append(nativeAttr.getDescriptiveString()); + sb.append(syncAttr.getDescriptiveString()); + + final int nTypes = (isConstructorMethodType() ? 1 : 0) + + (isGetterSetterMethodType() ? 1 : 0) + + (isCanonicalMethodType() ? 1 : 0) + + (isOtherMethodType() ? 1 : 0); + + int nTypesSeen = 0; + if (isConstructorMethodType()) { + sb.append(isInvertMethodType() ? "non-constructor" : "constructor"); + nTypesSeen++; + if (nTypesSeen < nTypes) { + sb.append("/"); + } + } + if (isGetterSetterMethodType()) { + sb.append(isInvertMethodType() ? "non-getter/setter" : "getter/setter"); + nTypesSeen++; + if (nTypesSeen < nTypes) { + sb.append("/"); + } + } + if (isCanonicalMethodType()) { + sb.append(isInvertMethodType() ? "non-canonical" : "canonical"); + nTypesSeen++; + if (nTypesSeen < nTypes) { + sb.append("/"); + } + } + if (isOtherMethodType()) { + sb.append(isInvertMethodType() ? "non-other-type" : "other"); + nTypesSeen++; + if (nTypesSeen < nTypes) { + sb.append("/"); + } + } + if (nTypes > 0) { + sb.append(' '); + } + sb.append(abstractAttr.getDescriptiveString()); + sb.append(overriddenAttr.getDescriptiveString()); + sb.append(overridingAttr.getDescriptiveString()); + sb.append(implementedAttr.getDescriptiveString()); + sb.append(implementingAttr.getDescriptiveString()); + + if (sb.length() == 0) { + sb.append("all methods"); + } + else { + sb.append("methods"); + } + predicateAdded = false; + nextPredicate = null; + if (minParamsAttr.isMatch() || maxParamsAttr.isMatch()) { + if (!maxParamsAttr.isMatch()) { + nextPredicate = minParamsAttr.getDescriptiveString(); + } + else if (!minParamsAttr.isMatch()) { + nextPredicate = maxParamsAttr.getDescriptiveString(); + } + else { + if (minParamsAttr.getValue() == maxParamsAttr.getValue()) { + nextPredicate = "with " + minParamsAttr.getValue() + + (minParamsAttr.getValue() == 1 + ? " parameter" + : " parameters"); + } + else { + nextPredicate = "with " + minParamsAttr.getValue() + " to " + + maxParamsAttr.getValue() + " parameters"; + } + } + } + if (nameAttr.isMatch()) { + checkPredicate(sb, false); + nextPredicate = nameAttr.getDescriptiveString(); + } + if (returnTypeAttr.isMatch()) { + checkPredicate(sb, false); + nextPredicate = returnTypeAttr.getDescriptiveString(); + } + checkPredicate(sb, true); + sb.append(sortAttr.getDescriptiveString()); + if (noExtractedMethods) { + sb.append(" (no extracted methods)"); + } + return sb.toString(); + } + + private void checkPredicate(StringBuffer sb, boolean finalPredicate) { + if (predicateAdded && nextPredicate != null) { + sb.append(','); + if (finalPredicate) { + sb.append(" and"); + } + } + if (nextPredicate != null) { + sb.append(' '); + sb.append(nextPredicate); + predicateAdded = true; + nextPredicate = null; + } + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface AttributeGroup --------------------- + + // Start Methods of Interface AttributeGroup + public final /*ItemAttributes*/AttributeGroup deepCopy() { + final MethodAttributes result = new MethodAttributes(); + deepCopyCommonItems(result); + result.abstractAttr = (AbstractAttribute)abstractAttr.deepCopy(); + result.nativeAttr = (NativeAttribute)nativeAttr.deepCopy(); + result.syncAttr = (SynchronizedAttribute)syncAttr.deepCopy(); + result.constructorMethodType = constructorMethodType; + result.getterSetterMethodType = getterSetterMethodType; + result.canonicalMethodType = canonicalMethodType; + result.otherMethodType = otherMethodType; + result.invertMethodType = invertMethodType; + result.overriddenAttr = (OverriddenAttribute)overriddenAttr.deepCopy(); + result.overridingAttr = (OverridingAttribute)overridingAttr.deepCopy(); + result.implementedAttr = (ImplementedAttribute)implementedAttr.deepCopy(); + result.implementingAttr = (ImplementingAttribute)implementingAttr.deepCopy(); + result.staticInitAttr = (InitializerAttribute)staticInitAttr.deepCopy(); + result.returnTypeAttr = (ReturnTypeAttribute)returnTypeAttr.deepCopy(); + result.minParamsAttr = (MinParamsAttribute)minParamsAttr.deepCopy(); + result.maxParamsAttr = (MaxParamsAttribute)maxParamsAttr.deepCopy(); + result.noExtractedMethods = noExtractedMethods; + result.getterSetterDefinition = getterSetterDefinition.deepCopy(); + return result; + } + + public final void writeExternal(final Element parent) { + final Element me = new Element("Method"); + writeExternalCommonAttributes(me); + abstractAttr.appendAttributes(me); + nativeAttr.appendAttributes(me); + syncAttr.appendAttributes(me); + overriddenAttr.appendAttributes(me); + overridingAttr.appendAttributes(me); + implementedAttr.appendAttributes(me); + implementingAttr.appendAttributes(me); + staticInitAttr.appendAttributes(me); + returnTypeAttr.appendAttributes(me); + minParamsAttr.appendAttributes(me); + maxParamsAttr.appendAttributes(me); + final Element miscElement = new Element("Misc"); + me.getChildren().add(miscElement); + miscElement.setAttribute("constructorMethod", Boolean.valueOf(constructorMethodType).toString()); + miscElement.setAttribute("getterSetter", Boolean.valueOf(getterSetterMethodType).toString()); + miscElement.setAttribute("canonicalMethod", Boolean.valueOf(canonicalMethodType).toString()); + miscElement.setAttribute("otherMethod", Boolean.valueOf(otherMethodType).toString()); + miscElement.setAttribute("invertMethod", Boolean.valueOf(invertMethodType).toString()); + miscElement.setAttribute("noExtractedMethods", Boolean.valueOf(noExtractedMethods).toString()); + getterSetterDefinition.appendAttributes(me); + parent.getChildren().add(me); + } + +// -------------------------- OTHER METHODS -------------------------- + + public boolean equals(final Object object) { + if (!(object instanceof MethodAttributes)) return false; + final MethodAttributes ma = (MethodAttributes)object; + return (super.equals(object) && + abstractAttr.equals(ma.abstractAttr) && + overriddenAttr.equals(ma.overriddenAttr) && + overridingAttr.equals(ma.overridingAttr) && + implementedAttr.equals(ma.implementedAttr) && + implementingAttr.equals(ma.implementingAttr) && + staticInitAttr.equals(ma.staticInitAttr) && + nativeAttr.equals(ma.nativeAttr) && + syncAttr.equals(ma.syncAttr) && + returnTypeAttr.equals(ma.returnTypeAttr) && + minParamsAttr.equals(ma.minParamsAttr) && + maxParamsAttr.equals(ma.maxParamsAttr) && + isConstructorMethodType() == ma.isConstructorMethodType() && + isGetterSetterMethodType() == ma.isGetterSetterMethodType() && + isCanonicalMethodType() == ma.isCanonicalMethodType() && + isOtherMethodType() == ma.isOtherMethodType() && + invertMethodType == ma.invertMethodType && + noExtractedMethods == ma.noExtractedMethods && + getterSetterDefinition.equals(ma.getterSetterDefinition)); + } + +// End Methods of Interface IRule + + public JPanel getMethodAttributes() { + final JPanel methodPanel = new JPanel(new GridBagLayout()); + final Border border = BorderFactory.createEtchedBorder(); + methodPanel.setBorder(border); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0.0d; + constraints.weighty = 0.0d; + constraints.gridx = constraints.gridy = 0; + methodPanel.add(getPlAttr().getProtectionLevelPanel(), constraints); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.gridx = 1; + constraints.weightx = 1; + methodPanel.add(getMethodTypePanel(), constraints); + constraints.gridy = 1; + constraints.insets = new Insets(5, 0, 0, 0); + constraints.gridx = 0; + constraints.gridheight = 1; + constraints.gridwidth = 1; + methodPanel.add(getStAttr().getAndNotPanel(), constraints); + constraints.gridx++; + methodPanel.add(getAbstractAttr().getAndNotPanel(), constraints); + constraints.gridx = 0; + constraints.gridy++; + methodPanel.add(getfAttr().getAndNotPanel(), constraints); + constraints.gridx++; + methodPanel.add(getSyncAttr().getAndNotPanel(), constraints); + constraints.gridx = 0; + constraints.gridy++; + methodPanel.add(getOverriddenAttr().getAndNotPanel(), constraints); + constraints.gridx++; + methodPanel.add(getOverridingAttr().getAndNotPanel(), constraints); + constraints.gridx = 0; + constraints.gridy++; + methodPanel.add(getImplementedAttr().getAndNotPanel(), constraints); + constraints.gridx++; + methodPanel.add(getImplementingAttr().getAndNotPanel(), constraints); + constraints.gridx = 0; + constraints.gridy++; + methodPanel.add(getStaticInitAttr().getAndNotPanel(), constraints); + constraints.gridx++; + methodPanel.add(getNativeAttr().getAndNotPanel(), constraints); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 0; + constraints.gridy++; + methodPanel.add(getMinParamsAttr().getIntegerPanel(), constraints); + constraints.gridy++; + methodPanel.add(getMaxParamsAttr().getIntegerPanel(), constraints); + constraints.gridy++; + methodPanel.add(getNameAttr().getStringPanel(), constraints); + constraints.gridy++; + methodPanel.add(getReturnTypeAttr().getStringPanel(), constraints); + constraints.gridy++; + constraints.insets = new Insets(0, 0, 0, 0); + methodPanel.add(getExcludePanel(), constraints); + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.weighty = 1.0d; + methodPanel.add(sortAttr.getSortOptionsPanel(), constraints); + return methodPanel; + } + + private JPanel getMethodTypePanel() { + final JPanel mtPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.BOTH; + constraints.gridwidth = 1; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.anchor = GridBagConstraints.WEST; + constraints.weightx = 0.0d; + constraints.weighty = 1.0d; + constraints.gridx = constraints.gridy = 0; + final JCheckBox notBox = new JCheckBox("not"); + notBox.setSelected(isInvertMethodType()); + notBox.setForeground(notBox.isSelected() ? Color.BLACK : Color.GRAY); + mtPanel.add(notBox, constraints); + constraints.gridx++; + constraints.weightx = 1.0d; + constraints.gridwidth = GridBagConstraints.REMAINDER; + mtPanel.add(getMethodTypeInnerPanel(), constraints); + notBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setInvertMethodType(notBox.isSelected()); + notBox.setForeground(notBox.isSelected() ? Color.BLACK : Color.GRAY); + } + }); + + return mtPanel; + } + + private JPanel getMethodTypeInnerPanel() { + final JPanel mtPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + constraints.weightx = 1.0d; + constraints.weighty = 0.0d; + constraints.gridx = constraints.gridy = 0; + final JCheckBox constructorBox = new JCheckBox("constructor or"); + constructorBox.setSelected(isConstructorMethodType()); + final JCheckBox getterSetterBox = new JCheckBox(); + final JButton gsDefButton = new JButton("getter/setter"); + final JLabel gsOrLabel = new JLabel(" or"); + getterSetterBox.setSelected(isGetterSetterMethodType()); + final JCheckBox canonicalBox = new JCheckBox("canonical or"); + canonicalBox.setSelected(isCanonicalMethodType()); + final JCheckBox otherTypeBox = new JCheckBox("other type"); + otherTypeBox.setSelected(isOtherMethodType()); + mtPanel.add(constructorBox, constraints); + constraints.gridy++; + constraints.weightx = 0; + constraints.gridwidth = 1; + mtPanel.add(getterSetterBox, constraints); + constraints.gridx++; + mtPanel.add(gsDefButton, constraints); + constraints.gridx++; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1; + mtPanel.add(gsOrLabel, constraints); + constraints.gridx = 0; + constraints.gridy++; + mtPanel.add(canonicalBox, constraints); + constraints.gridy++; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.weighty = 1.0d; + mtPanel.add(otherTypeBox, constraints); + constructorBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setConstructorMethodType(constructorBox.isSelected()); + } + }); + getterSetterBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setGetterSetterMethodType(getterSetterBox.isSelected()); + } + }); + canonicalBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setCanonicalMethodType(canonicalBox.isSelected()); + } + }); + otherTypeBox.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + setOtherMethodType(otherTypeBox.isSelected()); + } + }); + gsDefButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + GetterSetterDefinition tempgsd = getterSetterDefinition.deepCopy(); + final JPanel gsDefPanel = tempgsd.getGSDefinitionPanel(); + final JOptionPane op = new JOptionPane( + gsDefPanel, + JOptionPane.PLAIN_MESSAGE, + JOptionPane.OK_CANCEL_OPTION, + null, null, null); + final JDialog jd = op.createDialog(null, "Getter/Setter definition"); + jd.setVisible(true); + final Object result = op.getValue(); + if (result != null && + ((Integer)result) == JOptionPane.OK_OPTION) + { + getterSetterDefinition = tempgsd; + } + } + }); + + return mtPanel; + } + +// End Methods of Interface AttributeGroup +// Start Methods of Interface IRule + + public final boolean isMatch(RangeEntry entry) { + final boolean result = (entry.getEnd() instanceof PsiMethod || + entry.getEnd() instanceof PsiClassInitializer) && + super.isMatch(entry) && + abstractAttr.isMatch(entry.getModifiers()) && + overriddenAttr.isMatch(entry.getModifiers()) && + overridingAttr.isMatch(entry.getModifiers()) && + implementedAttr.isMatch(entry.getModifiers()) && + implementingAttr.isMatch(entry.getModifiers()) && + staticInitAttr.isMatch(entry.getModifiers()) && + nativeAttr.isMatch(entry.getModifiers()) && + syncAttr.isMatch(entry.getModifiers()) && + returnTypeAttr.isMatch(entry.getType()) && + minParamsAttr.isMatch(entry.getEnd()) && + maxParamsAttr.isMatch(entry.getEnd()); + if (result == false) { + return false; + } + boolean typeResult = false; + if (isConstructorMethodType()) { + typeResult |= (entry.getModifiers() & ModifierConstants.CONSTRUCTOR) == ModifierConstants.CONSTRUCTOR; + } + if (isGetterSetterMethodType() && + entry.getEnd() instanceof PsiMethod) + { + /** + * determine if the method is a getter or setter according to this rule's specific + * definition. + */ + boolean isGetter = MethodUtil.isGetter((PsiMethod)entry.getEnd(), + getterSetterDefinition); + boolean isSetter = MethodUtil.isSetter((PsiMethod)entry.getEnd(), + getterSetterDefinition); + typeResult |= isGetter | isSetter; + } + if (isCanonicalMethodType()) { + typeResult |= (entry.getModifiers() & ModifierConstants.CANONICAL) == ModifierConstants.CANONICAL; + } + if (isOtherMethodType()) { + typeResult |= (entry.getModifiers() & ModifierConstants.OTHER_METHOD) == ModifierConstants.OTHER_METHOD; + } + typeResult ^= invertMethodType; + if (!constructorMethodType && + !getterSetterMethodType && + !canonicalMethodType && + !otherMethodType) + { + typeResult = true; // true if no method type options are selected. + } + return result && typeResult; + } +} + diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/RegexUtil.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/RegexUtil.java new file mode 100644 index 000000000000..4ea8f5a0838d --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/RegexUtil.java @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +import java.util.regex.PatternSyntaxException; + +/** Supplies several utilities for regular expression handling and global comment generation. */ +public class RegexUtil { + /** + * Handles escaping of regular expression syntax in an ordinary string so that the resulting string may be used as + * a pattern to match the original string. + * + * @param in original string + * @return pattern match string, which matches original string + */ + public static String escape(String in) { + StringBuffer sb = new StringBuffer(in.length() * 2); + for (int i = 0; i < in.length(); i++) { + char c = in.charAt(i); + switch (c) { + case '\t': + sb.append("\\t"); + break; + case '\n': + sb.append("\\n"); + break; + case '\\': + case '[': + case ']': + case '(': + case ')': + case '.': + case '^': + case '$': + case '?': + case '*': + case '+': + sb.append('\\'); + sb.append(c); + break; + default: + sb.append(c); + } + } + // now inspect for occurrences of the same character 4 times or more in a row; replace with + // {N} where N is the number of occurrences. + final int MIN_REPEAT = 4; + for (int i = 0; i < sb.length() - MIN_REPEAT; i++) { + /** Count the number of identical characters in sequence at this location. */ + boolean escaped = sb.charAt(i) == '\\'; + int escapeBias = (escaped ? 1 : 0); + char match = sb.charAt(i + escapeBias); + int sequenceCount = 1; // a character always begins a sequence of at least one character + for (int j = i + 1 + escapeBias; + j < sb.length() - escapeBias; + j += 1 + escapeBias) + { + if (escaped) { + if (sb.charAt(j) == '\\' && + sb.charAt(j + 1) == match) + { + sequenceCount++; + continue; + } + } + else if (sb.charAt(j) == match) { + sequenceCount++; + continue; + } + break; + } + if (sequenceCount >= MIN_REPEAT) { + // we've seen a sequence of MIN_REPEAT identical characters. + // Substitute {sequenceCount} + int startOffset = i; + int endOffset = i + sequenceCount * (1 + escapeBias); + sb.delete(startOffset, endOffset); + final String s = (escaped ? "\\" : "") + match + "{" + sequenceCount + "}"; + sb.insert(startOffset, s); + i += s.length() - 1; // subtract one; the for-loop will increment it + } + } + return sb.toString(); + } + + /** + * Performs a literal substitution in commentText, replacing all occurrences of "%FS%" with the + * fill string. + * + * @param commentText + * @param fillString + * @return + */ + public static String replaceAllFS(String commentText, String fillString) { + StringBuffer sb = new StringBuffer(commentText.length()); + int i; + int lastOffset = 0; + while ((i = commentText.indexOf("%FS%", lastOffset)) >= 0) { + // copy everything from last offset to index. + sb.append(commentText.substring(lastOffset, i)); + // copy the replacement string. + sb.append(fillString); + // bump index past %FS%. + i += 4; + lastOffset = i; + } + // now copy everything from lastOffset to end of string. + sb.append(commentText.substring(lastOffset)); + return sb.toString(); + } + + /** + * Extracts common starting and ending characters from a list of expression patterns and creates a new + * combined expression pattern. + * + * @param expressionList list of individual regular expression patterns + * @return combined expression pattern + */ + public static String combineExpressions(List expressionList) { + final String firstString = expressionList.get(0); + if (expressionList.size() == 1) { + return firstString; + } + int commonStart = 0, commonEnd = 0; + commonStart = calculateCommonStart(expressionList); + commonEnd = calculateCommonEnd(commonStart, expressionList); + + if (commonStart == 0 && commonEnd == 0) { + return combineSubgroups(expressionList); + } + String result = ""; + /** + * now check validity of resulting pattern. If commonStart or commonEnd broke apart some regular expression + * syntax, e.g. // \*{(10}|20}) the pattern is invalid. Try all combinations of commonStart/commonEnd + * until we find one that works. + */ + boolean valid = false; + for (int start = commonStart; start >= 0; start--) { + for (int end = commonEnd; end >= 0; end--) { + valid = true; + int totalLength = 0; + for (Object aExpressionList : expressionList) { + String s = ((String)aExpressionList); + totalLength += s.length() + 1; + } + StringBuffer sb = new StringBuffer(totalLength + 2); + sb.append(firstString.substring(0, start)); + List subgroups = new ArrayList(expressionList.size()); + for (Object aExpressionList1 : expressionList) { + String s = ((String)aExpressionList1); + s = s.substring(start, s.length() - end); + subgroups.add(s); + } + String combined = combineSubgroups(subgroups); + sb.append(combined); + sb.append(firstString.substring(firstString.length() - end, firstString.length())); + result = sb.toString(); + try { + if (valid && " ".matches(result)) ; + } + catch (PatternSyntaxException e) { + valid = false; + } + if (valid) { + return result; + } + } + } + return result; + } + + private static String combineSubgroups(List expressionList) { + int totalSize = 0; + List> groups = new ArrayList>(); + List strings = new ArrayList(expressionList); + while (strings.size() > 0) { + List subgroup = new ArrayList(); + String firstString = strings.remove(0); + totalSize += firstString.length(); + subgroup.add(firstString); + + + ListIterator otherStrings = strings.listIterator(); + while (otherStrings.hasNext()) { + String otherString = otherStrings.next(); + List testGroup = new ArrayList(); + testGroup.add(firstString); + testGroup.add(otherString); + int commonStart = calculateCommonStart(testGroup); + int commonEnd = calculateCommonEnd(commonStart, testGroup); + if (commonStart >= 2 || commonEnd >= 2) { + subgroup.add(otherString); + totalSize += otherString.length(); + otherStrings.remove(); + } + } + groups.add(subgroup); + } + // now groups contains a list of subgroups. Each subgroup consists of one or more strings. + // strings in a subgroup share at least two leading and/or trailing characters. + // return a parenthesized list of the subgroups. + StringBuffer sb = new StringBuffer(totalSize); + ListIterator> groupLI = groups.listIterator(); + if (groups.size() > 1) { + sb.append('('); + } + boolean first = true; + while (groupLI.hasNext()) { + if (first) { + first = false; + } + else { + sb.append('|'); + } + List nextGroup = groupLI.next(); + final String s = combineExpressions(nextGroup); + sb.append(s); + } + if (groups.size() > 1) { + sb.append(')'); + } + return sb.toString(); + } + + private static int calculateCommonEnd(int commonStart, List expressionList) { + final String firstString = expressionList.get(0); + return calculateCommonEnd(commonStart, expressionList, firstString.length() - commonStart); + } + + private static int calculateCommonEnd(int commonStart, List expressionList, int maxCommonEnd) { + final String firstString = (expressionList.get(0)); + int commonEnd = 0; + boolean matching = true; + while (matching && commonEnd < maxCommonEnd) { + if (commonEnd == firstString.length() - commonStart) { + break; + } + commonEnd++; + String match = firstString.substring(firstString.length() - commonEnd, + firstString.length()); + for (int i = 1; i < expressionList.size(); i++) { + if (!((expressionList.get(i))).endsWith(match)) { + matching = false; + commonEnd--; + break; + } + } + } + String match = firstString.substring(firstString.length() - commonEnd, + firstString.length()); + if (commonEnd > 0 && + !checkSubstringPatternValidity(match)) + { + return calculateCommonEnd(commonStart - 1, expressionList, commonEnd - 1); + } + return commonEnd; + } + + private static int calculateCommonStart(List expressionList) { + final String firstString = ((java.lang.String)expressionList.get(0)); + return calculateCommonStart(expressionList, firstString.length()); + } + + private static int calculateCommonStart(List expressionList, int maxCommonStart) { + final String firstString = ((java.lang.String)expressionList.get(0)); + int commonStart = 0; + boolean matching = true; + while (matching && commonStart < maxCommonStart) { + if (commonStart == firstString.length()) { + break; + } + commonStart++; + String match = firstString.substring(0, commonStart); + for (int i = 1; i < expressionList.size(); i++) { + if (!(((java.lang.String)expressionList.get(i))).startsWith(match)) { + matching = false; + commonStart--; + break; + } + } + } + if (commonStart > 0) { + if (!checkSubstringPatternValidity(firstString.substring(0, commonStart)) || + !checkRemainderPatternValidity(firstString.substring(commonStart))) + { + return calculateCommonStart(expressionList, commonStart - 1); + } + } + return commonStart; + } + + private static boolean checkRemainderPatternValidity(String s) { + char c = s.charAt(0); + return (c != '{' && c != '}'); + } + + private static boolean checkSubstringPatternValidity(String s) { + char c = s.charAt(0); + if (c == '+' || c == '*' || c == '?') return false; + if (s.length() >= 2) { + if (s.charAt(s.length() - 1) == '\\' && s.charAt(s.length() - 2) != '\\') { + return false; + } + } + return (count(s, '[') == count(s, ']') && + count(s, '{') == count(s, '}')); + } + + private static int count(String s, char c) { + char[] chars = s.toCharArray(); + int result = 0; + for (int i = 0; i < chars.length; i++) { + if (chars[i] == c) { + if (i == 0 || chars[i - 1] != '\\') { + // character is not escaped, count it + result++; + } + } + } + return result; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java new file mode 100644 index 000000000000..388c92f79896 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.settings.attributeGroups; + +import com.wrq.rearranger.entry.RangeEntry; +import com.wrq.rearranger.ruleinstance.HeaderTrailerRuleInstance; +import com.wrq.rearranger.ruleinstance.IRuleInstance; + +import java.util.ArrayList; +import java.util.List; + +/** A rule to match header text (text which does not constitute a matchable item such as a field or method.) */ +public class TrailerRule + implements IRule +{ + public IRuleInstance createRuleInstance() { + return new HeaderTrailerRuleInstance(this); + } + + public int getPriority() { + return -1; // priority doesn't matter since header rules only match the one trailer entry (if it exists), and + // the trailer entry is never matched by another rule. + } + + public void setPriority(int priority) { + // does nothing + } + + public boolean isMatch(RangeEntry rangeEntry) { + return rangeEntry.isFixedTrailer(); + } + + public boolean commentsMatchGlobalPattern(String pattern) { + return true; + } + + public List getOffendingPatterns(String pattern) { + return new ArrayList(1); + } + + public int getCommentCount() { + return 0; + } + + public void addCommentPatternsToList(List list) { + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java b/plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java new file mode 100644 index 000000000000..64ade9ae3e29 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.util; + +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.IRule; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CommentUtil { + final RearrangerSettings settings; + static CommentUtil singleton; + List commentStrings; + List commentMatchers; + + public CommentUtil(RearrangerSettings settings) { + this.settings = settings; + createCommentPatternList(); + createCommentMatcherList(); + singleton = this; + } + + public static List getCommentStrings() { + return singleton.commentStrings; + } + + public static List getCommentMatchers() { + return singleton.commentMatchers; + } + + private void createCommentMatcherList() { + if (settings.getGlobalCommentPattern() != null && + settings.getGlobalCommentPattern().length() > 0) + { + // create only one Matcher for the global comment pattern. + commentMatchers = new ArrayList(1); + commentMatchers.add((getMatcher(settings.getGlobalCommentPattern()))); + } + else { + commentMatchers = new ArrayList(commentStrings.size()); + for (String comment : commentStrings) { + Matcher matcher = getMatcher(comment); + commentMatchers.add(matcher); + } + } + } + + /** + * Strips any "\n" patterns off the front and end of the comment; inserts "\n*" patterns at front and end + * of the comment; and creates a Matcher for the comment. This will ultimately match any sequence of + * blank lines before/after the separator comment. + * Also ignores leading blanks after any newline character. + * + * @param comment comment string, already 'escaped' so it is safe for literal matching + * @return matcher which will match that comment, ignoring any leading or trailing newline characters and + * any leading space. + */ + private Matcher getMatcher(String comment) { + StringBuffer sb = new StringBuffer(comment); + /** + * remove any literal newline characters or escaped equivalent ('\n') at beginning of comment. + */ + while (true) { + if (sb.length() >= 2 && sb.charAt(0) == '\\' && sb.charAt(1) == 'n') { + sb.delete(0, 2); + continue; + } + if (sb.length() >= 1 && sb.charAt(0) == '\n') { + sb.delete(0, 1); + continue; + } + break; + } + /** + * similarly, remove any literal newline characters or escaped equivalents at end of comment. + */ + while (true) { + if (sb.length() >= 2 && sb.charAt(sb.length() - 2) == '\\' && sb.charAt(sb.length() - 1) == 'n') { + sb.delete(sb.length() - 2, sb.length()); + continue; + } + if (sb.length() >= 1 && sb.charAt(sb.length() - 1) == '\n') { + sb.delete(sb.length() - 1, sb.length()); + continue; + } + break; + } + if (sb.length() > 0) { + // now replace all intermediate newline characters with an expression to match leading spaces as well. + String intermediate = sb.toString().replaceAll("\\\\n", "\\\\n\\\\s*"); + sb.replace(0, sb.length(), intermediate); + sb.insert(0, "([\\n\\s]*"); + sb.append(")+[\\n\\s]*?\\n+"); + } + else { + sb.replace(0, sb.length(), "[\\n\\s]*?\\n+"); + } + Matcher matcher = Pattern.compile(sb.toString()).matcher(""); + return matcher; + } + + private void createCommentPatternList() { + commentStrings = new ArrayList(); + for (IRule rule : settings.getClassOrderAttributeList()) { + rule.addCommentPatternsToList(commentStrings); + } + for (IRule rule : settings.getItemOrderAttributeList()) { + rule.addCommentPatternsToList(commentStrings); + } + settings.getExtractedMethodsSettings().addCommentPatternsToList(commentStrings); + } + + /** + * Calculate the apparent length of a string if tabs are expanded. + * Leading tabs are no problem; embedded tabs would be, if the %FS% fill string expansions are not multiples of + * "%FS%".length() == 4, because after expansion the embedded tabs would misalign. However, I'm not going to + * address that yet. (This is just to fix Thomas Singer's bug with leading tab.) + * + * @param s + * @param tabSize + * @return + */ + private static int logicalLength(String s, int tabSize) { + int result = 0; + boolean sawNonTab = false; + for (char c : s.toCharArray()) { + if (c == '\t' && !sawNonTab) { + result += tabSize; + } + else { + sawNonTab = true; + result++; + } + } + return result; + } + + /** + * Utility to take a comment string which may contain %FS% keywords and replace them with equal number of + * fill characters to cause the comment to fill an entire line. + * + * @param comment String containing comment; may contain zero or more %FS% keywords; may be multiline. + * @param width desired column width of line. + * @param tabSize + * @param fillString string containing characters to replicate as needed for fill. @return + */ + public static String expandFill(String comment, + int width, + int tabSize, + String fillString) + { + StringBuffer result = new StringBuffer(comment.length() * 2); + int EOLindex = 0; + StringBuffer fillChars = new StringBuffer(); + if (fillString.length() == 0) { + fillString = " "; // fill with spaces if no pattern supplied + } + do { + // strip next line from previous end of line index to next new line character (or end of string if none) + int index = comment.indexOf('\n', EOLindex); + if (index < 0) { + index = comment.length(); + } + else { + index++; // include newline character + } + String str = comment.substring(EOLindex, index); + if (str.length() > 0) { + // count number of %FS% occurrences in the string. + int nFS = 0; + int offset = 0; + while ((offset = str.indexOf("%FS%", offset)) >= 0) { + nFS++; + offset += 4; // bump past %FS% + } + // determine line length excluding %FS% strings. Don't count final newline character, if present. + int fixedLength = logicalLength(str, tabSize) - nFS * 4; + if (str.charAt(str.length() - 1) == '\n') { + fixedLength--; + } + // determine number of characters to fill + int fillLength = width - fixedLength; + int[] fillWidths = new int[nFS]; + int maxFillWidth = 0; + // do no filling if the length of the comment is already the desired width (or greater). + if (fillLength > 0 && nFS > 0) { + int eachFill = fillLength / nFS; + int remainder = fillLength % nFS; + for (int i = 0; i < nFS; i++) { + // calculate fill widths for each %FS%. + // any remainder (fillLength % nFS) is distributed among the first %FS% fills. + fillWidths[i] = eachFill + (i < remainder ? 1 : 0); + maxFillWidth = Math.max(maxFillWidth, fillWidths[i]); + } + } + // get enough fill chars + fillChars.ensureCapacity(maxFillWidth); + while (fillChars.length() < maxFillWidth) { + fillChars.append(fillString); + } + // now do the expansion + offset = 0; + int previousOffset = 0; + int fillWidthIndex = 0; + while ((offset = str.indexOf("%FS%", offset)) >= 0) { + // copy everything from previousOffset to offset. + result.append(str.substring(previousOffset, offset)); + offset += 4; // bump past %FS% + previousOffset = offset; + // then expand the fill string to fillWidths[fillWidthIndex] characters and append it. + result.append(fillChars.toString().substring(0, fillWidths[fillWidthIndex++])); + // todo - JDK 1.5, .append(fillChars, 0, width) + } + // copy everything from previousOffset to end of line, and append a new line. + result.append(str.substring(previousOffset)); + } + EOLindex = index; + } + while (EOLindex < comment.length()); + return result.toString(); + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/util/Constraints.java b/plugins/rearranger/src/com/wrq/rearranger/util/Constraints.java new file mode 100644 index 000000000000..bdaa6754d85a --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/util/Constraints.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.util; + +import java.awt.*; + +/** Utility class for performing common operations on GridBagConstraints. */ +public class Constraints + extends GridBagConstraints +{ + boolean newRow; + + /** + * Constructs a new Constraints object and initializes a new row.
+ * Side effects are: + *

+   *    gridy = 0
+   *    gridx = 0
+   *    gridheight = 1
+   *    gridwidth = 1
+   *    weightx = 0
+   *    weighty = 0
+   *    fill = NONE
+   *    anchor = WEST
+   * 
+ */ + public Constraints() { + fill = GridBagConstraints.NONE; + gridwidth = 1; + gridheight = 1; + anchor = GridBagConstraints.WEST; + weightx = 0.0d; + weighty = 0.0d; + gridx = gridy = 0; + newRow = true; + newRow(); + } + + /** + * Constructs a new Constraints object and initializes a new row.
+ * Side effects are: + *
+   *    gridy = 0
+   *    gridx = 0
+   *    gridheight = 1
+   *    gridwidth = 1
+   *    weightx = 0
+   *    weighty = 0
+   *    fill = NONE
+   *    anchor = specified parameter
+   * 
+ */ + public Constraints(int anchor) { + this(); + this.anchor = anchor; + } + + /** + * Prepares for adding components to a new row.
+ * Side effects are: + *
+   *    gridy++ (if not already at the beginning of a new row)
+   *    gridx = 0
+   *    gridheight = 1
+   *    weighty = 0
+   * 
+ */ + public void newRow() { + if (!newRow) { + gridy++; + } + gridx = 0; + gridheight = 1; + weighty = 0; + newRow = true; + } + + /** + * Prepares for adding components to a new row, which is weighted.
+ * Side effects are: + *
+   *    gridy++ (if not the first row)
+   *    gridx = 0
+   *    gridheight = 1
+   *    weighty = supplied parameter
+   * 
+ */ + public void weightedNewRow(double weight) { + newRow(); + weighty = weight; + } + + /** + * Prepares for adding components to a new row, which is weighted.
+ * Side effects are: + *
+   *    gridy++ (if not the first row)
+   *    gridx = 0
+   *    gridheight = 1
+   *    weighty = 1
+   * 
+ */ + public void weightedNewRow() { + weightedNewRow(1); + } + + /** + * Prepares for adding components to a new row which will be the last row.
+ * Side effects are: + *
+   *    gridy++ (if not the first row)
+   *    gridx = 0
+   *    gridheight = REMAINDER
+   *    weighty = 0
+   * 
+ */ + public void lastRow() { + newRow(); + gridheight = REMAINDER; + } + + /** + * Prepares for adding components to a new weightd row which will be the last row.
+ * Side effects are: + *
+   *    gridy++ (if not the first row)
+   *    gridx = 0
+   *    gridheight = REMAINDER
+   *    weighty = supplied parameter
+   * 
+ */ + public void weightedLastRow(double weight) { + lastRow(); + weighty = weight; + } + + /** + * Prepares for adding components to a new weightd row which will be the last row.
+ * Side effects are: + *
+   *    gridy++ (if not the first row)
+   *    gridx = 0
+   *    gridheight = REMAINDER
+   *    weighty = 1
+   * 
+ */ + public void weightedLastRow() { + weightedLastRow(1); + } + + /** + * Automatically starts a new row if not explicitly done already or if columns have been added since the last + * newRow() call.
+ * Side effects are: + *
+   *    gridx = 0
+   *    newRow = false
+   *    gridwidth = 1
+   *    weightx = 0
+   * 
+ * + * @return this Constraints object + */ + public Constraints firstCol() { + if (!newRow) { + newRow(); + } + gridx = 0; + newRow = false; + gridwidth = 1; + weightx = 0; + return this; + } + + /** + * Automatically starts a new weighted row if not explicitly done already or if columns have been added since the last + * newRow() call.
+ * Side effects are: + *
+   *    gridx = 0
+   *    newRow = false
+   *    gridwidth = 1
+   *    weightx = 1
+   * 
+ * + * @return this Constraints object + */ + public Constraints weightedFirstCol() { + firstCol(); + weightx = 1; + return this; + } + + /** + * Prepares to add a component to the next column. If this is the first column in the row, + * gridx will be zero (not one).
+ * Side effects are: + *
+   *    gridx = gridx + 1 (or zero, if this is the beginning of a new row)
+   *    newRow = false
+   *    gridwidth = 1
+   *    weightx = 0
+   * 
+ * + * @return this Constraints object + */ + public Constraints nextCol() { + gridx = newRow ? 0 : gridx + 1; + newRow = false; + gridwidth = 1; + weightx = 0; + return this; + } + + /** + * Prepares to add a weighted component to the next column.
+ * Side effects are: + *
+   *    gridx = gridx + 1 (or zero, if this is the beginning of a new row)
+   *    newRow = false
+   *    gridwidth = 1
+   *    weightx = supplied parameter
+   * 
+ * + * @return this Constraints object + */ + public Constraints weightedNextCol(double weight) { + nextCol(); + weightx = weight; + return this; + } + + /** + * Prepares to add a weighted component to the next column.
+ * Side effects are: + *
+   *    gridx = gridx + 1 (or zero, if this is the beginning of a new row)
+   *    newRow = false
+   *    gridwidth = 1
+   *    weightx = 1
+   * 
+ * + * @return this Constraints object + */ + public Constraints weightedNextCol() { + return weightedNextCol(1); + } + + /** + * Prepares to add a component to the last column.
+ * Side effects are: + *
+   *    gridx = gridx + 1 (or zero, if this is the beginning of a new row)
+   *    newRow = false
+   *    gridwidth = REMAINDER
+   *    weightx = 0
+   * 
+ * + * @return this Constraints object + */ + public Constraints lastCol() { + nextCol(); + gridwidth = REMAINDER; + return this; + } + + /** + * Prepares to add a weighted component to the last column.
+ * Side effects are: + *
+   *    gridx = gridx + 1 (or zero, if this is the beginning of a new row)
+   *    newRow = false
+   *    gridwidth = REMAINDER
+   *    weightx = supplied parameter
+   * 
+ * + * @return this Constraints object + */ + public Constraints weightedLastCol(double weight) { + weightedNextCol(weight); + gridwidth = REMAINDER; + return this; + } + + /** + * Prepares to add a weighted component to the last column.
+ * Side effects are: + *
+   *    gridx = gridx + 1 (or zero, if this is the beginning of a new row)
+   *    newRow = false
+   *    gridwidth = REMAINDER
+   *    weightx = 1
+   * 
+ * + * @return this Constraints object + */ + public Constraints weightedLastCol() { + weightedLastCol(1); + gridwidth = REMAINDER; + return this; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/util/IconUtil.java b/plugins/rearranger/src/com/wrq/rearranger/util/IconUtil.java new file mode 100644 index 000000000000..2e5c5437a23d --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/util/IconUtil.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.util; + +import com.intellij.openapi.diagnostic.Logger; +import com.wrq.rearranger.Rearranger; + +import javax.swing.*; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +/** Utility methods to obtain an icon from a resource or file. */ +public class IconUtil { +// ------------------------------ FIELDS ------------------------------ + + private static final Logger LOG = Logger.getInstance("#" + IconUtil.class.getName()); + +// -------------------------- STATIC METHODS -------------------------- + + + public static final Icon getIcon(String iconName) { + URL iconURL = Rearranger.class.getClassLoader().getResource("com/wrq/rearranger/" + iconName + ".png"); + if (iconURL == null) { + if (true) { +// // for debugging only; +// // in development, there's no resource (no jar file built), +// // so go to the file directly. + try { + URLClassLoader cl = new URLClassLoader( + new URL[] + {new File("/rearranger/lib/rearranger.jar").toURL(), + new File("/IntelliJ-IDEA-4.0/lib/icons.jar").toURL()} + ); + iconURL = cl.getResource("com/wrq/rearranger/" + iconName + ".png"); + if (iconURL == null) { + iconURL = cl.getResource(iconName + ".png"); + } + } + catch (MalformedURLException e) { + iconURL = null; + } + } + } + if (iconURL != null) { + final ImageIcon imageIcon = new ImageIcon(iconURL, iconName); + return imageIcon; + } + LOG.debug( + "getIcon: getResource() could not locate URL for com/wrq/rearranger/" + + iconName + + ".png or " + + iconName + ".png in icons.jar" + ); + return null; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/util/MethodUtil.java b/plugins/rearranger/src/com/wrq/rearranger/util/MethodUtil.java new file mode 100644 index 000000000000..c83ba74f8157 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/util/MethodUtil.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.util; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; +import com.wrq.rearranger.settings.attributeGroups.GetterSetterDefinition; + +/** Code to determine if a method is truly a simple getter or setter, courtesy of Alain Ravet. */ +public final class MethodUtil { + + public static boolean isGetter(PsiMethod i_method, + GetterSetterDefinition gsd) + { + if (i_method == null) { + return false; + } + + final boolean hasParameters = 1 <= nofParameters(i_method); + if (hasParameters) { + return false; + } + + + final String name = i_method.getName(); + + if (name.startsWith("get")) return getterNameMatchedReturnedValue(i_method, name, "get", gsd); + if (name.startsWith("is")) return getterNameMatchedReturnedValue(i_method, name, "is", gsd); + if (name.startsWith("has")) return getterNameMatchedReturnedValue(i_method, name, "has", gsd); + + return false; + } + + private static boolean getterNameMatchedReturnedValue(PsiMethod i_method, + String i_name, + String i_prefix, + GetterSetterDefinition gsd) + { + String i_methodNameTrail = i_name.substring(i_prefix.length()); + if (!nameIsWellFormed(i_methodNameTrail)) { + return false; + } + + if (isAbstract(i_method)) { + return false; + } + + boolean nameOK = false, bodyOK = false; + switch (gsd.getGetterNameCriterion()) { + case GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX: + nameOK = true; + break; + case GetterSetterDefinition.GETTER_NAME_MATCHES_FIELD: + final String nameFromBody = nameOfVariableReturnedInBody(i_method); + final String propertyName = propertyNameFromMethodTrail(i_methodNameTrail); + nameOK = nameFromBody.equals(fieldName(propertyName, i_method.getProject())); + break; + } + switch (gsd.getGetterBodyCriterion()) { + case GetterSetterDefinition.GETTER_BODY_IMMATERIAL: + bodyOK = true; + break; + case GetterSetterDefinition.GETTER_BODY_RETURNS: + bodyOK = methodContainsReturnStatementOnly(i_method); + break; + case GetterSetterDefinition.GETTER_BODY_RETURNS_FIELD: + final String nameFromBody = nameOfVariableReturnedInBody(i_method); + final String propertyName = propertyNameFromMethodTrail(i_methodNameTrail); + bodyOK = nameFromBody.equals(fieldName(propertyName, i_method.getProject())); + break; + } + return nameOK && bodyOK; + } + + private static boolean methodContainsReturnStatementOnly(PsiMethod i_method) { + final PsiStatement[] statements = i_method.getBody().getStatements(); + return isReturnStatement(statements[0]); + } + + private static String nameOfVariableReturnedInBody(PsiMethod i_method) { + + final PsiStatement[] statements = i_method.getBody().getStatements(); + + if (nofStatements(i_method) == 0) { + return ""; + } + + int returnIndex = statements.length - 1; + if (!isReturnStatement(statements[returnIndex])) { + return ""; + } + final PsiReturnStatement returnStatement = (PsiReturnStatement)statements[returnIndex]; + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (null == returnValue) { + return ""; + } + String returnValueText = returnValue.getText(); + returnValueText = returnValueText.replaceFirst("this\\.", ""); + return returnValueText; + } + + private static String propertyNameFromMethodTrail(String i_source) { + if (i_source.length() > 0) { + final String left = i_source.substring(0, 1).toLowerCase(); + final String right = i_source.substring(1); + + return left + right; + } + else { + return ""; + } + } + + public static String getPropertyName(PsiMethod i_method) { + final String name = i_method.getName(); + + if (name.startsWith("get") || + name.startsWith("has") || + name.startsWith("set")) + { + return name.substring(3); + } + + if (name.startsWith("is")) return name.substring(2); + return name; + } + + public static boolean isSetter(PsiMethod i_method, + GetterSetterDefinition gsd) + { + if (i_method == null) return false; + if (i_method.getBody() == null) return false; + if (nofParameters(i_method) != 1) return false; + if (!i_method.getName().startsWith("set")) return false; + String i_methodNameTrail = i_method.getName().substring("set".length()); + if (i_methodNameTrail.length() == 0) return false; + /** if setter body is immaterial, it can be empty. Otherwise, it must contain at least one statement. */ + if (nofStatements(i_method) == 0 && + gsd.getSetterBodyCriterion() != GetterSetterDefinition.SETTER_BODY_IMMATERIAL) + { + return false; + } + + boolean nameOK = false, bodyOK = false; + PsiElement psiElement = null; + if (nofStatements(i_method) > 0) { + psiElement = i_method.getBody().getStatements()[nofStatements(i_method) - 1].getChildren()[0]; + } + PsiAssignmentExpression assignment = null; + String lExpression = null; + String parameterName = null; + if (psiElement instanceof PsiAssignmentExpression) { + assignment = (PsiAssignmentExpression)psiElement; + lExpression = ((assignment.getLExpression()).getText()).replaceFirst("this.", ""); + parameterName = (i_method.getParameterList()).getParameters()[0].getName(); + } + + String fieldName = fieldName(propertyNameFromMethodTrail(i_methodNameTrail), i_method.getProject()); + switch (gsd.getSetterNameCriterion()) { + case GetterSetterDefinition.SETTER_NAME_CORRECT_PREFIX: + nameOK = true; + break; + case GetterSetterDefinition.SETTER_NAME_MATCHES_FIELD: + nameOK = lExpression != null && + lExpression.equals(fieldName); + break; + } + switch (gsd.getSetterBodyCriterion()) { + case GetterSetterDefinition.SETTER_BODY_IMMATERIAL: + bodyOK = true; + break; + case GetterSetterDefinition.SETTER_BODY_SETS_FIELD: + if (assignment != null && + nameIsWellFormed(i_methodNameTrail) && + assignment.getOperationSign().getText().equals("=")) +// PsiJavaToken.EQ == assignment.getOperationSign().getTokenType() ) + { + PsiExpression rExpressionRaw = assignment.getRExpression(); + bodyOK = rExpressionRaw != null && + parameterName.equals(rExpressionRaw.getText()) && + lExpression != null && + lExpression.equals(fieldName); + } + break; + } + return nameOK && bodyOK; + } + + private static boolean nameIsWellFormed(String i_methodNameTrail) { + final boolean methodNameIsTooShort = i_methodNameTrail.length() == 0; + if (methodNameIsTooShort) { + return false; + } + + final char firstCandidateMemberChar = i_methodNameTrail.charAt(0); + return !Character.isLowerCase(firstCandidateMemberChar); + } + + + private static String fieldName(String i_propertyName, Project project) { + JavaCodeStyleManager i_codeStyleManager = JavaCodeStyleManager.getInstance(project); + return i_codeStyleManager.propertyNameToVariableName(i_propertyName, VariableKind.FIELD); + } + + public static int nofParameters(PsiMethod i_method) { + return i_method.getParameterList().getParameters().length; + } + + private static int nofStatements(PsiMethod i_method) { + return i_method.getBody().getStatements().length; + } + + private static boolean isAbstract(PsiMethod i_method) { + return null == i_method.getBody(); + } + + private static boolean isReturnStatement(final PsiStatement i_statement) { + return i_statement instanceof PsiReturnStatement; + } +} diff --git a/plugins/rearranger/src/com/wrq/rearranger/util/ModifierUtils.java b/plugins/rearranger/src/com/wrq/rearranger/util/ModifierUtils.java new file mode 100644 index 000000000000..a72551d101b8 --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/util/ModifierUtils.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger.util; + +import java.lang.reflect.Modifier; +import java.util.StringTokenizer; + +/** Contains utility functions to parse modifiers. */ +public final class ModifierUtils { + /** + * Converts string form of modifiers into a mask. + * + * @param modifierString modifiers to be parsed. + * @return modifier mask corresponding to modifiers in the supplied string. + */ + public static int getModifierMask(final String modifierString) { + /** + * first, determine the modifier mask for the modifiers in the incoming modifier string. + */ + final StringTokenizer st = new StringTokenizer(modifierString); + int mask = 0; + while (st.hasMoreTokens()) { + final String m = st.nextToken(); + for (int i = 1; i != 0; i <<= 1) { + if (Modifier.toString(i).equals(m)) { + mask = mask | i; + break; + } + } + } + return mask; + } +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java b/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java new file mode 100644 index 000000000000..a8c6653d1ad2 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger; + +import com.intellij.openapi.editor.Document; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.testFramework.LightCodeInsightTestCase; +import com.wrq.rearranger.configuration.RearrangerSettingsPanel; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.settings.attributeGroups.IPrioritizableRule; +import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.util.Constraints; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; + +import javax.swing.*; +import java.awt.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ListIterator; + +/** + * @author davek + * Date: Mar 30, 2004 + */ +public class InteractiveTest + extends LightCodeInsightTestCase +{ + private RearrangerSettings rs; + public static final String DEFAULT_CONFIGURATION_ROOT = ".."; // up one level from test + public static final String DEFAULT_CONFIGURATION = DEFAULT_CONFIGURATION_ROOT + "/src/com/wrq/rearranger/defaultConfiguration.xml"; + + @Override + protected String getTestDataPath() { + return "testData"; // run unit tests with effective working directory of "C:\Rearranger\test" + } + + protected final void setUp() throws Exception { + super.setUp(); + Logger logger = Logger.getLogger("com.wrq.rearranger"); +// logger.setAdditivity(false); +// logger.addAppender(new ConsoleAppender(new PatternLayout("[%7r] %6p - %30.30c - %m \n"))); +// logger.setLevel(Level.DEBUG); + logger.setLevel(Level.INFO); + rs = new RearrangerSettings(); + rs.setAskBeforeRearranging(true); + rs.setRearrangeInnerClasses(true); + } + + public final void testLiveRearrangerDialog() throws Exception { + configureByFile("/com/wrq/rearranger/RearrangementTest28.java"); + final PsiFile file = getFile(); + final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); + final LiveRearrangerActionHandler rah = new LiveRearrangerActionHandler(); + rah.liveRearrangeDocument(getProject(), file, rs, doc, 0); + super.checkResultByFile("/com/wrq/rearranger/RearrangementTest28.java"); + } + + public final void testSettingsPanel() throws Exception { + Rearranger rearranger = new Rearranger(); + SAXBuilder builder = new SAXBuilder(); + org.jdom.Document doc = null; + try { + FileInputStream f = new FileInputStream(new File(DEFAULT_CONFIGURATION)); + doc = builder.build(f); + f.close(); + } + catch (JDOMException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + catch (FileNotFoundException e) { + File f = new File(DEFAULT_CONFIGURATION); + System.out.println(f.getAbsolutePath()); + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + Element appElement = doc.getRootElement(); + java.util.List componentList = appElement.getChildren(); + Element rearrangerElement = null; + if (appElement.getName().equals("component") && + appElement.getAttributeValue("name").equals(Rearranger.COMPONENT_NAME)) + { + rearrangerElement = appElement; + } + else { + ListIterator li = componentList.listIterator(); + while (li.hasNext()) +// for (Element e : componentList) + { + Element e = (Element)li.next(); + if (e.getAttributeValue("name").equals(Rearranger.COMPONENT_NAME)) { + rearrangerElement = e; + break; + } + } + } + if (rearrangerElement != null) { + rearranger.readExternal(rearrangerElement); + } + final JDialog frame = new JDialog((Frame)null, "SwingApplication"); + final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightedLastRow(); + RearrangerSettings settings = rearranger.getSettings(); + final RearrangerSettingsPanel object = new RearrangerSettingsPanel(settings); + frame.getContentPane().setLayout(new GridBagLayout()); + frame.getContentPane().add(object, constraints.weightedLastCol()); + //Finish setting up the frame, and show it. + frame.pack(); + frame.setResizable(true); + frame.setModal(true); + frame.setVisible(true); + final RearrangerSettings rs = object.settings.deepCopy(); + assertTrue("Settings are unequal", rs.equals(object.settings)); + System.out.println("Class Order"); + ListIterator li; + for (Object o : object.settings.getClassOrderAttributeList()) { + if (o instanceof IPrioritizableRule) { + System.out.println(o + ", pri=" + ((IRule)o).getPriority()); + } + else { + System.out.println(o); + } + } + System.out.println("Item order"); + for (Object o : object.settings.getItemOrderAttributeList()) { + if (o instanceof IPrioritizableRule) { + System.out.println(o + ", pri=" + ((IRule)o).getPriority()); + } + else { + System.out.println(o); + } + } + object.checkCommentsAgainstGlobalPattern(object.settings); + } +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy b/plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy new file mode 100644 index 000000000000..a0667d6e1593 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy @@ -0,0 +1,2188 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.wrq.rearranger; + + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.wrq.rearranger.settings.RearrangerSettings +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable + +/** JUnit tests for the rearranger plugin. */ +class RearrangerTest extends LightCodeInsightFixtureTestCase { + + private RearrangerSettings mySettings; + + @Override + protected String getBasePath() { + return "/plugins/rearranger/test/testData/com/wrq/rearranger"; + } + + protected final void setUp() throws Exception { + super.setUp(); + mySettings = new RearrangerSettings(); +// rs.setAskBeforeRearranging(true); // uncomment for debugging file structure popup + mySettings.showFields = true + mySettings.showParameterNames = true + mySettings.showParameterTypes = true + mySettings.showRules = true + mySettings.rearrangeInnerClasses =true + } + + public final void testNoRearrangement() throws Exception { + doTest('RearrangementTest', 'NoRearrangementResult1') + } + +// public final void testPublicFieldRearrangement() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final FieldAttributes fa; +// fa = new FieldAttributes(); +// fa.getPlAttr().setPlPublic(true); +// rs.addItem(fa, 0); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult2.java"); +// } +// +// public final void testNotPublicFieldRearrangement() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final FieldAttributes fa; +// fa = new FieldAttributes(); +// fa.getPlAttr().setPlPublic(true); +// fa.getPlAttr().setInvertProtectionLevel(true); +// rs.addItem(fa, 0); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult3.java"); +// } +// +// public final void testConstructorRearrangement() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.getPlAttr().setPlPackage(true); +// ma.getPlAttr().setPlPublic(true); +// ma.setConstructorMethodType(true); +// rs.addItem(ma, 0); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult4.java"); +// } +// +// public final void testClassRearrangement() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final ClassAttributes ca = new ClassAttributes(); +// ca.getPlAttr().setPlPackage(true); +// rs.addClass(ca, 0); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult5.java"); +// } +// +// public final void testPSFRearrangement() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest2.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final FieldAttributes fa; +// fa = new FieldAttributes(); +// fa.getPlAttr().setPlPublic(true); +// fa.getfAttr().setValue(true); +// fa.getStAttr().setValue(true); +// rs.addItem(fa, 0); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult6.java"); +// } +// +// public final void testAnonClassInit() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest7.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final FieldAttributes fa; +// fa = new FieldAttributes(); +// fa.getInitToAnonClassAttr().setValue(true); +// rs.addItem(fa, 0); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult7.java"); +// } +// +// public final void testNameMatch() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final FieldAttributes fa; +// fa = new FieldAttributes(); +// fa.getNameAttr().setMatch(true); +// fa.getNameAttr().setExpression(".*5"); +// rs.addItem(fa, 0); +// final MethodAttributes ma = new MethodAttributes(); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression(".*2"); +// rs.addItem(ma, 1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult8.java"); +// } +// +// public final void testStaticInitializer() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest8.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.getStaticInitAttr().setValue(true); +// rs.addItem(ma, 0); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult8A.java"); +// } +// +// public final void testAlphabetizingGSMethods() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.setGetterSetterMethodType(true); +// ma.setOtherMethodType(true); +// ma.setConstructorMethodType(false); +// ma.getSortAttr().setByName(true); +// rs.addItem(ma, 0); +// rs.setKeepGettersSettersTogether(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult9.java"); +// } +// +// public final void testSimpleComment() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlPublic(true); +// rs.addItem(fa, 0); +// final CommentRule c = new CommentRule(); +// c.setCommentText("// simple comment **********"); +// c.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_PRECEDING_RULE); +// rs.addItem(c, 1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult10.java"); +// } +// +// /** +// * Delete old comment and insert (identical) new one. This tests proper identification and deletion of old +// * comments. +// * +// * @throws Exception test exception +// */ +// public final void testReplayComment() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementResult10.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlPublic(true); +// rs.addItem(fa, 0); +// final CommentRule c = new CommentRule(); +// c.setCommentText("// simple comment **********"); +// c.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_PRECEDING_RULE); +// rs.addItem(c, 1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult10.java"); +// } +// +// public final void testMultipleRuleCommentMatch() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest11.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// CommentRule c; +// FieldAttributes fa; +// +// c = new CommentRule(); +// c.setCommentText("// FIELDS:"); +// c.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE); +// c.setAllSubsequentRules(false); +// c.setnSubsequentRulesToMatch(3); +// rs.addItem(c, 0); +// +// c = new CommentRule(); +// c.setCommentText("// PROTECTED FIELDS:"); +// c.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE); +// c.setAllSubsequentRules(false); +// c.setnSubsequentRulesToMatch(1); +// rs.addItem(c, 1); +// +// fa = new FieldAttributes(); +// fa.getPlAttr().setPlProtected(true); +// rs.addItem(fa, 2); +// +// c = new CommentRule(); +// c.setCommentText("// FINAL FIELDS:"); +// c.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE); +// c.setAllSubsequentRules(true); +// c.setnSubsequentRulesToMatch(1); +// rs.addItem(c, 3); +// +// fa = new FieldAttributes(); +// fa.getfAttr().setValue(true); +// rs.addItem(fa, 4); +// +// c = new CommentRule(); +// c.setCommentText("// NON-FINAL FIELDS:"); +// c.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE); +// c.setAllSubsequentRules(true); +// c.setnSubsequentRulesToMatch(1); +// rs.addItem(c, 5); +// +// fa = new FieldAttributes(); +// fa.getfAttr().setValue(true); +// fa.getfAttr().setInvert(true); +// rs.addItem(fa, 6); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult11.java"); +// } +// +// public final void testOpsBlockingQueueExample() throws Exception { +// testOpsBlockingQueueExampleWorker(false, "/com/wrq/rearranger/OpsBlockingQueue.java", +// false, "/com/wrq/rearranger/OpsBlockingQueue.java"); +// } +// +// public final void testOpsBlockingQueueExampleWithGlobalPattern() throws Exception { +// testOpsBlockingQueueExampleWorker(true, "/com/wrq/rearranger/OpsBlockingQueue.java", +// false, "/com/wrq/rearranger/OpsBlockingQueue.java"); +// } +// +// public final void testOpsBlockingQueueExampleWithIndentedComments() throws Exception { +// testOpsBlockingQueueExampleWorker(false, "/com/wrq/rearranger/OpsBlockingQueueIndented.java", +// true, "/com/wrq/rearranger/OpsBlockingQueueIndentedResult.java"); +// } +// +// private void testOpsBlockingQueueExampleWorker(boolean doGlobalPattern, +// String srcFilename, +// boolean doublePublicMethods, +// String compareFilename) +// throws Exception +// { +// // submitted by Joe Martinez. +// configureByFile(srcFilename); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// CommentRule c; +// FieldAttributes fa; +// c = new CommentRule(); +// c.setCommentText("//************************************** PUBLIC STATIC FIELDS *************************************"); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(2); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(false); +// rs.addItem(c, 0); +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// fa.getPlAttr().setPlPublic(true); +// fa.getStAttr().setValue(true); +// fa.getfAttr().setValue(true); +// rs.addItem(fa, 1); +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// fa.getPlAttr().setPlPublic(true); +// fa.getStAttr().setValue(true); +// rs.addItem(fa, 2); +// c = new CommentRule(); +// c.setCommentText("//************************************** PUBLIC FIELDS *****************************************"); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(1); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(true); +// rs.addItem(c, 3); +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// fa.getPlAttr().setPlPublic(true); +// rs.addItem(fa, 4); +// c = new CommentRule(); +// c.setCommentText("//*********************************** PROTECTED/PACKAGE FIELDS **************************************"); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(3); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(false); +// rs.addItem(c, 5); +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// fa.getPlAttr().setPlProtected(true); +// fa.getPlAttr().setPlPackage(true); +// fa.getStAttr().setValue(true); +// fa.getfAttr().setValue(true); +// rs.addItem(fa, 6); +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// fa.getPlAttr().setPlProtected(true); +// fa.getPlAttr().setPlPackage(true); +// fa.getStAttr().setValue(true); +// rs.addItem(fa, 7); +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// fa.getPlAttr().setPlProtected(true); +// fa.getPlAttr().setPlPackage(true); +// rs.addItem(fa, 8); +// c = new CommentRule(); +// c.setCommentText("//************************************** PRIVATE FIELDS *****************************************"); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(1); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(false); +// rs.addItem(c, 9); +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// fa.getPlAttr().setPlPrivate(true); +// rs.addItem(fa, 10); +// c = new CommentRule(); +// c.setCommentText("//************************************** CONSTRUCTORS ************************************* "); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(2); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(false); +// rs.addItem(c, 11); +// MethodAttributes ma = new MethodAttributes(); +// ma.getPlAttr().setPlPublic(true); +// ma.setConstructorMethodType(true); +// rs.addItem(ma, 12); +// ma = new MethodAttributes(); +// ma.setConstructorMethodType(true); +// rs.addItem(ma, 13); +// c = new CommentRule(); +// c.setCommentText("//*********************************** GETTERS AND SETTERS ********************************** "); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(2); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(false); +// rs.addItem(c, 14); +// ma = new MethodAttributes(); +// ma.getSortAttr().setByName(true); +// ma.getPlAttr().setPlPublic(true); +// ma.setGetterSetterMethodType(true); +// rs.addItem(ma, 15); +// ma = new MethodAttributes(); +// ma.getSortAttr().setByName(true); +// ma.setGetterSetterMethodType(true); +// rs.addItem(ma, 16); +// c = new CommentRule(); +// String commentText = +// "//************************************** PUBLIC METHODS ************************************* "; +// if (doublePublicMethods) { +// commentText += "\n// PUBLIC METHODS LINE 2"; +// } +// c.setCommentText(commentText); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(1); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(true); +// rs.addItem(c, 17); +// ma = new MethodAttributes(); +// ma.getSortAttr().setByName(true); +// ma.getPlAttr().setPlPublic(true); +// rs.addItem(ma, 18); +// c = new CommentRule(); +// c.setCommentText("//********************************* PACKAGE/PROTECTED METHODS ******************************** "); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(1); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(true); +// rs.addItem(c, 19); +// ma = new MethodAttributes(); +// ma.getSortAttr().setByName(true); +// ma.getPlAttr().setPlProtected(true); +// ma.getPlAttr().setPlPackage(true); +// rs.addItem(ma, 20); +// c = new CommentRule(); +// c.setCommentText("//************************************** PRIVATE METHODS *************************************"); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(1); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(true); +// rs.addItem(c, 21); +// ma = new MethodAttributes(); +// ma.getSortAttr().setByName(true); +// ma.getPlAttr().setPlPrivate(true); +// rs.addItem(ma, 22); +// c = new CommentRule(); +// c.setCommentText("//************************************** INNER CLASSES ************************************* "); +// c.setEmitCondition(2); +// c.setnPrecedingRulesToMatch(1); +// c.setnSubsequentRulesToMatch(1); +// c.setAllPrecedingRules(true); +// c.setAllSubsequentRules(true); +// rs.addItem(c, 23); +// InnerClassAttributes ic = new InnerClassAttributes(); +// ic.getSortAttr().setByName(true); +// rs.addItem(ic, 24); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(false); +// if (doGlobalPattern) { +// rs.setGlobalCommentPattern("//\\*{20,45}[A-Z /]*\\*{20,45}\n"); +// } +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile(compareFilename); +// } +// +// public final void testReturnTypeMatch() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest12.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.getReturnTypeAttr().setMatch(true); +// ma.getReturnTypeAttr().setExpression("void"); +// rs.addItem(ma, 0); +// FieldAttributes fa = new FieldAttributes(); +// fa.getTypeAttr().setMatch(true); +// fa.getTypeAttr().setExpression("int"); +// rs.addItem(fa, 1); +// ma = new MethodAttributes(); +// ma.getReturnTypeAttr().setMatch(true); +// ma.getReturnTypeAttr().setExpression(".*je.*"); +// rs.addItem(ma, 2); +// ma = new MethodAttributes(); +// ma.getReturnTypeAttr().setMatch(true); +// ma.getReturnTypeAttr().setExpression("Integer\\[\\]"); +// rs.addItem(ma, 3); +// ma = new MethodAttributes(); +// ma.getReturnTypeAttr().setMatch(true); +// ma.getReturnTypeAttr().setExpression("int"); +// rs.addItem(ma, 4); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult12.java"); +// } +// +// public final void testRelatedMethodsDepthOriginal() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.RETAIN_ORIGINAL_ORDER); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13DO.java"); +// } +// +// public final void testRelatedMethodsDepthAlphabetical() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.ALPHABETICAL_ORDER); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13DA.java"); +// } +// +// public final void testRelatedMethodsDepthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13DI.java"); +// } +// +// public final void testRelatedMethodsBreadthOriginal() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.RETAIN_ORIGINAL_ORDER); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13BO.java"); +// } +// +// public final void testRelatedMethodsBreadthAlphabetical() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.ALPHABETICAL_ORDER); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13BA.java"); +// } +// +// public final void testRelatedMethodsBreadthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13BI.java"); +// } +// +// public final void testEmitTLCommentsRelatedMethodsBreadthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_TOP_LEVEL); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13BITLC.java"); +// } +// +// public final void testEmitEMCommentsRelatedMethodsBreadthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_EACH_METHOD); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13BIEMC.java"); +// } +// +// public final void testEmitELCommentsRelatedMethodsBreadthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_EACH_LEVEL); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13BIELC.java"); +// } +// +// public final void testEmitNFCommentsRelatedMethodsBreadthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_NEW_FAMILY); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13BINFC.java"); +// } +// +// public final void testEmitTLCommentsRelatedMethodsDepthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_TOP_LEVEL); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13DITLC.java"); +// } +// +// public final void testEmitEMCommentsRelatedMethodsDepthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_EACH_METHOD); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13DIEMC.java"); +// } +// +// public final void testEmitELCommentsRelatedMethodsDepthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_EACH_LEVEL); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13DIELC.java"); +// } +// +// public final void testEmitNFCommentsRelatedMethodsDepthInvocation() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_NEW_FAMILY); +// CommentRule c = new CommentRule(); +// c.setCommentText("// Preceding comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setPrecedingComment(c); +// c = new CommentRule(); +// c.setCommentText("// Trailing comment: TL=%TL%\n" + +// "// MN=%MN%\n" + +// "// AM=%AM%\n" + +// "// Level %LV%"); +// rs.getExtractedMethodsSettings().setTrailingComment(c); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13DINFC.java"); +// } +// +// public final void testRelatedMethodsException() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest13.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.RETAIN_ORIGINAL_ORDER); +// MethodAttributes ma = new MethodAttributes(); +// ma.setNoExtractedMethods(true); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression("GF"); +// rs.addItem(ma, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult13Ex.java"); +// } +// +// public final void testKeepOverloadedMethodsTogether() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest14.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(false); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.INVOCATION_ORDER); +// rs.setKeepOverloadedMethodsTogether(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult14.java"); +// } +// +// public final void testOverrides() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest15.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// } +// +// public final void testImplements() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest16.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// } +// +// public final void testXML() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest17.xml"); +// // we should not do anything to XML files. +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementTest17.xml"); +// } +// +// public final void testKeepGSTogether() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest18.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.ALPHABETICAL_ORDER); +// FieldAttributes fa = new FieldAttributes(); +// rs.addItem(fa, 0); +// MethodAttributes ma = new MethodAttributes(); +// ma.setConstructorMethodType(true); +// rs.addItem(ma, 1); +// ma = new MethodAttributes(); +// ma.setGetterSetterMethodType(true); +// ma.getSortAttr().setByName(true); +// rs.addItem(ma, 2); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult18.java"); +// } +// +// public final void testKeepGSWithProperty() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest18.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(true); +// rs.setKeepGettersSettersWithProperty(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.ALPHABETICAL_ORDER); +// FieldAttributes fa = new FieldAttributes(); +// rs.addItem(fa, 0); +// MethodAttributes ma = new MethodAttributes(); +// ma.setConstructorMethodType(true); +// rs.addItem(ma, 1); +// ma = new MethodAttributes(); +// ma.setGetterSetterMethodType(true); +// ma.getSortAttr().setByName(true); +// rs.addItem(ma, 2); +//// rs.setAskBeforeRearranging(true); // testing only +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult18A.java"); +// } +// +// public final void testKeepGSWithPropertyElseTogether() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest18B.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(true); +// rs.setKeepGettersSettersWithProperty(true); +// rs.getExtractedMethodsSettings().setOrdering(RelatedMethodsSettings.ALPHABETICAL_ORDER); +// FieldAttributes fa = new FieldAttributes(); +// rs.addItem(fa, 0); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("// Getters/Setters"); +// cr.setEmitCondition(CommentRule.EMIT_ALWAYS); +// rs.addItem(cr, 1); +// MethodAttributes ma = new MethodAttributes(); +// ma.setGetterSetterMethodType(true); +// ma.getSortAttr().setByName(true); +// ma.getGetterSetterDefinition().setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// ma.getGetterSetterDefinition().setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_IMMATERIAL); +// ma.getGetterSetterDefinition().setSetterNameCriterion(GetterSetterDefinition.SETTER_NAME_CORRECT_PREFIX); +// ma.getGetterSetterDefinition().setSetterBodyCriterion(GetterSetterDefinition.SETTER_BODY_IMMATERIAL); +// rs.addItem(ma, 2); +// cr = new CommentRule(); +// cr.setCommentText("// Other Methods"); +// cr.setEmitCondition(CommentRule.EMIT_ALWAYS); +// rs.addItem(cr, 3); +// ma = new MethodAttributes(); +// ma.getSortAttr().setByName(true); +// rs.addItem(ma, 4); +// +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult18B.java"); +// } +// +// public final void testKeepOverloadsTogetherOriginalOrder() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest19.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(false); +// rs.setKeepOverloadedMethodsTogether(true); +// rs.setOverloadedOrder(RearrangerSettings.OVERLOADED_ORDER_RETAIN_ORIGINAL); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult19A.java"); +// } +// +// public final void testKeepOverloadsTogetherAscendingOrder() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest19.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(false); +// rs.setKeepOverloadedMethodsTogether(true); +// rs.setOverloadedOrder(RearrangerSettings.OVERLOADED_ORDER_ASCENDING_PARAMETERS); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult19B.java"); +// } +// +// public final void testKeepOverloadsTogetherDescendingOrder() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest19.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(false); +// rs.setKeepOverloadedMethodsTogether(true); +// rs.setOverloadedOrder(RearrangerSettings.OVERLOADED_ORDER_DESCENDING_PARAMETERS); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult19C.java"); +// } +// +// public final void testInnerClassReferenceToChild() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest20.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult20.java"); +// } +// +// public final void testMultipleFieldDecl() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest21.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getSortAttr().setByName(true); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult21.java"); +// } +// +// public final void testRemoveBlankLines() throws Exception { +// configureByFile("/com/wrq/rearranger/SpaceTest1.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(0); +// rs.getAfterMethodLBrace().setForce(true); +// rs.getAfterMethodLBrace().setnBlankLines(0); +// rs.getBeforeMethodRBrace().setForce(true); +// rs.getBeforeMethodRBrace().setnBlankLines(0); +// rs.getAfterMethodRBrace().setForce(true); +// rs.getAfterMethodRBrace().setnBlankLines(0); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(0); +// rs.getAfterClassRBrace().setForce(true); +// rs.getAfterClassRBrace().setnBlankLines(0); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/SpaceResult1.java"); +// } +// +// public final void testAddBlankLines() throws Exception { +// configureByFile("/com/wrq/rearranger/SpaceTest2.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(2); +// rs.getAfterMethodLBrace().setForce(true); +// rs.getAfterMethodLBrace().setnBlankLines(3); +// rs.getBeforeMethodRBrace().setForce(true); +// rs.getBeforeMethodRBrace().setnBlankLines(2); +// rs.getAfterMethodRBrace().setForce(true); +// rs.getAfterMethodRBrace().setnBlankLines(1); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(3); +// rs.getAfterClassRBrace().setForce(true); +// rs.getAfterClassRBrace().setnBlankLines(4); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/SpaceResult2.java"); +// } +// +// public final void testInnerClassBlankLines() throws Exception { +// configureByFile("/com/wrq/rearranger/SpaceTest4.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(0); +// rs.getAfterMethodLBrace().setForce(true); +// rs.getAfterMethodLBrace().setnBlankLines(0); +// rs.getBeforeMethodRBrace().setForce(true); +// rs.getBeforeMethodRBrace().setnBlankLines(0); +// rs.getAfterMethodRBrace().setForce(true); +// rs.getAfterMethodRBrace().setnBlankLines(1); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(1); +// rs.getAfterClassRBrace().setForce(true); +// rs.getAfterClassRBrace().setnBlankLines(1); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/SpaceResult4.java"); +// } +// +// public void testInnerClassSpacing() throws Exception { +// configureByFile("/com/wrq/rearranger/SpaceTest5.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final File physFile = new File(InteractiveTest.DEFAULT_CONFIGURATION); +// rs = RearrangerSettings.getSettingsFromFile(physFile); +// rs.setAskBeforeRearranging(false); +// rs.getAfterClassRBrace().setnBlankLines(2); +// rs.getAfterClassRBrace().setForce(true); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(3); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/SpaceResult5.java"); +// } +// +// public void testNoRearrangementInnerClass() throws Exception { +// configureByFile("/com/wrq/rearranger/NoRearrangeInnerClassTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final File settingsFile = new File(InteractiveTest.DEFAULT_CONFIGURATION_ROOT + +// "/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml"); +// rs = RearrangerSettings.getSettingsFromFile(settingsFile); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/NoRearrangeInnerClassResult.java"); +// } +// +// public void testSpacingWithTrailingWhitespace() throws Exception { +// configureByFile("/com/wrq/rearranger/SpaceTest6.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/SpaceResult6.java"); +// } +// +// public void testSpacingJoinLineBug() throws Exception { +// configureByFile("/com/wrq/rearranger/SpaceTest7.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// File settingsFile = new File(InteractiveTest.DEFAULT_CONFIGURATION_ROOT + +// "/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml"); +// rs = RearrangerSettings.getSettingsFromFile(settingsFile); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/SpaceResult7.java"); +// } +// +// /** +// * Submitted by Brian Buckley. +// * +// * @throws Exception test exception +// */ +// public void testSpacingConflictingSettingBug() throws Exception { +// configureByFile("/com/wrq/rearranger/SpaceTest8.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(0); +// rs.getBeforeMethodLBrace().setForce(true); +// rs.getBeforeMethodLBrace().setnBlankLines(1); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/SpaceResult8.java"); +// } +// +// public void testGetPrefixImmaterial() throws Exception { +// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma = new MethodAttributes(); +// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); +// rs.addItem(ma, 0); +// ma.setGetterSetterMethodType(true); +// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_IMMATERIAL); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/GetPrefixImmaterialResult.java"); +// } +// +// public void testGetPrefixReturns() throws Exception { +// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma = new MethodAttributes(); +// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); +// rs.addItem(ma, 0); +// ma.setGetterSetterMethodType(true); +// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/GetPrefixReturnsResult.java"); +// } +// +// public void testGetPrefixReturnsField() throws Exception { +// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma = new MethodAttributes(); +// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); +// rs.addItem(ma, 0); +// ma.setGetterSetterMethodType(true); +// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS_FIELD); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/GetPrefixReturnsFieldResult.java"); +// } +// +// public void testGetFieldReturns() throws Exception { +// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma = new MethodAttributes(); +// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); +// rs.addItem(ma, 0); +// ma.setGetterSetterMethodType(true); +// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_MATCHES_FIELD); +// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/GetFieldReturnsResult.java"); +// } +// +// public void testGetFieldReturnsField() throws Exception { +// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma = new MethodAttributes(); +// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); +// rs.addItem(ma, 0); +// ma.setGetterSetterMethodType(true); +// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_MATCHES_FIELD); +// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS_FIELD); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/GetFieldReturnsFieldResult.java"); +// } +// +// public void testSpecialGS() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest22.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma = new MethodAttributes(); +// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); +// rs.addItem(ma, 0); +// ma.setGetterSetterMethodType(true); +// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS); +// gsd.setSetterBodyCriterion(GetterSetterDefinition.SETTER_BODY_IMMATERIAL); +// gsd.setSetterNameCriterion(GetterSetterDefinition.SETTER_NAME_CORRECT_PREFIX); +// rs.setKeepGettersSettersTogether(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult22.java"); +// } +// +// public void testInterfaceNoNameNotAlphabeticalNoExcludeMethodAlphabetical() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest23.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(false); +// InterfaceAttributes ia = new InterfaceAttributes(); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Header ****/"); +// ia.setPrecedingComment(cr); +// cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Trailer ***/"); +// ia.setTrailingComment(cr); +// ia.setNoExtractedMethods(true); +// ia.setMethodOrder(InterfaceAttributes.METHOD_ORDER_ALPHABETICAL); +// ia.setAlphabetizeInterfaces(false); +// rs.addItem(ia, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult23NNNANXMA.java"); +// } +// +// public void testInterfaceNoNameNotAlphabeticalNoExcludeMethodEncountered() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest23.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(false); +// InterfaceAttributes ia = new InterfaceAttributes(); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Header ****/"); +// ia.setPrecedingComment(cr); +// cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Trailer ***/"); +// ia.setTrailingComment(cr); +// ia.setNoExtractedMethods(true); +// ia.setMethodOrder(InterfaceAttributes.METHOD_ORDER_ENCOUNTERED); +// ia.setAlphabetizeInterfaces(false); +// rs.addItem(ia, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult23NNNANXME.java"); +// } +// +// public void testInterfaceNoNameNotAlphabeticalNoExcludeMethodInterfaceOrder() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest23.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(false); +// InterfaceAttributes ia = new InterfaceAttributes(); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Header ****/"); +// ia.setPrecedingComment(cr); +// cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Trailer ***/"); +// ia.setTrailingComment(cr); +// ia.setNoExtractedMethods(true); +// ia.setMethodOrder(InterfaceAttributes.METHOD_ORDER_INTERFACE_ORDER); +// ia.setAlphabetizeInterfaces(false); +// rs.addItem(ia, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult23NNNANXMI.java"); +// } +// +// public void testInterfaceByNameNotAlphabeticalNoExcludeMethodEncountered() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest23.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(false); +// InterfaceAttributes ia = new InterfaceAttributes(); +// ia.getNameAttr().setMatch(true); +// ia.getNameAttr().setExpression("IFace1"); +// ia.setNoExtractedMethods(true); +// ia.setMethodOrder(InterfaceAttributes.METHOD_ORDER_ENCOUNTERED); +// ia.setAlphabetizeInterfaces(false); +// rs.addItem(ia, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult23BNNANXME.java"); +// } +// +// public void testInterfaceIsAlphabeticalNoExcludeMethodEncountered() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest23.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(false); +// InterfaceAttributes ia = new InterfaceAttributes(); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Header ****/"); +// ia.setPrecedingComment(cr); +// cr = new CommentRule(); +// cr.setCommentText("/**** Interface %IF% Trailer ***/"); +// ia.setTrailingComment(cr); +// ia.setNoExtractedMethods(true); +// ia.setMethodOrder(InterfaceAttributes.METHOD_ORDER_ENCOUNTERED); +// ia.setAlphabetizeInterfaces(true); +// rs.addItem(ia, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult23NNIANXME.java"); +// } +// +// public void testNPE24() throws Exception { +// // submitted by Nathan Brown. Caused NPE in Rearranger plugin version 1.7. +// int itemIndex = 0; +// configureByFile("/com/wrq/rearranger/RearrangementTest24.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(true); +// rs.setKeepOverloadedMethodsTogether(true); +//// rs.setAskBeforeRearranging(false); +// rs.setOverloadedOrder(1); +// rs.setGlobalCommentPattern(""); +// rs.setRemoveBlanksInsideCodeBlocks(false); +// FieldAttributes fa; +// fa = new FieldAttributes(); +// fa.getSortAttr().setByName(false); +// fa.getPlAttr().setPlPublic(true); +// fa.getPlAttr().setPlPrivate(true); +// fa.getPlAttr().setPlProtected(true); +// fa.getPlAttr().setPlPackage(true); +// fa.getPlAttr().setInvertProtectionLevel(false); +// fa.getStAttr().setValue(true); +// fa.getStAttr().setInvert(false); +// rs.addItem(fa, itemIndex++); +// fa = new FieldAttributes(); +// fa.getStAttr().setValue(true); +// fa.getStAttr().setInvert(true); +// fa.getInitToAnonClassAttr().setValue(true); +// fa.getInitToAnonClassAttr().setInvert(true); +// rs.addItem(fa, itemIndex++); +// fa = new FieldAttributes(); +// fa.getInitToAnonClassAttr().setValue(true); +// rs.addItem(fa, itemIndex++); +// MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.getStaticInitAttr().setValue(true); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.setConstructorMethodType(true); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression("clone"); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression("dispose"); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression("_dispose"); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression("build"); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.getAbstractAttr().setValue(true); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.getStAttr().setValue(true); +// ma.getStAttr().setInvert(true); +// ma.getAbstractAttr().setValue(true); +// ma.getAbstractAttr().setInvert(true); +// ma.setOtherMethodType(true); +// rs.addItem(ma, itemIndex++); +// ma = new MethodAttributes(); +// ma.setGetterSetterMethodType(true); +// rs.addItem(ma, itemIndex++); +// InnerClassAttributes ica = new InnerClassAttributes(); +// rs.addItem(ica, itemIndex++); +// ma = new MethodAttributes(); +// ma.getStAttr().setValue(true); +// rs.addItem(ma, itemIndex); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setBelowFirstCaller(false); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// rs.getExtractedMethodsSettings().setOrdering(0); +// rs.getExtractedMethodsSettings().setNonPrivateTreatment(2); +// rs.getExtractedMethodsSettings().setCommentType(0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// } +// +// public void testSpacingOptions() throws Exception { +// /** +// * From Thomas Singer: +// * I've enabled +// * - Force 0 blank lines before class close brace "}" +// * - Force 0 blank lines before method close brace "}" +// * - Remove initial and final blank lines inside code block +// * but in the code below the blank lines don't get removed when invoking +// * Rearrager from editor's context menu: +// */ +// configureByFile("/com/wrq/rearranger/RearrangementTest25.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(0); +// rs.getBeforeMethodRBrace().setForce(true); +// rs.getBeforeMethodRBrace().setnBlankLines(0); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult25.java"); +// } +// +// public void testPriority() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.setPriority(1); +// rs.addItem(ma, 0); +// ma = new MethodAttributes(); +// ma.setPriority(2); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression("method.*"); +// rs.addItem(ma, 1); +// ma = new MethodAttributes(); +// ma.setPriority(2); +// ma.getNameAttr().setMatch(true); +// ma.getNameAttr().setExpression(".*Method"); +// rs.addItem(ma, 2); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult1A.java"); +// } +// +// public void testGSRuleWithClassInitializer() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest26.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.setGetterSetterMethodType(true); +// rs.addItem(ma, 0); +// rs.setKeepGettersSettersTogether(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult26.java"); +// } +// +// public void testKeepGSTogetherAndExtractedMethods() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest27.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(true); +// rs.setKeepOverloadedMethodsTogether(true); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult27.java"); +// } +// +// public void testRegexEscape() throws Exception { +// String s = "// ********* start of fields *********"; +// String result = RegexUtil.escape(s); +// assertEquals("sequence reduction failed", "// \\*{9} start of fields \\*{9}", result); +// s = "// \\ backslash \n \t \\d [...] (^...$)"; +// result = RegexUtil.escape(s); +// assertEquals("special character escape failed", "// \\\\ backslash \\n \\t \\\\d \\[\\.\\.\\.\\]" + +// " \\(\\^\\.\\.\\.\\$\\)", result); +// } +// +// public void testRegexCombine() throws Exception { +// String p1 = RegexUtil.escape("// ********* start of fields *********"); +// String p2 = RegexUtil.escape("// ********* start of methods *********"); +// List list = new ArrayList(); +// list.add(p1); +// list.add(p2); +// String result = RegexUtil.combineExpressions(list); +// assertEquals("combination failed", "// \\*{9} start of (fiel|metho)ds \\*{9}", result); +// String p3 = RegexUtil.escape("// ***** start of interfaces *******"); +// list.add(p3); +// result = RegexUtil.combineExpressions(list); +// assertEquals("combination failed", "// (\\*{9} start of (fiel|metho)ds \\*{9}|" + +// "\\*{5} start of interfaces \\*{7})", result); +// } +// +// public void testVariousComments() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest28.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(true); +// rs.setKeepOverloadedMethodsTogether(true); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("// start of fields"); +// cr.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE); +// cr.setAllSubsequentRules(true); +// cr.setnSubsequentRulesToMatch(1); +// rs.addItem(cr, 0); +// FieldAttributes fa = new FieldAttributes(); +// rs.addItem(fa, 1); +// cr = new CommentRule(); +// cr.setCommentText("// end of fields"); +// cr.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_PRECEDING_RULE); +// cr.setAllPrecedingRules(true); +// cr.setnPrecedingRulesToMatch(1); +// rs.addItem(cr, 2); +// InterfaceAttributes ia = new InterfaceAttributes(); +// ia.setMethodOrder(InterfaceAttributes.METHOD_ORDER_ENCOUNTERED); +// ia.setAlphabetizeInterfaces(false); +// ia.setNoExtractedMethods(false); +// cr = new CommentRule(); +// cr.setCommentText("// start of interface %IF%"); +// ia.setPrecedingComment(cr); +// cr = new CommentRule(); +// cr.setCommentText("// end of interface %IF%"); +// ia.setTrailingComment(cr); +// rs.addItem(ia, 3); +// rs.getExtractedMethodsSettings().setBelowFirstCaller(false); +// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); +// rs.getExtractedMethodsSettings().setCommentType(RelatedMethodsSettings.COMMENT_TYPE_EACH_LEVEL); +// rs.getExtractedMethodsSettings().setNonPrivateTreatment(RelatedMethodsSettings.NON_PRIVATE_EXTRACTED_ANY_CALLERS); +// rs.getExtractedMethodsSettings().setDepthFirstOrdering(true); +// cr = new CommentRule(); +// cr.setCommentText("// Level %LV% methods"); +// rs.getExtractedMethodsSettings().setPrecedingComment(cr); +// cr = new CommentRule(); +// cr.setCommentText("// end Level %LV% methods"); +// rs.getExtractedMethodsSettings().setTrailingComment(cr); +// // should work with or without the global comment pattern +//// rs.setGlobalCommentPattern("// (((start|end) of (fields|interface [A-Za-z_0-9]+))|(end|)Level [0-9]+ methods)"); +// rah.rearrangeDocument(getProject(), file, rs, doc); // note - blank lines end up "reversed" +// // where a blank line, generated comment, and method occur in order; the generated comment is removed +// // and the blank line precedes the method; when the new comment is generated, it is inserted before +// // the blank line. +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult28.java"); +// } +// +// public void testParseBugInfiniteLoop() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest29.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementTest29.java"); +// } +// +// public void testSpacingBug() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest30.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(0); +// rs.getAfterClassRBrace().setForce(true); +// rs.getAfterClassRBrace().setnBlankLines(1); +// rs.getAfterMethodLBrace().setForce(true); +// rs.getAfterMethodLBrace().setnBlankLines(0); +// rs.getAfterMethodRBrace().setForce(true); +// rs.getAfterMethodRBrace().setnBlankLines(1); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(0); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult30.java"); +// } +// +// public void testSpacingBug2() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest31.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(0); +// rs.getAfterClassRBrace().setForce(true); +// rs.getAfterClassRBrace().setnBlankLines(1); +// rs.getAfterMethodLBrace().setForce(true); +// rs.getAfterMethodLBrace().setnBlankLines(0); +// rs.getAfterMethodRBrace().setForce(true); +// rs.getAfterMethodRBrace().setnBlankLines(1); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(0); +// rs.getBeforeMethodRBrace().setForce(true); +// rs.getBeforeMethodRBrace().setnBlankLines(0); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult31.java"); +// } +// +// public void testSpacingBug3() throws Exception { +// configureByFile("/com/wrq/rearranger/DomainExpanderTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(0); +// rs.getAfterClassRBrace().setForce(true); +// rs.getAfterClassRBrace().setnBlankLines(1); +// rs.getAfterMethodLBrace().setForce(true); +// rs.getAfterMethodLBrace().setnBlankLines(0); +// rs.getAfterMethodRBrace().setForce(true); +// rs.getAfterMethodRBrace().setnBlankLines(0); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(0); +// rs.getBeforeMethodRBrace().setForce(true); +// rs.getBeforeMethodRBrace().setnBlankLines(0); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/DomainExpanderResult.java"); +// } +// +// /** +// * Bug occurs when one or more blank lines precede a generated comment. +// * When comment is removed, blank lines now precede the item. Comment is inserted +// * at the beginning (i.e. before the blank lines) and a newline character is +// * prefixed to the comment. Net effect is that new blank line(s) appear after the comment. +// * +// * @throws Exception test exception +// */ +// public void testGeneratedCommentSpacingBug() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest32.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult32.java"); +// } +// +// public void testGeneratedCommentSpacing() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest32.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult32.java"); +// } +// +// public void testInnerClassComments() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest34.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.setRearrangeInnerClasses(true); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("// ----- OUTER CLASS -----\n"); +// rs.getClassOrderAttributeList().add(0, cr); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult34.java"); +// } +// +// public void testInnerClassCommentsNoRearrangement() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest34.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.setRearrangeInnerClasses(false); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("// ----- OUTER CLASS -----\n"); +// rs.getClassOrderAttributeList().add(0, cr); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult34B.java"); +// } +// +// public void testFirstInsertionOfComment() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest35.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// CommentRule cr = new CommentRule(); +// cr.setCommentText("// ----- FIELDS -----\n"); +// FieldAttributes fa = new FieldAttributes(); +// rs.addItem(cr, 0); +// rs.addItem(fa, 1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult35.java"); +// } +// +// public void testExcludeFromExtraction() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest36.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementTest36.java"); +// } +// +// public void testInterferingGSNames() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest37.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(true); +// rs.getDefaultGSDefinition().setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_IMMATERIAL); +// rs.getDefaultGSDefinition().setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// rs.getDefaultGSDefinition().setSetterBodyCriterion(GetterSetterDefinition.SETTER_BODY_IMMATERIAL); +// rs.getDefaultGSDefinition().setSetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult37.java"); +// } +// +// public void testInterferingGSNamesNoKGSTogether() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest37.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.setKeepGettersSettersTogether(false); +// rs.getDefaultGSDefinition().setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_IMMATERIAL); +// rs.getDefaultGSDefinition().setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// rs.getDefaultGSDefinition().setSetterBodyCriterion(GetterSetterDefinition.SETTER_BODY_IMMATERIAL); +// rs.getDefaultGSDefinition().setSetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementTest37.java"); +// } +// +// public void testRemoveBlankLineInsideMethodBug() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest38.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// File settingsFile = new File(InteractiveTest.DEFAULT_CONFIGURATION_ROOT + +// "/test/testData/com/wrq/rearranger/RearrangementTest38cfg.xml"); +// rs = RearrangerSettings.getSettingsFromFile(settingsFile); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementTest38.java"); +// } +// +// public void testSortFieldsByTypeAndName() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest39.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getSortAttr().setByType(true); +// fa.getSortAttr().setByName(true); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult39B.java"); +// } +// +// public void testSortFieldsByType() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest39.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getSortAttr().setByType(true); +// fa.getSortAttr().setByName(false); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult39C.java"); +// } +// +// public void testSortFieldsByTypeICAndName() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest39.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getSortAttr().setByType(true); +// fa.getSortAttr().setTypeCaseInsensitive(true); +// fa.getSortAttr().setByName(true); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult39.java"); +// } +// +// public void testSortFieldsByTypeIC() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest39.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getSortAttr().setByType(true); +// fa.getSortAttr().setTypeCaseInsensitive(true); +// fa.getSortAttr().setByName(false); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult39A.java"); +// } +// +// /** +// * test detection of method overrides/overridden/implements/implemented attributes. +// * +// * @throws Exception test exception +// */ +// public void testOverImpl() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest40.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult40.java"); +// } +// +// public final void testRemoveBlankLinesBeforeMethod() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest41.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rs.getAfterClassLBrace().setForce(true); +// rs.getAfterClassLBrace().setnBlankLines(0); +// rs.getBeforeMethodLBrace().setForce(true); +// rs.getBeforeMethodLBrace().setnBlankLines(0); +// rs.getAfterMethodLBrace().setForce(true); +// rs.getAfterMethodLBrace().setnBlankLines(0); +// rs.getBeforeMethodRBrace().setForce(true); +// rs.getBeforeMethodRBrace().setnBlankLines(0); +// rs.getAfterMethodRBrace().setForce(true); +// rs.getAfterMethodRBrace().setnBlankLines(0); +// rs.getBeforeClassRBrace().setForce(true); +// rs.getBeforeClassRBrace().setnBlankLines(0); +// rs.getAfterClassRBrace().setForce(true); +// rs.getAfterClassRBrace().setnBlankLines(0); +// rs.setRemoveBlanksInsideCodeBlocks(true); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult41.java"); +// } +// +// public final void testEnumClass() throws Exception { +// final Project project = getProject(); +// final LanguageLevelProjectExtension llpExtension = LanguageLevelProjectExtension.getInstance(project); +// LanguageLevel oldLevel = llpExtension.getLanguageLevel(); +// llpExtension.setLanguageLevel(LanguageLevel.JDK_1_5); +// configureByFile("/com/wrq/rearranger/RearrangementTest42.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult42.java"); +// llpExtension.setLanguageLevel(oldLevel); +// } +// +// public final void testNumParameters() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest43.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// MethodAttributes ma; +// ma = new MethodAttributes(); +// ma.getMinParamsAttr().setMatch(true); +// ma.getMinParamsAttr().setValue(2); +// ma.getMaxParamsAttr().setMatch(true); +// ma.getMaxParamsAttr().setValue(3); +// rs.addItem(ma, 0); +// ma = new MethodAttributes(); +// ma.getMinParamsAttr().setMatch(true); +// ma.getMinParamsAttr().setValue(1); +// rs.addItem(ma, 1); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult43.java"); +// } +// +// public final void testGeneratedComment() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest44.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// CommentRule cr = new CommentRule(); +// CommentFillString cfs = cr.getCommentFillString(); +// cfs.setFillString("-+"); +// cfs.setUseProjectWidthForFill(false); +// cfs.setFillWidth(30); +// cr.setEmitCondition(CommentRule.EMIT_ALWAYS); +// cr.setCommentText("// %FS% METHODS %FS%"); +// rs.addItem(cr, 0); +// MethodAttributes ma; +// ma = new MethodAttributes(); // match all methods +// rs.addItem(ma, 1); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult44.java"); +// } +// +// public void testEnum1() throws Exception { +// final Project project = getProject(); +// final LanguageLevelProjectExtension llpExtension = LanguageLevelProjectExtension.getInstance(project); +// LanguageLevel oldLevel = llpExtension.getLanguageLevel(); +// llpExtension.setLanguageLevel(LanguageLevel.JDK_1_5); +// configureByFile("/com/wrq/rearranger/Enum1Test.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(project).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// rs.setRearrangeInnerClasses(true); +// rs.getExtractedMethodsSettings().setBelowFirstCaller(true); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(project, file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/Enum1Result.java"); +// llpExtension.setLanguageLevel(oldLevel); +// } +// +// public void testEnum2() throws Exception { +// final Project project = getProject(); +// final LanguageLevelProjectExtension llpExtension = LanguageLevelProjectExtension.getInstance(project); +// LanguageLevel oldLevel = llpExtension.getLanguageLevel(); +// llpExtension.setLanguageLevel(LanguageLevel.JDK_1_5); +// configureByFile("/com/wrq/rearranger/Enum2Test.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(project).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.setRearrangeInnerClasses(true); +// rs.getAfterClassRBrace().setForce(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(project, file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/Enum2Result.java"); +// llpExtension.setLanguageLevel(oldLevel); +// } +// +// public void testEnum2A() throws Exception { +// final Project project = getProject(); +// final LanguageLevelProjectExtension llpExtension = LanguageLevelProjectExtension.getInstance(project); +// LanguageLevel oldLevel = llpExtension.getLanguageLevel(); +// llpExtension.setLanguageLevel(LanguageLevel.JDK_1_5); +// configureByFile("/com/wrq/rearranger/Enum2Test.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(project).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.setRearrangeInnerClasses(false); +// rs.getAfterClassRBrace().setForce(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(project, file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/Enum2AResult.java"); +// llpExtension.setLanguageLevel(oldLevel); +// } +// +// public void testRearrangementIncompleteLastLine() throws Exception { +// configureByFile("/com/wrq/rearranger/IncompleteLineTest.java"); +// final PsiFile file = getFile(); +// Project project = getProject(); +// final Document doc = PsiDocumentManager.getInstance(project).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(project, file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/IncompleteLineResult.java"); +// } +// +// public void testOverloadedMethodCategorization() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest45.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); +// rs.setAskBeforeRearranging(false); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(1); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult45.java"); +// } +// +// public void testSuperclassAlgorithm() throws Exception { +// final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(getProject()); +// final PsiClass aClass = +// psiFacade.getElementFactory(). +// createClassFromText("public String toString() {return null;}", null); +// final PsiMethod method = aClass.getMethods()[0]; +// final PsiMethod[] superMethods = method.findSuperMethods(); +// assertEquals(1, superMethods.length); +// PsiClass psiClass = superMethods[0].getContainingClass(); +// if (psiClass == null) { +// fail("missing containing class"); +// } +// else { +// assertEquals("java.lang.Object", psiClass.getQualifiedName()); +// } +// } +// +// public void testSortingOriginalOrder() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest46.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlProtected(true); +// fa.getSortAttr().setByModifiers(false); +// fa.getSortAttr().setByType(false); +// fa.getSortAttr().setTypeCaseInsensitive(false); +// fa.getSortAttr().setByName(false); +// fa.getSortAttr().setNameCaseInsensitive(false); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult46A.java"); +// } +// +// public void testSortingModifierOrder() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest46.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlProtected(true); +// fa.getSortAttr().setByModifiers(true); +// fa.getSortAttr().setByType(false); +// fa.getSortAttr().setTypeCaseInsensitive(false); +// fa.getSortAttr().setByName(false); +// fa.getSortAttr().setNameCaseInsensitive(false); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult46B.java"); +// } +// +// public void testSortingTypeOrder() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest46.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlProtected(true); +// fa.getSortAttr().setByModifiers(false); +// fa.getSortAttr().setByType(true); +// fa.getSortAttr().setTypeCaseInsensitive(false); +// fa.getSortAttr().setByName(false); +// fa.getSortAttr().setNameCaseInsensitive(false); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult46C.java"); +// } +// +// public void testSortingTypeOrderCI() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest46.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlProtected(true); +// fa.getSortAttr().setByModifiers(false); +// fa.getSortAttr().setByType(true); +// fa.getSortAttr().setTypeCaseInsensitive(true); +// fa.getSortAttr().setByName(false); +// fa.getSortAttr().setNameCaseInsensitive(false); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult46D.java"); +// } +// +// public void testSortingMTNOrderCI() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest46.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlProtected(true); +// fa.getSortAttr().setByModifiers(true); +// fa.getSortAttr().setByType(true); +// fa.getSortAttr().setTypeCaseInsensitive(true); +// fa.getSortAttr().setByName(true); +// fa.getSortAttr().setNameCaseInsensitive(true); +// rs.addItem(fa, 0); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult46E.java"); +// } +// +// public void testEnumSelection() throws Exception { +// configureByFile("/com/wrq/rearranger/RearrangementTest47.java"); +// final PsiFile file = getFile(); +// final Project project = getProject(); +// final LanguageLevelProjectExtension llpExtension = LanguageLevelProjectExtension.getInstance(project); +// LanguageLevel oldLevel = llpExtension.getLanguageLevel(); +// llpExtension.setLanguageLevel(LanguageLevel.JDK_1_5); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// FieldAttributes fa = new FieldAttributes(); +// fa.getStAttr().setValue(true); +// rs.addItem(fa, 0); +// InnerClassAttributes ica = new InnerClassAttributes(); +// ica.getEnumAttr().setValue(true); +// rs.addItem(ica, 1); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult47.java"); +// llpExtension.setLanguageLevel(oldLevel); +// } +// +// public void testOverloaded1() throws Exception { +// configureByFile("/com/wrq/rearranger/OverloadedTest1.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File("testData/com/wrq/rearranger/OverloadedConfig.xml")); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/OverloadedResult1.java"); +// } +// +// public void testGenerics1() throws Exception { +// configureByFile("/com/wrq/rearranger/GenericsTest1.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File("testData/com/wrq/rearranger/OverloadedConfig.xml")); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/GenericsResult1.java"); +// } +// +// public void testInterface1() throws Exception { +// configureByFile("/com/wrq/rearranger/InterfaceTest1.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlPublic(true); // match all public fields; in an interface, all constants are regarded as public +// fa.getStAttr().setValue(true); // match all static fields; in an interface, all constants are regarded as public +// rs.addItem(fa, 0); +// MethodAttributes ma = new MethodAttributes(); +// ma.getPlAttr().setPlPublic(true); // match all public methods; in an interface, all methods are regarded as public +// rs.addItem(ma, 1); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/InterfaceResult1.java"); +// } +// +// public void testCorruptRespacing() throws Exception { +// configureByFile("/com/wrq/rearranger/CorruptRespacingTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// rs = RearrangerSettings.getSettingsFromFile(new File("testData/com/wrq/rearranger/CorruptionConfig.xml")); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/CorruptRespacingResult.java"); +// } +// +// public void testCommentSeparator1() throws Exception { +// configureByFile("/com/wrq/rearranger/CommentSeparatorTest1.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final CommentRule c = new CommentRule(); +// c.setCommentText("\n\t// Fields %FS%\n"); +// c.setEmitCondition(CommentRule.EMIT_IF_ITEMS_MATCH_SUBSEQUENT_RULE); +// CommentFillString cfs = new CommentFillString(); +// cfs.setFillString("="); +// cfs.setUseProjectWidthForFill(false); +// cfs.setFillWidth(80); +// c.setCommentFillString(cfs); +// rs.addItem(c, 0); +// FieldAttributes fa = new FieldAttributes(); +// fa.getPlAttr().setPlPublic(true); +// rs.addItem(fa, 1); +// rs.setAskBeforeRearranging(false); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.setTabSize(4); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/CommentSeparatorResult1.java"); +// } +// +// public void testEmptySetter() throws Exception { +// configureByFile("/com/wrq/rearranger/BitFieldTest.java"); +// final PsiFile file = getFile(); +// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); +// final File physFile = new File(InteractiveTest.DEFAULT_CONFIGURATION); +// rs = RearrangerSettings.getSettingsFromFile(physFile); +// rs.setAskBeforeRearranging(false); +// rs.getAfterClassRBrace().setnBlankLines(2); +// rs.getAfterClassRBrace().setForce(true); +// rs.getNewlinesAtEOF().setForce(true); +// rs.getNewlinesAtEOF().setnBlankLines(3); +// final RearrangerActionHandler rah = new RearrangerActionHandler(); +// rah.rearrangeDocument(getProject(), file, rs, doc); +// super.checkResultByFile("/com/wrq/rearranger/BitFieldResult.java"); +// } + + private void doTest(@NotNull String srcFileName, @Nullable String expectedResultFileName) { + myFixture.configureByFile("${srcFileName}.java") + ApplicationManager.application.runWriteAction { + new RearrangerActionHandler().rearrangeDocument(myFixture.project, myFixture.file, mySettings, myFixture.editor.document); + } + myFixture.checkResultByFile("${expectedResultFileName}.java") + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/settings/CommentFillStringTest.java b/plugins/rearranger/test/src/com/wrq/rearranger/settings/CommentFillStringTest.java new file mode 100644 index 000000000000..58da684adbb4 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/settings/CommentFillStringTest.java @@ -0,0 +1,27 @@ +package com.wrq.rearranger.settings; + +/** + * Test fill string pattern generation. + */ + +import junit.framework.TestCase; + +public class CommentFillStringTest + extends TestCase +{ + CommentFillString cfs; + + public void testGetFillStringPattern() throws Exception { + String result; + cfs = new CommentFillString(); + cfs.setFillString("a"); + result = cfs.getFillStringPattern(); + assertEquals("(a)*", result); + cfs.setFillString("abc"); + result = cfs.getFillStringPattern(); + assertEquals("(abc)*(ab|a)?", result); + cfs.setFillString("-=*"); + result = cfs.getFillStringPattern(); + assertEquals("(-=\\*)*(-=|-)?", result); + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributesTest.java b/plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributesTest.java new file mode 100644 index 000000000000..ccb6a4281ad3 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/MethodAttributesTest.java @@ -0,0 +1,66 @@ +package com.wrq.rearranger.settings.attributeGroups; + +/** + * Test toString() method for MethodAttributes. + */ + +import junit.framework.TestCase; + +public class MethodAttributesTest + extends TestCase +{ + MethodAttributes ma; + + public void testToString() throws Exception { + ma = new MethodAttributes(); + // test various combinations of min/max parameters, name, and return type. + ma.getPlAttr().setPlPublic(true); + // min = ? max = ? name = ? return = ? + setma(false, 0, false, 0, null, null, "public methods"); + // min = 1 max = ? name = ? return = ? + setma(true, 0, false, 0, null, null, "public methods with at least 0 parameters"); + setma(true, 1, false, 0, null, null, "public methods with at least 1 parameter"); + setma(true, 2, false, 0, null, null, "public methods with at least 2 parameters"); + // min = ? max = 1 name = ? return = ? + setma(false, 0, true, 0, null, null, "public methods with at most 0 parameters"); + setma(false, 0, true, 1, null, null, "public methods with at most 1 parameter"); + setma(false, 0, true, 2, null, null, "public methods with at most 2 parameters"); + // min = ? max = ? name = N return = ? + setma(false, 0, false, 0, "NAME", null, "public methods whose names match 'NAME'"); + // min = ? max = ? name = ? return = R + setma(false, 0, false, 0, null, "int", "public methods whose return types match 'int'"); + // + // min = 1 max = 3 name = ? return = ? + setma(true, 0, true, 0, null, null, "public methods with 0 parameters"); + setma(true, 1, true, 1, null, null, "public methods with 1 parameter"); + setma(true, 2, true, 2, null, null, "public methods with 2 parameters"); + setma(true, 0, true, 2, null, null, "public methods with 0 to 2 parameters"); + // min = 1 max = 1 name = N return = ? + setma(true, 0, true, 2, "NAME", null, "public methods with 0 to 2 parameters, " + + "and whose names match 'NAME'"); + // min = 1 max = 1 name = ? return = R + setma(true, 0, true, 2, null, "int", "public methods with 0 to 2 parameters, " + + "and whose return types match 'int'"); + // min = 1 max = 1 name = N return = R + setma(true, 0, true, 2, "NAME", "int", "public methods with 0 to 2 parameters, " + + "whose names match 'NAME', and whose return types match 'int'"); + ma.getMinParamsAttr().setMatch(true); + ma.getMinParamsAttr().setValue(1); + ma.getMinParamsAttr().setMatch(true); + ma.getMinParamsAttr().setValue(1); + } + + private void setma(boolean minMatch, int min, boolean maxMatch, int max, String name, String returnValue, + String description) + { + ma.getMinParamsAttr().setMatch(minMatch); + ma.getMinParamsAttr().setValue(min); + ma.getMaxParamsAttr().setMatch(maxMatch); + ma.getMaxParamsAttr().setValue(max); + ma.getNameAttr().setMatch(name != null); + ma.getNameAttr().setExpression(name); + ma.getReturnTypeAttr().setMatch(returnValue != null); + ma.getReturnTypeAttr().setExpression(returnValue); + assertEquals("wrong description", description, ma.toString()); + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/RegexUtilTest.java b/plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/RegexUtilTest.java new file mode 100644 index 000000000000..1be748071964 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/settings/attributeGroups/RegexUtilTest.java @@ -0,0 +1,25 @@ +package com.wrq.rearranger.settings.attributeGroups; + +/** + * Todo - describe class. + *

+ * Corresponds to portions of: todo - insert .c and .h file references + */ + +import junit.framework.TestCase; + +public class RegexUtilTest + extends TestCase +{ + RegexUtil regexUtil; + + public void testReplaceAllFS() throws Exception { + String result; + result = RegexUtil.replaceAllFS("abc", ""); + assertEquals("abc", result); + result = RegexUtil.replaceAllFS("ab%FS%c", ""); + assertEquals("abc", result); + result = RegexUtil.replaceAllFS("%FS%ab%FS%", "xx"); + assertEquals("xxabxx", result); + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass1.java b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass1.java new file mode 100644 index 000000000000..0c978a0f09d2 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass1.java @@ -0,0 +1,19 @@ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Oct 30, 2003 + * Time: 2:53:43 PM + * To change this template use Options | File Templates. + */ +final class TestClass1 { + public static final int CONSTANT1 = 1; + public static final int CONSTANT2 = 2; + /** end of public static final fields */ + private final int privateField1; + + public TestClass1(final int privateField1) { + this.privateField1 = privateField1; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass2.java b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass2.java new file mode 100644 index 000000000000..86871ec6db2f --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestClass2.java @@ -0,0 +1,38 @@ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Oct 31, 2003 + * Time: 11:48:02 AM + * To change this template use Options | File Templates. + */ +final class TestClass2 { +// ------------------------------ FIELDS ------------------------------ + + public static final int CONSTANT3 = 3; + public static final int CONSTANT4 = 4; + /** end of public static final fields */ + private final int privateField5; + +// --------------------------- CONSTRUCTORS --------------------------- + + public TestClass2(final int privateField1) { + this.privateField5 = privateField1; + } + +// -------------------------- INNER CLASSES -------------------------- + + class inner1 { + // test class + } + + + class inner2 { + // test class + } +} + +class outer1 { + // test class +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestEnum.java b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestEnum.java new file mode 100644 index 000000000000..e641493305d4 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestEnum.java @@ -0,0 +1,24 @@ +/** + * $id + * Author: Dave Kriewall + * Created: Oct 20, 2005 + * Copyright 2004, WRQ, Inc. + */ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. User: JJohnson Date: Aug 30, 2005 Time: 11:06:54 AM To change this template use File | + * Settings | File Templates. + */ +public class TestEnum implements Cloneable { +} + +class Utilities { +// -------------------------- STATIC METHODS -------------------------- + + public static String toString(Object receipt) + + { + return null; //To change body of created methods use File | Settings | File Templates. + } +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestImplementation.java b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestImplementation.java new file mode 100644 index 000000000000..277ff056f252 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestImplementation.java @@ -0,0 +1,13 @@ +package com.wrq.rearranger.testClasses; + +public class TestImplementation + implements TestInterface +{ + public void method1() { + // implements the method of the interface + } + + public boolean equals(Object obj) { + return super.equals(obj); + } +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestInterface.java b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestInterface.java new file mode 100644 index 000000000000..4b7787460917 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestInterface.java @@ -0,0 +1,19 @@ +package com.wrq.rearranger.testClasses; + +public interface TestInterface { +// -------------------------- OTHER METHODS -------------------------- + + void method1(); + +// -------------------------- INNER CLASSES -------------------------- + + class inner { + int i; + } +} + +class outer { +// ------------------------------ FIELDS ------------------------------ + + int j; +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestOverride.java b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestOverride.java new file mode 100644 index 000000000000..831806681dc1 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/testClasses/TestOverride.java @@ -0,0 +1,20 @@ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Dec 31, 2003 + * Time: 2:27:46 PM + * To change this template use Options | File Templates. + */ +public class TestOverride + extends TestImplementation +{ + public void method1() { + super.method1(); //To change body of overriden methods use Options | File Templates. + } + + public boolean equals(Object obj) { + return super.equals(obj); //To change body of overriden methods use Options | File Templates. + } +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/util/CommentUtilTest.java b/plugins/rearranger/test/src/com/wrq/rearranger/util/CommentUtilTest.java new file mode 100644 index 000000000000..854d10bfb7f4 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/util/CommentUtilTest.java @@ -0,0 +1,57 @@ +package com.wrq.rearranger.util; + +/** + * Test comment expansion with fill patterns. + */ + +import junit.framework.TestCase; + +public class CommentUtilTest + extends TestCase +{ + CommentUtil commentUtil; + + public void testExpandFill() throws Exception { + String result; + // test left justify, right justify, center justify, multiline, multiple fills + result = CommentUtil.expandFill("Method Name %FS%\n", 30, 4, "-="); + assertEquals("left justify failed", "Method Name -=-=-=-=-=-=-=-=-=\n", result); + result = CommentUtil.expandFill("%FS% Method Name\n", 30, 4, "-="); + assertEquals("right justify failed", "-=-=-=-=-=-=-=-=-= Method Name\n", result); + result = CommentUtil.expandFill("%FS% Method Name %FS%\n", 30, 4, "-="); + assertEquals("center justify failed", "-=-=-=-=- Method Name -=-=-=-=\n", result); + result = CommentUtil.expandFill("Method Name %FS%\n" + + "%FS% Method Name\n" + + "%FS% Method Name %FS%\n\n", 30, 4, "-="); + assertEquals("multiline failed", "Method Name -=-=-=-=-=-=-=-=-=\n" + + "-=-=-=-=-=-=-=-=-= Method Name\n" + + "-=-=-=-=- Method Name -=-=-=-=\n\n", result); + result = CommentUtil.expandFill("Method Name %FS%\n" + + "%FS% Method Name\n" + + "%FS% Method Name %FS%\n", 30, 4, "-="); + assertEquals("multiline failed", "Method Name -=-=-=-=-=-=-=-=-=\n" + + "-=-=-=-=-=-=-=-=-= Method Name\n" + + "-=-=-=-=- Method Name -=-=-=-=\n", result); + result = CommentUtil.expandFill("Method Name %FS%\n" + + "%FS% Method Name\n" + + "%FS% Method Name %FS%", 30, 4, "-="); + assertEquals("multiline failed", "Method Name -=-=-=-=-=-=-=-=-=\n" + + "-=-=-=-=-=-=-=-=-= Method Name\n" + + "-=-=-=-=- Method Name -=-=-=-=", result); + result = CommentUtil.expandFill("1%FS%2%FS%3%FS%4\n", 36, 4, "abcde"); + assertEquals("multiple fills failed", "1abcdeabcdea2abcdeabcdea3abcdeabcde4\n", result); + // test no fill with too few and too many characters + result = CommentUtil.expandFill("Method Name", 30, 4, "-="); + assertEquals("no fill failed", "Method Name", result); + result = CommentUtil.expandFill("Method Name", 5, 4, "-="); + assertEquals("no fill failed", "Method Name", result); + result = CommentUtil.expandFill("Method Name\n", 30, 4, "-="); + assertEquals("no fill failed", "Method Name\n", result); + result = CommentUtil.expandFill("Method Name\n", 5, 4, "-="); + assertEquals("no fill failed", "Method Name\n", result); + result = CommentUtil.expandFill("\n\t// Fields %FS%\n", 80, 4, "="); + assertEquals("tab fill failed", + "\n\t// Fields ==================================================================\n", + result); + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldResult.java new file mode 100644 index 000000000000..b9fcce1caad8 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldResult.java @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.parboiled.common; + +import com.google.common.base.Preconditions; + +import java.util.ArrayList; +import java.util.List; + +/** This class represents an arbitrarily sized bitfield that provides for efficient operations on large arrays of booleans. */ +public class BitField { +// ------------------------------ FIELDS ------------------------------ + + private final int[] data; + private final int length; + +// -------------------------- STATIC METHODS -------------------------- + + /** + * ORs the given BitFields. + * + * @param a the first Field. + * @param b the second Field. + * @return the OR of of both fields. + */ + public static BitField or(BitField a, BitField b) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = a.data[i] | b.data[i]; + } + return result; + } + + /** + * XORs the given BitFields. + * + * @param a the first Field. + * @param b the second Field. + * @return the XOR of of both fields. + */ + public static BitField xor(BitField a, BitField b) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = a.data[i] ^ b.data[i]; + } + return result; + } + + /** + * Determines whether the AND of the two given BitFields is non-empty. + * + * @param a the first field. + * @param b the second field. + * @return a boolean indicating whether the two given fields overlap. + */ + public static boolean overlap(BitField a, BitField b) { + if ((a.data[0] & b.data[0]) > 0) { + return true; + } + + int l = a.data.length; + for (int i = 1; i < l; i++) { + if ((a.data[i] & b.data[i]) > 0) { + return true; + } + } + return false; + } + + /** + * Parses the specified string into a BitField. + * + * @param str the string to parse + * @return the created BitField + * @throws IllegalArgumentException for non-wellformed input strings + */ + public static BitField valueOf(String str) throws IllegalArgumentException { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException(); + } + + String[] s = str.split("|"); + if (s.length < 2) { + throw new IllegalArgumentException(); + } + + BitField bf = new BitField(Integer.decode(s[0])); + if (bf.data.length != s.length - 1) { + throw new IllegalArgumentException(); + } + + for (int i = 0; i < bf.data.length; i++) { + bf.data[i] = Integer.decode(s[i + 1]); + } + + return bf; + } + + /** + * Returns a BitField with only those bits that are set in a but not in b. + * + * @param a the first field + * @param b the second field + * @return the substract field. + */ + public static BitField substract(BitField a, BitField b) { + return and(a, not(and(a, b))); + } + + /** + * Negates the given field. + * + * @param a the field to negate. + * @return the bitwise NOT of the given field. + */ + public static BitField not(BitField a) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = ~a.data[i]; + } + return result; + } + + /** + * ANDs the given BitFields. + * + * @param a the first Field. + * @param b the second Field. + * @return the AND of of both fields. + */ + public static BitField and(BitField a, BitField b) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = a.data[i] & b.data[i]; + } + return result; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + /** + * Creates a new BitField with the given number of bits. + * + * @param length the number of bits + */ + public BitField(int length) { + Preconditions.checkArgument(length > 0); + this.length = length; + this.data = new int[(length >> 5) + 1]; // the number of ints we need to store the field is length / 32 + } + + /** + * Creates a new BitField initialized with the contents of the given BitField. + * + * @param field the BitField to initialize with + */ + public BitField(BitField field) { + this.length = field.getLength(); + this.data = field.data.clone(); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + /** + * Gets the indexes of the set bit as an array of int. + * + * @return a list of all indices of the set bits in this field. + */ + public List getBits() { + List bits = new ArrayList(); + for (int i = 0; i < length; i++) { + if (get(i)) { + bits.add(i); + } + } + return bits; + } + + /** + * @param ix the index of the bit to get. + * @return the bit at the given position + */ + public boolean get(int ix) { + Preconditions.checkArgument(0 <= ix && ix < length); + return ((data[ix >> 5] >> ix) & 0x1) != 0; + } + + /** @return the number of bits in this field */ + public int getLength() { + return length; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + /** + * @param other another BitField to compare against. + * @return a boolean indicating whether this BitField is equal to the given one. + */ + @Override + public boolean equals(Object other) { + if (other == this) return true; + if (!(other instanceof BitField)) return false; + + BitField bitField = (BitField)other; + if (bitField.length != length) return false; + + for (int i = 0; i < data.length; i++) { + if (bitField.data[i] != data[i]) return false; + } + return true; + } + + /** @return A hashcode for this BitField. */ + @Override + public int hashCode() { + int hash = 31 * length; + for (int i = 0; i < data.length; i++) { + hash ^= data[i] + i; + } + return hash; + } + + /** @return A string representation of this field. */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(length); + for (int d : data) { + sb.append('|'); + sb.append(d); + } + return sb.toString(); + } + +// -------------------------- OTHER METHODS -------------------------- + + /** + * ANDs the given field into this one. + * + * @param field the other field to AND in. + */ + public void and(BitField field) { + for (int i = 0; i < data.length; i++) { + data[i] &= field.data[i]; + } + } + + /** + * Determines whether this BitField fully covers the given BitField, + * i.e. whether this BitField doesn't change when the given one is ORed in. + * + * @param field The field to check for inclusion for. + * @return A boolean indicating whether all bits of the given field are also set in this field. + */ + public boolean contains(BitField field) { + for (int i = 0; i < data.length; i++) { + int d = data[i]; + if (d != (d | field.data[i])) { + return false; + } + } + return true; + } + + /** @return A boolean indicating whether no bit in the field is currently set. */ + public boolean isAllClear() { + for (int d : data) { + if (d != 0x00000000) { + return false; + } + } + return true; + } + + /** @return A boolean indicating whether all bits in the field are currently set. */ + public boolean isAllSet() { + for (int d : data) { + if (d != 0xFFFFFFFF) { + return false; + } + } + return true; + } + + /** Performs a bitwise NOT operation on this field. */ + public void not() { + for (int i = 0; i < data.length; i++) { + data[i] = ~data[i]; + } + } + + /** + * ORs the given field into this one. + * + * @param field the other field to OR in. + */ + public void or(BitField field) { + for (int i = 0; i < data.length; i++) { + data[i] |= field.data[i]; + } + } + + /** + * Set the given bit. + * + * @param ix the index of the bit to set + */ + public void set(int ix) { + Preconditions.checkArgument(0 <= ix && ix < length); + + // fill up the unused bits with the highest bit + int d = ix == length - 1 ? 0xFFFFFFFF << ix : 0x1 << ix; + data[ix >> 5] |= d; // switch the respective bit "on" by ORing in the bit mask + } + + /** + * Sets the bit at the given index to the given value. + * + * @param value the value to set the bit to. + * @param ix the index of the bit to set. + */ + public void set(boolean value, int ix) { + if (value) { + set(ix); + } + else { + clear(ix); + } + } + + /** + * Unsets the given bit. + * + * @param ix the index of the bit to clear + */ + public void clear(int ix) { + Preconditions.checkArgument(0 <= ix && ix < length); + + // fill up the unused bits with the highest bit + int d = ix == length - 1 ? 0xFFFFFFFF << ix : 0x1 << ix; + data[ix >> 5] &= ~d; // switch the respective bit "off" by ANDing with the inversed mask + } + + /** + * Sets all bits in the field to the given value. + * + * @param value The bit value to set all bits to. + */ + public void setAll(boolean value) { + int d = value ? 0xFFFFFFFF : 0x00000000; + for (int i = 0; i < data.length; i++) { + data[i] = d; + } + } + + /** + * XORs the given field into this one. + * + * @param field the other field to XOR in. + */ + public void xor(BitField field) { + for (int i = 0; i < data.length; i++) { + data[i] ^= field.data[i]; + } + } +} + + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldTest.java b/plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldTest.java new file mode 100644 index 000000000000..3b78c7865a50 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/BitFieldTest.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2003, 2010, Dave Kriewall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.parboiled.common; + +import com.google.common.base.Preconditions; + +import java.util.ArrayList; +import java.util.List; + +/** This class represents an arbitrarily sized bitfield that provides for efficient operations on large arrays of booleans. */ +public class BitField { + + private final int[] data; + private final int length; + + /** + * Creates a new BitField with the given number of bits. + * + * @param length the number of bits + */ + public BitField(int length) { + Preconditions.checkArgument(length > 0); + this.length = length; + this.data = new int[(length >> 5) + 1]; // the number of ints we need to store the field is length / 32 + } + + /** + * Creates a new BitField initialized with the contents of the given BitField. + * + * @param field the BitField to initialize with + */ + public BitField(BitField field) { + this.length = field.getLength(); + this.data = field.data.clone(); + } + + /** @return the number of bits in this field */ + public int getLength() { + return length; + } + + /** + * @param ix the index of the bit to get. + * @return the bit at the given position + */ + public boolean get(int ix) { + Preconditions.checkArgument(0 <= ix && ix < length); + return ((data[ix >> 5] >> ix) & 0x1) != 0; + } + + /** + * Set the given bit. + * + * @param ix the index of the bit to set + */ + public void set(int ix) { + Preconditions.checkArgument(0 <= ix && ix < length); + + // fill up the unused bits with the highest bit + int d = ix == length - 1 ? 0xFFFFFFFF << ix : 0x1 << ix; + data[ix >> 5] |= d; // switch the respective bit "on" by ORing in the bit mask + } + + /** + * Unsets the given bit. + * + * @param ix the index of the bit to clear + */ + public void clear(int ix) { + Preconditions.checkArgument(0 <= ix && ix < length); + + // fill up the unused bits with the highest bit + int d = ix == length - 1 ? 0xFFFFFFFF << ix : 0x1 << ix; + data[ix >> 5] &= ~d; // switch the respective bit "off" by ANDing with the inversed mask + } + + /** + * Sets the bit at the given index to the given value. + * + * @param value the value to set the bit to. + * @param ix the index of the bit to set. + */ + public void set(boolean value, int ix) { + if (value) { + set(ix); + } + else { + clear(ix); + } + } + + /** + * Sets all bits in the field to the given value. + * + * @param value The bit value to set all bits to. + */ + public void setAll(boolean value) { + int d = value ? 0xFFFFFFFF : 0x00000000; + for (int i = 0; i < data.length; i++) { + data[i] = d; + } + } + + /** @return A boolean indicating whether all bits in the field are currently set. */ + public boolean isAllSet() { + for (int d : data) { + if (d != 0xFFFFFFFF) { + return false; + } + } + return true; + } + + /** @return A boolean indicating whether no bit in the field is currently set. */ + public boolean isAllClear() { + for (int d : data) { + if (d != 0x00000000) { + return false; + } + } + return true; + } + + /** @return A hashcode for this BitField. */ + @Override + public int hashCode() { + int hash = 31 * length; + for (int i = 0; i < data.length; i++) { + hash ^= data[i] + i; + } + return hash; + } + + /** + * @param other another BitField to compare against. + * @return a boolean indicating whether this BitField is equal to the given one. + */ + @Override + public boolean equals(Object other) { + if (other == this) return true; + if (!(other instanceof BitField)) return false; + + BitField bitField = (BitField)other; + if (bitField.length != length) return false; + + for (int i = 0; i < data.length; i++) { + if (bitField.data[i] != data[i]) return false; + } + return true; + } + + /** + * ANDs the given BitFields. + * + * @param a the first Field. + * @param b the second Field. + * @return the AND of of both fields. + */ + public static BitField and(BitField a, BitField b) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = a.data[i] & b.data[i]; + } + return result; + } + + /** + * ANDs the given field into this one. + * + * @param field the other field to AND in. + */ + public void and(BitField field) { + for (int i = 0; i < data.length; i++) { + data[i] &= field.data[i]; + } + } + + /** + * ORs the given BitFields. + * + * @param a the first Field. + * @param b the second Field. + * @return the OR of of both fields. + */ + public static BitField or(BitField a, BitField b) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = a.data[i] | b.data[i]; + } + return result; + } + + /** + * ORs the given field into this one. + * + * @param field the other field to OR in. + */ + public void or(BitField field) { + for (int i = 0; i < data.length; i++) { + data[i] |= field.data[i]; + } + } + + /** + * XORs the given BitFields. + * + * @param a the first Field. + * @param b the second Field. + * @return the XOR of of both fields. + */ + public static BitField xor(BitField a, BitField b) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = a.data[i] ^ b.data[i]; + } + return result; + } + + /** + * XORs the given field into this one. + * + * @param field the other field to XOR in. + */ + public void xor(BitField field) { + for (int i = 0; i < data.length; i++) { + data[i] ^= field.data[i]; + } + } + + /** + * Negates the given field. + * + * @param a the field to negate. + * @return the bitwise NOT of the given field. + */ + public static BitField not(BitField a) { + BitField result = new BitField(a.length); + for (int i = 0; i < result.data.length; i++) { + result.data[i] = ~a.data[i]; + } + return result; + } + + /** Performs a bitwise NOT operation on this field. */ + public void not() { + for (int i = 0; i < data.length; i++) { + data[i] = ~data[i]; + } + } + + /** + * Determines whether the AND of the two given BitFields is non-empty. + * + * @param a the first field. + * @param b the second field. + * @return a boolean indicating whether the two given fields overlap. + */ + public static boolean overlap(BitField a, BitField b) { + if ((a.data[0] & b.data[0]) > 0) { + return true; + } + + int l = a.data.length; + for (int i = 1; i < l; i++) { + if ((a.data[i] & b.data[i]) > 0) { + return true; + } + } + return false; + } + + /** + * Determines whether this BitField fully covers the given BitField, + * i.e. whether this BitField doesn't change when the given one is ORed in. + * + * @param field The field to check for inclusion for. + * @return A boolean indicating whether all bits of the given field are also set in this field. + */ + public boolean contains(BitField field) { + for (int i = 0; i < data.length; i++) { + int d = data[i]; + if (d != (d | field.data[i])) { + return false; + } + } + return true; + } + + /** @return A string representation of this field. */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(length); + for (int d : data) { + sb.append('|'); + sb.append(d); + } + return sb.toString(); + } + + /** + * Parses the specified string into a BitField. + * + * @param str the string to parse + * @return the created BitField + * @throws IllegalArgumentException for non-wellformed input strings + */ + public static BitField valueOf(String str) throws IllegalArgumentException { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException(); + } + + String[] s = str.split("|"); + if (s.length < 2) { + throw new IllegalArgumentException(); + } + + BitField bf = new BitField(Integer.decode(s[0])); + if (bf.data.length != s.length - 1) { + throw new IllegalArgumentException(); + } + + for (int i = 0; i < bf.data.length; i++) { + bf.data[i] = Integer.decode(s[i + 1]); + } + + return bf; + } + + /** + * Gets the indexes of the set bit as an array of int. + * + * @return a list of all indices of the set bits in this field. + */ + public List getBits() { + List bits = new ArrayList(); + for (int i = 0; i < length; i++) { + if (get(i)) { + bits.add(i); + } + } + return bits; + } + + /** + * Returns a BitField with only those bits that are set in a but not in b. + * + * @param a the first field + * @param b the second field + * @return the substract field. + */ + public static BitField substract(BitField a, BitField b) { + return and(a, not(and(a, b))); + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorResult1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorResult1.java new file mode 100644 index 000000000000..8f113e82c851 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorResult1.java @@ -0,0 +1,6 @@ +public class CommentSeparatorTest1 { + + // Fields ================================================================== + + public int i; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorTest1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorTest1.java new file mode 100644 index 000000000000..4d6744b96350 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/CommentSeparatorTest1.java @@ -0,0 +1,3 @@ +public class CommentSeparatorTest1 { + public int i; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingResult.java new file mode 100644 index 000000000000..a65d0d0061e1 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingResult.java @@ -0,0 +1,15 @@ +import javax.swing.*; + + +public abstract class TestCorrupt implements ComboBoxModel { + //-------------------------------------------------------------------- + //---------------------------------------------- ComboBoxModel Methods + + public Object getSelectedItem() { + return null; + } + + + public void setSelectedItem(Object p_item) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingTest.java b/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingTest.java new file mode 100644 index 000000000000..a7c0327dcec1 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptRespacingTest.java @@ -0,0 +1,12 @@ +import javax.swing.*; + + +public abstract class TestCorrupt implements ComboBoxModel { + public Object getSelectedItem() { + return null; + } + + + public void setSelectedItem(Object p_item) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptionConfig.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptionConfig.xml new file mode 100644 index 000000000000..259eabb68ecf --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/CorruptionConfig.xml @@ -0,0 +1,557 @@ + + + + \ \ \ //%FS%\n\ \ \ //%FS%\ Constants\n + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Inner\ Classes\n + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Instance\ Variables\n + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Variables\n + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Constructors\n + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Instance\ Methods\n + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Getters/Setters\n + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Public\ Methods\n + + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ %IF%\ Methods\n + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Protected/Package\ + Getters/Setters\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Protected/Package\ Methods\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Private\ Methods\n + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Inner\ Classes\n + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Variables\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Private\ Constants\n + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Instance\ Variables\n + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Main\ Method\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n//%FS%\n//%FS%\n\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderResult.java new file mode 100644 index 000000000000..c1aa26047f76 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderResult.java @@ -0,0 +1,230 @@ +package com.carp.casper2.chitchat; + +import com.carp.nlp.lexicon.Word; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.Vector; + +/** + * Gebruikt de synoniemen lijst om onbekende woorden af te beeld op de bekende woorden uit de + * patterns. Met een synoniemen lijst breid deze de patterns uit met rules om van onbekende woorden + * op bekende te komen Hij maakt dus het (wiskundige) domein groter omdat er op meer dingen + * getriggerd wordt, vandaar de naam. Het is een beetje onhandig om door DomainExpander gemaakt + * rules weer toe te voegen. Voordat je de terminals uit een grammar haalt wil je meestal eerst die + * synoniemen rules er uit plukken.
Je stopt er een hashset met bekende dingen in en je krijgt + * een mapping terug. + * + * @author Oebele van der Veen + * @version 1.0 + */ +public class DomainExpander { + Vector baselevel = new Vector(); + + + // idee + // Er is een baseset waarop geprojecteerd moet worden + // dit gaat met een reduction graph die iteratief opgebouwd word + // reductiongraph = vector of level + // level = vector of (word,backref) + // baseset word in level 0 gezet en dan wordt elke element bij na gegaan + // is er een synoniem s van woord x dan krijgt s een ref naar x en komt s een level hoger + // daarna wordt het volgende level verwerkt. + // Als er niks meer toegevoegd kan worden, dan wordt bij elke woord uit de baseset alle synoniemen + // verzameld en wordt er een rule (synoniem1|..|synoniemx) do rewrite(woord) end van gemaakt. (collapsen) + // mischien frontref ipv backref. Dan gaat het collapsen makkelijker. laten we dat ook doen ja + // merk op dat er geen dubbelen in de reduction graph mogen voorkomen + + + // een node van de reduction tree + + Set noDubArea = new HashSet(); // elk woord gooien we ook hierin (bij reference) + + + // Dat is fijn want dan kunnen we snel doublures voorkomen + Vector reductionGraph = new Vector(); //elk element is een level met nodes + SynonymList synlist; + + /** + * Maakt een Domain Expander bij een baseset en synoniemenlijst. Gegeven de bekende woorden van de + * patterns in de baseset kan deze DomainExpander met de synoniemen nieuwe patterns maken + * + * @param baseset een HashSet met de terminals van de patterns + * @param synlist een synonymList, + */ + public DomainExpander(Set baseset, SynonymList synlist) { + // we zetten de basisset op level 0 van de reductionGraph; + setBase(baseset); + // even onthouden + this.synlist = synlist; + } + + /** + * Slaat de mapping plat zodat deze weggeschreven kan worden Als er genoeg woorden zijn toegevoegd + * dan zorgt deze functie er voor dat de data structuur wordt aangepast voor wegschrijven als + * grammar rules + */ + public void collapse() { + // de nodes van de base level hebben nu alle kinderen als hun kinderen + Vector base = (Vector)reductionGraph.firstElement(); + Node thisnode; + for (int i = 0; i < base.size(); i++) { + thisnode = (Node)base.elementAt(i); + thisnode.children = thisnode.getChildren(); // de kinderen gelijk stellen aan alle kinderen + } + } + + /** + * Voegt meer woorden toe aan de mapping. Dit ding voegt meer woorden toe aan de mapping. + * expand(3);expand(4) is hetzelfde als expand(7) + * + * @param max het maximum aantal hops door de synoniemen vanaf de bekende woorden + * @return hoeveel hops de laatste woorden echt zijn. Dit kan kleiner zijn dan max als er geen + * synoniemen meer zijn. + */ + public int expand(int max) { + int curlevels = reductionGraph.size(); + Vector newlevel; + boolean adding = true; // houd bij of er wat toegevoegd wordt, anders kunnen we ook wel stoppen. + while ((adding) && (reductionGraph.size() - curlevels) < max) { + newlevel = expandLevel((Vector)reductionGraph.lastElement()); + reductionGraph.add(newlevel); + if (newlevel.size() == 0) { + adding = false; + } + } + return reductionGraph.size() - curlevels; + } + + private Vector expandLevel(Vector level) { + System.out.println("Expanding level with " + level.size() + " elements"); + System.out.println("Strings in noDubArea: " + noDubArea.size()); + Vector synonyms; + Node thisnode, newnode; + Vector newlevel = new Vector(); + String aword; + + for (int i = 0; i < level.size(); i++) { + thisnode = ((Node)level.elementAt(i)); + synonyms = synlist.getSynonymsOf(thisnode.word); + if (synonyms != null) { + for (int s = 0; s < synonyms.size(); s++) { + aword = (String)synonyms.elementAt(s); + if (!noDubArea.contains(aword)) { + newnode = new Node(aword); //Node(s) stopts s ook direct in de noDubArea + newlevel.add(newnode); + thisnode.addChild(newnode); + } + } + } + } + return newlevel; + } + + private void setBase(Set baseSet) { + Word word; + String str; + System.out.println("Adding base set"); + if (baseSet == null) { + System.out.println("Given baseset is null"); + return; + } + Vector newlevel = new Vector(200); + Iterator iterator = baseSet.iterator(); + while (iterator.hasNext()) { + word = (Word)iterator.next(); + if (word != null) { + str = word.toString(); + if (str != null) { + newlevel.add(new Node(str)); + } + } + } + reductionGraph.add(newlevel); + System.out.println("Done"); + } + + /** + * Schrijf de synoniemen mapping naar rules. Stopt de mapping in de writer + * + * @param w een Writer waar de rules heen geschreven worden. + */ + public void writeToGrammar(Writer w) throws IOException { + BufferedWriter writer = new BufferedWriter(w); + String setting = "rule ^setIgnoreHead(true) ^setIgnoreTail(true) ^setMaxIgnored(256) end"; + String commentaar = + "// Dit bestand is automatisch gegenereert door een DomainExpander object, Het is absoluut slim hier af te blijven."; + String line; + Vector base = (Vector)reductionGraph.firstElement(); + Node thisnode; + try { + writer.write(commentaar, 0, commentaar.length()); + writer.newLine(); + writer.newLine(); + writer.newLine(); + writer.write(setting, 0, setting.length()); + writer.newLine(); + for (int i = 0; i < base.size(); i++) { + thisnode = (Node)base.elementAt(i); + line = thisnode.toParserString(); + if (line.length() > 0) { + writer.write(line, 0, line.length()); + writer.newLine(); + } + } + } + finally { + writer.close(); + } + } + + private class Node { + private Vector children = new Vector(); // de synonymen van dit woord in een hoger level + private String word; + + Node(String word) { + this.word = word; + noDubArea.add(word); // Kijk stoppen we er gewoon direct in + } + + public void addChild(Node node) { + children.add(node); + } + + //recursief alle kinderen verzamelen + public Vector getChildren() { + Vector result = new Vector(); + for (int i = 0; i < children.size(); i++) { + result.addAll(((Node)children.elementAt(i)).getChildren()); + } + result.addAll(children); + return result; + } + + public String toParserString() { + // maak een "rule (childer1|childer2...) do rewrite(word) end" + if (children.size() == 0) { + return ""; // geen kinderen, geen regel + } + if (children.size() == 1) { + return "rule \"" + ((Node)children.firstElement()).word + "\" do rewrite(" + word + ") end"; + } + StringBuffer result = new StringBuffer(); + result.append("rule ("); + for (int i = 0; i < children.size(); i++) { + if (i > 0) { + result.append("|"); + } + result.append("\""); + result.append(((Node)children.elementAt(i)).word); + result.append("\""); + } + result.append(") do rewrite(" + word + ") end"); + return result.toString(); + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderTest.java b/plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderTest.java new file mode 100644 index 000000000000..544ccf33fa0f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/DomainExpanderTest.java @@ -0,0 +1,231 @@ +package com.carp.casper2.chitchat; + +import com.carp.nlp.lexicon.Word; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.Vector; + +/** + * Gebruikt de synoniemen lijst om onbekende woorden af te beeld op de bekende woorden uit de + * patterns. Met een synoniemen lijst breid deze de patterns uit met rules om van onbekende woorden + * op bekende te komen Hij maakt dus het (wiskundige) domein groter omdat er op meer dingen + * getriggerd wordt, vandaar de naam. Het is een beetje onhandig om door DomainExpander gemaakt + * rules weer toe te voegen. Voordat je de terminals uit een grammar haalt wil je meestal eerst die + * synoniemen rules er uit plukken.
Je stopt er een hashset met bekende dingen in en je krijgt + * een mapping terug. + * + * @author Oebele van der Veen + * @version 1.0 + */ +public class DomainExpander { + Vector baselevel = new Vector(); + + + // idee + // Er is een baseset waarop geprojecteerd moet worden + // dit gaat met een reduction graph die iteratief opgebouwd word + // reductiongraph = vector of level + // level = vector of (word,backref) + // baseset word in level 0 gezet en dan wordt elke element bij na gegaan + // is er een synoniem s van woord x dan krijgt s een ref naar x en komt s een level hoger + // daarna wordt het volgende level verwerkt. + // Als er niks meer toegevoegd kan worden, dan wordt bij elke woord uit de baseset alle synoniemen + // verzameld en wordt er een rule (synoniem1|..|synoniemx) do rewrite(woord) end van gemaakt. (collapsen) + // mischien frontref ipv backref. Dan gaat het collapsen makkelijker. laten we dat ook doen ja + // merk op dat er geen dubbelen in de reduction graph mogen voorkomen + + + // een node van de reduction tree + + Set noDubArea = new HashSet(); // elk woord gooien we ook hierin (bij reference) + + + // Dat is fijn want dan kunnen we snel doublures voorkomen + Vector reductionGraph = new Vector(); //elk element is een level met nodes + SynonymList synlist; + + /** + * Maakt een Domain Expander bij een baseset en synoniemenlijst. Gegeven de bekende woorden van de + * patterns in de baseset kan deze DomainExpander met de synoniemen nieuwe patterns maken + * + * @param baseset een HashSet met de terminals van de patterns + * @param synlist een synonymList, + */ + public DomainExpander(Set baseset, SynonymList synlist) { + // we zetten de basisset op level 0 van de reductionGraph; + setBase(baseset); + // even onthouden + this.synlist = synlist; + } + + /** + * Slaat de mapping plat zodat deze weggeschreven kan worden Als er genoeg woorden zijn toegevoegd + * dan zorgt deze functie er voor dat de data structuur wordt aangepast voor wegschrijven als + * grammar rules + */ + public void collapse() { + // de nodes van de base level hebben nu alle kinderen als hun kinderen + Vector base = (Vector)reductionGraph.firstElement(); + Node thisnode; + for (int i = 0; i < base.size(); i++) { + thisnode = (Node)base.elementAt(i); + thisnode.children = thisnode.getChildren(); // de kinderen gelijk stellen aan alle kinderen + } + } + + /** + * Voegt meer woorden toe aan de mapping. Dit ding voegt meer woorden toe aan de mapping. + * expand(3);expand(4) is hetzelfde als expand(7) + * + * @param max het maximum aantal hops door de synoniemen vanaf de bekende woorden + * @return hoeveel hops de laatste woorden echt zijn. Dit kan kleiner zijn dan max als er geen + * synoniemen meer zijn. + */ + public int expand(int max) { + int curlevels = reductionGraph.size(); + Vector newlevel; + boolean adding = true; // houd bij of er wat toegevoegd wordt, anders kunnen we ook wel stoppen. + while ((adding) && (reductionGraph.size() - curlevels) < max) { + newlevel = expandLevel((Vector)reductionGraph.lastElement()); + reductionGraph.add(newlevel); + if (newlevel.size() == 0) { + adding = false; + } + } + return reductionGraph.size() - curlevels; + } + + + private Vector expandLevel(Vector level) { + System.out.println("Expanding level with " + level.size() + " elements"); + System.out.println("Strings in noDubArea: " + noDubArea.size()); + Vector synonyms; + Node thisnode, newnode; + Vector newlevel = new Vector(); + String aword; + + for (int i = 0; i < level.size(); i++) { + thisnode = ((Node)level.elementAt(i)); + synonyms = synlist.getSynonymsOf(thisnode.word); + if (synonyms != null) { + for (int s = 0; s < synonyms.size(); s++) { + aword = (String)synonyms.elementAt(s); + if (!noDubArea.contains(aword)) { + newnode = new Node(aword); //Node(s) stopts s ook direct in de noDubArea + newlevel.add(newnode); + thisnode.addChild(newnode); + } + } + } + } + return newlevel; + } + + private void setBase(Set baseSet) { + Word word; + String str; + System.out.println("Adding base set"); + if (baseSet == null) { + System.out.println("Given baseset is null"); + return; + } + Vector newlevel = new Vector(200); + Iterator iterator = baseSet.iterator(); + while (iterator.hasNext()) { + word = (Word)iterator.next(); + if (word != null) { + str = word.toString(); + if (str != null) { + newlevel.add(new Node(str)); + } + } + } + reductionGraph.add(newlevel); + System.out.println("Done"); + } + + /** + * Schrijf de synoniemen mapping naar rules. Stopt de mapping in de writer + * + * @param w een Writer waar de rules heen geschreven worden. + */ + public void writeToGrammar(Writer w) throws IOException { + BufferedWriter writer = new BufferedWriter(w); + String setting = "rule ^setIgnoreHead(true) ^setIgnoreTail(true) ^setMaxIgnored(256) end"; + String commentaar = + "// Dit bestand is automatisch gegenereert door een DomainExpander object, Het is absoluut slim hier af te blijven."; + String line; + Vector base = (Vector)reductionGraph.firstElement(); + Node thisnode; + try { + writer.write(commentaar, 0, commentaar.length()); + writer.newLine(); + writer.newLine(); + writer.newLine(); + writer.write(setting, 0, setting.length()); + writer.newLine(); + for (int i = 0; i < base.size(); i++) { + thisnode = (Node)base.elementAt(i); + line = thisnode.toParserString(); + if (line.length() > 0) { + writer.write(line, 0, line.length()); + writer.newLine(); + } + } + } + finally { + writer.close(); + } + } + + private class Node { + private Vector children = new Vector(); // de synonymen van dit woord in een hoger level + private String word; + + Node(String word) { + this.word = word; + noDubArea.add(word); // Kijk stoppen we er gewoon direct in + } + + public void addChild(Node node) { + children.add(node); + } + + //recursief alle kinderen verzamelen + public Vector getChildren() { + Vector result = new Vector(); + for (int i = 0; i < children.size(); i++) { + result.addAll(((Node)children.elementAt(i)).getChildren()); + } + result.addAll(children); + return result; + } + + public String toParserString() { + // maak een "rule (childer1|childer2...) do rewrite(word) end" + if (children.size() == 0) { + return ""; // geen kinderen, geen regel + } + if (children.size() == 1) { + return "rule \"" + ((Node)children.firstElement()).word + "\" do rewrite(" + word + ") end"; + } + StringBuffer result = new StringBuffer(); + result.append("rule ("); + for (int i = 0; i < children.size(); i++) { + if (i > 0) { + result.append("|"); + } + result.append("\""); + result.append(((Node)children.elementAt(i)).word); + result.append("\""); + } + result.append(") do rewrite(" + word + ") end"); + return result.toString(); + } + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Result.java b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Result.java new file mode 100644 index 000000000000..3d662839533a --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Result.java @@ -0,0 +1,715 @@ +/** + * $id + * Author: Dave Kriewall + * Created: Oct 20, 2005 + * Copyright 2004, WRQ, Inc. + */ +package com.wrq.rearranger.testClasses; + +import com.intellij.codeInspection.dataFlow.DataFlowRunner; + +import javax.swing.tree.TreePath; +import java.io.File; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + * Created by IntelliJ IDEA. User: JJohnson Date: Aug 30, 2005 Time: 11:06:54 AM To change this template use File | + * Settings | File Templates. + */ +public class Enum1Test implements Cloneable { +// ------------------------------ FIELDS ------------------------------ + + private static final String STEREOTYPE_PREFIX = "STEREOTYPE_"; + private Enum1Test parent = null; + private SuiteModel suiteModel; + private SuiteItem storage; + private List childNodes = new ArrayList(10); + +// -------------------------- STATIC METHODS -------------------------- + + public static Stereotype getStereotype(String stStr) { + return null; + } + +// --------------------------- CONSTRUCTORS --------------------------- + + public Enum1Test(SuiteModel model, Stereotype type) { + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + public Enum1Test getParent() { + return parent; + } + + public ExecutionState getState() { + ExecutionState state = ExecutionState.UNTESTED; + if (storage.getInstructionItem() != null) { + byte[] receipt = getInstructionItem().getReceipt(); + if (receipt != null) { + byte[] expectedReceipt = getInstructionItem().getExpectedReceipt(); + if (expectedReceipt == null) { + state = ExecutionState.FAILED; + } + else if (receipt.length != expectedReceipt.length) { + state = ExecutionState.FAILED; + } + else { + state = ExecutionState.PASSED; + for (int i = 0; i < receipt.length; i++) { + if (receipt[i] != expectedReceipt[i]) { + state = ExecutionState.FAILED; + break; + } + } + } + } + } + return state; + } + + public SuiteItem getStorage() { + return storage; + } + +// ------------------------ CANONICAL METHODS ------------------------ + + public Object clone() throws CloneNotSupportedException { + try { + return super.clone(); + } + catch (final CloneNotSupportedException e) { + return null; + } + } + + public String toString() { + return getName(); + } + + public String getName() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return getInstruction(getInstructionItem().getInstructionRef()).getName(); + } + return storage.getName(); + } + +// -------------------------- OTHER METHODS -------------------------- + + public void add(Enum1Test appendingNode, boolean createStorage) { + childNodes.add(appendingNode); + appendingNode.setParent(this, createStorage); + } + + public void setParent(Enum1Test parent, boolean createStorage) { + Enum1Test oldParent = this.parent; + this.parent = parent; + if (createStorage) { + parent.addChild(this); + } + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_PARENT, oldParent, parent, this); + } + + private void addChild(Enum1Test childNode) { + storage.addSuiteItem(childNode.getStorage()); + } + + public void add(Enum1Test insertingNode, Enum1Test selection) { + childNodes.add(childNodes.indexOf(selection) + 1, insertingNode); + insertingNode.setParent(this, true); + } + + public void add(int index, Enum1Test t) { + t.setParent(this, true); + childNodes.add(index, t); + } + + public boolean canMove(Direction direction) { + switch (direction) { + case UP: + return (getNextUp() != null); + case DOWN: + return (getNextDown() != null); + } + return false; + } + + public Enum1Test getNextUp() { + if (getStereotype().equals(Stereotype.STEREOTYPE_ROOT)) { + return null; + } + Enum1Test nextUpNode; + if (isFirstChild()) { +// nextUpNode = getParent().getNextUp(); + nextUpNode = getParent().getNextDown(); + } + else { + int newIndexUp = indexOf() - 1; + nextUpNode = (Enum1Test)getParent().getChild(newIndexUp); + } + return nextUpNode; + } + + public boolean isFirstChild() { + return indexOf() == 0; + } + + /** Get index of this node within its parents children list. */ + public int indexOf() { + Enum1Test parent = getParent(); + if (parent == null) { + return 0; + } + return parent.indexOf(this); + } + + public Object getChild(int index) { + return childNodes.get(index); + } + + public Enum1Test getNextDown() { + if (getStereotype().equals(Stereotype.STEREOTYPE_ROOT)) { + return null; + } + Enum1Test nextDownNode; + if (isLastChild()) { +// nextDownNode = getParent().getNextDown(); + nextDownNode = getParent().getNextUp(); + } + else { + int newIndexDown = indexOf() + 1; + nextDownNode = (Enum1Test)getParent().getChild(newIndexDown); + } + return nextDownNode; + } + + public boolean isLastChild() { + if (parent == null) { + return true; // root is an only-child + } + int indexOf = indexOf(); + return (indexOf == parent.getChildCount() - 1); + } + + public int getChildCount() { + return childNodes.size(); + } + + public void execute() { + // Repeat this node -iterations- times + for (int repeatCount = 0; repeatCount < getIterations(); repeatCount++) { + if (getStereotype().equals(Enum1Test.Stereotype.STEREOTYPE_INSTRUCTION)) { + executeInstruction(); + } + else { + executeChildren(); + } + // Pause after each execution this number of milliseconds before continuing + try { + Thread.sleep(getDelay()); + } + catch (InterruptedException e) { + e.printStackTrace(); // todo - logger + } + } + } + + public int getIterations() { + return storage.getIterations(); + } + + private void executeInstruction() { + } + + private void executeChildren() { + Enum1Test[] children = getChildren(); + for (Enum1Test node : children) { + node.execute(); // recursive execution for nested groups of instructions. + } + } + + public Enum1Test[] getChildren() { + return childNodes.toArray(new Enum1Test[]{}); + } + + public long getDelay() { + return storage.getDelay(); + } + + private String getExpectedReceiptString() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return Utilities.toString(getInstructionItem().getExpectedReceipt()); + } + return ""; + } + + public Instruction getInstruction() { + String id = this.getInstructionItem().getInstructionRef(); + return getInstruction(id); + } + + public ByteBuffer getPacketToSend() { + return getPacketToSend(getInstructionItem()); + } + + private ByteBuffer getPacketToSend(InstructionItem instruction) { + return null; + } + + public String getParameter() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return getInstructionItem().getParameter(); + } + return ""; + } + + public TreePath getPath() { + List parents = new ArrayList(20); + for (Enum1Test node = this; node != null; node = node.getParent()) { + parents.add(node); + } + Collections.reverse(parents); + return new TreePath(parents.toArray(new Enum1Test[0])); + } + + public String getReceiptString() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return Utilities.toString(getInstructionItem().getReceipt()); + } + return ""; + } + + public String getStateText() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + ExecutionState state = getState(); + switch (state) { + case UNTESTED: + return "Untested"; + case PASSED: + return "Passed"; + case FAILED: + return "Failed"; + } + } + return this.getPassed() + " / " + this.getFailed() + " of " + this.getTotalInstructions(); + } + + public int getTotalInstructions() { + int count = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + count++; + } + for (Enum1Test t : childNodes) { + if (!getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + count += t.getTotalInstructions(); + } + } + return count; + } + + public int getFailed() { + int count = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + if (getState().equals(ExecutionState.FAILED)) { + count++; + } + } + else { + for (Enum1Test t : childNodes) { + count += t.getFailed(); + } + } + return count; + } + + public int getPassed() { + int count = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + if (getState().equals(ExecutionState.PASSED)) { + count++; + } + } + else { + for (Enum1Test t : childNodes) { + count += t.getPassed(); + } + } + return count; + } + + public String getStateText(boolean firstCap) { + String stateText; + switch (getState()) { + case UNTESTED: + stateText = "untested"; + break; + case PASSED: + stateText = "passed"; + break; + case FAILED: + stateText = "failed"; + break; + default: + stateText = "** unknown **"; + } + return stateText; + } + + public String getToolTip() { + StringBuilder tt = new StringBuilder(200); + tt.append(""); + switch (getStereotype()) { + case STEREOTYPE_ROOT: + buildRootToolTip(tt); + break; + case STEREOTYPE_GROUP: + buildGroupToolTip(tt); + break; + case STEREOTYPE_INSTRUCTION: + buildInstructionToolTip(tt); + break; + } + buildRunInfoToolTip(tt); + tt.append(""); + return tt.toString(); + } + + public Stereotype getStereotype() { + return null; + } + + private void buildRootToolTip(StringBuilder tt) { + String author = suiteModel.getAuthor(); + String desc = getDescription(); + String filePath = suiteModel.hasStorage() ? suiteModel.getStorageFile().getAbsolutePath() : null; + if (author != null && author.length() > 0) { + tt.append(author).append("

"); + } + if (desc != null && desc.length() > 0) { + tt.append(desc).append("

"); + } + if (filePath != null && filePath.length() > 0) { + tt.append(filePath).append("

"); + } + } + + private void buildGroupToolTip(StringBuilder tt) { + String desc = getDescription(); + if (desc != null && desc.length() > 0) { + tt.append(desc).append("

"); + } + } + + public String getDescription() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return getInstruction(getInstructionItem().getInstructionRef()).getDescription(); + } + return storage.getDescription(); + } + + private void buildInstructionToolTip(StringBuilder tt) { + InstructionItem inst = getInstructionItem(); + if (inst != null) { + String id = inst.getInstructionRef(); + Instruction instruction = getInstruction(id); + tt.append("Command: ").append(instruction.getCommand()).append("

"); + } + tt.append("Parameter: ").append(getParameter()).append("

"); + tt.append("Received: ").append(getReceiptString()).append("

"); + tt.append("Expected: ").append(getExpectedReceiptString()).append("

"); + } + + public InstructionItem getInstructionItem() { + return storage.getInstructionItem(); + } + + public Instruction getInstruction(String id) { + return null; + } + + private void buildRunInfoToolTip(StringBuilder tt) { + tt.append("


"); // a divider line + tt.append("Iterations: ").append(getIterations()).append("

"); + tt.append("Pause: ").append(getDelay()).append("

"); + tt.append("State: ").append(getStateText()).append("

"); // todo add state color getStatecolor()... + tt.append("Duration: ").append(getDuration()).append("

"); + tt.append("Executed: ").append(getLastTested()).append("

"); + } + + public boolean hasChildren() { + return childNodes.size() > 0; + } + + public int indexOf(Enum1Test t) { + return childNodes.indexOf(t); + } + + public boolean isGroup() { + return getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION); + } + + public void remove(Enum1Test node) { + childNodes.remove(node); + // node.setParent(null); + } + + public void setDelay(long delay) { + long oldDelay = storage.getDelay(); + storage.setDelay(delay); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_DELAY, oldDelay, delay, this); + } + + public void setDescription(String description) { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return; // name is fixed for instructions + } + String oldDescription = storage.getDescription(); + storage.setDescription(description); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_DESC, oldDescription, description, this); + } + + public void setDuration(long duration) { + if (!getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return; // name is fixed anything execept instructions + } + long oldDuration = getDuration(); + storage.setDuration(duration); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_DURATION, oldDuration, duration, this); + } + + public long getDuration() { + long durationSum = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + durationSum += storage.getDuration(); + } + else { + for (Enum1Test t : childNodes) { + durationSum += t.getDuration(); + } + } + return durationSum; + } + + public void setExpectedReceipt(byte[] newValue) { + } + + public void setInstructionItem(InstructionItem instruction) { + InstructionItem oldInstruction = this.getInstructionItem(); + storage.setInstructionItem(instruction); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_INSTRUCTION, oldInstruction, instruction, this); + } + + public void setIterations(int iterations) { + int oldIterations = storage.getIterations(); + storage.setIterations(iterations); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_ITERATIONS, oldIterations, iterations, this); + } + + public void setLastTested(Date lastTested) { + Date oldLastTested = getLastTested(); + storage.setLastTested(new Date()); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_LAST_TESTED, oldLastTested, lastTested, this); + } + + public Date getLastTested() { + Date date = storage.getLastTested(); + return date == null ? null : date; + } + + public void setName(String name) { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return; // name is fixed for instructions + } + String oldName = storage.getName(); + storage.setName(name); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_NAME, oldName, name, this); + } + + public void setParameter(String value) { + } + + private void setStereotype(Stereotype type) { + } + + public void setStorage(SuiteItem suiteItem) { + } + +// -------------------------- ENUMERATIONS -------------------------- + + public enum ExecutionState { + PASSED, FAILED, UNTESTED + } + + public enum Stereotype { + STEREOTYPE_ROOT, STEREOTYPE_GROUP, STEREOTYPE_INSTRUCTION + } + + public enum Direction { + UP, DOWN + } +} + +class InstructionItem { +// -------------------------- OTHER METHODS -------------------------- + + public byte[] getExpectedReceipt() { + return new byte[0]; //To change body of created methods use File | Settings | File Templates. + } + + public String getInstructionRef() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getParameter() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public byte[] getReceipt() { + return null; + } + + public void setExpectedReceipt(byte[] newValue) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setParameter(String value) { + //To change body of created methods use File | Settings | File Templates. + } +} + +class Instruction { +// -------------------------- OTHER METHODS -------------------------- + + public String getCommand() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getDescription() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getName() { + return null; //To change body of created methods use File | Settings | File Templates. + } +} + +class SuiteModel { +// ------------------------------ FIELDS ------------------------------ + + public static final Object EVT_TOPIC_EXPECTED_RECEIPT = ""; + public static final Object EVT_TOPIC_PARAMETER = ""; + public static final Object EVT_TOPIC_PARENT = ""; + public static final Object EVT_TOPIC_DELAY = ""; + public static Object EVT_TOPIC_DESC = ""; + public static Object EVT_TOPIC_DURATION = ""; + public static Object EVT_TOPIC_INSTRUCTION = ""; + public static Object EVT_TOPIC_ITERATIONS = ""; + public static Object EVT_TOPIC_LAST_TESTED = ""; + public static Object EVT_TOPIC_NAME = ""; + +// -------------------------- OTHER METHODS -------------------------- + + public void fireChangeEvent(Object p0, Object oldValue, Object newValue, Enum1Test testEnum) { + //To change body of created methods use File | Settings | File Templates. + } + + public String getAuthor() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public DataFlowRunner getInstructionSet() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public File getStorageFile() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public boolean hasStorage() { + return false; //To change body of created methods use File | Settings | File Templates. + } +} + +class SuiteItem { +// -------------------------- OTHER METHODS -------------------------- + + public void addSuiteItem(SuiteItem storage) { + //To change body of created methods use File | Settings | File Templates. + } + + public long getDelay() { + return 0; //To change body of created methods use File | Settings | File Templates. + } + + public String getDescription() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public long getDuration() { + return 0; //To change body of created methods use File | Settings | File Templates. + } + + public InstructionItem getInstructionItem() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public int getIterations() { + return 0; //To change body of created methods use File | Settings | File Templates. + } + + public Date getLastTested() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getName() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getStereotype() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public void setDelay(long delay) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setDescription(String description) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setDuration(long duration) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setInstructionItem(InstructionItem instruction) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setIterations(int i) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setLastTested(Date date) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setName(String name) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setStereotype(String s) { + //To change body of created methods use File | Settings | File Templates. + } +} + +class Utilities { +// -------------------------- STATIC METHODS -------------------------- + + public static String toString(Object receipt) { + return null; //To change body of created methods use File | Settings | File Templates. + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Test.java b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Test.java new file mode 100644 index 000000000000..a6c07a06482d --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum1Test.java @@ -0,0 +1,696 @@ +/** + * $id + * Author: Dave Kriewall + * Created: Oct 20, 2005 + * Copyright 2004, WRQ, Inc. + */ +package com.wrq.rearranger.testClasses; + +import com.intellij.codeInspection.dataFlow.DataFlowRunner; + +import javax.swing.tree.TreePath; +import java.io.File; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + * Created by IntelliJ IDEA. User: JJohnson Date: Aug 30, 2005 Time: 11:06:54 AM To change this template use File | + * Settings | File Templates. + */ +public class Enum1Test implements Cloneable { + private static final String STEREOTYPE_PREFIX = "STEREOTYPE_"; + + public void setExpectedReceipt(byte[] newValue) { + } + + public void setParameter(String value) { + } + + public void setStorage(SuiteItem suiteItem) { + } + + // ------------------------------ FIELDS ------------------------------ + public enum ExecutionState { + PASSED, FAILED, UNTESTED + } + + private Enum1Test parent = null; + private SuiteModel suiteModel; + private SuiteItem storage; + private List childNodes = new ArrayList(10); + + // --------------------------- CONSTRUCTORS --------------------------- + public Enum1Test(SuiteModel model, Stereotype type) { + } + + // --------------------- GETTER / SETTER METHODS --------------------- + private void setStereotype(Stereotype type) { + } + + public Stereotype getStereotype() { + return null; + } + + public static Stereotype getStereotype(String stStr) { + return null; + } + + public long getDelay() { + return storage.getDelay(); + } + + public InstructionItem getInstructionItem() { + return storage.getInstructionItem(); + } + + public int getIterations() { + return storage.getIterations(); + } + + public Date getLastTested() { + Date date = storage.getLastTested(); + return date == null ? null : date; + } + + public String getName() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return getInstruction(getInstructionItem().getInstructionRef()).getName(); + } + return storage.getName(); + } + + public Enum1Test getParent() { + return parent; + } + + // ------------------------ CANONICAL METHODS ------------------------ + public Object clone() throws CloneNotSupportedException { + try { + return super.clone(); + } + catch (final CloneNotSupportedException e) { + return null; + } + } + + public String toString() { + return getName(); + } + + // -------------------------- OTHER METHODS -------------------------- + public void add(Enum1Test appendingNode, boolean createStorage) { + childNodes.add(appendingNode); + appendingNode.setParent(this, createStorage); + } + + public void add(Enum1Test insertingNode, Enum1Test selection) { + childNodes.add(childNodes.indexOf(selection) + 1, insertingNode); + insertingNode.setParent(this, true); + } + + public void add(int index, Enum1Test t) { + t.setParent(this, true); + childNodes.add(index, t); + } + + public void setParent(Enum1Test parent, boolean createStorage) { + Enum1Test oldParent = this.parent; + this.parent = parent; + if (createStorage) { + parent.addChild(this); + } + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_PARENT, oldParent, parent, this); + } + + private void addChild(Enum1Test childNode) { + storage.addSuiteItem(childNode.getStorage()); + } + + public SuiteItem getStorage() { + return storage; + } + + public boolean canMove(Direction direction) { + switch (direction) { + case UP: + return (getNextUp() != null); + case DOWN: + return (getNextDown() != null); + } + return false; + } + + public Enum1Test getNextUp() { + if (getStereotype().equals(Stereotype.STEREOTYPE_ROOT)) { + return null; + } + Enum1Test nextUpNode; + if (isFirstChild()) { +// nextUpNode = getParent().getNextUp(); + nextUpNode = getParent().getNextDown(); + } + else { + int newIndexUp = indexOf() - 1; + nextUpNode = (Enum1Test)getParent().getChild(newIndexUp); + } + return nextUpNode; + } + + public boolean isFirstChild() { + return indexOf() == 0; + } + + /** Get index of this node within its parents children list. */ + public int indexOf() { + Enum1Test parent = getParent(); + if (parent == null) { + return 0; + } + return parent.indexOf(this); + } + + public Object getChild(int index) { + return childNodes.get(index); + } + + public Enum1Test getNextDown() { + if (getStereotype().equals(Stereotype.STEREOTYPE_ROOT)) { + return null; + } + Enum1Test nextDownNode; + if (isLastChild()) { +// nextDownNode = getParent().getNextDown(); + nextDownNode = getParent().getNextUp(); + } + else { + int newIndexDown = indexOf() + 1; + nextDownNode = (Enum1Test)getParent().getChild(newIndexDown); + } + return nextDownNode; + } + + public boolean isLastChild() { + if (parent == null) { + return true; // root is an only-child + } + int indexOf = indexOf(); + return (indexOf == parent.getChildCount() - 1); + } + + public int getChildCount() { + return childNodes.size(); + } + + public Enum1Test[] getChildren() { + return childNodes.toArray(new Enum1Test[]{}); + } + + public String getDescription() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return getInstruction(getInstructionItem().getInstructionRef()).getDescription(); + } + return storage.getDescription(); + } + + public long getDuration() { + long durationSum = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + durationSum += storage.getDuration(); + } + else { + for (Enum1Test t : childNodes) { + durationSum += t.getDuration(); + } + } + return durationSum; + } + + public String getParameter() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return getInstructionItem().getParameter(); + } + return ""; + } + + public TreePath getPath() { + List parents = new ArrayList(20); + for (Enum1Test node = this; node != null; node = node.getParent()) { + parents.add(node); + } + Collections.reverse(parents); + return new TreePath(parents.toArray(new Enum1Test[0])); + } + + public String getReceiptString() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return Utilities.toString(getInstructionItem().getReceipt()); + } + return ""; + } + + public ExecutionState getState() { + ExecutionState state = ExecutionState.UNTESTED; + if (storage.getInstructionItem() != null) { + byte[] receipt = getInstructionItem().getReceipt(); + if (receipt != null) { + byte[] expectedReceipt = getInstructionItem().getExpectedReceipt(); + if (expectedReceipt == null) { + state = ExecutionState.FAILED; + } + else if (receipt.length != expectedReceipt.length) { + state = ExecutionState.FAILED; + } + else { + state = ExecutionState.PASSED; + for (int i = 0; i < receipt.length; i++) { + if (receipt[i] != expectedReceipt[i]) { + state = ExecutionState.FAILED; + break; + } + } + } + } + } + return state; + } + + public String getStateText() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + ExecutionState state = getState(); + switch (state) { + case UNTESTED: + return "Untested"; + case PASSED: + return "Passed"; + case FAILED: + return "Failed"; + } + } + return this.getPassed() + " / " + this.getFailed() + " of " + this.getTotalInstructions(); + } + + public int getPassed() { + int count = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + if (getState().equals(ExecutionState.PASSED)) { + count++; + } + } + else { + for (Enum1Test t : childNodes) { + count += t.getPassed(); + } + } + return count; + } + + public int getFailed() { + int count = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + if (getState().equals(ExecutionState.FAILED)) { + count++; + } + } + else { + for (Enum1Test t : childNodes) { + count += t.getFailed(); + } + } + return count; + } + + public int getTotalInstructions() { + int count = 0; + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + count++; + } + for (Enum1Test t : childNodes) { + if (!getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + count += t.getTotalInstructions(); + } + } + return count; + } + + public String getToolTip() { + StringBuilder tt = new StringBuilder(200); + tt.append(""); + switch (getStereotype()) { + case STEREOTYPE_ROOT: + buildRootToolTip(tt); + break; + case STEREOTYPE_GROUP: + buildGroupToolTip(tt); + break; + case STEREOTYPE_INSTRUCTION: + buildInstructionToolTip(tt); + break; + } + buildRunInfoToolTip(tt); + tt.append(""); + return tt.toString(); + } + + private void buildRunInfoToolTip(StringBuilder tt) { + tt.append("


"); // a divider line + tt.append("Iterations: ").append(getIterations()).append("

"); + tt.append("Pause: ").append(getDelay()).append("

"); + tt.append("State: ").append(getStateText()).append("

"); // todo add state color getStatecolor()... + tt.append("Duration: ").append(getDuration()).append("

"); + tt.append("Executed: ").append(getLastTested()).append("

"); + } + + private void buildInstructionToolTip(StringBuilder tt) { + InstructionItem inst = getInstructionItem(); + if (inst != null) { + String id = inst.getInstructionRef(); + Instruction instruction = getInstruction(id); + tt.append("Command: ").append(instruction.getCommand()).append("

"); + } + tt.append("Parameter: ").append(getParameter()).append("

"); + tt.append("Received: ").append(getReceiptString()).append("

"); + tt.append("Expected: ").append(getExpectedReceiptString()).append("

"); + } + + private String getExpectedReceiptString() { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return Utilities.toString(getInstructionItem().getExpectedReceipt()); + } + return ""; + } + + private void buildGroupToolTip(StringBuilder tt) { + String desc = getDescription(); + if (desc != null && desc.length() > 0) { + tt.append(desc).append("

"); + } + } + + private void buildRootToolTip(StringBuilder tt) { + String author = suiteModel.getAuthor(); + String desc = getDescription(); + String filePath = suiteModel.hasStorage() ? suiteModel.getStorageFile().getAbsolutePath() : null; + if (author != null && author.length() > 0) { + tt.append(author).append("

"); + } + if (desc != null && desc.length() > 0) { + tt.append(desc).append("

"); + } + if (filePath != null && filePath.length() > 0) { + tt.append(filePath).append("

"); + } + } + + public boolean hasChildren() { + return childNodes.size() > 0; + } + + public int indexOf(Enum1Test t) { + return childNodes.indexOf(t); + } + + public boolean isGroup() { + return getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION); + } + + public void remove(Enum1Test node) { + childNodes.remove(node); + // node.setParent(null); + } + + public void setDelay(long delay) { + long oldDelay = storage.getDelay(); + storage.setDelay(delay); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_DELAY, oldDelay, delay, this); + } + + public void setDescription(String description) { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return; // name is fixed for instructions + } + String oldDescription = storage.getDescription(); + storage.setDescription(description); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_DESC, oldDescription, description, this); + } + + public void setDuration(long duration) { + if (!getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return; // name is fixed anything execept instructions + } + long oldDuration = getDuration(); + storage.setDuration(duration); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_DURATION, oldDuration, duration, this); + } + + public void setInstructionItem(InstructionItem instruction) { + InstructionItem oldInstruction = this.getInstructionItem(); + storage.setInstructionItem(instruction); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_INSTRUCTION, oldInstruction, instruction, this); + } + + public void setIterations(int iterations) { + int oldIterations = storage.getIterations(); + storage.setIterations(iterations); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_ITERATIONS, oldIterations, iterations, this); + } + + public void setLastTested(Date lastTested) { + Date oldLastTested = getLastTested(); + storage.setLastTested(new Date()); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_LAST_TESTED, oldLastTested, lastTested, this); + } + + public void setName(String name) { + if (getStereotype().equals(Stereotype.STEREOTYPE_INSTRUCTION)) { + return; // name is fixed for instructions + } + String oldName = storage.getName(); + storage.setName(name); + suiteModel.fireChangeEvent(SuiteModel.EVT_TOPIC_NAME, oldName, name, this); + } + + // -------------------------- INNER CLASSES -------------------------- + public enum Stereotype { + STEREOTYPE_ROOT, STEREOTYPE_GROUP, STEREOTYPE_INSTRUCTION + } + + public enum Direction { + UP, DOWN + } + + public void execute() { + // Repeat this node -iterations- times + for (int repeatCount = 0; repeatCount < getIterations(); repeatCount++) { + if (getStereotype().equals(Enum1Test.Stereotype.STEREOTYPE_INSTRUCTION)) { + executeInstruction(); + } + else { + executeChildren(); + } + // Pause after each execution this number of milliseconds before continuing + try { + Thread.sleep(getDelay()); + } + catch (InterruptedException e) { + e.printStackTrace(); // todo - logger + } + } + } + + private void executeChildren() { + Enum1Test[] children = getChildren(); + for (Enum1Test node : children) { + node.execute(); // recursive execution for nested groups of instructions. + } + } + + private void executeInstruction() { + } + + private ByteBuffer getPacketToSend(InstructionItem instruction) { + return null; + } + + public ByteBuffer getPacketToSend() { + return getPacketToSend(getInstructionItem()); + } + + public String getStateText(boolean firstCap) { + String stateText; + switch (getState()) { + case UNTESTED: + stateText = "untested"; + break; + case PASSED: + stateText = "passed"; + break; + case FAILED: + stateText = "failed"; + break; + default: + stateText = "** unknown **"; + } + return stateText; + } + + public Instruction getInstruction(String id) { + return null; + } + + public Instruction getInstruction() { + String id = this.getInstructionItem().getInstructionRef(); + return getInstruction(id); + } +} + +class InstructionItem { + public byte[] getExpectedReceipt() { + return new byte[0]; //To change body of created methods use File | Settings | File Templates. + } + + public void setExpectedReceipt(byte[] newValue) { + //To change body of created methods use File | Settings | File Templates. + } + + public String getParameter() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public void setParameter(String value) { + //To change body of created methods use File | Settings | File Templates. + } + + public String getInstructionRef() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public byte[] getReceipt() { + return null; + } +} + +class Instruction { + public String getName() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getDescription() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getCommand() { + return null; //To change body of created methods use File | Settings | File Templates. + } +} + +class SuiteModel { + public static final Object EVT_TOPIC_EXPECTED_RECEIPT = ""; + public static final Object EVT_TOPIC_PARAMETER = ""; + public static final Object EVT_TOPIC_PARENT = ""; + public static final Object EVT_TOPIC_DELAY = ""; + public static Object EVT_TOPIC_DESC = ""; + public static Object EVT_TOPIC_DURATION = ""; + public static Object EVT_TOPIC_INSTRUCTION = ""; + public static Object EVT_TOPIC_ITERATIONS = ""; + public static Object EVT_TOPIC_LAST_TESTED = ""; + public static Object EVT_TOPIC_NAME = ""; + + public void fireChangeEvent(Object p0, Object oldValue, Object newValue, Enum1Test testEnum) { + //To change body of created methods use File | Settings | File Templates. + } + + public String getAuthor() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public boolean hasStorage() { + return false; //To change body of created methods use File | Settings | File Templates. + } + + public File getStorageFile() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public DataFlowRunner getInstructionSet() { + return null; //To change body of created methods use File | Settings | File Templates. + } +} + +class SuiteItem { + public void setIterations(int i) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setStereotype(String s) { + //To change body of created methods use File | Settings | File Templates. + } + + public String getStereotype() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public long getDelay() { + return 0; //To change body of created methods use File | Settings | File Templates. + } + + public InstructionItem getInstructionItem() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public int getIterations() { + return 0; //To change body of created methods use File | Settings | File Templates. + } + + public Date getLastTested() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public String getName() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public void addSuiteItem(SuiteItem storage) { + //To change body of created methods use File | Settings | File Templates. + } + + public String getDescription() { + return null; //To change body of created methods use File | Settings | File Templates. + } + + public long getDuration() { + return 0; //To change body of created methods use File | Settings | File Templates. + } + + public void setDelay(long delay) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setDescription(String description) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setDuration(long duration) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setInstructionItem(InstructionItem instruction) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setLastTested(Date date) { + //To change body of created methods use File | Settings | File Templates. + } + + public void setName(String name) { + //To change body of created methods use File | Settings | File Templates. + } +} + +class Utilities { + public static String toString(Object receipt) { + return null; //To change body of created methods use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2AResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2AResult.java new file mode 100644 index 000000000000..2b078c110cbf --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2AResult.java @@ -0,0 +1,26 @@ +class Enum2Test { +// -------------------------- ENUMERATIONS -------------------------- + + /** Presentation Events. */ + public enum Event { + barcodeBorder, + htmlResponse; + } + + public enum Event2 { + barcodeBorder, + htmlResponse + } + + ; + + enum Coin { + Nickel(5), + Dime(10); + final int value; + + Coin(int value) { + this.value = value; + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Result.java b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Result.java new file mode 100644 index 000000000000..a7326ea7056b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Result.java @@ -0,0 +1,31 @@ +class Enum2Test { +// -------------------------- ENUMERATIONS -------------------------- + + /** Presentation Events. */ + public enum Event { + barcodeBorder, + htmlResponse; + } + + public enum Event2 { + barcodeBorder, + htmlResponse + } + + ; + + enum Coin { + Nickel(5), + Dime(10); + +// ------------------------------ FIELDS ------------------------------ + + final int value; + +// --------------------------- CONSTRUCTORS --------------------------- + + Coin(int value) { + this.value = value; + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Test.java b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Test.java new file mode 100644 index 000000000000..3eae2a547765 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/Enum2Test.java @@ -0,0 +1,24 @@ +class Enum2Test { + /** Presentation Events. */ + public enum Event { + barcodeBorder, + htmlResponse; + } + + public enum Event2 { + barcodeBorder, + htmlResponse + } + + ; + + enum Coin { + Nickel(5), + Dime(10); + final int value; + + Coin(int value) { + this.value = value; + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GenericsResult1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GenericsResult1.java new file mode 100644 index 000000000000..16b18c44c73d --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GenericsResult1.java @@ -0,0 +1,8 @@ +public class TestGenerics { + //-------------------------------------------------------------------- + //------------------------------------------ Protected/Package Methods + + static T test() { + return null; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GenericsTest1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GenericsTest1.java new file mode 100644 index 000000000000..8322066c1ab1 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GenericsTest1.java @@ -0,0 +1,5 @@ +public class TestGenerics { + static T test() { + return null; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java new file mode 100644 index 000000000000..a0f03cfacfab --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java @@ -0,0 +1,33 @@ +public class GetterDefinitionTest { + /** name: matches field; body: returns field */ + public int getField2() { + return field2; + } + + int dummyField; + int field; + int field2; + + /** name: correct prefix; body: immaterial */ + public int getY() { + dummyField++; + return dummyField; + } + + /** name: correct prefix; body: returns */ + public int getX() { + return field + 1; + } + + /** name: correct prefix; body: returns field */ + public int getZ() { + return field; + } + + /** name: matches field; body: returns */ + public int getField() { + return field + 1; + } + + int dummyField2; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java new file mode 100644 index 000000000000..a0f03cfacfab --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java @@ -0,0 +1,33 @@ +public class GetterDefinitionTest { + /** name: matches field; body: returns field */ + public int getField2() { + return field2; + } + + int dummyField; + int field; + int field2; + + /** name: correct prefix; body: immaterial */ + public int getY() { + dummyField++; + return dummyField; + } + + /** name: correct prefix; body: returns */ + public int getX() { + return field + 1; + } + + /** name: correct prefix; body: returns field */ + public int getZ() { + return field; + } + + /** name: matches field; body: returns */ + public int getField() { + return field + 1; + } + + int dummyField2; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java new file mode 100644 index 000000000000..4e4b1508b8b1 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java @@ -0,0 +1,32 @@ +public class GetterDefinitionTest { + /** name: correct prefix; body: immaterial */ + public int getY() { + dummyField++; + return dummyField; + } + + /** name: correct prefix; body: returns */ + public int getX() { + return field + 1; + } + + /** name: correct prefix; body: returns field */ + public int getZ() { + return field; + } + + /** name: matches field; body: returns */ + public int getField() { + return field + 1; + } + + /** name: matches field; body: returns field */ + public int getField2() { + return field2; + } + + int dummyField; + int field; + int field2; + int dummyField2; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java new file mode 100644 index 000000000000..a0f03cfacfab --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java @@ -0,0 +1,33 @@ +public class GetterDefinitionTest { + /** name: matches field; body: returns field */ + public int getField2() { + return field2; + } + + int dummyField; + int field; + int field2; + + /** name: correct prefix; body: immaterial */ + public int getY() { + dummyField++; + return dummyField; + } + + /** name: correct prefix; body: returns */ + public int getX() { + return field + 1; + } + + /** name: correct prefix; body: returns field */ + public int getZ() { + return field; + } + + /** name: matches field; body: returns */ + public int getField() { + return field + 1; + } + + int dummyField2; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java new file mode 100644 index 000000000000..07e95ab15c4f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java @@ -0,0 +1,33 @@ +public class GetterDefinitionTest { + /** name: correct prefix; body: returns */ + public int getX() { + return field + 1; + } + + /** name: correct prefix; body: returns field */ + public int getZ() { + return field; + } + + /** name: matches field; body: returns */ + public int getField() { + return field + 1; + } + + /** name: matches field; body: returns field */ + public int getField2() { + return field2; + } + + int dummyField; + int field; + int field2; + + /** name: correct prefix; body: immaterial */ + public int getY() { + dummyField++; + return dummyField; + } + + int dummyField2; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetterDefinitionTest.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetterDefinitionTest.java new file mode 100644 index 000000000000..f4aed22fccbb --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetterDefinitionTest.java @@ -0,0 +1,33 @@ +public class GetterDefinitionTest { + int dummyField; + int field; + int field2; + + /** name: correct prefix; body: immaterial */ + public int getY() { + dummyField++; + return dummyField; + } + + /** name: correct prefix; body: returns */ + public int getX() { + return field + 1; + } + + /** name: correct prefix; body: returns field */ + public int getZ() { + return field; + } + + /** name: matches field; body: returns */ + public int getField() { + return field + 1; + } + + /** name: matches field; body: returns field */ + public int getField2() { + return field2; + } + + int dummyField2; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineResult.java new file mode 100644 index 000000000000..8e684354b3e7 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineResult.java @@ -0,0 +1,22 @@ +/** + * $id + * Author: Dave Kriewall + * Created: Oct 20, 2005 + * Copyright 2004, WRQ, Inc. + */ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. User: JJohnson Date: Aug 30, 2005 Time: 11:06:54 AM To change this template use File | + * Settings | File Templates. + */ +public class TestEnum implements Cloneable { +} + +class Utilities { +// -------------------------- STATIC METHODS -------------------------- + + public static String toString(Object receipt) { + return null; //To change body of created methods use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineTest.java b/plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineTest.java new file mode 100644 index 000000000000..0a0141eb148a --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/IncompleteLineTest.java @@ -0,0 +1,20 @@ +/** + * $id + * Author: Dave Kriewall + * Created: Oct 20, 2005 + * Copyright 2004, WRQ, Inc. + */ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. User: JJohnson Date: Aug 30, 2005 Time: 11:06:54 AM To change this template use File | + * Settings | File Templates. + */ +public class TestEnum implements Cloneable { +} + +class Utilities { + public static String toString(Object receipt) { + return null; //To change body of created methods use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceResult1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceResult1.java new file mode 100644 index 000000000000..0add5205bd14 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceResult1.java @@ -0,0 +1,8 @@ +public interface TestInterface { + int CONSTANT = 5; + public int CONSTANT2 = 6; + + void testMethod(); + + public void testMethod2(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceTest1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceTest1.java new file mode 100644 index 000000000000..651208159a9f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/InterfaceTest1.java @@ -0,0 +1,9 @@ +public interface TestInterface { + int CONSTANT = 5; + + void testMethod(); + + public int CONSTANT2 = 6; + + public void testMethod2(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassResult.java new file mode 100644 index 000000000000..ee6c7c065aad --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassResult.java @@ -0,0 +1,25 @@ +public class RearrangerTrouble { + + // ----- Constructor(s) -------------------------------------------------------------------------------------------- + + + // ----- Public API ------------------------------------------------------------------------------------------------ + + + // ----- Package API ----------------------------------------------------------------------------------------------- + + + // ----- Helper method(s) ------------------------------------------------------------------------------------------ + + + // ----- Helper class(es) ------------------------------------------------------------------------------------------ + + private class DoNotRearrangeMe + implements Comparable + { + + public int compareTo(Object o) { + return 0; + } + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassTest.java b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassTest.java new file mode 100644 index 000000000000..1fc6ce984e42 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangeInnerClassTest.java @@ -0,0 +1,12 @@ +public class RearrangerTrouble { + + + private class DoNotRearrangeMe + implements Comparable + { + + public int compareTo(Object o) { + return 0; + } + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml new file mode 100644 index 000000000000..06765c372a62 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\ \ + //\ -----\ Constructor(s)\ --------------------------------------------------------------------------------------------\n + + + + + + + + + + + + + + + + + + + + + + + \n\ \ //-----\ Interface\ %IF%\ \ ----------------------------------\n + + + + + + + \n\ \ + //\ -----\ Public\ API\ ------------------------------------------------------------------------------------------------\n + + + + + + + + + + + + + + + + + + + \n\ \ + //\ -----\ Package\ API\ -----------------------------------------------------------------------------------------------\n + + + + + + + + + + + + + + + + + + + \n\ \ + //\ -----\ Helper\ method(s)\ ------------------------------------------------------------------------------------------\n + + + + + + + + + + + + + + + + + + + \n\ \ + //\ -----\ Helper\ class(es)\ ------------------------------------------------------------------------------------------\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementResult1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementResult1.java new file mode 100644 index 000000000000..8882b2f69480 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementResult1.java @@ -0,0 +1,57 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + /** field 1. */ + private int field1; + private int field2; + public static final int field3 = 3; + public static final int field4 = 4; + final int field5 = 5; + protected int field6 = 6; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueue.java b/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueue.java new file mode 100644 index 000000000000..fedb5e2587e5 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueue.java @@ -0,0 +1,70 @@ +/* + * OpsBlockingQueue.java + * + * Created on May 3, 2001, 3:11 PM + */ +package opsx.util; + +import opsx.log.OpsLogCategory; +import opsx.server.email.OpsEmailGenerator; + +/** @author dchan */ +public class OpsBlockingQueue extends OpsNonBlockingQueue { + //*********************************** PROTECTED/PACKAGE FIELDS ************************************** + protected final Object putLock; + protected final Object takeLock; + protected volatile int waitCount; + //************************************** PRIVATE FIELDS ***************************************** + private static final OpsLogCategory logCat = (OpsLogCategory)OpsLogCategory.getInstance(OpsEmailGenerator.class); +//************************************** CONSTRUCTORS ************************************* + + /** Creates new OpsBlockingQueue */ + public OpsBlockingQueue() { + takeLock = new Object(); + putLock = new Object(); + waitCount = 0; + } + + //************************************** PUBLIC METHODS ************************************* + public void put(Object obj) { + synchronized (putLock) { + insert(obj); + if (waitCount > 0) { + putLock.notifyAll(); + } + } + } + + public Object take() { + Object obj = takeNext(); + if (obj != null) { + return obj; + } + else { + synchronized (putLock) { + waitCount++; + while (true) { + obj = takeNext(); + if (obj != null) { + waitCount--; + return obj; + } + try { + putLock.wait(); + } + catch (InterruptedException e) { + logCat.error("Blocking Queue threw interrupt", e); + return null; + } + } + } + } + } + + //********************************* PACKAGE/PROTECTED METHODS ******************************** + protected Object takeNext() { + synchronized (takeLock) { + return super.takeNext(); + } + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndented.java b/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndented.java new file mode 100644 index 000000000000..1dc7e756fc9f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndented.java @@ -0,0 +1,75 @@ +/* + * OpsBlockingQueue.java + * + * Created on May 3, 2001, 3:11 PM + */ +package opsx.util; + +import opsx.log.OpsLogCategory; +import opsx.server.email.OpsEmailGenerator; + +/** @author dchan */ +public class OpsBlockingQueue extends OpsNonBlockingQueue { + //*********************************** PROTECTED/PACKAGE FIELDS ************************************** + protected final Object putLock; + protected final Object takeLock; + protected volatile int waitCount; + + //************************************** PRIVATE FIELDS ***************************************** + + private static final OpsLogCategory logCat = (OpsLogCategory)OpsLogCategory.getInstance(OpsEmailGenerator.class); + + //************************************** CONSTRUCTORS ************************************* + + /** Creates new OpsBlockingQueue */ + public OpsBlockingQueue() { + takeLock = new Object(); + putLock = new Object(); + waitCount = 0; + } + + //************************************** PUBLIC METHODS ************************************* + // PUBLIC METHODS LINE 2 + + public void put(Object obj) { + synchronized (putLock) { + insert(obj); + if (waitCount > 0) { + putLock.notifyAll(); + } + } + } + + public Object take() { + Object obj = takeNext(); + if (obj != null) { + return obj; + } + else { + synchronized (putLock) { + waitCount++; + while (true) { + obj = takeNext(); + if (obj != null) { + waitCount--; + return obj; + } + try { + putLock.wait(); + } + catch (InterruptedException e) { + logCat.error("Blocking Queue threw interrupt", e); + return null; + } + } + } + } + } + + //********************************* PACKAGE/PROTECTED METHODS ******************************** + protected Object takeNext() { + synchronized (takeLock) { + return super.takeNext(); + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndentedResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndentedResult.java new file mode 100644 index 000000000000..a8ba010d2f51 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/OpsBlockingQueueIndentedResult.java @@ -0,0 +1,71 @@ +/* + * OpsBlockingQueue.java + * + * Created on May 3, 2001, 3:11 PM + */ +package opsx.util; + +import opsx.log.OpsLogCategory; +import opsx.server.email.OpsEmailGenerator; + +/** @author dchan */ +public class OpsBlockingQueue extends OpsNonBlockingQueue { + //*********************************** PROTECTED/PACKAGE FIELDS ************************************** + protected final Object putLock; + protected final Object takeLock; + protected volatile int waitCount; + //************************************** PRIVATE FIELDS ***************************************** + private static final OpsLogCategory logCat = (OpsLogCategory)OpsLogCategory.getInstance(OpsEmailGenerator.class); +//************************************** CONSTRUCTORS ************************************* + + /** Creates new OpsBlockingQueue */ + public OpsBlockingQueue() { + takeLock = new Object(); + putLock = new Object(); + waitCount = 0; + } + + //************************************** PUBLIC METHODS ************************************* +// PUBLIC METHODS LINE 2 + public void put(Object obj) { + synchronized (putLock) { + insert(obj); + if (waitCount > 0) { + putLock.notifyAll(); + } + } + } + + public Object take() { + Object obj = takeNext(); + if (obj != null) { + return obj; + } + else { + synchronized (putLock) { + waitCount++; + while (true) { + obj = takeNext(); + if (obj != null) { + waitCount--; + return obj; + } + try { + putLock.wait(); + } + catch (InterruptedException e) { + logCat.error("Blocking Queue threw interrupt", e); + return null; + } + } + } + } + } + + //********************************* PACKAGE/PROTECTED METHODS ******************************** + protected Object takeNext() { + synchronized (takeLock) { + return super.takeNext(); + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedConfig.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedConfig.xml new file mode 100644 index 000000000000..8f00c29e79a3 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedConfig.xml @@ -0,0 +1,500 @@ + + + + \ \ \ //%FS%\n\ \ \ //%FS%\ Constants\n + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Inner\ Classes\n + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Instance\ Variables\n + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Variables\n + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Constructors\n + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Instance\ Methods\n + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Getters/Setters\n + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Public\ Methods\n + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ %IF%\ Methods\n + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Protected/Package\ + Getters/Setters\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Protected/Package\ Methods\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Private\ Methods\n + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Inner\ Classes\n + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Variables\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Instance\ Variables\n + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Private\ Constants\n + + + + + + + + + + + + \n\n\ \ \ //%FS%\n\ \ \ //%FS%\ Main\ Method\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\n//%FS%\n//%FS%\n\n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedResult1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedResult1.java new file mode 100644 index 000000000000..64ec60be8083 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedResult1.java @@ -0,0 +1,11 @@ +public class TestOverloaded { + //-------------------------------------------------------------------- + //------------------------------------------------------- Constructors + + public TestOverloaded(String p_login) { + } + + + public TestOverloaded(Integer p_user) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedTest1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedTest1.java new file mode 100644 index 000000000000..64ec60be8083 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/OverloadedTest1.java @@ -0,0 +1,11 @@ +public class TestOverloaded { + //-------------------------------------------------------------------- + //------------------------------------------------------- Constructors + + public TestOverloaded(String p_login) { + } + + + public TestOverloaded(Integer p_user) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult10.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult10.java new file mode 100644 index 000000000000..07f2dd6cbab9 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult10.java @@ -0,0 +1,58 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + public static final int field3 = 3; + public static final int field4 = 4; +// simple comment ********** + /** field 1. */ + private int field1; + private int field2; + final int field5 = 5; + protected int field6 = 6; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult11.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult11.java new file mode 100644 index 000000000000..6686430237da --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult11.java @@ -0,0 +1,8 @@ +public class RearrangementTest11 { + // FIELDS: +// FINAL FIELDS: + final int i; + public final int k; + // NON-FINAL FIELDS: + int j; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult12.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult12.java new file mode 100644 index 000000000000..fdcee3db5fb1 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult12.java @@ -0,0 +1,21 @@ +class RearrangementTest12 { + void method(int y) { + x = y; + } + + int x; + + Object convertX() { + return new Integer(x); + } + + Integer[] convertXs() { + return new Integer[]{new Integer(x), new Integer(0)}; + } + + int getX() { + return x; + } + + String s; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13.java new file mode 100644 index 000000000000..171b824726d8 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + void S1B() { + } + + void S1A() { + } + + private void F2() { + S2A(); + S2B(); + } + + void S2A() { + } + + void S2B() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BA.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BA.java new file mode 100644 index 000000000000..a66c1c573e7a --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BA.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + private void F2() { + S2A(); + S2B(); + } + + void S1A() { + } + + void S1B() { + } + + void S2A() { + } + + void S2B() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BI.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BI.java new file mode 100644 index 000000000000..01a2d9fa3a53 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BI.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + private void F2() { + S2A(); + S2B(); + } + + void S1B() { + } + + void S1A() { + } + + void S2A() { + } + + void S2B() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIELC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIELC.java new file mode 100644 index 000000000000..1c8c38a5889c --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIELC.java @@ -0,0 +1,52 @@ +public class RearrangerTest13 { + // Preceding comment: TL=GF +// MN=GF +// AM= +// Level 1 + void GF() { // grandfather + F1(); + F2(); + } +// Preceding comment: TL=GF +// MN=GF +// AM=GF() +// Level 2 + + private void F1() { + S1B(); + S1A(); + } + + private void F2() { + S2A(); + S2B(); + } + + // Preceding comment: TL=GF +// MN=F2 +// AM=GF().[F1(),F2()] +// Level 3 + void S1B() { + } + + void S1A() { + } + + void S2A() { + } + + void S2B() { + } +// Trailing comment: TL=GF +// MN=F2 +// AM=GF().[F1(),F2()] +// Level 3 +// Trailing comment: TL=GF +// MN=GF +// AM=GF() +// Level 2 +// Trailing comment: TL=GF +// MN=GF +// AM= +// Level 1 +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIEMC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIEMC.java new file mode 100644 index 000000000000..a1767777decb --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BIEMC.java @@ -0,0 +1,84 @@ +public class RearrangerTest13 { + // Preceding comment: TL=GF +// MN=GF +// AM= +// Level 1 + void GF() { // grandfather + F1(); + F2(); + } +// Trailing comment: TL=GF +// MN=GF +// AM= +// Level 1 +// Preceding comment: TL=GF +// MN=F1 +// AM=GF() +// Level 2 + + private void F1() { + S1B(); + S1A(); + } +// Trailing comment: TL=GF +// MN=F1 +// AM=GF() +// Level 2 +// Preceding comment: TL=GF +// MN=F2 +// AM=GF() +// Level 2 + + private void F2() { + S2A(); + S2B(); + } + + // Trailing comment: TL=GF +// MN=F2 +// AM=GF() +// Level 2 +// Preceding comment: TL=GF +// MN=S1B +// AM=GF().[F1(),F2()] +// Level 3 + void S1B() { + } + + // Trailing comment: TL=GF +// MN=S1B +// AM=GF().[F1(),F2()] +// Level 3 +// Preceding comment: TL=GF +// MN=S1A +// AM=GF().[F1(),F2()] +// Level 3 + void S1A() { + } + + // Trailing comment: TL=GF +// MN=S1A +// AM=GF().[F1(),F2()] +// Level 3 +// Preceding comment: TL=GF +// MN=S2A +// AM=GF().[F1(),F2()] +// Level 3 + void S2A() { + } + + // Trailing comment: TL=GF +// MN=S2A +// AM=GF().[F1(),F2()] +// Level 3 +// Preceding comment: TL=GF +// MN=S2B +// AM=GF().[F1(),F2()] +// Level 3 + void S2B() { + } +// Trailing comment: TL=GF +// MN=S2B +// AM=GF().[F1(),F2()] +// Level 3 +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BINFC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BINFC.java new file mode 100644 index 000000000000..70229ad1245b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BINFC.java @@ -0,0 +1,32 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } +// Preceding comment: TL=GF +// MN=GF +// AM=GF() +// Level 2 + + private void F2() { + S2A(); + S2B(); + } + + void S1B() { + } + + void S1A() { + } + + void S2A() { + } + + void S2B() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BITLC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BITLC.java new file mode 100644 index 000000000000..2e6913993b4e --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BITLC.java @@ -0,0 +1,36 @@ +public class RearrangerTest13 { + // Preceding comment: TL=GF +// MN=GF +// AM= +// Level 1 + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + private void F2() { + S2A(); + S2B(); + } + + void S1B() { + } + + void S1A() { + } + + void S2A() { + } + + void S2B() { + } +// Trailing comment: TL=GF +// MN=GF +// AM= +// Level 1 +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BO.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BO.java new file mode 100644 index 000000000000..1060fea2f3dd --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13BO.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F2() { + S2A(); + S2B(); + } + + private void F1() { + S1B(); + S1A(); + } + + void S2B() { + } + + void S1B() { + } + + void S2A() { + } + + void S1A() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DA.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DA.java new file mode 100644 index 000000000000..c8aa6eae8825 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DA.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + void S1A() { + } + + void S1B() { + } + + private void F2() { + S2A(); + S2B(); + } + + void S2A() { + } + + void S2B() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DI.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DI.java new file mode 100644 index 000000000000..171b824726d8 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DI.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + void S1B() { + } + + void S1A() { + } + + private void F2() { + S2A(); + S2B(); + } + + void S2A() { + } + + void S2B() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIELC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIELC.java new file mode 100644 index 000000000000..16cafde0c90f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIELC.java @@ -0,0 +1,60 @@ +public class RearrangerTest13 { + // Preceding comment: TL=GF +// MN=GF +// AM= +// Level 1 + void GF() { // grandfather + F1(); + F2(); + } +// Preceding comment: TL=GF +// MN=GF +// AM=GF() +// Level 2 + + private void F1() { + S1B(); + S1A(); + } + + // Preceding comment: TL=GF +// MN=F1 +// AM=GF().F1() +// Level 3 + void S1B() { + } + + void S1A() { + } +// Trailing comment: TL=GF +// MN=F1 +// AM=GF().F1() +// Level 3 + + private void F2() { + S2A(); + S2B(); + } + + // Preceding comment: TL=GF +// MN=F2 +// AM=GF().F2() +// Level 3 + void S2A() { + } + + void S2B() { + } +// Trailing comment: TL=GF +// MN=F2 +// AM=GF().F2() +// Level 3 +// Trailing comment: TL=GF +// MN=GF +// AM=GF() +// Level 2 +// Trailing comment: TL=GF +// MN=GF +// AM= +// Level 1 +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIEMC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIEMC.java new file mode 100644 index 000000000000..6f90b4913aa3 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DIEMC.java @@ -0,0 +1,84 @@ +public class RearrangerTest13 { + // Preceding comment: TL=GF +// MN=GF +// AM= +// Level 1 + void GF() { // grandfather + F1(); + F2(); + } +// Trailing comment: TL=GF +// MN=GF +// AM= +// Level 1 +// Preceding comment: TL=GF +// MN=F1 +// AM=GF() +// Level 2 + + private void F1() { + S1B(); + S1A(); + } + + // Trailing comment: TL=GF +// MN=F1 +// AM=GF() +// Level 2 +// Preceding comment: TL=GF +// MN=S1B +// AM=GF().F1() +// Level 3 + void S1B() { + } + + // Trailing comment: TL=GF +// MN=S1B +// AM=GF().F1() +// Level 3 +// Preceding comment: TL=GF +// MN=S1A +// AM=GF().F1() +// Level 3 + void S1A() { + } +// Trailing comment: TL=GF +// MN=S1A +// AM=GF().F1() +// Level 3 +// Preceding comment: TL=GF +// MN=F2 +// AM=GF() +// Level 2 + + private void F2() { + S2A(); + S2B(); + } + + // Trailing comment: TL=GF +// MN=F2 +// AM=GF() +// Level 2 +// Preceding comment: TL=GF +// MN=S2A +// AM=GF().F2() +// Level 3 + void S2A() { + } + + // Trailing comment: TL=GF +// MN=S2A +// AM=GF().F2() +// Level 3 +// Preceding comment: TL=GF +// MN=S2B +// AM=GF().F2() +// Level 3 + void S2B() { + } +// Trailing comment: TL=GF +// MN=S2B +// AM=GF().F2() +// Level 3 +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DINFC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DINFC.java new file mode 100644 index 000000000000..235760aaf93f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DINFC.java @@ -0,0 +1,32 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + void S1B() { + } + + void S1A() { + } +// Preceding comment: TL=GF +// MN=GF +// AM=GF() +// Level 2 + + private void F2() { + S2A(); + S2B(); + } + + void S2A() { + } + + void S2B() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DITLC.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DITLC.java new file mode 100644 index 000000000000..b238fa8d540c --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DITLC.java @@ -0,0 +1,36 @@ +public class RearrangerTest13 { + // Preceding comment: TL=GF +// MN=GF +// AM= +// Level 1 + void GF() { // grandfather + F1(); + F2(); + } + + private void F1() { + S1B(); + S1A(); + } + + void S1B() { + } + + void S1A() { + } + + private void F2() { + S2A(); + S2B(); + } + + void S2A() { + } + + void S2B() { + } +// Trailing comment: TL=GF +// MN=GF +// AM= +// Level 1 +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DO.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DO.java new file mode 100644 index 000000000000..4654b27e6d55 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13DO.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F2() { + S2A(); + S2B(); + } + + void S2B() { + } + + void S2A() { + } + + private void F1() { + S1B(); + S1A(); + } + + void S1B() { + } + + void S1A() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13Ex.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13Ex.java new file mode 100644 index 000000000000..4654b27e6d55 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult13Ex.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F2() { + S2A(); + S2B(); + } + + void S2B() { + } + + void S2A() { + } + + private void F1() { + S1B(); + S1A(); + } + + void S1B() { + } + + void S1A() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult14.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult14.java new file mode 100644 index 000000000000..3b56c71a5c79 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult14.java @@ -0,0 +1,14 @@ +public class RearrangementTest14 { + + void GF() { + doIt(2, 3); + } + + int doIt(int x, int y) { + return x + y; + } + + int doIt(int x) { + return x + 1; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18.java new file mode 100644 index 000000000000..061e8da24d9b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18.java @@ -0,0 +1,34 @@ +public class RearrangementTest18 { + int field1; + char char2; + + RearrangementTest18() { + field1 = 10; + } + + char getChar2() { + return char2; + } + + void setChar2(char val) { + char2 = val; + } + + int getField1() { + return field1; + } + + void setField1(int val) { + field1 = val; + } + + void method1() { + char2 = 'a'; + } + + void method3() { + } + + void method4() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18A.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18A.java new file mode 100644 index 000000000000..9d1267993f26 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18A.java @@ -0,0 +1,35 @@ +public class RearrangementTest18 { + int field1; + + int getField1() { + return field1; + } + + void setField1(int val) { + field1 = val; + } + + char char2; + + char getChar2() { + return char2; + } + + void setChar2(char val) { + char2 = val; + } + + RearrangementTest18() { + field1 = 10; + } + + void method1() { + char2 = 'a'; + } + + void method3() { + } + + void method4() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18B.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18B.java new file mode 100644 index 000000000000..491581297451 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult18B.java @@ -0,0 +1,29 @@ +public class MethodEntry { + private boolean isSetter; + + public boolean isIsSetter() { + return isSetter; + } + + // Getters/Setters + public String getCustomizedPrecedingComment() { + if (customizedPrecedingComment == null) { + return ""; + } + return "comment"; + } + + public boolean isGetter() { + return isGetter; + } + + public boolean isSetter() { + return isSetter; + } + + // Other Methods + public DefaultMutableTreeNode addToPopupTree() { + if (isSetter()) return null; + return null; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19A.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19A.java new file mode 100644 index 000000000000..b65c27c7af2a --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19A.java @@ -0,0 +1,24 @@ +public class RearrangementTest19 { + RearrangementTest19() { + } + + RearrangementTest19(int x, int y) { + } + + RearrangementTest19(int oneParam) { + } + + void overloadedMethod1(int x, int y, int z) { + } + + void overloadedMethod1(int x) { + overloadedMethod1(x, 0, 0); + } + + void overloadedMethod1(int x, int y) { + overloadedMethod1(x, y, 0); + } + + void unoverloadedMethod() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19B.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19B.java new file mode 100644 index 000000000000..f9d161a504ee --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19B.java @@ -0,0 +1,24 @@ +public class RearrangementTest19 { + RearrangementTest19() { + } + + RearrangementTest19(int oneParam) { + } + + RearrangementTest19(int x, int y) { + } + + void overloadedMethod1(int x) { + overloadedMethod1(x, 0, 0); + } + + void overloadedMethod1(int x, int y) { + overloadedMethod1(x, y, 0); + } + + void overloadedMethod1(int x, int y, int z) { + } + + void unoverloadedMethod() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java new file mode 100644 index 000000000000..9231cd2e03f6 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java @@ -0,0 +1,25 @@ +public class RearrangementTest19 { + + RearrangementTest19(int x, int y) { + } + + RearrangementTest19(int oneParam) { + } + + RearrangementTest19() { + } + + void overloadedMethod1(int x, int y, int z) { + } + + void overloadedMethod1(int x, int y) { + overloadedMethod1(x, y, 0); + } + + void overloadedMethod1(int x) { + overloadedMethod1(x, 0, 0); + } + + void unoverloadedMethod() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult1A.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult1A.java new file mode 100644 index 000000000000..66788594ffdd --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult1A.java @@ -0,0 +1,58 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + void anotherMethod(int j) { + // anotherMethod body + } + + /** field 1. */ + private int field1; + private int field2; + public static final int field3 = 3; + public static final int field4 = 4; + final int field5 = 5; + protected int field6 = 6; + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult2.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult2.java new file mode 100644 index 000000000000..186f0581ef94 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult2.java @@ -0,0 +1,57 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + public static final int field3 = 3; + public static final int field4 = 4; + /** field 1. */ + private int field1; + private int field2; + final int field5 = 5; + protected int field6 = 6; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java new file mode 100644 index 000000000000..cb18ad6e24db --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java @@ -0,0 +1,18 @@ +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class RearrangementTest20 { + + public static void Father(final Object event) { + JCheckBox box = new JCheckBox("text"); + box.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + ChildA(e); + } + }; + } + + private static void ChildA(final Object event) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult21.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult21.java new file mode 100644 index 000000000000..5d70f209a297 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult21.java @@ -0,0 +1,3 @@ +public class RearrangementTest21 { + int v, u; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java new file mode 100644 index 000000000000..d7c2e1347fbd --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java @@ -0,0 +1,11 @@ +public class RearrangementTest22 { + public int getMyValue() { + return 0; + } + + public void setMyValue(int x) { + // does nothing + } + + int i; +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23BNNANXME.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23BNNANXME.java new file mode 100644 index 000000000000..4e7bf76cd622 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23BNNANXME.java @@ -0,0 +1,39 @@ +public class RearrangementTest23 + implements IFace2, IFace1 +{ + public int getY() { + return 6; + } + + public int getX() { + return getA() ? 5 : 3; + } + + int method1() { + return 4; + } + + public boolean getB() { + return false; + } + + public boolean getA() { + return true; + } + + int method2() { + return 7; + } +} + +interface IFace2 { + public boolean getA(); + + public boolean getB(); +} + +interface IFace1 { + public int getY(); + + public int getX(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNIANXME.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNIANXME.java new file mode 100644 index 000000000000..73e08795186f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNIANXME.java @@ -0,0 +1,42 @@ +public class RearrangementTest23 + implements IFace2, IFace1 +{ + /** * Interface IFace1 Header *** */ + public int getY() { + return 6; + } + + public int getX() { + return getA() ? 5 : 3; + } +/**** Interface IFace1 Trailer ***/ + /** * Interface IFace2 Header *** */ + public boolean getB() { + return false; + } + + public boolean getA() { + return true; + } + + /** * Interface IFace2 Trailer ** */ + int method1() { + return 4; + } + + int method2() { + return 7; + } +} + +interface IFace2 { + public boolean getA(); + + public boolean getB(); +} + +interface IFace1 { + public int getY(); + + public int getX(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMA.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMA.java new file mode 100644 index 000000000000..22a6c10e38e7 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMA.java @@ -0,0 +1,42 @@ +public class RearrangementTest23 + implements IFace2, IFace1 +{ + /** * Interface IFace2 Header *** */ + public boolean getA() { + return true; + } + + public boolean getB() { + return false; + } +/**** Interface IFace2 Trailer ***/ + /** * Interface IFace1 Header *** */ + public int getX() { + return getA() ? 5 : 3; + } + + public int getY() { + return 6; + } + + /** * Interface IFace1 Trailer ** */ + int method1() { + return 4; + } + + int method2() { + return 7; + } +} + +interface IFace2 { + public boolean getA(); + + public boolean getB(); +} + +interface IFace1 { + public int getY(); + + public int getX(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXME.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXME.java new file mode 100644 index 000000000000..f903e3e5cc05 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXME.java @@ -0,0 +1,42 @@ +public class RearrangementTest23 + implements IFace2, IFace1 +{ + /** * Interface IFace2 Header *** */ + public boolean getB() { + return false; + } + + public boolean getA() { + return true; + } +/**** Interface IFace2 Trailer ***/ + /** * Interface IFace1 Header *** */ + public int getY() { + return 6; + } + + public int getX() { + return getA() ? 5 : 3; + } + + /** * Interface IFace1 Trailer ** */ + int method1() { + return 4; + } + + int method2() { + return 7; + } +} + +interface IFace2 { + public boolean getA(); + + public boolean getB(); +} + +interface IFace1 { + public int getY(); + + public int getX(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMI.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMI.java new file mode 100644 index 000000000000..8088b74fa28a --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult23NNNANXMI.java @@ -0,0 +1,42 @@ +public class RearrangementTest23 + implements IFace2, IFace1 +{ + /** * Interface IFace2 Header *** */ + public boolean getA() { + return true; + } + + public boolean getB() { + return false; + } +/**** Interface IFace2 Trailer ***/ + /** * Interface IFace1 Header *** */ + public int getY() { + return 6; + } + + public int getX() { + return getA() ? 5 : 3; + } + + /** * Interface IFace1 Trailer ** */ + int method1() { + return 4; + } + + int method2() { + return 7; + } +} + +interface IFace2 { + public boolean getA(); + + public boolean getB(); +} + +interface IFace1 { + public int getY(); + + public int getX(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult25.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult25.java new file mode 100644 index 000000000000..900ae758c11e --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult25.java @@ -0,0 +1,24 @@ +public class RearrangementTest25 { + // ... + + private double getHorizontalstrecke() { + // ... + Double meanValue = new Double(4.0f); + if (meanValue != null) { + return meanValue.getValue(); + } + // ... + return 0.0f; + } + + private double getRichtungErrorLimit(double sr, double sz, double s) { + if (s == 0f) { // (!G2Null.isValid(s)) { + return sr; + } + return Math.sqrt(QMath.square(sr) + QMath.square(sz / s)); + } + + private void checkDoubleMessung(double messung) { + + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult26.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult26.java new file mode 100644 index 000000000000..fd22dd84a491 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult26.java @@ -0,0 +1,16 @@ +class RearrangementTest26 { + + public int getValue() { + return value; + } + + public void setValue(int i) { + value = i; + } + + int value; + + { + value = 2; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult27.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult27.java new file mode 100644 index 000000000000..2eaffda7d564 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult27.java @@ -0,0 +1,45 @@ +public class RearrangerTest27 { + private boolean constructorMethodType; + private boolean getterSetterMethodType; + private int i; + + public MethodAttributes() { + init(); + } + + private void init() { + i = 1; + } + + public MethodAttributes(int i) { + init(); + this.i = i; + } + + private boolean isConstructorMethodType() { + return constructorMethodType; + } + + public final void setConstructorMethodType(final boolean constructorMethodType) { + this.constructorMethodType = constructorMethodType; + } + + private boolean isGetterSetterMethodType() { + return getterSetterMethodType; + } + + public final void setGetterSetterMethodType(final boolean getterSetterMethodType) { + this.getterSetterMethodType = getterSetterMethodType; + } + + private Object getMethodTypePanel() { + return getMethodTypeInnerPanel(); + } + + private JPanel getMethodTypeInnerPanel() { + setConstructorMethodType(true); + setGetterSetterMethodType(false); + return new Object(); + } +} + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult28.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult28.java new file mode 100644 index 000000000000..f7382377292c --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult28.java @@ -0,0 +1,50 @@ +public class RearrangementTest28 + implements InterfaceName, InterfaceName2 +{ + // start of fields + int i; + + // end of fields +// start of interface InterfaceName +// Level 1 methods + public int getTime() { + return getAnother(); + } + + // Level 2 methods + public int getAnother() { + return 0; + } + + // end Level 2 methods +// end Level 1 methods +// end of interface InterfaceName +// start of interface InterfaceName2 + public int getDate() { + return 0; + } + + // end of interface InterfaceName2 +// Level 1 methods + public void m1() { + m2(); + m3(); + } + + // Level 2 methods + public void m2() { + } + + public void m3() { + } +// end Level 2 methods +// end Level 1 methods +} + +interface InterfaceName { + public int getTime(); +} + +interface InterfaceName2 { + public int getDate(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult3.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult3.java new file mode 100644 index 000000000000..3da9daf9be25 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult3.java @@ -0,0 +1,57 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + /** field 1. */ + private int field1; + private int field2; + final int field5 = 5; + protected int field6 = 6; + public static final int field3 = 3; + public static final int field4 = 4; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult30.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult30.java new file mode 100644 index 000000000000..fb4989f57275 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult30.java @@ -0,0 +1,328 @@ +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; + +/** Handles right-click in project view; applies rearrangement to a directory and its files recursively. */ +public final class ProjectTreeActionHandler + extends AnAction +{ + private static final Logger logger = Logger.getLogger("com.wrq.rearranger.ProjectTreeActionHandler"); + + + public final void actionPerformed(final AnActionEvent anActionEvent) { + logger.debug("entered actionPerformed"); + // we're being called on the Swing event dispatch thread. Spin off another thread to do the + // rearranging and let Swing's thread go. +// Thread t = new Thread(new Runnable() { +// public void run() +// { +// //To change body of implemented methods use Options | File Templates. + final Application application = ApplicationManager.getApplication(); + application.runWriteAction(new RearrangeIt(anActionEvent.getDataContext())); +// } +// }, "RearrangerThread"); +// t.start(); +// new RearrangeIt(anActionEvent.getDataContext()).run(); + } + + /** + * Test progress bar functionality. Read 10 "filenames" from console, pausing between each to update the + * progress bar dialog. Handle cancel button and dialog window close button properly. + * + * @param args + */ + public static void main(final String[] args) { + org.apache.log4j.BasicConfigurator.configure(); + // test the progress bar. + final BufferedReader reader; + final ProjectTreeActionHandler ptah = new ProjectTreeActionHandler(); + final RearrangeIt ri = ptah.new RearrangeIt(null); + final RearrangeIt.IntHolder cancelled = ri.new IntHolder(); + + reader = new BufferedReader(new InputStreamReader(System.in)); + final Cancellable c = new Cancellable() { + public void setCancel() { + System.out.println("cancel test"); + cancelled.n = 1; + } + }; + + final JDialog dialog = ri.getProgressFrame(c, 10); + int count = 0; + dialog.pack(); + dialog.setVisible(true); + while (count <= 10 && cancelled.n == 0) { + String s = null; + try { + s = reader.readLine(); + } + catch (IOException e) { + e.printStackTrace(); + } + if (cancelled.n == 0) { + ri.filename.setText(s); + count++; + ri.bar.setValue(count); + } + } + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + System.exit(0); + } + + interface Cancellable { + void setCancel(); + } + + abstract class VirtualFileVisitor implements Cancellable { + volatile boolean cancel = false; + + public final void setCancel() { + logger.debug("VirtualFileVisitor.setCancel called"); + cancel = true; + } + + abstract void visitVirtualFile(VirtualFile f); + + final void accept(final VirtualFile f) { + if (f != null) { + visitVirtualFile(f); + } + final VirtualFile[] vfa = f.getChildren(); + if (vfa != null) { + for (int i = 0; i < vfa.length; i++) { + if (!cancel) { + accept(vfa[i]); + } + } + } + } + } + + final class RearrangeIt implements Runnable { + final class IntHolder { + public int n; + } + + final DataContext dc; + final Project project; + final JProgressBar bar = new JProgressBar(JProgressBar.HORIZONTAL); + final JLabel filename = new JLabel(); + + public RearrangeIt(final DataContext dc) { + this.dc = dc; + this.project = (Project)dc.getData(DataConstants.PROJECT); + } + + public final void run() { + final VirtualFile virtualFile = (VirtualFile)dc.getData(DataConstants.VIRTUAL_FILE); + final IntHolder count = new IntHolder(); + final VirtualFileVisitor counter = new VirtualFileVisitor() { + void visitVirtualFile(final VirtualFile f) { + if (!f.isDirectory()) count.n++; + } + }; + + counter.accept(virtualFile); + logger.debug("counted " + count.n + " files"); + + final RearrangerActionHandler rah = new RearrangerActionHandler(); + final PsiDocumentManager dm = PsiDocumentManager.getInstance(project); + final PsiManager pm = PsiManager.getInstance(project); + final VirtualFileVisitor executor = new VirtualFileVisitor() { + int currentCount = 0; + + void visitVirtualFile(final VirtualFile f) { + try { + final PsiFile psiFile = pm.findFile(f); + if (psiFile != null && psiFile.canContainJavaCode()) { + logger.debug("rearrange psiFile=" + psiFile.toString()); + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("event dispatch thread setting filename to " + psiFile.getName()); + filename.setText(psiFile.getName()); + } + else { + logger.debug("invokeAndWait to set filename to " + psiFile.getName()); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("event dispatch thread within invokeAndWait setting filename to " + + psiFile.getName()); + filename.setText(psiFile.getName()); + } + }); + } + filename.repaint(); +// filename.setText(psiFile.getName()); +// filename.paint(filename.getGraphics()); + filename.paintImmediately(filename.getVisibleRect()); + Thread.sleep(8000); + final Document document = dm.getDocument(psiFile); + if (document == null) { + logger.debug("document was null"); + } + else { +// Thread t = new Thread(new Runnable() { +// public void run() +// { + //To change body of implemented methods use Options | File Templates. + rah.runWriteActionRearrangement(project, document, psiFile); +// } +// } ); +// t.start(); + } + logger.debug("done rearranging psiFile=" + psiFile.toString()); + } + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("EventDispatchThread updating progress bar value to " + currentCount); + bar.setValue(currentCount); + } + else { + logger.debug("invokeAndWait to set progress bar value to " + currentCount); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("EventDispatchThread within InvokeAndWait setting progress bar value to " + + currentCount); + bar.setValue(currentCount); + } + }); + } + bar.repaint(); + bar.paintImmediately(bar.getVisibleRect()); + bar.paint(bar.getGraphics()); + currentCount++; + Thread.sleep(5000); + } + catch (InterruptedException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + catch (InvocationTargetException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + } + }; + + final JDialog dialog = getProgressFrame(executor, count.n); + + dialog.show(); + dialog.setVisible(true); + dialog.paint(dialog.getGraphics()); + executor.accept(virtualFile); + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + } + + final JDialog getProgressFrame(final Cancellable cancellableObject, final int max) { + final Object parent = WindowManager.getInstance().suggestParentWindow(project); + logger.debug("suggested parent window=" + parent); + final JDialog dialog = parent == null ? + new JDialog() : (parent instanceof JDialog ? + new JDialog((JDialog)parent) : new JDialog((JFrame)parent)); + final Container pane = dialog.getContentPane(); + final JLabel rearrangingLabel = new JLabel("Rearranging files, please wait..."); +// rearrangingLabel.setFont(new Font("dialog", Font.PLAIN, 12)); + final JPanel progressPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.weightx = 1; + constraints.insets = new Insets(15, 15, 0, 0); + progressPanel.add(rearrangingLabel, constraints); + constraints.gridwidth = 1; + constraints.gridy = 1; + bar.setMinimum(0); + bar.setMaximum(max); + bar.setPreferredSize(new Dimension(500, 15)); + bar.setMinimumSize(new Dimension(500, 15)); + bar.setStringPainted(true); + constraints.insets = new Insets(15, 15, 5, 15); + progressPanel.add(bar, constraints); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 1; + constraints.insets = new Insets(9, 0, 5, 15); + final JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + logger.debug("cancel button pressed"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + }); + + progressPanel.add(cancelButton, constraints); + constraints.gridx = 0; + constraints.gridy = 2; + constraints.weighty = 1; + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.insets = new Insets(0, 15, 15, 0); + filename.setSize(500, 15); + filename.setPreferredSize(new Dimension(500, 15)); +// filename.setFont(new Font("dialog", Font.PLAIN, 12)); + progressPanel.add(filename, constraints); + pane.add(progressPanel, BorderLayout.CENTER); + dialog.setTitle("Rearranger"); + dialog.addWindowListener(new WindowListener() { + public void windowClosed(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowActivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowClosing(final WindowEvent e) { + logger.debug("dialog closed, cancel Rearranger"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + + public void windowDeactivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowDeiconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowIconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowOpened(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + }); + + dialog.pack(); + return dialog; + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult31.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult31.java new file mode 100644 index 000000000000..e6caba257bf6 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult31.java @@ -0,0 +1,176 @@ +/** + * Id$ + * + * Rearranger plugin for IntelliJ IDEA. + * + * Source code may be freely copied and reused. Please copy credits, and send any bug fixes to the author. + * + * @author Dave Kriewall, WRQ, Inc. + * January, 2004 + */ +package com.wrq.rearranger; + +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.CaretModel; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.wrq.rearranger.popup.LiveRearrangerPopup; +import com.wrq.rearranger.rearrangement.Mover; +import com.wrq.rearranger.rearrangement.Parser; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.CommentUtil; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import java.awt.*; +import java.util.ArrayList; + +/** Supports manual rearrangement of a file. */ +public final class LiveRearrangerActionHandler extends EditorActionHandler { + // ------------------------------ FIELDS ------------------------------ + private static final Logger logger = Logger.getLogger("com.wrq.rearranger.LiveRearrangerActionHandler"); + + private static boolean inProgress = false; +// -------------------------- STATIC METHODS -------------------------- + + public static CodeStyleManager getCsm() { + return RearrangerActionHandler.getCsm(); + } + +// -------------------------- OTHER METHODS -------------------------- + + public final void execute(final Editor editor, final DataContext context) { + if (editor == null) { + return; + } + final Project project = (Project)context.getData(DataConstants.PROJECT); + logger.debug("project=" + project); + logger.debug("editor=" + editor); + final Document document = editor.getDocument(); + final CaretModel caret = editor.getCaretModel(); + int cursorOffset = caret.getOffset(); + final PsiFile psiFile = getFile(editor, context); + if (!psiFile.getName().endsWith(".java")) { + logger.debug("not a .java file -- skipping " + psiFile.getName()); + return; + } + if (!psiFile.isWritable()) { + logger.debug("not a writable .java file -- skipping " + psiFile.getName()); + return; + } + logger.debug("inProgress=" + inProgress); + if (inProgress) { + return; + } + + setInProgress(true); + buildLiveRearrangerData(project, document, psiFile, cursorOffset); + } + + private static PsiFile getFile(final Editor editor, + final DataContext context) + { + final Project project = (Project)context.getData(DataConstants.PROJECT); + final Document document = editor.getDocument(); + final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + final VirtualFile virtualFile = fileDocumentManager.getFile(document); + final PsiManager psiManager = PsiManager.getInstance(project); + return psiManager.findFile(virtualFile); + } + + public static void setInProgress(boolean inProgress) { + logger.debug("set inProgress=" + inProgress); + LiveRearrangerActionHandler.inProgress = inProgress; + } + + /** + * must be called from within an IDEA read-action thread. + * + * @param project + * @param document + * @param psiFile + */ + void buildLiveRearrangerData(final Project project, + final Document document, + final PsiFile psiFile, + final int cursorOffset) + { + /** + * Per instructions from IntelliJ, we have to commit any changes to the document to the Psi + * tree. + */ + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + documentManager.commitDocument(document); + final RearrangerSettings settings = new RearrangerSettings(); // use default settings with no rules + settings.setAskBeforeRearranging(true); + final Runnable task = new Runnable() { + public void run() { + logger.debug("liveRearrangeDocument task started"); + liveRearrangeDocument(project, psiFile, settings, document, cursorOffset); + } + }; + + Thread t = new Thread(new Runnable() { + public void run() { + logger.debug("started thread " + Thread.currentThread().getName()); + final Application application = ApplicationManager.getApplication(); + application.runReadAction(new Runnable() { + public void run() { + logger.debug("enter application.runReadAction() on thread " + Thread.currentThread().getName()); + task.run(); + logger.debug("exit application.runReadAction() on thread " + Thread.currentThread().getName()); + } + }); + } + }, "Live Rearranger parser"); + t.start(); + logger.debug("exit buildLiveRearrangerData on thread " + Thread.currentThread().getName()); + } + + public final void liveRearrangeDocument(final Project project, + final PsiFile psiFile, + final RearrangerSettings settings, + final Document document, + final int cursorOffset) + { + logger.setLevel(Level.DEBUG); // TODO - remove debugging flag + logger.debug("enter liveRearrangeDocument on thread " + Thread.currentThread().getName()); + + RearrangerActionHandler.setCsm(CodeStyleManager.getInstance(project)); + new CommentUtil(settings); // create CommentUtil singleton + final Window window = WindowManager.getInstance().suggestParentWindow(project); + LiveRearrangerPopup fsp = new LiveRearrangerPopup(settings, psiFile, document, project, window, cursorOffset); + final Parser p = new Parser(project, settings, psiFile); + final ArrayList outerClasses = p.parseOuterLevel(); + if (outerClasses.size() > 0) { + final Mover m = new Mover(outerClasses, settings); + final ArrayList resultRuleInstances = m.rearrangeOuterClasses(); + fsp.setResultRuleInstances(resultRuleInstances); + fsp.liveRearranger(); + } + logger.debug("exit liveRearrangeDocument on thread " + Thread.currentThread().getName()); + } + + public boolean isFileWritable(PsiElement element) { + VirtualFile file = element.getContainingFile().getVirtualFile(); + if (!file.isWritable()) { + VirtualFileManager.getInstance().fireReadOnlyModificationAttempt(new VirtualFile[]{file}); + return file.isWritable(); + } + return true; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult32.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult32.java new file mode 100644 index 000000000000..e569bbfc433f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult32.java @@ -0,0 +1,11 @@ +public class Temp { +// ------------------------------ FIELDS ------------------------------ + + int field1; + +// -------------------------- OTHER METHODS -------------------------- + + public void finish() { + field1 = 2; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult33.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult33.java new file mode 100644 index 000000000000..095358b63d7b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult33.java @@ -0,0 +1,7 @@ +public class RearrangementTest33 { + double price; + + public final void setPrice(final double price) { + this.price = price; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34.java new file mode 100644 index 000000000000..1f0429571f4f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34.java @@ -0,0 +1,15 @@ +// ----- OUTER CLASS ----- + +public class RearrangementTest34 { +// ------------------------------ FIELDS ------------------------------ + + int i; + +// -------------------------- INNER CLASSES -------------------------- + + class inner { +// ------------------------------ FIELDS ------------------------------ + + int j; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34B.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34B.java new file mode 100644 index 000000000000..4a7bde488b96 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult34B.java @@ -0,0 +1,13 @@ +// ----- OUTER CLASS ----- + +public class RearrangementTest34 { +// ------------------------------ FIELDS ------------------------------ + + int i; + +// -------------------------- INNER CLASSES -------------------------- + + class inner { + int j; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult35.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult35.java new file mode 100644 index 000000000000..4075a6afd401 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult35.java @@ -0,0 +1,7 @@ +public class RearrangementTest35 { +// ----- FIELDS ----- + + int field; + + int field2; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult37.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult37.java new file mode 100644 index 000000000000..aae25d07c8c9 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult37.java @@ -0,0 +1,21 @@ +public class RearrangementTest37 { + String productOther; + + String getProductOther() { + return productOther; + } + + boolean isProductOther() { + return productOther.length() > 0; + } + + boolean setProductOther(String s) { + productOther = s; + } + + method interim1() { + } + + method interim2() { + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39.java new file mode 100644 index 000000000000..528f4584ce0b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39.java @@ -0,0 +1,8 @@ +public class RearrangementTest39 { + boolean b0; + boolean b1; + int i2; + String s0; + String s1; + String s2; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39A.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39A.java new file mode 100644 index 000000000000..3ad3bcb20be7 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39A.java @@ -0,0 +1,8 @@ +public class RearrangementTest39 { + boolean b1; + boolean b0; + int i2; + String s1; + String s2; + String s0; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39B.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39B.java new file mode 100644 index 000000000000..b4b41f419928 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39B.java @@ -0,0 +1,8 @@ +public class RearrangementTest39 { + String s0; + String s1; + String s2; + boolean b0; + boolean b1; + int i2; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39C.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39C.java new file mode 100644 index 000000000000..b9b6e21f67df --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult39C.java @@ -0,0 +1,8 @@ +public class RearrangementTest39 { + String s1; + String s2; + String s0; + boolean b1; + boolean b0; + int i2; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult4.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult4.java new file mode 100644 index 000000000000..12b241aa0be4 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult4.java @@ -0,0 +1,58 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + + NoRearrangementTest() { + // constructor body + } + + /** field 1. */ + private int field1; + private int field2; + public static final int field3 = 3; + public static final int field4 = 4; + final int field5 = 5; + protected int field6 = 6; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult40.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult40.java new file mode 100644 index 000000000000..77d8f4f703d4 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult40.java @@ -0,0 +1,31 @@ +abstract public class TestOverImpl40 + implements Runnable +{ + public String toString() { + // overrides Object.toString() + return super.toString(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void run() { + // implements Runnable.run() + } + + abstract void abstractMethod(); // is implemented + + void overrideableMethod() // is overridden + { + // do nothing + } +} + +class TestOverImpl2 extends TestOverImpl { + void abstractMethod() // implements + { + // implements abstractMethod() + } + + void overrideableMethod() // overrides + { + super.overrideableMethod(); //To change body of overridden methods use File | Settings | File Templates. + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult41.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult41.java new file mode 100644 index 000000000000..899c73d58aea --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult41.java @@ -0,0 +1,5 @@ +public class RearrangementTest41 { + public final void setPrice(final double price) { + this.price = price; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult42.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult42.java new file mode 100644 index 000000000000..2ab26d2f02e5 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult42.java @@ -0,0 +1,5 @@ +public class Foo { + enum Bar {a, b, c} + + ; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult43.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult43.java new file mode 100644 index 000000000000..3c9995a3c124 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult43.java @@ -0,0 +1,13 @@ +public class RearrangementTest43 { + void method2(int a, int b) { + } + + void method3(int a, int b, int c) { + } + + void method1(int a) { + } + + void method0() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult44.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult44.java new file mode 100644 index 000000000000..8a24d11d1a0d --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult44.java @@ -0,0 +1,6 @@ +/** test generated comment with fill. */ +public class RearrangementTest44 { + // -+-+-+-+- METHODS -+-+-+-+- + private void method(int i) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult45.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult45.java new file mode 100644 index 000000000000..98727d9842f9 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult45.java @@ -0,0 +1,59 @@ +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +/** + * Class A implements Externalizable and has its own toString, equals and hashcode methods. + * Class B extends A and has its own toString, equals and hashcode methods. + * Ensure that when rearranging class B, its methods show up under 'canonical' -- not "other methods" (bug). + */ +public class NestedOverridesTest + implements Externalizable +{ +// ------------------------ CANONICAL METHODS ------------------------ + + public boolean equals(Object object) { + return super.equals(object); + } + + public int hashCode() { + return super.hashCode(); + } + + public String toString() { + return ""; + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface Externalizable --------------------- + + public void writeExternal(ObjectOutput objectOutput) throws IOException { + } + + public void readExternal(ObjectInput objectInput) throws IOException, ClassNotFoundException { + } +} + +class B extends NestedOverridesTest { +// ------------------------ CANONICAL METHODS ------------------------ + + public int hashCode() { + return super.hashCode(); + } + + public String toString() { + return super.toString(); + } + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface Externalizable --------------------- + + public void writeExternal(ObjectOutput objectOutput) throws IOException { + super.writeExternal(objectOutput); + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46A.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46A.java new file mode 100644 index 000000000000..56889ac57281 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46A.java @@ -0,0 +1,19 @@ +import java.util.List; +import java.util.Vector; + +public class RearrangementTest46 { + protected List validator = new Vector(); + protected Object value; + protected final String dbColumnName; + protected boolean isMandatory; + protected final String table; + protected boolean isInvalid; + protected final int sqlType; + protected String invalidText; + + RearrangementTest46() { + dbColumnName = "column"; + table = "table"; + sqlType = 0; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46B.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46B.java new file mode 100644 index 000000000000..92889eb0d9b7 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46B.java @@ -0,0 +1,19 @@ +import java.util.List; +import java.util.Vector; + +public class RearrangementTest46 { + protected List validator = new Vector(); + protected Object value; + protected boolean isMandatory; + protected boolean isInvalid; + protected String invalidText; + protected final String dbColumnName; + protected final String table; + protected final int sqlType; + + RearrangementTest46() { + dbColumnName = "column"; + table = "table"; + sqlType = 0; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46C.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46C.java new file mode 100644 index 000000000000..ad9441dddf20 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46C.java @@ -0,0 +1,19 @@ +import java.util.List; +import java.util.Vector; + +public class RearrangementTest46 { + protected List validator = new Vector(); + protected Object value; + protected final String dbColumnName; + protected final String table; + protected String invalidText; + protected boolean isMandatory; + protected boolean isInvalid; + protected final int sqlType; + + RearrangementTest46() { + dbColumnName = "column"; + table = "table"; + sqlType = 0; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46D.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46D.java new file mode 100644 index 000000000000..3cb5853fa8b2 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46D.java @@ -0,0 +1,19 @@ +import java.util.List; +import java.util.Vector; + +public class RearrangementTest46 { + protected boolean isMandatory; + protected boolean isInvalid; + protected final int sqlType; + protected List validator = new Vector(); + protected Object value; + protected final String dbColumnName; + protected final String table; + protected String invalidText; + + RearrangementTest46() { + dbColumnName = "column"; + table = "table"; + sqlType = 0; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46E.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46E.java new file mode 100644 index 000000000000..4a1b25780ae1 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult46E.java @@ -0,0 +1,19 @@ +import java.util.List; +import java.util.Vector; + +public class RearrangementTest46 { + protected final int sqlType; + protected final String dbColumnName; + protected final String table; + protected boolean isInvalid; + protected boolean isMandatory; + protected List validator = new Vector(); + protected Object value; + protected String invalidText; + + RearrangementTest46() { + dbColumnName = "column"; + table = "table"; + sqlType = 0; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult47.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult47.java new file mode 100644 index 000000000000..b7e52ca2b1b8 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult47.java @@ -0,0 +1,9 @@ +public class RearrangementTest47 { + public final static int CONSTANT1 = 1; + public final static int CONSTANT2 = 2; + + enum suits {CLUBS, DIAMONDS, HEARTS, SPADES} + + int var2 = 2; + int var3 = 3; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult5.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult5.java new file mode 100644 index 000000000000..a87994b91437 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult5.java @@ -0,0 +1,57 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +class AnotherOuterClass { + +} + +/** public class comments. */ +public class RearrangementTest { + /** field 1. */ + private int field1; + private int field2; + public static final int field3 = 3; + public static final int field4 = 4; + final int field5 = 5; + protected int field6 = 6; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult6.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult6.java new file mode 100644 index 000000000000..84252bc72ceb --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult6.java @@ -0,0 +1,8 @@ +public class Test { + public static final String sillyField = ""; + public static final String sillyField2 = ""; + private String wibble; + protected String wobble; + public String hitandmiss; + public static int hithere; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult7.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult7.java new file mode 100644 index 000000000000..fcf27e010ae8 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult7.java @@ -0,0 +1,14 @@ +import java.util.Comparator; + +public class RearrangementTest7 { + Comparator c = new Comparator() { + public int compare(Object o, Object o1) { + return 0; //To change body of implemented methods use Options | File Templates. + } + + public boolean equals(Object o) { + return false; //To change body of implemented methods use Options | File Templates. + } + }; + int f; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8.java new file mode 100644 index 000000000000..1e8111d0cc4b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8.java @@ -0,0 +1,58 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + final int field5 = 5; + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + /** field 1. */ + private int field1; + private int field2; + public static final int field3 = 3; + public static final int field4 = 4; + protected int field6 = 6; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + final void method3() { + // method 3 body. + } + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8A.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8A.java new file mode 100644 index 000000000000..9979ce1ba98b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult8A.java @@ -0,0 +1,19 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + + static { + // static initializer class. + } + + private int field2; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult9.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult9.java new file mode 100644 index 000000000000..8107c56ad920 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult9.java @@ -0,0 +1,58 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + + void anotherMethod(int j) { + // anotherMethod body + } + + public int getField1() { + return field1; // getter for field1 + } + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + /** field 1. */ + private int field1; + private int field2; + public static final int field3 = 3; + public static final int field4 = 4; + final int field5 = 5; + protected int field6 = 6; + + NoRearrangementTest() { + // constructor body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest.java new file mode 100644 index 000000000000..8882b2f69480 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest.java @@ -0,0 +1,57 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + /** field 1. */ + private int field1; + private int field2; + public static final int field3 = 3; + public static final int field4 = 4; + final int field5 = 5; + protected int field6 = 6; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + /** method 2 comment. */ + public void method2() { + // method 2 body. + } + + final void method3() { + // method 3 body. + } + + NoRearrangementTest() { + // constructor body + } + + public int getField1() { + return field1; // getter for field1 + } + + public int setField1(int f) { + field1 = f; // setter for field1 + } + + void anotherMethod(int j) { + // anotherMethod body + } + + class innerClass { + // inner class definition + } +} + +class AnotherOuterClass { + +} + +/** + * end of file comment. + */ diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest11.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest11.java new file mode 100644 index 000000000000..54df5e39a7d2 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest11.java @@ -0,0 +1,5 @@ +public class RearrangementTest11 { + final int i; + public final int k; + int j; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest12.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest12.java new file mode 100644 index 000000000000..bc950e619355 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest12.java @@ -0,0 +1,20 @@ +class RearrangementTest12 { + int x; + String s; + + void method(int y) { + x = y; + } + + int getX() { + return x; + } + + Object convertX() { + return new Integer(x); + } + + Integer[] convertXs() { + return new Integer[]{new Integer(x), new Integer(0)}; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest13.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest13.java new file mode 100644 index 000000000000..1060fea2f3dd --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest13.java @@ -0,0 +1,28 @@ +public class RearrangerTest13 { + void GF() { // grandfather + F1(); + F2(); + } + + private void F2() { + S2A(); + S2B(); + } + + private void F1() { + S1B(); + S1A(); + } + + void S2B() { + } + + void S1B() { + } + + void S2A() { + } + + void S1A() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest14.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest14.java new file mode 100644 index 000000000000..a4e9e2575e89 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest14.java @@ -0,0 +1,13 @@ +public class RearrangementTest14 { + int doIt(int x) { + return x + 1; + } + + void GF() { + doIt(2, 3); + } + + int doIt(int x, int y) { + return x + y; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest15.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest15.java new file mode 100644 index 000000000000..edf46091b5bd --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest15.java @@ -0,0 +1,15 @@ +// test method inheritance + +public class RearrangementTest15 { + public String toString() { + return "no name"; + } + + public boolean equals(Object o) { + return false; + } + + public void noSuperMethod(boolean b) { + return false; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest16.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest16.java new file mode 100644 index 000000000000..7c021053e037 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest16.java @@ -0,0 +1,18 @@ +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class RearrangementTest16 + implements ActionListener +{ + public void notImplementor(ActionEvent e) { + } + + public void actionPerformed(ActionEvent e) { + } + + public void actionPerformed() { + } + + public void actionPerformed(int i) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest17.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest17.xml new file mode 100644 index 000000000000..e3920d519b7b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest17.xml @@ -0,0 +1,5 @@ + + + Test text. + + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18.java new file mode 100644 index 000000000000..09e6b7105016 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18.java @@ -0,0 +1,34 @@ +public class RearrangementTest18 { + int field1; + char char2; + + RearrangementTest18() { + field1 = 10; + } + + void method1() { + char2 = 'a'; + } + + void setField1(int val) { + field1 = val; + } + + int getField1() { + return field1; + } + + char getChar2() { + return char2; + } + + void method3() { + } + + void setChar2(char val) { + char2 = val; + } + + void method4() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18B.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18B.java new file mode 100644 index 000000000000..3306fea0c49b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest18B.java @@ -0,0 +1,27 @@ +public class MethodEntry { + private boolean isSetter; + + public boolean isGetter() { + return isGetter; + } + + public boolean isIsSetter() { + return isSetter; + } + + public String getCustomizedPrecedingComment() { + if (customizedPrecedingComment == null) { + return ""; + } + return "comment"; + } + + public DefaultMutableTreeNode addToPopupTree() { + if (isSetter()) return null; + return null; + } + + public boolean isSetter() { + return isSetter; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest19.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest19.java new file mode 100644 index 000000000000..eebda377975b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest19.java @@ -0,0 +1,24 @@ +public class RearrangementTest19 { + RearrangementTest19() { + } + + void overloadedMethod1(int x, int y, int z) { + } + + RearrangementTest19(int x, int y) { + } + + void unoverloadedMethod() { + } + + void overloadedMethod1(int x) { + overloadedMethod1(x, 0, 0); + } + + void overloadedMethod1(int x, int y) { + overloadedMethod1(x, y, 0); + } + + RearrangementTest19(int oneParam) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest2.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest2.java new file mode 100644 index 000000000000..c94e9d4546f9 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest2.java @@ -0,0 +1,8 @@ +public class Test { + private String wibble; + protected String wobble; + public static final String sillyField = ""; + public String hitandmiss; + public static int hithere; + public static final String sillyField2 = ""; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest20.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest20.java new file mode 100644 index 000000000000..fc60ba8199b5 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest20.java @@ -0,0 +1,17 @@ +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class RearrangementTest20 { + private static void ChildA(final Object event) { + } + + public static void Father(final Object event) { + JCheckBox box = new JCheckBox("text"); + box.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + ChildA(e); + } + }; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest21.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest21.java new file mode 100644 index 000000000000..5d70f209a297 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest21.java @@ -0,0 +1,3 @@ +public class RearrangementTest21 { + int v, u; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest22.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest22.java new file mode 100644 index 000000000000..681b6b9ba008 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest22.java @@ -0,0 +1,11 @@ +public class RearrangementTest22 { + int i; + + public void setMyValue(int x) { + // does nothing + } + + public int getMyValue() { + return 0; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest23.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest23.java new file mode 100644 index 000000000000..ffce2e34a321 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest23.java @@ -0,0 +1,39 @@ +public class RearrangementTest23 + implements IFace2, IFace1 +{ + int method1() { + return 4; + } + + public boolean getB() { + return false; + } + + public int getY() { + return 6; + } + + public int getX() { + return getA() ? 5 : 3; + } + + public boolean getA() { + return true; + } + + int method2() { + return 7; + } +} + +interface IFace2 { + public boolean getA(); + + public boolean getB(); +} + +interface IFace1 { + public int getY(); + + public int getX(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest24.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest24.java new file mode 100644 index 000000000000..8075cdde140b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest24.java @@ -0,0 +1,137 @@ +/** + * Submitted by Nathan Brown. Causes NPE in Rearranger 1.7. (Modified to compile in test directory.) + */ + + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +/** + * @author Nathan Brown + * @version $Revision: $ $Date: $ + * @todo : doc this Copyright (c) 2001-2004 UReason. All Rights Reserved. + */ +public abstract class TestClass extends JPanel { + private JComponent _component; + private boolean _initialized; + + protected TestClass() { + this(new BorderLayout()); + } + + protected TestClass(java.awt.LayoutManager layoutManager) { + super(layoutManager); + setOpaque(false); + add(getComponent(), BorderLayout.CENTER); + getComponent().addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + componentFocusGained(e); + } + + public void focusLost(FocusEvent e) { + componentFocusLost(e); + } + }); + _initialized = true; + } + + protected void componentFocusGained(FocusEvent e) { + } + + protected void componentFocusLost(FocusEvent e) { + } + + protected JComponent getComponent() { + if (_component == null) { + _component = createComponent(); + } + return _component; + } + + protected abstract JComponent createComponent(); + + public Dimension getPreferredSize() { + return getComponent().getPreferredSize(); + } + + public Dimension getMaximumSize() { + return getComponent().getMaximumSize(); + } + + public Dimension getMinimumSize() { + return getComponent().getMinimumSize(); + } + + public void setPreferredSize(Dimension preferredSize) { + getComponent().setPreferredSize(preferredSize); + } + + public void setMaximumSize(Dimension maximumSize) { + getComponent().setMaximumSize(maximumSize); + } + + public void setMinimumSize(Dimension minimumSize) { + getComponent().setMinimumSize(minimumSize); + } + + public void updateUI() { + // we're purely a container, we don't want any defaults set on us + } + + public synchronized void addFocusListener(FocusListener l) { + getComponent().addFocusListener(l); + } + + public synchronized void removeFocusListener(FocusListener l) { + getComponent().removeFocusListener(l); + } + + public void setBorder(Border border) { + if (_initialized) { + getComponent().setBorder(border); + } + else { + super.setBorder(border); + } + } + + public Border getBorder() { + return getComponent().getBorder(); + } + + public void setToolTipText(String text) { + getComponent().setToolTipText(text); + } + + public Color getBackground() { + return getComponent().getBackground(); + } + + public Color getForeground() { + return getComponent().getForeground(); + } + + public Font getFont() { + return getComponent().getFont(); + } + + public void setForeground(Color fg) { + getComponent().setForeground(fg); + } + + public void setBackground(Color bg) { + getComponent().setBackground(bg); + } + + public void setFont(Font font) { + getComponent().setFont(font); + } + + public void setEnabled(boolean enabled) { + getComponent().setEnabled(enabled); + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest25.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest25.java new file mode 100644 index 000000000000..cdf3e7d06b6a --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest25.java @@ -0,0 +1,25 @@ +public class RearrangementTest25 { + // ... + + private double getHorizontalstrecke() { + // ... + Double meanValue = new Double(4.0f); + if (meanValue != null) { + return meanValue.getValue(); + } + // ... + return 0.0f; + } + + private double getRichtungErrorLimit(double sr, double sz, double s) { + if (s == 0f) { // (!G2Null.isValid(s)) { + + return sr; + } + return Math.sqrt(QMath.square(sr) + QMath.square(sz / s)); + } + + private void checkDoubleMessung(double messung) { + + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest26.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest26.java new file mode 100644 index 000000000000..157e4f143f8d --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest26.java @@ -0,0 +1,15 @@ +class RearrangementTest26 { + int value; + + { + value = 2; + } + + public int getValue() { + return value; + } + + public void setValue(int i) { + value = i; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest27.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest27.java new file mode 100644 index 000000000000..f51c2f9cec12 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest27.java @@ -0,0 +1,45 @@ +public class RearrangerTest27 { + private boolean constructorMethodType; + private boolean getterSetterMethodType; + private int i; + + public MethodAttributes() { + init(); + } + + private void init() { + i = 1; + } + + public final void setConstructorMethodType(final boolean constructorMethodType) { + this.constructorMethodType = constructorMethodType; + } + + public MethodAttributes(int i) { + init(); + this.i = i; + } + + private boolean isConstructorMethodType() { + return constructorMethodType; + } + + private boolean isGetterSetterMethodType() { + return getterSetterMethodType; + } + + private Object getMethodTypePanel() { + return getMethodTypeInnerPanel(); + } + + public final void setGetterSetterMethodType(final boolean getterSetterMethodType) { + this.getterSetterMethodType = getterSetterMethodType; + } + + private JPanel getMethodTypeInnerPanel() { + setConstructorMethodType(true); + setGetterSetterMethodType(false); + return new Object(); + } +} + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest28.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest28.java new file mode 100644 index 000000000000..5b21dabe1daa --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest28.java @@ -0,0 +1,46 @@ +public class RearrangementTest28 + implements InterfaceName, InterfaceName2 +{ + // start of fields + int i; +// end of fields + + // start of interface InterfaceName + public int getTime() { + return getAnother(); + } + + // end of interface InterfaceName +// start of interface InterfaceName2 + public int getDate() { + return 0; + } + + // end of interface InterfaceName2 + public int getAnother() { + return 0; + } + + // Level 1 methods + public void m1() { + m2(); + m3(); + } + + // Level 2 methods + public void m2() { + } + + public void m3() { + } +// end Level 2 methods +// end Level 1 methods +} + +interface InterfaceName { + public int getTime(); +} + +interface InterfaceName2 { + public int getDate(); +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest29.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest29.java new file mode 100644 index 000000000000..1a3c0f0d6a9b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest29.java @@ -0,0 +1,26 @@ +/** + * Id$ + * + * Rearranger plugin for IntelliJ IDEA. + * + * Source code may be freely copied and reused. Please copy credits, and send any bug fixes to the author. + * + * @author Dave Kriewall, WRQ, Inc. + * January, 2004 + */ +package com.wrq.rearranger; + +/** Illustrates rearrangement by the plugin. */ +abstract public class RearrangeMe { + abstract boolean isGood(); // matches rule 12, "abstract methods" + + /** field1 is documented here. This documentation moves with the field. */ + int field1; // matches rule 3, "non-static fields ..." + + protected RearrangeMe(int field1) // Constructor matches rule 6 + { + this.field1 = field1; + } + + public final static int CONSTANT = 1; // matches rule 1, "... static fields" +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest30.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest30.java new file mode 100644 index 000000000000..fb4989f57275 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest30.java @@ -0,0 +1,328 @@ +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; + +/** Handles right-click in project view; applies rearrangement to a directory and its files recursively. */ +public final class ProjectTreeActionHandler + extends AnAction +{ + private static final Logger logger = Logger.getLogger("com.wrq.rearranger.ProjectTreeActionHandler"); + + + public final void actionPerformed(final AnActionEvent anActionEvent) { + logger.debug("entered actionPerformed"); + // we're being called on the Swing event dispatch thread. Spin off another thread to do the + // rearranging and let Swing's thread go. +// Thread t = new Thread(new Runnable() { +// public void run() +// { +// //To change body of implemented methods use Options | File Templates. + final Application application = ApplicationManager.getApplication(); + application.runWriteAction(new RearrangeIt(anActionEvent.getDataContext())); +// } +// }, "RearrangerThread"); +// t.start(); +// new RearrangeIt(anActionEvent.getDataContext()).run(); + } + + /** + * Test progress bar functionality. Read 10 "filenames" from console, pausing between each to update the + * progress bar dialog. Handle cancel button and dialog window close button properly. + * + * @param args + */ + public static void main(final String[] args) { + org.apache.log4j.BasicConfigurator.configure(); + // test the progress bar. + final BufferedReader reader; + final ProjectTreeActionHandler ptah = new ProjectTreeActionHandler(); + final RearrangeIt ri = ptah.new RearrangeIt(null); + final RearrangeIt.IntHolder cancelled = ri.new IntHolder(); + + reader = new BufferedReader(new InputStreamReader(System.in)); + final Cancellable c = new Cancellable() { + public void setCancel() { + System.out.println("cancel test"); + cancelled.n = 1; + } + }; + + final JDialog dialog = ri.getProgressFrame(c, 10); + int count = 0; + dialog.pack(); + dialog.setVisible(true); + while (count <= 10 && cancelled.n == 0) { + String s = null; + try { + s = reader.readLine(); + } + catch (IOException e) { + e.printStackTrace(); + } + if (cancelled.n == 0) { + ri.filename.setText(s); + count++; + ri.bar.setValue(count); + } + } + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + System.exit(0); + } + + interface Cancellable { + void setCancel(); + } + + abstract class VirtualFileVisitor implements Cancellable { + volatile boolean cancel = false; + + public final void setCancel() { + logger.debug("VirtualFileVisitor.setCancel called"); + cancel = true; + } + + abstract void visitVirtualFile(VirtualFile f); + + final void accept(final VirtualFile f) { + if (f != null) { + visitVirtualFile(f); + } + final VirtualFile[] vfa = f.getChildren(); + if (vfa != null) { + for (int i = 0; i < vfa.length; i++) { + if (!cancel) { + accept(vfa[i]); + } + } + } + } + } + + final class RearrangeIt implements Runnable { + final class IntHolder { + public int n; + } + + final DataContext dc; + final Project project; + final JProgressBar bar = new JProgressBar(JProgressBar.HORIZONTAL); + final JLabel filename = new JLabel(); + + public RearrangeIt(final DataContext dc) { + this.dc = dc; + this.project = (Project)dc.getData(DataConstants.PROJECT); + } + + public final void run() { + final VirtualFile virtualFile = (VirtualFile)dc.getData(DataConstants.VIRTUAL_FILE); + final IntHolder count = new IntHolder(); + final VirtualFileVisitor counter = new VirtualFileVisitor() { + void visitVirtualFile(final VirtualFile f) { + if (!f.isDirectory()) count.n++; + } + }; + + counter.accept(virtualFile); + logger.debug("counted " + count.n + " files"); + + final RearrangerActionHandler rah = new RearrangerActionHandler(); + final PsiDocumentManager dm = PsiDocumentManager.getInstance(project); + final PsiManager pm = PsiManager.getInstance(project); + final VirtualFileVisitor executor = new VirtualFileVisitor() { + int currentCount = 0; + + void visitVirtualFile(final VirtualFile f) { + try { + final PsiFile psiFile = pm.findFile(f); + if (psiFile != null && psiFile.canContainJavaCode()) { + logger.debug("rearrange psiFile=" + psiFile.toString()); + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("event dispatch thread setting filename to " + psiFile.getName()); + filename.setText(psiFile.getName()); + } + else { + logger.debug("invokeAndWait to set filename to " + psiFile.getName()); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("event dispatch thread within invokeAndWait setting filename to " + + psiFile.getName()); + filename.setText(psiFile.getName()); + } + }); + } + filename.repaint(); +// filename.setText(psiFile.getName()); +// filename.paint(filename.getGraphics()); + filename.paintImmediately(filename.getVisibleRect()); + Thread.sleep(8000); + final Document document = dm.getDocument(psiFile); + if (document == null) { + logger.debug("document was null"); + } + else { +// Thread t = new Thread(new Runnable() { +// public void run() +// { + //To change body of implemented methods use Options | File Templates. + rah.runWriteActionRearrangement(project, document, psiFile); +// } +// } ); +// t.start(); + } + logger.debug("done rearranging psiFile=" + psiFile.toString()); + } + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("EventDispatchThread updating progress bar value to " + currentCount); + bar.setValue(currentCount); + } + else { + logger.debug("invokeAndWait to set progress bar value to " + currentCount); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("EventDispatchThread within InvokeAndWait setting progress bar value to " + + currentCount); + bar.setValue(currentCount); + } + }); + } + bar.repaint(); + bar.paintImmediately(bar.getVisibleRect()); + bar.paint(bar.getGraphics()); + currentCount++; + Thread.sleep(5000); + } + catch (InterruptedException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + catch (InvocationTargetException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + } + }; + + final JDialog dialog = getProgressFrame(executor, count.n); + + dialog.show(); + dialog.setVisible(true); + dialog.paint(dialog.getGraphics()); + executor.accept(virtualFile); + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + } + + final JDialog getProgressFrame(final Cancellable cancellableObject, final int max) { + final Object parent = WindowManager.getInstance().suggestParentWindow(project); + logger.debug("suggested parent window=" + parent); + final JDialog dialog = parent == null ? + new JDialog() : (parent instanceof JDialog ? + new JDialog((JDialog)parent) : new JDialog((JFrame)parent)); + final Container pane = dialog.getContentPane(); + final JLabel rearrangingLabel = new JLabel("Rearranging files, please wait..."); +// rearrangingLabel.setFont(new Font("dialog", Font.PLAIN, 12)); + final JPanel progressPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.weightx = 1; + constraints.insets = new Insets(15, 15, 0, 0); + progressPanel.add(rearrangingLabel, constraints); + constraints.gridwidth = 1; + constraints.gridy = 1; + bar.setMinimum(0); + bar.setMaximum(max); + bar.setPreferredSize(new Dimension(500, 15)); + bar.setMinimumSize(new Dimension(500, 15)); + bar.setStringPainted(true); + constraints.insets = new Insets(15, 15, 5, 15); + progressPanel.add(bar, constraints); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 1; + constraints.insets = new Insets(9, 0, 5, 15); + final JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + logger.debug("cancel button pressed"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + }); + + progressPanel.add(cancelButton, constraints); + constraints.gridx = 0; + constraints.gridy = 2; + constraints.weighty = 1; + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.insets = new Insets(0, 15, 15, 0); + filename.setSize(500, 15); + filename.setPreferredSize(new Dimension(500, 15)); +// filename.setFont(new Font("dialog", Font.PLAIN, 12)); + progressPanel.add(filename, constraints); + pane.add(progressPanel, BorderLayout.CENTER); + dialog.setTitle("Rearranger"); + dialog.addWindowListener(new WindowListener() { + public void windowClosed(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowActivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowClosing(final WindowEvent e) { + logger.debug("dialog closed, cancel Rearranger"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + + public void windowDeactivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowDeiconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowIconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowOpened(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + }); + + dialog.pack(); + return dialog; + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest31.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest31.java new file mode 100644 index 000000000000..577103c681d7 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest31.java @@ -0,0 +1,175 @@ +/** + * Id$ + * + * Rearranger plugin for IntelliJ IDEA. + * + * Source code may be freely copied and reused. Please copy credits, and send any bug fixes to the author. + * + * @author Dave Kriewall, WRQ, Inc. + * January, 2004 + */ +package com.wrq.rearranger; + +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.CaretModel; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.wrq.rearranger.popup.LiveRearrangerPopup; +import com.wrq.rearranger.rearrangement.Mover; +import com.wrq.rearranger.rearrangement.Parser; +import com.wrq.rearranger.settings.RearrangerSettings; +import com.wrq.rearranger.util.CommentUtil; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import java.awt.*; +import java.util.ArrayList; + +/** Supports manual rearrangement of a file. */ +public final class LiveRearrangerActionHandler extends EditorActionHandler { + // ------------------------------ FIELDS ------------------------------ + private static final Logger logger = Logger.getLogger("com.wrq.rearranger.LiveRearrangerActionHandler"); + + private static boolean inProgress = false; +// -------------------------- STATIC METHODS -------------------------- + + public static CodeStyleManager getCsm() { + return RearrangerActionHandler.getCsm(); + } +// -------------------------- OTHER METHODS -------------------------- + + public final void execute(final Editor editor, final DataContext context) { + if (editor == null) { + return; + } + final Project project = (Project)context.getData(DataConstants.PROJECT); + logger.debug("project=" + project); + logger.debug("editor=" + editor); + final Document document = editor.getDocument(); + final CaretModel caret = editor.getCaretModel(); + int cursorOffset = caret.getOffset(); + final PsiFile psiFile = getFile(editor, context); + if (!psiFile.getName().endsWith(".java")) { + logger.debug("not a .java file -- skipping " + psiFile.getName()); + return; + } + if (!psiFile.isWritable()) { + logger.debug("not a writable .java file -- skipping " + psiFile.getName()); + return; + } + logger.debug("inProgress=" + inProgress); + if (inProgress) { + return; + } + + setInProgress(true); + buildLiveRearrangerData(project, document, psiFile, cursorOffset); + } + + private static PsiFile getFile(final Editor editor, + final DataContext context) + { + final Project project = (Project)context.getData(DataConstants.PROJECT); + final Document document = editor.getDocument(); + final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + final VirtualFile virtualFile = fileDocumentManager.getFile(document); + final PsiManager psiManager = PsiManager.getInstance(project); + return psiManager.findFile(virtualFile); + } + + public static void setInProgress(boolean inProgress) { + logger.debug("set inProgress=" + inProgress); + LiveRearrangerActionHandler.inProgress = inProgress; + } + + /** + * must be called from within an IDEA read-action thread. + * + * @param project + * @param document + * @param psiFile + */ + void buildLiveRearrangerData(final Project project, + final Document document, + final PsiFile psiFile, + final int cursorOffset) + { + /** + * Per instructions from IntelliJ, we have to commit any changes to the document to the Psi + * tree. + */ + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + documentManager.commitDocument(document); + final RearrangerSettings settings = new RearrangerSettings(); // use default settings with no rules + settings.setAskBeforeRearranging(true); + final Runnable task = new Runnable() { + public void run() { + logger.debug("liveRearrangeDocument task started"); + liveRearrangeDocument(project, psiFile, settings, document, cursorOffset); + } + }; + + Thread t = new Thread(new Runnable() { + public void run() { + logger.debug("started thread " + Thread.currentThread().getName()); + final Application application = ApplicationManager.getApplication(); + application.runReadAction(new Runnable() { + public void run() { + logger.debug("enter application.runReadAction() on thread " + Thread.currentThread().getName()); + task.run(); + logger.debug("exit application.runReadAction() on thread " + Thread.currentThread().getName()); + } + }); + } + }, "Live Rearranger parser"); + t.start(); + logger.debug("exit buildLiveRearrangerData on thread " + Thread.currentThread().getName()); + } + + public final void liveRearrangeDocument(final Project project, + final PsiFile psiFile, + final RearrangerSettings settings, + final Document document, + final int cursorOffset) + { + logger.setLevel(Level.DEBUG); // TODO - remove debugging flag + logger.debug("enter liveRearrangeDocument on thread " + Thread.currentThread().getName()); + + RearrangerActionHandler.setCsm(CodeStyleManager.getInstance(project)); + new CommentUtil(settings); // create CommentUtil singleton + final Window window = WindowManager.getInstance().suggestParentWindow(project); + LiveRearrangerPopup fsp = new LiveRearrangerPopup(settings, psiFile, document, project, window, cursorOffset); + final Parser p = new Parser(project, settings, psiFile); + final ArrayList outerClasses = p.parseOuterLevel(); + if (outerClasses.size() > 0) { + final Mover m = new Mover(outerClasses, settings); + final ArrayList resultRuleInstances = m.rearrangeOuterClasses(); + fsp.setResultRuleInstances(resultRuleInstances); + fsp.liveRearranger(); + } + logger.debug("exit liveRearrangeDocument on thread " + Thread.currentThread().getName()); + } + + public boolean isFileWritable(PsiElement element) { + VirtualFile file = element.getContainingFile().getVirtualFile(); + if (!file.isWritable()) { + VirtualFileManager.getInstance().fireReadOnlyModificationAttempt(new VirtualFile[]{file}); + return file.isWritable(); + } + return true; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest32.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest32.java new file mode 100644 index 000000000000..58d1b54e6d63 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest32.java @@ -0,0 +1,10 @@ +public class Temp { + // ------------------------------ FIELDS ------------------------------ + int field1; + +// -------------------------- OTHER METHODS -------------------------- + + public void finish() { + field1 = 2; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest33.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest33.java new file mode 100644 index 000000000000..33bdc3d43b0a --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest33.java @@ -0,0 +1,9 @@ +public class RearrangementTest33 { + double price; + + public final void setPrice(final double price) + + { + this.price = price; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest34.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest34.java new file mode 100644 index 000000000000..e744780bee40 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest34.java @@ -0,0 +1,10 @@ +// ----- OUTER CLASS ----- + +public class RearrangementTest34 { + int i; + + // -------------------------- INNER CLASSES -------------------------- + class inner { + int j; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest35.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest35.java new file mode 100644 index 000000000000..3bccd71e49d1 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest35.java @@ -0,0 +1,7 @@ +public class RearrangementTest35 { + + + int field; + + int field2; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest36.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest36.java new file mode 100644 index 000000000000..ec9fb7c8d6ca --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest36.java @@ -0,0 +1,48 @@ +public class RearrangementTest36 { + void getRelatedMethodsPane() { + getRelatedMethodsArrangementPane(); + getRelatedMethodsCommentsPane(); + } + + private void getRelatedMethodsArrangementPane() { + getTraversalOrderPanel(); + getOrderingPanel(); + getExtractedPanel(); + getMoveMethodsPanel(); + } + + void getTraversalOrderPanel() { + } + + void getOrderingPanel() { + } + + void getExtractedPanel() { + } + + void getMoveMethodsPanel() { + enableComponents(); + enableOtherComponents(); + } + + private void enableComponents() { + } + + private void enableOtherComponents() { + enablePanel(); + } + + private void enablePanel() { + } + + private void getRelatedMethodsCommentsPane() { + getCommentAreaPanel(); + } + + private void getCommentAreaPanel(final CommentRule comment) { + } + + public static void main(final String[] args) { + new RearrangementTest36().getRelatedMethodsPane(); + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest37.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest37.java new file mode 100644 index 000000000000..1eecd4ba1e45 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest37.java @@ -0,0 +1,21 @@ +public class RearrangementTest37 { + String productOther; + + String getProductOther() { + return productOther; + } + + method interim1() { + } + + boolean isProductOther() { + return productOther.length() > 0; + } + + method interim2() { + } + + boolean setProductOther(String s) { + productOther = s; + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38.java new file mode 100644 index 000000000000..39765534b53e --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38.java @@ -0,0 +1,19 @@ +public class RearrangementTest38 { + + ////////////////////////////////////////////// + // Instance Methods + ////////////////////////////////////////////// + public void createData() throws Exception { + method1(); + + method2(); + } + + + private void method1() { + } + + + private void method2() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38cfg.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38cfg.xml new file mode 100644 index 000000000000..d900d4239981 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest38cfg.xml @@ -0,0 +1,274 @@ + + + + \n\ + \ //////////////////////////////////////////////\n\ \ //\ Static\ Vars\n\ \ ////////////////////////////////////////////// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\ + \ //////////////////////////////////////////////\n\ \ //\ Instance\ Vars\n\ \ ////////////////////////////////////////////// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\ \ + //////////////////////////////////////////////\n\ \ //\ CTORS\n\ \ ////////////////////////////////////////////// + + + + + + + + + + + + + + + + + \n\ \ + //////////////////////////////////////////////\n\ \ //\ Getters/Setters\n\ \ ////////////////////////////////////////////// + + + + + + + + + + + + + + + + + \n\ + \ //////////////////////////////////////////////\n\ \ //\ Static\ Methods\n\ \ ////////////////////////////////////////////// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\ + \ //////////////////////////////////////////////\n\ \ //\ Instance\ Methods\n\ \ ////////////////////////////////////////////// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n\ \ + ////////////////////////////////////////////\n\ \ //\ EJB\ methods\n\ \ //////////////////////////////////////////// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39.java new file mode 100644 index 000000000000..f460e7c60dd8 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39.java @@ -0,0 +1,8 @@ +public class RearrangementTest39 { + String s1; + boolean b1; + int i2; + boolean b0; + String s2; + String s0; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39A.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39A.java new file mode 100644 index 000000000000..3ad3bcb20be7 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest39A.java @@ -0,0 +1,8 @@ +public class RearrangementTest39 { + boolean b1; + boolean b0; + int i2; + String s1; + String s2; + String s0; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest40.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest40.java new file mode 100644 index 000000000000..77d8f4f703d4 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest40.java @@ -0,0 +1,31 @@ +abstract public class TestOverImpl40 + implements Runnable +{ + public String toString() { + // overrides Object.toString() + return super.toString(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void run() { + // implements Runnable.run() + } + + abstract void abstractMethod(); // is implemented + + void overrideableMethod() // is overridden + { + // do nothing + } +} + +class TestOverImpl2 extends TestOverImpl { + void abstractMethod() // implements + { + // implements abstractMethod() + } + + void overrideableMethod() // overrides + { + super.overrideableMethod(); //To change body of overridden methods use File | Settings | File Templates. + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest41.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest41.java new file mode 100644 index 000000000000..f8fdbe7b7526 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest41.java @@ -0,0 +1,7 @@ +public class RearrangementTest41 { + public final void setPrice(final double price) + + { + this.price = price; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest42.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest42.java new file mode 100644 index 000000000000..2ab26d2f02e5 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest42.java @@ -0,0 +1,5 @@ +public class Foo { + enum Bar {a, b, c} + + ; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest43.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest43.java new file mode 100644 index 000000000000..f474f9d263a2 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest43.java @@ -0,0 +1,13 @@ +public class RearrangementTest43 { + void method0() { + } + + void method1(int a) { + } + + void method2(int a, int b) { + } + + void method3(int a, int b, int c) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest44.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest44.java new file mode 100644 index 000000000000..bd8281b7d800 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest44.java @@ -0,0 +1,5 @@ +/** test generated comment with fill. */ +public class RearrangementTest44 { + private void method(int i) { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest45.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest45.java new file mode 100644 index 000000000000..0bcaf4e06bd7 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest45.java @@ -0,0 +1,45 @@ +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +/** + * Class A implements Externalizable and has its own toString, equals and hashcode methods. + * Class B extends A and has its own toString, equals and hashcode methods. + * Ensure that when rearranging class B, its methods show up under 'canonical' -- not "other methods" (bug). + */ +public class NestedOverridesTest + implements Externalizable +{ + public int hashCode() { + return super.hashCode(); + } + + public void writeExternal(ObjectOutput objectOutput) throws IOException { + } + + public boolean equals(Object object) { + return super.equals(object); + } + + public void readExternal(ObjectInput objectInput) throws IOException, ClassNotFoundException { + } + + public String toString() { + return ""; + } +} + +class B extends NestedOverridesTest { + public String toString() { + return super.toString(); + } + + public void writeExternal(ObjectOutput objectOutput) throws IOException { + super.writeExternal(objectOutput); + } + + public int hashCode() { + return super.hashCode(); + } +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest46.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest46.java new file mode 100644 index 000000000000..56889ac57281 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest46.java @@ -0,0 +1,19 @@ +import java.util.List; +import java.util.Vector; + +public class RearrangementTest46 { + protected List validator = new Vector(); + protected Object value; + protected final String dbColumnName; + protected boolean isMandatory; + protected final String table; + protected boolean isInvalid; + protected final int sqlType; + protected String invalidText; + + RearrangementTest46() { + dbColumnName = "column"; + table = "table"; + sqlType = 0; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest47.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest47.java new file mode 100644 index 000000000000..e749e4a2f454 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest47.java @@ -0,0 +1,9 @@ +public class RearrangementTest47 { + public final static int CONSTANT1 = 1; + int var2 = 2; + + enum suits {CLUBS, DIAMONDS, HEARTS, SPADES} + + int var3 = 3; + public final static int CONSTANT2 = 2; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest7.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest7.java new file mode 100644 index 000000000000..7993e4a8c4f5 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest7.java @@ -0,0 +1,14 @@ +import java.util.Comparator; + +public class RearrangementTest7 { + int f; + Comparator c = new Comparator() { + public int compare(Object o, Object o1) { + return 0; //To change body of implemented methods use Options | File Templates. + } + + public boolean equals(Object o) { + return false; //To change body of implemented methods use Options | File Templates. + } + }; +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest8.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest8.java new file mode 100644 index 000000000000..37802e109f93 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementTest8.java @@ -0,0 +1,19 @@ +/** + * leading comments. + */ +package com.wrq.rearranger; + +/** public class comments. */ +public class RearrangementTest { + + private int field2; + + /** method 1 comment. */ + void method1() { + // method 1 body. + } + + static { + // static initializer class. + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult1.java new file mode 100644 index 000000000000..2a93e8f6a92b --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult1.java @@ -0,0 +1,13 @@ +/** class comment */ +public class SpaceTest1 { + /** first field. */ + int firstField; + + /** method */ + void method1() { + int i = 3; + if (i < 3) { + i = 5; + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult2.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult2.java new file mode 100644 index 000000000000..f3a09fc1ab33 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult2.java @@ -0,0 +1,20 @@ +/** class comment */ +public class SpaceTest1 { + + + /** first field. */ + int firstField; + + /** method */ + void method1() { + + + int i = 3; + if (i < 3) { + i = 5; + } + } + + void method2() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult3.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult3.java new file mode 100644 index 000000000000..adbeb6f7725f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult3.java @@ -0,0 +1,18 @@ +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class SpaceTest3 { + void method() { + final JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + int i = 0; // logger.debug("cancel button pressed"); + String s = "cancelling"; // filename.setText("cancelling..."); + // cancellableObject.setCancel(); + } + }); + JPanel progressPanel = new JPanel(); + progressPanel.add(cancelButton); + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult4.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult4.java new file mode 100644 index 000000000000..6e21c3e5e254 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult4.java @@ -0,0 +1,335 @@ +/** + * Id$ + * + * Rearranger plugin for IntelliJ IDEA. + * + * Source code may be freely copied and reused. Please copy credits, and send any bug fixes to the author. + * + * @author Dave Kriewall, WRQ, Inc. + * October, 2003 + */ +package com.wrq.rearranger; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; + +/** Handles right-click in project view; applies rearrangement to a directory and its files recursively. */ +public final class ProjectTreeActionHandler + extends AnAction +{ + private static final Logger logger = Logger.getLogger("com.wrq.rearranger.ProjectTreeActionHandler"); + + + public final void actionPerformed(final AnActionEvent anActionEvent) { + logger.debug("entered actionPerformed"); + // we're being called on the Swing event dispatch thread. Spin off another thread to do the + // rearranging and let Swing's thread go. +// Thread t = new Thread(new Runnable() { +// public void run() +// { +// //To change body of implemented methods use Options | File Templates. + final Application application = ApplicationManager.getApplication(); + application.runWriteAction(new RearrangeIt(anActionEvent.getDataContext())); +// } +// }, "RearrangerThread"); +// t.start(); +// new RearrangeIt(anActionEvent.getDataContext()).run(); + } + + /** + * Test progress bar functionality. Read 10 "filenames" from console, pausing between each to update the + * progress bar dialog. Handle cancel button and dialog window close button properly. + * + * @param args + */ + public static void main(final String[] args) { + org.apache.log4j.BasicConfigurator.configure(); + // test the progress bar. + final BufferedReader reader; + final ProjectTreeActionHandler ptah = new ProjectTreeActionHandler(); + final RearrangeIt ri = ptah.new RearrangeIt(null); + final RearrangeIt.IntHolder cancelled = ri.new IntHolder(); + + reader = new BufferedReader(new InputStreamReader(System.in)); + final Cancellable c = new Cancellable() { + public void setCancel() { + System.out.println("cancel test"); + cancelled.n = 1; + } + }; + final JDialog dialog = ri.getProgressFrame(c, 10); + int count = 0; + dialog.pack(); + dialog.setVisible(true); + while (count <= 10 && cancelled.n == 0) { + String s = null; + try { + s = reader.readLine(); + } + catch (IOException e) { + e.printStackTrace(); + } + if (cancelled.n == 0) { + ri.filename.setText(s); + count++; + ri.bar.setValue(count); + } + } + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + System.exit(0); + } + + interface Cancellable { + void setCancel(); + } + + abstract class VirtualFileVisitor implements Cancellable { + volatile boolean cancel = false; + + public final void setCancel() { + logger.debug("VirtualFileVisitor.setCancel called"); + cancel = true; + } + + abstract void visitVirtualFile(VirtualFile f); + + final void accept(final VirtualFile f) { + if (f != null) { + visitVirtualFile(f); + } + final VirtualFile[] vfa = f.getChildren(); + if (vfa != null) { + for (int i = 0; i < vfa.length; i++) { + if (!cancel) { + accept(vfa[i]); + } + } + } + } + } + + final class RearrangeIt implements Runnable { + final class IntHolder { + public int n; + } + + final DataContext dc; + final Project project; + final JProgressBar bar = new JProgressBar(JProgressBar.HORIZONTAL); + final JLabel filename = new JLabel(); + + public RearrangeIt(final DataContext dc) { + this.dc = dc; + this.project = (Project)dc.getData(DataConstants.PROJECT); + } + + public final void run() { + final VirtualFile virtualFile = (VirtualFile)dc.getData(DataConstants.VIRTUAL_FILE); + final IntHolder count = new IntHolder(); + final VirtualFileVisitor counter = new VirtualFileVisitor() { + void visitVirtualFile(final VirtualFile f) { + if (!f.isDirectory()) count.n++; + } + }; + counter.accept(virtualFile); + logger.debug("counted " + count.n + " files"); + + final RearrangerActionHandler rah = new RearrangerActionHandler(); + final PsiDocumentManager dm = PsiDocumentManager.getInstance(project); + final PsiManager pm = PsiManager.getInstance(project); + final VirtualFileVisitor executor = new VirtualFileVisitor() { + int currentCount = 0; + + void visitVirtualFile(final VirtualFile f) { + try { + final PsiFile psiFile = pm.findFile(f); + if (psiFile != null && psiFile.canContainJavaCode()) { + logger.debug("rearrange psiFile=" + psiFile.toString()); + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("event dispatch thread setting filename to " + psiFile.getName()); + filename.setText(psiFile.getName()); + } + else { + logger.debug("invokeAndWait to set filename to " + psiFile.getName()); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("event dispatch thread within invokeAndWait setting filename to " + + psiFile.getName()); + filename.setText(psiFile.getName()); + } + }); + } + filename.repaint(); +// filename.setText(psiFile.getName()); +// filename.paint(filename.getGraphics()); + filename.paintImmediately(filename.getVisibleRect()); + Thread.sleep(8000); + final Document document = dm.getDocument(psiFile); + if (document == null) { + logger.debug("document was null"); + } + else { +// Thread t = new Thread(new Runnable() { +// public void run() +// { + //To change body of implemented methods use Options | File Templates. + rah.runWriteActionRearrangement(project, document, psiFile); +// } +// } ); +// t.start(); + } + logger.debug("done rearranging psiFile=" + psiFile.toString()); + } + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("EventDispatchThread updating progress bar value to " + currentCount); + bar.setValue(currentCount); + } + else { + logger.debug("invokeAndWait to set progress bar value to " + currentCount); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("EventDispatchThread within InvokeAndWait setting progress bar value to " + + currentCount); + bar.setValue(currentCount); + } + }); + } + bar.repaint(); + bar.paintImmediately(bar.getVisibleRect()); + bar.paint(bar.getGraphics()); + currentCount++; + Thread.sleep(5000); + } + catch (InterruptedException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + catch (InvocationTargetException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + } + }; + final JDialog dialog = getProgressFrame(executor, count.n); + + dialog.show(); + dialog.setVisible(true); + dialog.paint(dialog.getGraphics()); + executor.accept(virtualFile); + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + } + + final JDialog getProgressFrame(final Cancellable cancellableObject, final int max) { + final Object parent = WindowManager.getInstance().suggestParentWindow(project); + logger.debug("suggested parent window=" + parent); + final JDialog dialog = parent == null ? + new JDialog() : (parent instanceof JDialog ? + new JDialog((JDialog)parent) : new JDialog((JFrame)parent)); + final Container pane = dialog.getContentPane(); + final JLabel rearrangingLabel = new JLabel("Rearranging files, please wait..."); +// rearrangingLabel.setFont(new Font("dialog", Font.PLAIN, 12)); + final JPanel progressPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.weightx = 1; + constraints.insets = new Insets(15, 15, 0, 0); + progressPanel.add(rearrangingLabel, constraints); + constraints.gridwidth = 1; + constraints.gridy = 1; + bar.setMinimum(0); + bar.setMaximum(max); + bar.setPreferredSize(new Dimension(500, 15)); + bar.setMinimumSize(new Dimension(500, 15)); + bar.setStringPainted(true); + constraints.insets = new Insets(15, 15, 5, 15); + progressPanel.add(bar, constraints); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 1; + constraints.insets = new Insets(9, 0, 5, 15); + final JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + logger.debug("cancel button pressed"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + }); + progressPanel.add(cancelButton, constraints); + constraints.gridx = 0; + constraints.gridy = 2; + constraints.weighty = 1; + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.insets = new Insets(0, 15, 15, 0); + filename.setSize(500, 15); + filename.setPreferredSize(new Dimension(500, 15)); +// filename.setFont(new Font("dialog", Font.PLAIN, 12)); + progressPanel.add(filename, constraints); + pane.add(progressPanel, BorderLayout.CENTER); + dialog.setTitle("Rearranger"); + dialog.addWindowListener(new WindowListener() { + public void windowClosed(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowActivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowClosing(final WindowEvent e) { + logger.debug("dialog closed, cancel Rearranger"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + + public void windowDeactivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowDeiconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowIconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowOpened(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + }); + dialog.pack(); + return dialog; + } + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java new file mode 100644 index 000000000000..7bce95f3b2d6 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java @@ -0,0 +1,41 @@ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Oct 31, 2003 + * Time: 11:48:02 AM + * To change this template use Options | File Templates. + */ +final class SpaceTest5 { +// ------------------------------ FIELDS ------------------------------ + + public static final int CONSTANT3 = 3; + public static final int CONSTANT4 = 4; + /** end of public static final fields */ + private final int privateField5; + +// --------------------------- CONSTRUCTORS --------------------------- + + public TestClass2(final int privateField1) { + this.privateField5 = privateField1; + } + +// -------------------------- INNER CLASSES -------------------------- + + class inner1 { + // test class + } + + + class inner2 { + // test class + } +} + + +class outer1 { + // test class +} + + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java new file mode 100644 index 000000000000..43a50907c1a5 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java @@ -0,0 +1,37 @@ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Oct 31, 2003 + * Time: 11:48:02 AM + * To change this template use Options | File Templates. + */ +final class TestClass2 { +// ------------------------------ FIELDS ------------------------------ + + public static final int CONSTANT3 = 3; + public static final int CONSTANT4 = 4; + /** end of public static final fields */ + private final int privateField5; + +// --------------------------- CONSTRUCTORS --------------------------- + + public TestClass2(final int privateField1) { + this.privateField5 = privateField1; + } + +// -------------------------- INNER CLASSES -------------------------- + + class inner1 { + // test class + } + + class inner2 { + // test class + } +} + +class outer1 { + // test class +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult7.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult7.java new file mode 100644 index 000000000000..679c93032622 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult7.java @@ -0,0 +1,97 @@ +package com.opsx.bean; + +import com.opsx.exception.EnvironmentsNotDefinedException; +import com.opsx.main.Environment; +import com.opsx.main.EnvironmentManager; +import com.opsx.main.UserManager; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.util.List; + +/** + * @author abrown + * Copyright OpsTechnology Mar 31, 2004 + */ +public class Setup { + + + ******************************FIELDS****************************** + private JTextField environmentName; + private JTextField firstLogFolder; + private JTextField optionalLogFolder; + private JComboBox environmentList; + private JButton save; + private JPanel mainPanel; + private EnvironmentManager environmentManager = null; + private JTextField pathToOutputFile; + + + ******************************CONSTRUCTORS****************************** + + public Setup() throws EnvironmentsNotDefinedException, IOException, ClassNotFoundException { + UserManager userManager = UserManager.getUserManager(); + + environmentManager = EnvironmentManager.getEnvironmentManager(userManager.getUserName()); + + + Environment currentEnvironment = environmentManager.getCurrentEnvironment(); + + environmentName.setText(currentEnvironment.getName()); + firstLogFolder.setText(currentEnvironment.getFirstLogFolder()); + optionalLogFolder.setText(currentEnvironment.getOptionalLogFolder()); + pathToOutputFile.setText(currentEnvironment.getPathToOutputFile()); + + createDropDownList(currentEnvironment.getName()); + + + save.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (Setup.this.environmentName == null || + Setup.this.environmentName.getText().equals("")) + { + JOptionPane dialog = new JOptionPane(); + dialog.showMessageDialog(null, "Environment name can not be blank"); + return; + } + if (Setup.this.firstLogFolder == null || + Setup.this.firstLogFolder.getText().equals("")) + { + JOptionPane dialog = new JOptionPane(); + dialog.showMessageDialog(null, "First log folder can not be blank"); + return; + } + Environment environment = new Environment(Setup.this.environmentName.getText(), + Setup.this.firstLogFolder.getText(), + Setup.this.optionalLogFolder.getText(), + Setup.this.pathToOutputFile.getText()); + try { + Setup.this.environmentManager.saveEnvironment(environment); + Setup.this.createDropDownList(environment.getName()); + } + catch (IOException e1) { + JOptionPane dialog = new JOptionPane(); + dialog.showMessageDialog(null, "Could not persist the environment info: " + e1.getMessage()); + e1.printStackTrace(); + return; + } + } + }); + } + + ******************************METHODS****************************** + + private void createDropDownList(String currentEnvironmentName) { + List envList = environmentManager.getEnvironmentNames(); + String[] names = (String[])envList.toArray(new String[0]); + ComboBoxModel comboModel = new DefaultComboBoxModel(names); + environmentList.setModel(comboModel); + environmentList.setSelectedItem(currentEnvironmentName); + } + + public JPanel getMainPanel() { + return mainPanel; + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java new file mode 100644 index 000000000000..363ec5485017 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java @@ -0,0 +1,11 @@ +public class Tester { +// -------------------------- OTHER METHODS -------------------------- + + void test() { + X x = new X() { + }; + } +} + +interface X { +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest1.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest1.java new file mode 100644 index 000000000000..ebc57ecea80c --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest1.java @@ -0,0 +1,22 @@ +/** class comment */ +public class SpaceTest1 { + + + /** first field. */ + int firstField; + + /** method */ + void method1() { + + + int i = 3; + if (i < 3) { + + i = 5; + } + } +} + + + + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest2.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest2.java new file mode 100644 index 000000000000..d6d7a9d1f144 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest2.java @@ -0,0 +1,16 @@ +/** class comment */ +public class SpaceTest1 { + /** first field. */ + int firstField; + + /** method */ + void method1() { + int i = 3; + if (i < 3) { + i = 5; + } + } + + void method2() { + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest3.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest3.java new file mode 100644 index 000000000000..adbeb6f7725f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest3.java @@ -0,0 +1,18 @@ +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class SpaceTest3 { + void method() { + final JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + int i = 0; // logger.debug("cancel button pressed"); + String s = "cancelling"; // filename.setText("cancelling..."); + // cancellableObject.setCancel(); + } + }); + JPanel progressPanel = new JPanel(); + progressPanel.add(cancelButton); + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest4.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest4.java new file mode 100644 index 000000000000..c6c6a1e5499f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest4.java @@ -0,0 +1,337 @@ +/** + * Id$ + * + * Rearranger plugin for IntelliJ IDEA. + * + * Source code may be freely copied and reused. Please copy credits, and send any bug fixes to the author. + * + * @author Dave Kriewall, WRQ, Inc. + * October, 2003 + */ +package com.wrq.rearranger; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; + +/** Handles right-click in project view; applies rearrangement to a directory and its files recursively. */ +public final class ProjectTreeActionHandler + extends AnAction +{ + private static final Logger logger = Logger.getLogger("com.wrq.rearranger.ProjectTreeActionHandler"); + + + public final void actionPerformed(final AnActionEvent anActionEvent) { + logger.debug("entered actionPerformed"); + // we're being called on the Swing event dispatch thread. Spin off another thread to do the + // rearranging and let Swing's thread go. +// Thread t = new Thread(new Runnable() { +// public void run() +// { +// //To change body of implemented methods use Options | File Templates. + final Application application = ApplicationManager.getApplication(); + application.runWriteAction(new RearrangeIt(anActionEvent.getDataContext())); +// } +// }, "RearrangerThread"); +// t.start(); +// new RearrangeIt(anActionEvent.getDataContext()).run(); + } + + /** + * Test progress bar functionality. Read 10 "filenames" from console, pausing between each to update the + * progress bar dialog. Handle cancel button and dialog window close button properly. + * + * @param args + */ + public static void main(final String[] args) { + org.apache.log4j.BasicConfigurator.configure(); + // test the progress bar. + final BufferedReader reader; + final ProjectTreeActionHandler ptah = new ProjectTreeActionHandler(); + final RearrangeIt ri = ptah.new RearrangeIt(null); + final RearrangeIt.IntHolder cancelled = ri.new IntHolder(); + + reader = new BufferedReader(new InputStreamReader(System.in)); + final Cancellable c = new Cancellable() { + public void setCancel() { + System.out.println("cancel test"); + cancelled.n = 1; + } + }; + final JDialog dialog = ri.getProgressFrame(c, 10); + int count = 0; + dialog.pack(); + dialog.setVisible(true); + while (count <= 10 && cancelled.n == 0) { + String s = null; + try { + s = reader.readLine(); + } + catch (IOException e) { + e.printStackTrace(); + } + if (cancelled.n == 0) { + ri.filename.setText(s); + count++; + ri.bar.setValue(count); + } + } + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + System.exit(0); + } + + interface Cancellable { + void setCancel(); + } + + abstract class VirtualFileVisitor implements Cancellable { + volatile boolean cancel = false; + + public final void setCancel() { + logger.debug("VirtualFileVisitor.setCancel called"); + cancel = true; + } + + abstract void visitVirtualFile(VirtualFile f); + + final void accept(final VirtualFile f) { + if (f != null) { + visitVirtualFile(f); + } + final VirtualFile[] vfa = f.getChildren(); + if (vfa != null) { + for (int i = 0; i < vfa.length; i++) { + if (!cancel) { + + accept(vfa[i]); + } + } + } + } + } + + final class RearrangeIt implements Runnable { + final class IntHolder { + public int n; + } + + final DataContext dc; + final Project project; + final JProgressBar bar = new JProgressBar(JProgressBar.HORIZONTAL); + final JLabel filename = new JLabel(); + + public RearrangeIt(final DataContext dc) { + this.dc = dc; + this.project = (Project)dc.getData(DataConstants.PROJECT); + } + + public final void run() { + final VirtualFile virtualFile = (VirtualFile)dc.getData(DataConstants.VIRTUAL_FILE); + final IntHolder count = new IntHolder(); + final VirtualFileVisitor counter = new VirtualFileVisitor() { + void visitVirtualFile(final VirtualFile f) { + if (!f.isDirectory()) count.n++; + } + }; + counter.accept(virtualFile); + logger.debug("counted " + count.n + " files"); + + final RearrangerActionHandler rah = new RearrangerActionHandler(); + final PsiDocumentManager dm = PsiDocumentManager.getInstance(project); + final PsiManager pm = PsiManager.getInstance(project); + final VirtualFileVisitor executor = new VirtualFileVisitor() { + int currentCount = 0; + + void visitVirtualFile(final VirtualFile f) { + try { + final PsiFile psiFile = pm.findFile(f); + if (psiFile != null && psiFile.canContainJavaCode()) { + logger.debug("rearrange psiFile=" + psiFile.toString()); + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("event dispatch thread setting filename to " + psiFile.getName()); + filename.setText(psiFile.getName()); + } + else { + logger.debug("invokeAndWait to set filename to " + psiFile.getName()); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("event dispatch thread within invokeAndWait setting filename to " + + psiFile.getName()); + filename.setText(psiFile.getName()); + } + }); + } + filename.repaint(); +// filename.setText(psiFile.getName()); +// filename.paint(filename.getGraphics()); + filename.paintImmediately(filename.getVisibleRect()); + Thread.sleep(8000); + final Document document = dm.getDocument(psiFile); + if (document == null) { + logger.debug("document was null"); + } + else { +// Thread t = new Thread(new Runnable() { +// public void run() +// { + //To change body of implemented methods use Options | File Templates. + rah.runWriteActionRearrangement(project, document, psiFile); +// } +// } ); +// t.start(); + } + logger.debug("done rearranging psiFile=" + psiFile.toString()); + } + if (SwingUtilities.isEventDispatchThread()) { + logger.debug("EventDispatchThread updating progress bar value to " + currentCount); + bar.setValue(currentCount); + } + else { + logger.debug("invokeAndWait to set progress bar value to " + currentCount); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + logger.debug("EventDispatchThread within InvokeAndWait setting progress bar value to " + + currentCount); + bar.setValue(currentCount); + } + }); + } + bar.repaint(); + bar.paintImmediately(bar.getVisibleRect()); + bar.paint(bar.getGraphics()); + currentCount++; + Thread.sleep(5000); + } + catch (InterruptedException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + catch (InvocationTargetException e) { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + } + }; + final JDialog dialog = getProgressFrame(executor, count.n); + + dialog.show(); + dialog.setVisible(true); + dialog.paint(dialog.getGraphics()); + executor.accept(virtualFile); + dialog.setVisible(false); + dialog.hide(); + dialog.dispose(); + } + + final JDialog getProgressFrame(final Cancellable cancellableObject, final int max) { + final Object parent = WindowManager.getInstance().suggestParentWindow(project); + logger.debug("suggested parent window=" + parent); + final JDialog dialog = parent == null ? + new JDialog() : (parent instanceof JDialog ? + new JDialog((JDialog)parent) : new JDialog((JFrame)parent)); + final Container pane = dialog.getContentPane(); + final JLabel rearrangingLabel = new JLabel("Rearranging files, please wait..."); +// rearrangingLabel.setFont(new Font("dialog", Font.PLAIN, 12)); + final JPanel progressPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.NONE; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = 1; + constraints.weightx = 1; + constraints.insets = new Insets(15, 15, 0, 0); + progressPanel.add(rearrangingLabel, constraints); + constraints.gridwidth = 1; + constraints.gridy = 1; + bar.setMinimum(0); + bar.setMaximum(max); + bar.setPreferredSize(new Dimension(500, 15)); + bar.setMinimumSize(new Dimension(500, 15)); + bar.setStringPainted(true); + constraints.insets = new Insets(15, 15, 5, 15); + progressPanel.add(bar, constraints); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridx = 1; + constraints.insets = new Insets(9, 0, 5, 15); + final JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + logger.debug("cancel button pressed"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + }); + progressPanel.add(cancelButton, constraints); + constraints.gridx = 0; + constraints.gridy = 2; + constraints.weighty = 1; + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridheight = GridBagConstraints.REMAINDER; + constraints.insets = new Insets(0, 15, 15, 0); + filename.setSize(500, 15); + filename.setPreferredSize(new Dimension(500, 15)); +// filename.setFont(new Font("dialog", Font.PLAIN, 12)); + progressPanel.add(filename, constraints); + pane.add(progressPanel, BorderLayout.CENTER); + dialog.setTitle("Rearranger"); + dialog.addWindowListener(new WindowListener() { + public void windowClosed(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowActivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowClosing(final WindowEvent e) { + logger.debug("dialog closed, cancel Rearranger"); + filename.setText("cancelling..."); + cancellableObject.setCancel(); + } + + public void windowDeactivated(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowDeiconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowIconified(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + + public void windowOpened(final WindowEvent e) { + //To change body of implemented methods use Options | File Templates. + } + }); + dialog.pack(); + return dialog; + } + } +} + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest5.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest5.java new file mode 100644 index 000000000000..b3c7b8b14dde --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest5.java @@ -0,0 +1,42 @@ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Oct 31, 2003 + * Time: 11:48:02 AM + * To change this template use Options | File Templates. + */ +final class SpaceTest5 { +// ------------------------------ FIELDS ------------------------------ + + public static final int CONSTANT3 = 3; + public static final int CONSTANT4 = 4; + /** end of public static final fields */ + private final int privateField5; + +// --------------------------- CONSTRUCTORS --------------------------- + + public TestClass2(final int privateField1) { + this.privateField5 = privateField1; + } + + + class inner1 { + // test class + } + + + class inner2 { + // test class + } +} + + +class outer1 { + // test class +} + + + + diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest6.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest6.java new file mode 100644 index 000000000000..86871ec6db2f --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest6.java @@ -0,0 +1,38 @@ +package com.wrq.rearranger.testClasses; + +/** + * Created by IntelliJ IDEA. + * User: davek + * Date: Oct 31, 2003 + * Time: 11:48:02 AM + * To change this template use Options | File Templates. + */ +final class TestClass2 { +// ------------------------------ FIELDS ------------------------------ + + public static final int CONSTANT3 = 3; + public static final int CONSTANT4 = 4; + /** end of public static final fields */ + private final int privateField5; + +// --------------------------- CONSTRUCTORS --------------------------- + + public TestClass2(final int privateField1) { + this.privateField5 = privateField1; + } + +// -------------------------- INNER CLASSES -------------------------- + + class inner1 { + // test class + } + + + class inner2 { + // test class + } +} + +class outer1 { + // test class +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7.java new file mode 100644 index 000000000000..f7b849ddf327 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7.java @@ -0,0 +1,100 @@ +package com.opsx.bean; + +import com.opsx.exception.EnvironmentsNotDefinedException; +import com.opsx.main.Environment; +import com.opsx.main.EnvironmentManager; +import com.opsx.main.UserManager; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.util.List; + +/** + * @author abrown + * Copyright OpsTechnology Mar 31, 2004 + */ + + +public class Setup { + + + private JTextField environmentName; + private JTextField firstLogFolder; + private JTextField optionalLogFolder; + + private JComboBox environmentList; + private JButton save; + + + public JPanel getMainPanel() { + return mainPanel; + } + + + private JPanel mainPanel; + + private EnvironmentManager environmentManager = null; + private JTextField pathToOutputFile; + + + public Setup() throws EnvironmentsNotDefinedException, IOException, ClassNotFoundException { + UserManager userManager = UserManager.getUserManager(); + + environmentManager = EnvironmentManager.getEnvironmentManager(userManager.getUserName()); + + + Environment currentEnvironment = environmentManager.getCurrentEnvironment(); + + environmentName.setText(currentEnvironment.getName()); + firstLogFolder.setText(currentEnvironment.getFirstLogFolder()); + optionalLogFolder.setText(currentEnvironment.getOptionalLogFolder()); + pathToOutputFile.setText(currentEnvironment.getPathToOutputFile()); + + createDropDownList(currentEnvironment.getName()); + + + save.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (Setup.this.environmentName == null || + Setup.this.environmentName.getText().equals("")) + { + JOptionPane dialog = new JOptionPane(); + dialog.showMessageDialog(null, "Environment name can not be blank"); + return; + } + if (Setup.this.firstLogFolder == null || + Setup.this.firstLogFolder.getText().equals("")) + { + JOptionPane dialog = new JOptionPane(); + dialog.showMessageDialog(null, "First log folder can not be blank"); + return; + } + Environment environment = new Environment(Setup.this.environmentName.getText(), + Setup.this.firstLogFolder.getText(), + Setup.this.optionalLogFolder.getText(), + Setup.this.pathToOutputFile.getText()); + try { + Setup.this.environmentManager.saveEnvironment(environment); + Setup.this.createDropDownList(environment.getName()); + } + catch (IOException e1) { + JOptionPane dialog = new JOptionPane(); + dialog.showMessageDialog(null, "Could not persist the environment info: " + e1.getMessage()); + e1.printStackTrace(); + return; + } + } + }); + } + + + private void createDropDownList(String currentEnvironmentName) { + List envList = environmentManager.getEnvironmentNames(); + String[] names = (String[])envList.toArray(new String[0]); + ComboBoxModel comboModel = new DefaultComboBoxModel(names); + environmentList.setModel(comboModel); + environmentList.setSelectedItem(currentEnvironmentName); + } +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml new file mode 100644 index 000000000000..d46de5f9e532 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml @@ -0,0 +1,325 @@ + + + + \n + + + ****************************** FIELDS ****************************** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n + + + ****************************** CONSTRUCTORS ****************************** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n + + + ****************************** METHODS ****************************** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n + + + + + + + + + + + + + + + + + \n + + + ****************************** INNER CLASSES ****************************** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest8.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest8.java new file mode 100644 index 000000000000..31a55a373d47 --- /dev/null +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest8.java @@ -0,0 +1,9 @@ +public class Tester { + void test() { + X x = new X() { + }; + } +} + +interface X { +} \ No newline at end of file diff --git a/plugins/rearranger/test/testData/defaultConfiguration.xml b/plugins/rearranger/test/testData/defaultConfiguration.xml new file mode 100644 index 000000000000..8a25e6940fc2 --- /dev/null +++ b/plugins/rearranger/test/testData/defaultConfiguration.xml @@ -0,0 +1,262 @@ + + + + + // ------------------------------ FIELDS ------------------------------ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // -------------------------- STATIC METHODS -------------------------- + + + + + + + + + + + + + + + + + + // --------------------------- CONSTRUCTORS --------------------------- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // --------------------- GETTER / SETTER METHODS --------------------- + + + + + + + + + + + + + + + + + + // ------------------------ CANONICAL METHODS ------------------------ + + + + + + + + + + + + + + + + + + // ------------------------ INTERFACE METHODS ------------------------ + + + + + + // --------------------- Interface %IF% --------------------- + + + + + + + + // -------------------------- OTHER METHODS -------------------------- + + + + + + + + + + + + + + + + + + // -------------------------- INNER CLASSES -------------------------- + + + + + + + + + + // --------------------------- main() method --------------------------- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bd7be46de5ca71474e3b364f11353c71a013f260 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 14 May 2012 12:50:01 +0400 Subject: [PATCH 34/67] IDEA-19061 Integrate the Rearranger-plugin into core-IDEA *) IRule -> Rule; *) IRuleInstance -> RuleInstance; *) IFilePopupEntry -> FilePopupEntry; --- .../LiveRearrangerActionHandler.java | 4 +- .../rearranger/RearrangerActionHandler.java | 4 +- .../configuration/SettingsPane.java | 8 +-- .../rearranger/entry/ClassContentsEntry.java | 4 +- .../com/wrq/rearranger/entry/ClassEntry.java | 22 ++++---- .../com/wrq/rearranger/entry/MethodEntry.java | 10 ++-- .../com/wrq/rearranger/entry/RangeEntry.java | 12 ++-- ...ilePopupEntry.java => FilePopupEntry.java} | 6 +- .../rearranger/popup/FileStructurePopup.java | 14 ++--- .../wrq/rearranger/popup/ILiveRearranger.java | 4 +- .../popup/LiveRearrangerDialog.java | 16 +++--- .../rearranger/popup/LiveRearrangerPopup.java | 22 ++++---- .../com/wrq/rearranger/popup/PopupTree.java | 4 +- .../rearranger/popup/PopupTreeComponent.java | 22 ++++---- .../wrq/rearranger/rearrangement/Emitter.java | 14 ++--- .../rearrangement/GenericRearranger.java | 56 +++++++++---------- .../wrq/rearranger/rearrangement/Mover.java | 6 +- .../ruleinstance/CommentRuleInstance.java | 16 +++--- .../ruleinstance/CommonRuleInstance.java | 23 ++++---- .../ruleinstance/DefaultRuleInstance.java | 4 +- .../EmitAlwaysCommentRuleInstance.java | 2 +- .../HeaderTrailerRuleInstance.java | 33 +++++------ .../ruleinstance/InterfaceInstance.java | 4 +- .../ruleinstance/InterfaceRuleInstance.java | 4 +- .../PrecedingCommentRuleInstance.java | 2 +- .../{IRuleInstance.java => RuleInstance.java} | 8 ++- .../SubsequentCommentRuleInstance.java | 2 +- .../SurroundingCommentRuleInstance.java | 2 +- .../wrq/rearranger/settings/CommentRule.java | 8 +-- .../attributeGroups/AttributeGroup.java | 2 +- .../attributeGroups/CommonAttributes.java | 4 +- .../settings/attributeGroups/DefaultRule.java | 6 +- .../settings/attributeGroups/HeaderRule.java | 6 +- .../attributeGroups/InterfaceAttributes.java | 4 +- .../attributeGroups/{IRule.java => Rule.java} | 6 +- .../settings/attributeGroups/TrailerRule.java | 6 +- .../com/wrq/rearranger/util/CommentUtil.java | 6 +- .../com/wrq/rearranger/InteractiveTest.java | 6 +- 38 files changed, 192 insertions(+), 190 deletions(-) rename plugins/rearranger/src/com/wrq/rearranger/popup/{IFilePopupEntry.java => FilePopupEntry.java} (92%) rename plugins/rearranger/src/com/wrq/rearranger/ruleinstance/{IRuleInstance.java => RuleInstance.java} (94%) rename plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/{IRule.java => Rule.java} (95%) diff --git a/plugins/rearranger/src/com/wrq/rearranger/LiveRearrangerActionHandler.java b/plugins/rearranger/src/com/wrq/rearranger/LiveRearrangerActionHandler.java index 56598392b034..ce6abab76577 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/LiveRearrangerActionHandler.java +++ b/plugins/rearranger/src/com/wrq/rearranger/LiveRearrangerActionHandler.java @@ -43,7 +43,7 @@ import com.wrq.rearranger.popup.LiveRearrangerDialog; import com.wrq.rearranger.popup.LiveRearrangerPopup; import com.wrq.rearranger.rearrangement.Mover; import com.wrq.rearranger.rearrangement.Parser; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.CommentUtil; @@ -196,7 +196,7 @@ public final class LiveRearrangerActionHandler final List outerClasses = p.parseOuterLevel(); if (outerClasses.size() > 0) { final Mover mover = new Mover(outerClasses, settings); - final List resultRuleInstances = mover.rearrangeOuterClasses(); + final List resultRuleInstances = mover.rearrangeOuterClasses(); fsp.setResultRuleInstances(resultRuleInstances); fsp.liveRearranger(); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java b/plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java index 97d333290b3b..10bd83c6ce03 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java +++ b/plugins/rearranger/src/com/wrq/rearranger/RearrangerActionHandler.java @@ -45,7 +45,7 @@ import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.rearrangement.Mover; import com.wrq.rearranger.rearrangement.Parser; import com.wrq.rearranger.rearrangement.Spacer; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.CommentUtil; @@ -173,7 +173,7 @@ public final class RearrangerActionHandler extends EditorActionHandler { final List outerClasses = p.parseOuterLevel(); if (outerClasses.size() > 0) { final Mover m = new Mover(outerClasses, settings); - final List resultRuleInstances = m.rearrangeOuterClasses(); + final List resultRuleInstances = m.rearrangeOuterClasses(); boolean rearrange = true; if (settings.isAskBeforeRearranging()) { FileStructurePopup fsp = new FileStructurePopup(settings, resultRuleInstances, psiFile); diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java index 358a2312e225..4a72bcb11a66 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java @@ -24,7 +24,7 @@ package com.wrq.rearranger.configuration; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; import com.wrq.rearranger.settings.attributeGroups.IPrioritizableRule; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import com.wrq.rearranger.util.Constraints; import javax.swing.*; @@ -98,7 +98,7 @@ public abstract class SettingsPane { case PRIORITY_COLUMN: ChoicePanel cp = (modelData.get(rowIndex)); - IRule rule = cp.getChoice().getChoiceObject(); + Rule rule = cp.getChoice().getChoiceObject(); return new Priority(rule.getPriority()); case DESCRIPTION_COLUMN: @@ -138,7 +138,7 @@ public abstract class SettingsPane { public boolean isCellEditable(int rowIndex, int columnIndex) { if (columnIndex == PRIORITY_COLUMN && rowIndex >= 0) { ChoicePanel cp = (modelData.get(rowIndex)); - IRule rule = cp.getChoice().getChoiceObject(); + Rule rule = cp.getChoice().getChoiceObject(); if (rule instanceof IPrioritizableRule) { return true; } @@ -149,7 +149,7 @@ public abstract class SettingsPane { public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (columnIndex == PRIORITY_COLUMN) { ChoicePanel cp = (modelData.get(rowIndex)); - IRule rule = cp.getChoice().getChoiceObject(); + Rule rule = cp.getChoice().getChoiceObject(); if (rule instanceof IPrioritizableRule) { int priority; try { diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java index 1739647d8bc6..743e31a51e15 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassContentsEntry.java @@ -23,7 +23,7 @@ package com.wrq.rearranger.entry; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; -import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.FilePopupEntry; import com.wrq.rearranger.popup.RearrangerTreeNode; import com.wrq.rearranger.settings.RearrangerSettings; @@ -35,7 +35,7 @@ import javax.swing.tree.DefaultMutableTreeNode; */ public abstract class ClassContentsEntry extends RangeEntry - implements IFilePopupEntry + implements FilePopupEntry { public ClassContentsEntry(final PsiElement start, final PsiElement end, diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java index 028f08352cd7..f73d7c96543b 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/ClassEntry.java @@ -29,10 +29,10 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.util.Query; import com.wrq.rearranger.ModifierConstants; -import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.FilePopupEntry; import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.rearrangement.GenericRearranger; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.ModifierUtils; @@ -50,12 +50,12 @@ import java.util.List; */ public class ClassEntry extends ClassContentsEntry - implements IFilePopupEntry + implements FilePopupEntry { private static final Logger LOG = Logger.getInstance("#" + ClassEntry.class.getName()); protected final List contents; - private List resultRuleInstances; + private List myResultRuleInstances; private final RearrangerSettings settings; private final int nestingLevel; @@ -69,7 +69,7 @@ public class ClassEntry { super(start, end, modifiers, modifierString, name, ""); contents = new ArrayList(); - resultRuleInstances = null; + myResultRuleInstances = null; this.settings = settings; this.nestingLevel = nestingLevel; } @@ -501,7 +501,7 @@ public class ClassEntry DefaultMutableTreeNode result = super.addToPopupTree(parent, settings); // now add class contents, if any if (getResultRuleInstances() != null) { - for (IRuleInstance instance : getResultRuleInstances()) { + for (RuleInstance instance : getResultRuleInstances()) { instance.addRuleInstanceToPopupTree(result, settings); } } @@ -540,14 +540,14 @@ public class ClassEntry settings) { public void rearrangeRelatedItems(List entries, - List ruleInstanceList) + List ruleInstanceList) { - for (IRuleInstance ruleInstance : ruleInstanceList) { + for (RuleInstance ruleInstance : ruleInstanceList) { ruleInstance.rearrangeRuleItems(entries, settings); } } }; - resultRuleInstances = classContentsRearranger.rearrangeEntries(); + myResultRuleInstances = classContentsRearranger.rearrangeEntries(); } private void buildMethodCallGraph() { @@ -569,8 +569,8 @@ public class ClassEntry return contents; } - public List getResultRuleInstances() { - return resultRuleInstances; + public List getResultRuleInstances() { + return myResultRuleInstances; } } diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java index 0c4780ef24c4..450d3e7ddb97 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/MethodEntry.java @@ -27,13 +27,13 @@ import com.intellij.psi.*; import com.wrq.rearranger.ModifierConstants; import com.wrq.rearranger.popup.RearrangerTreeNode; import com.wrq.rearranger.rearrangement.Emitter; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.CommentRule; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.settings.RelatedMethodsSettings; import com.wrq.rearranger.settings.attributeGroups.IHasGetterSetterDefinition; import com.wrq.rearranger.settings.attributeGroups.IRestrictMethodExtraction; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import com.wrq.rearranger.util.CommentUtil; import com.wrq.rearranger.util.MethodUtil; @@ -146,7 +146,7 @@ public class MethodEntry * @param ruleInstance Rule containing parents (callers) of potentially related methods */ public static void rearrangeRelatedItems(List entries, - IRuleInstance ruleInstance, + RuleInstance ruleInstance, RelatedMethodsSettings rms) { List parentEntries = new ArrayList(ruleInstance.getMatches()); @@ -161,7 +161,7 @@ public class MethodEntry } } for (MethodEntry theSetter : me.correspondingGetterSetters) { - final IRuleInstance theRule = theSetter.getMatchedRule(); + final RuleInstance theRule = theSetter.getMatchedRule(); LOG.debug( "rearrangeRelatedItems: for getter method " + me + @@ -680,7 +680,7 @@ public class MethodEntry settings.getDefaultGSDefinition() ) ); - for (IRule rule : settings.getItemOrderAttributeList()) { + for (Rule rule : settings.getItemOrderAttributeList()) { if (rule instanceof IRestrictMethodExtraction) { if (rule.isMatch(this)) { if (((IRestrictMethodExtraction)rule).isNoExtractedMethods()) { diff --git a/plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java b/plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java index 5f41b963e9d2..96fd5a97102c 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java +++ b/plugins/rearranger/src/com/wrq/rearranger/entry/RangeEntry.java @@ -26,7 +26,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.psi.PsiElement; import com.wrq.rearranger.popup.RearrangerTreeNode; import com.wrq.rearranger.rearrangement.Emitter; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.CommentUtil; @@ -51,7 +51,7 @@ abstract public class RangeEntry implements IPopupTreeRangeEntry { private final boolean fixedHeader; private final boolean fixedTrailer; private final String type; - private IRuleInstance matchedRule; + private RuleInstance myMatchedRule; private boolean separatorCommentPrecedes; // --------------------------- CONSTRUCTORS --------------------------- @@ -100,12 +100,12 @@ abstract public class RangeEntry implements IPopupTreeRangeEntry { return end; } - public IRuleInstance getMatchedRule() { - return matchedRule; + public RuleInstance getMatchedRule() { + return myMatchedRule; } - public void setMatchedRule(IRuleInstance matchedRule) { - this.matchedRule = matchedRule; + public void setMatchedRule(RuleInstance matchedRule) { + this.myMatchedRule = matchedRule; } public int getModifiers() { diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/IFilePopupEntry.java b/plugins/rearranger/src/com/wrq/rearranger/popup/FilePopupEntry.java similarity index 92% rename from plugins/rearranger/src/com/wrq/rearranger/popup/IFilePopupEntry.java rename to plugins/rearranger/src/com/wrq/rearranger/popup/FilePopupEntry.java index bd0550870935..b1fbb6dd6229 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/popup/IFilePopupEntry.java +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/FilePopupEntry.java @@ -22,18 +22,20 @@ package com.wrq.rearranger.popup; import com.wrq.rearranger.settings.RearrangerSettings; +import org.jetbrains.annotations.Nullable; import javax.swing.*; /** Interface implemented by objects which can appear as entries in the file structure popup. */ -public interface IFilePopupEntry { +public interface FilePopupEntry { /** @return the name of the icon representing the popup entry's type of Java object (method, class, etc.) */ String getTypeIconName(); /** * @return the names of the icon representing the protection level of the popup entry, and any other - * icons (overrides/overriding/implements/implmenting). + * icons (overrides/overriding/implements/implementing). */ + @Nullable String[] getAdditionalIconNames(); /** @return a JLabel containing the text of the popup tree entry. */ diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java b/plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java index 5b6b4cad46e5..35b85edb5fc2 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/FileStructurePopup.java @@ -22,7 +22,7 @@ package com.wrq.rearranger.popup; import com.intellij.psi.PsiFile; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.Constraints; import com.wrq.rearranger.util.IconUtil; @@ -41,19 +41,19 @@ public class FileStructurePopup final PopupTreeComponent treeComponent; public FileStructurePopup(RearrangerSettings settings, - List resultRuleInstances, - final IFilePopupEntry psiFileEntry) + List resultRuleInstances, + final FilePopupEntry psiFileEntry) { this.settings = settings; treeComponent = new PopupTreeComponent(settings, resultRuleInstances, psiFileEntry); } public FileStructurePopup(RearrangerSettings settings, - List resultRuleInstances, + List resultRuleInstances, final PsiFile psiFile) { this.settings = settings; - IFilePopupEntry psiFileEntry = new IFilePopupEntry() { + FilePopupEntry psiFileEntry = new FilePopupEntry() { public String getTypeIconName() { return "ppFile"; } @@ -305,7 +305,7 @@ public class FileStructurePopup public static void main(String[] args) { final RearrangerSettings settings = new RearrangerSettings(); - IFilePopupEntry pf = new IFilePopupEntry() { + FilePopupEntry pf = new FilePopupEntry() { public String getTypeIconName() { return "nodes/ppFile"; } @@ -318,7 +318,7 @@ public class FileStructurePopup return new JLabel("FileName.java"); } }; - FileStructurePopup fsp = new FileStructurePopup(settings, new ArrayList(), pf); + FileStructurePopup fsp = new FileStructurePopup(settings, new ArrayList(), pf); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java b/plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java index dc1543023256..bdd1133219d3 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/ILiveRearranger.java @@ -21,14 +21,14 @@ */ package com.wrq.rearranger.popup; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import java.util.List; public interface ILiveRearranger { void setRearrangementOccurred(boolean rearrangementOccurred); - void setResultRuleInstances(List resultRuleInstances); + void setResultRuleInstances(List resultRuleInstances); void liveRearranger(); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java index 33204f9f285e..d848e269cc91 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerDialog.java @@ -26,7 +26,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.psi.PsiFile; import com.wrq.rearranger.LiveRearrangerActionHandler; import com.wrq.rearranger.rearrangement.Emitter; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.Constraints; import com.wrq.rearranger.util.IconUtil; @@ -48,11 +48,11 @@ public class LiveRearrangerDialog private static final Logger LOG = Logger.getInstance("#" + LiveRearrangerDialog.class.getName()); final RearrangerSettings settings; PopupTreeComponent treeComponent; - List resultRuleInstances; + List myResultRuleInstances; final Window outerPanel; final Document document; final PsiFile psiFile; - IFilePopupEntry psiFileEntry; + FilePopupEntry myPsiFileEntry; TreeDragSource tds; TreeDropTarget tdt; boolean rearrangementOccurred = false; @@ -61,7 +61,7 @@ public class LiveRearrangerDialog private PopupTree popupTree; private void createFilePopupEntry(final PsiFile psiFile) { - psiFileEntry = new IFilePopupEntry() { + myPsiFileEntry = new FilePopupEntry() { public String getTypeIconName() { return "nodes/ppFile"; } @@ -91,9 +91,9 @@ public class LiveRearrangerDialog this.rearrangementOccurred = rearrangementOccurred; } - public void setResultRuleInstances(List resultRuleInstances) { - this.resultRuleInstances = resultRuleInstances; - treeComponent = new PopupTreeComponent(settings, resultRuleInstances, psiFileEntry); + public void setResultRuleInstances(List resultRuleInstances) { + this.myResultRuleInstances = resultRuleInstances; + treeComponent = new PopupTreeComponent(settings, resultRuleInstances, myPsiFileEntry); } /** Display a live rearrangement window. */ @@ -125,7 +125,7 @@ public class LiveRearrangerDialog } LOG.debug("rearranging document"); if (document != null) { - final Emitter e = new Emitter(psiFile, resultRuleInstances, document); + final Emitter e = new Emitter(psiFile, myResultRuleInstances, document); e.emitRearrangedDocument(); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java index 700ee7527917..3b4a672719c9 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/LiveRearrangerPopup.java @@ -31,7 +31,7 @@ import com.intellij.psi.PsiFile; import com.wrq.rearranger.LiveRearrangerActionHandler; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.rearrangement.Emitter; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.IconUtil; @@ -55,11 +55,11 @@ public class LiveRearrangerPopup private static final Logger LOG = Logger.getInstance("#" + LiveRearrangerPopup.class.getName()); final RearrangerSettings settings; PopupTreeComponent treeComponent; - List resultRuleInstances; + List myResultRuleInstances; final Window outerPanel; final Document document; final PsiFile psiFile; - IFilePopupEntry psiFileEntry; + FilePopupEntry myPsiFileEntry; private WindowFocusListener windowFocusListener; private WindowAdapter windowAdapter; private MouseAdapter mouseAdapter; @@ -79,7 +79,7 @@ public class LiveRearrangerPopup boolean sawKeyPressed = false; public LiveRearrangerPopup(RearrangerSettings settings, - final IFilePopupEntry psiFileEntry, + final FilePopupEntry psiFileEntry, Window outerPanel, Document document, Project project) @@ -87,14 +87,14 @@ public class LiveRearrangerPopup LOG.debug("entered LiveRearrangerPopup constructor"); this.settings = settings; this.outerPanel = outerPanel; - this.psiFileEntry = psiFileEntry; + this.myPsiFileEntry = psiFileEntry; this.document = document; this.psiFile = null; this.project = project; } private void createFilePopupEntry(final PsiFile psiFile) { - psiFileEntry = new IFilePopupEntry() { + myPsiFileEntry = new FilePopupEntry() { public String getTypeIconName() { return "nodes/ppFile"; } @@ -166,9 +166,9 @@ public class LiveRearrangerPopup this.rearrangementOccurred = rearrangementOccurred; } - public void setResultRuleInstances(List resultRuleInstances) { - this.resultRuleInstances = resultRuleInstances; - treeComponent = new PopupTreeComponent(settings, resultRuleInstances, psiFileEntry); + public void setResultRuleInstances(List resultRuleInstances) { + this.myResultRuleInstances = resultRuleInstances; + treeComponent = new PopupTreeComponent(settings, resultRuleInstances, myPsiFileEntry); } /** Display a live rearrangement window. */ @@ -355,7 +355,7 @@ public class LiveRearrangerPopup final Runnable task = new Runnable() { public void run() { if (document != null) { - final Emitter e = new Emitter(psiFile, resultRuleInstances, document); + final Emitter e = new Emitter(psiFile, myResultRuleInstances, document); e.emitRearrangedDocument(); } } @@ -571,7 +571,7 @@ public class LiveRearrangerPopup // void testIt() // { final RearrangerSettings settings = new RearrangerSettings(); - IFilePopupEntry pf = new IFilePopupEntry() { + FilePopupEntry pf = new FilePopupEntry() { public String getTypeIconName() { return "nodes/ppFile"; } diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java index de925315e1fa..f3b612118c17 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTree.java @@ -23,7 +23,7 @@ package com.wrq.rearranger.popup; import com.intellij.openapi.diagnostic.Logger; import com.wrq.rearranger.entry.RangeEntry; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; @@ -195,7 +195,7 @@ public class PopupTree if (!before && dstIndex < peerParent.getChildCount()) { dstIndex++; } - IRuleInstance ruleInstance = entry.getMatchedRule(); + RuleInstance ruleInstance = entry.getMatchedRule(); DefaultTreeModel model = (DefaultTreeModel)getModel(); for (TreePath path : paths) { diff --git a/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java index fa825b548a75..b1af6fd36b8a 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java +++ b/plugins/rearranger/src/com/wrq/rearranger/popup/PopupTreeComponent.java @@ -23,7 +23,7 @@ package com.wrq.rearranger.popup; import com.intellij.openapi.diagnostic.Logger; import com.wrq.rearranger.Rearranger; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.util.Constraints; import com.wrq.rearranger.util.IconUtil; @@ -45,18 +45,18 @@ import java.util.List; /** Builds a JTree that can be used in a file structure popup or live rearranger popup. */ public class PopupTreeComponent { private static final Logger LOG = Logger.getInstance("#" + PopupTreeComponent.class.getName()); - private final IFilePopupEntry psiFileEntry; - private final List resultRuleInstances; + private final FilePopupEntry myPsiFileEntry; + private final List myResultRuleInstances; private final RearrangerSettings settings; private boolean rearrangementOccurred; public PopupTreeComponent(RearrangerSettings settings, - List resultRuleInstances, - final IFilePopupEntry psiFileEntry) + List resultRuleInstances, + final FilePopupEntry psiFileEntry) { this.settings = settings; - this.resultRuleInstances = resultRuleInstances; - this.psiFileEntry = psiFileEntry; + this.myResultRuleInstances = resultRuleInstances; + this.myPsiFileEntry = psiFileEntry; } public boolean isRearrangementOccurred() { @@ -239,13 +239,13 @@ public class PopupTreeComponent { } public DefaultMutableTreeNode createAllNodes() { - DefaultMutableTreeNode top = new RearrangerTreeNode(psiFileEntry, "root"); + DefaultMutableTreeNode top = new RearrangerTreeNode(myPsiFileEntry, "root"); createNodes(top); return top; } private void createNodes(DefaultMutableTreeNode top) { - for (IRuleInstance ruleInstance : resultRuleInstances) { + for (RuleInstance ruleInstance : myResultRuleInstances) { ruleInstance.addRuleInstanceToPopupTree(top, settings); } } @@ -279,8 +279,8 @@ public class PopupTreeComponent { userObject = ((DefaultMutableTreeNode)value).getUserObject(); } // obtain a component that will render the appropriate item. - if (userObject instanceof IFilePopupEntry) { - IFilePopupEntry entry = (IFilePopupEntry)userObject; + if (userObject instanceof FilePopupEntry) { + FilePopupEntry entry = (FilePopupEntry)userObject; final String iconTypeName = entry.getTypeIconName(); final String[] iconNames = entry.getAdditionalIconNames(); final JLabel textLabel = entry.getPopupEntryText(settings); diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java index 20e750b47ec9..6e6b7ddba87c 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Emitter.java @@ -23,20 +23,20 @@ package com.wrq.rearranger.rearrangement; import com.intellij.openapi.editor.Document; import com.intellij.psi.PsiFile; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import java.util.List; /** Emits a new document from the rearranged entries. */ public final class Emitter { private final PsiFile psiFile; - private final List resultRuleInstances; + private final List myResultRuleInstances; private final Document document; private StringBuffer stringBuffer; - public Emitter(final PsiFile psiFile, final List resultRuleInstances, final Document document) { + public Emitter(final PsiFile psiFile, final List resultRuleInstances, final Document document) { this.psiFile = psiFile; - this.resultRuleInstances = resultRuleInstances; + this.myResultRuleInstances = resultRuleInstances; this.document = document; stringBuffer = new StringBuffer(psiFile.getText().length() + 100); // room for inserted blank lines } @@ -50,7 +50,7 @@ public final class Emitter { } public void emitRearrangedDocument() { - emitRuleInstances(resultRuleInstances); + emitRuleInstances(myResultRuleInstances); document.replaceString( psiFile.getTextRange().getStartOffset(), psiFile.getTextRange().getEndOffset(), @@ -58,11 +58,11 @@ public final class Emitter { ); } - public void emitRuleInstances(List resultRuleInstances) { + public void emitRuleInstances(List resultRuleInstances) { if (resultRuleInstances == null) { return; } - for (IRuleInstance ruleInstance : resultRuleInstances) { + for (RuleInstance ruleInstance : resultRuleInstances) { ruleInstance.emit(this); } } diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java index 4289bba83c51..fb1232ee1650 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/GenericRearranger.java @@ -27,7 +27,7 @@ import com.wrq.rearranger.entry.ClassEntry; import com.wrq.rearranger.entry.IRelatableEntry; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.ruleinstance.CommentRuleInstance; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.settings.attributeGroups.*; @@ -40,7 +40,7 @@ public abstract class GenericRearranger { private static final Logger LOG = Logger.getInstance("#" + GenericRearranger.class.getName()); private final List rules; private final List entries; - private final List resultRuleInstances; + private final List myResultRuleInstances; private final int nestingLevel; private final RearrangerSettings settings; @@ -54,7 +54,7 @@ public abstract class GenericRearranger { entries = outerClasses; this.nestingLevel = nestingLevel; this.settings = settings; - resultRuleInstances = new ArrayList(rules.size() + 4); + myResultRuleInstances = new ArrayList(rules.size() + 4); } /** @@ -63,8 +63,8 @@ public abstract class GenericRearranger { * * @return rearranged list of RangeEntry and CommentRuleInstance objects. */ - public final List rearrangeEntries() { - final List prioritizedRuleInstances = new ArrayList(); + public final List rearrangeEntries() { + final List prioritizedRuleInstances = new ArrayList(); buildRuleInstanceLists(prioritizedRuleInstances); /** * recursively reorder contents of every nested ClassEntry. @@ -80,7 +80,7 @@ public abstract class GenericRearranger { * Move related methods together. Extracted methods and setters (emitted with getters) * were not moved by the rearrangement code ("MatchPrioritizedRules()") just above. */ - rearrangeRelatedItems(entries, resultRuleInstances); + rearrangeRelatedItems(entries, myResultRuleInstances); /** * Now go back and determine which comments are going to be emitted, based on their criteria and the * state of the immediately surrounding rules. Ignore inner classes if no rearrangement of inner @@ -89,19 +89,19 @@ public abstract class GenericRearranger { if (nestingLevel <= 1 || settings.isRearrangeInnerClasses()) { determineEmittedComments(); } - return resultRuleInstances; + return myResultRuleInstances; } /** For each comment rule instance, test its "emit" condition and set its emit flag appropriately. */ private void determineEmittedComments() { - for (int i = 0; i < resultRuleInstances.size(); i++) { - if (resultRuleInstances.get(i) instanceof CommentRuleInstance) { - final CommentRuleInstance ce = (CommentRuleInstance)resultRuleInstances.get(i); - ce.determineEmit(resultRuleInstances, i); + for (int i = 0; i < myResultRuleInstances.size(); i++) { + if (myResultRuleInstances.get(i) instanceof CommentRuleInstance) { + final CommentRuleInstance ce = (CommentRuleInstance)myResultRuleInstances.get(i); + ce.determineEmit(myResultRuleInstances, i); if (ce.isEmit()) { // set the "separator comment preceding" flag on the next matching RangeEntry. - for (int j = i + 1; j < resultRuleInstances.size(); j++) { - IRuleInstance instance = resultRuleInstances.get(j); + for (int j = i + 1; j < myResultRuleInstances.size(); j++) { + RuleInstance instance = myResultRuleInstances.get(j); if (instance.hasMatches()) { RangeEntry entry = (instance.getMatches().get(0)); entry.setSeparatorCommentPrecedes(true); @@ -122,9 +122,9 @@ public abstract class GenericRearranger { * @param prioritizedRules prioritized list of rules */ @SuppressWarnings({"StringContatenationInLoop"}) - private void matchPrioritizedRules(List prioritizedRules) { - for (IRuleInstance ruleInstance : prioritizedRules) { - final IRule rule = ruleInstance.getRule(); + private void matchPrioritizedRules(List prioritizedRules) { + for (RuleInstance ruleInstance : prioritizedRules) { + final Rule rule = ruleInstance.getRule(); final ListIterator entryIterator = entries.listIterator(); while (entryIterator.hasNext()) { final RangeEntry entry = (RangeEntry)entryIterator.next(); @@ -153,22 +153,22 @@ public abstract class GenericRearranger { * * @param prioritizedRuleInstances */ - private void buildRuleInstanceLists(final List prioritizedRuleInstances) { + private void buildRuleInstanceLists(final List prioritizedRuleInstances) { /** * add a HeaderTrailerRuleInstance to pick up any headers that might exist. */ - IRuleInstance hri = new HeaderRule().createRuleInstance(); - resultRuleInstances.add(hri); + RuleInstance hri = new HeaderRule().createRuleInstance(); + myResultRuleInstances.add(hri); prioritizedRuleInstances.add(hri); - for (IRule rule : rules) { - IRuleInstance instance = rule.createRuleInstance(); - resultRuleInstances.add(instance); + for (Rule rule : rules) { + RuleInstance instance = rule.createRuleInstance(); + myResultRuleInstances.add(instance); /** * now insert the rule instance into the prioritized list; highest priority first; stable insertion. */ boolean inserted = false; for (int i = prioritizedRuleInstances.size() - 1; i >= 0; i--) { - IRuleInstance entry = (prioritizedRuleInstances.get(i)); + RuleInstance entry = (prioritizedRuleInstances.get(i)); if (rule.getPriority() <= entry.getRule().getPriority()) { prioritizedRuleInstances.add(i + 1, instance); inserted = true; @@ -180,12 +180,12 @@ public abstract class GenericRearranger { } } // now add a default rule to pick up all unmatched items. - IRuleInstance defaultRuleInstance = new DefaultRule().createRuleInstance(); - resultRuleInstances.add(defaultRuleInstance); + RuleInstance defaultRuleInstance = new DefaultRule().createRuleInstance(); + myResultRuleInstances.add(defaultRuleInstance); prioritizedRuleInstances.add(defaultRuleInstance); // finally, add a TrailerRuleInstance to pick up any leftover text. - IRuleInstance tri = new TrailerRule().createRuleInstance(); - resultRuleInstances.add(tri); + RuleInstance tri = new TrailerRule().createRuleInstance(); + myResultRuleInstances.add(tri); prioritizedRuleInstances.add(tri); } @@ -197,6 +197,6 @@ public abstract class GenericRearranger { * @param rearrangedEntries */ public abstract void rearrangeRelatedItems(List entries, - List rearrangedEntries); + List rearrangedEntries); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java index 745099c43398..97c77425d617 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Mover.java @@ -22,7 +22,7 @@ package com.wrq.rearranger.rearrangement; import com.wrq.rearranger.entry.ClassContentsEntry; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import java.util.ArrayList; @@ -40,7 +40,7 @@ public final class Mover { this.settings = settings; } - public List rearrangeOuterClasses() { + public List rearrangeOuterClasses() { final GenericRearranger outerClassRearranger = new GenericRearranger( settings.getClassOrderAttributeList(), outerClasses, @@ -56,7 +56,7 @@ public final class Mover { @param rearrangedEntries */ public void rearrangeRelatedItems(List entries, - List rearrangedEntries) + List rearrangedEntries) { } }; diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java index 2e30b45d3161..a8493481dd7c 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommentRuleInstance.java @@ -23,11 +23,11 @@ package com.wrq.rearranger.ruleinstance; import com.wrq.rearranger.entry.ClassContentsEntry; import com.wrq.rearranger.entry.RangeEntry; -import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.FilePopupEntry; import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.settings.CommentRule; import com.wrq.rearranger.settings.RearrangerSettings; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -38,8 +38,8 @@ import java.util.List; /** Used to store a generated comment, and to determine if it should be emitted. */ public abstract class CommentRuleInstance - implements IRuleInstance, - IFilePopupEntry + implements RuleInstance, + FilePopupEntry { protected final CommentRule commentRule; protected boolean emit; @@ -57,12 +57,12 @@ public abstract class CommentRuleInstance this.emit = emit; } - public IRule getRule() { + public Rule getRule() { return commentRule; } /** Determine if this comment, in this instance, should be emitted. */ - public abstract void determineEmit(List resultRuleInstances, int startIndex); + public abstract void determineEmit(List resultRuleInstances, int startIndex); public boolean hasMatches() { return false; // a generated comment never matches any object @@ -152,7 +152,7 @@ public abstract class CommentRuleInstance * @return true if the match condition is met. */ @SuppressWarnings({"MethodParameterNamingConvention"}) - protected boolean match(final List resultRuleInstances, + protected boolean match(final List resultRuleInstances, final int nRules, final int direction, final int startIndex, @@ -167,7 +167,7 @@ public abstract class CommentRuleInstance if (!(resultRuleInstances.get(index) instanceof CommentRuleInstance)) { // this is a rule entry, not a comment. nRulesSeen++; - final IRuleInstance ruleInstance = resultRuleInstances.get(index); + final RuleInstance ruleInstance = resultRuleInstances.get(index); if (ruleInstance.hasMatches()) { if (!ANDing) { return true; // OR condition (any matching rule) met diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java index 4fa75c6bc511..502418ae4a7f 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/CommonRuleInstance.java @@ -26,12 +26,12 @@ import com.wrq.rearranger.entry.ClassContentsEntry; import com.wrq.rearranger.entry.IPopupTreeRangeEntry; import com.wrq.rearranger.entry.MethodEntry; import com.wrq.rearranger.entry.RangeEntry; -import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.FilePopupEntry; import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.settings.atomicAttributes.SortOptions; import com.wrq.rearranger.settings.attributeGroups.CommonAttributes; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; @@ -41,20 +41,21 @@ import java.util.List; /** Handles basic Rule functions. */ public abstract class CommonRuleInstance - implements IRuleInstance, - IFilePopupEntry + implements RuleInstance, + FilePopupEntry { private static final Logger LOG = Logger.getInstance("#" + CommonRuleInstance.class.getName()); - protected final IRule rule; + + protected final Rule myRule; protected final List matchedItems; - public CommonRuleInstance(IRule rule) { - this.rule = rule; + public CommonRuleInstance(Rule rule) { + myRule = rule; matchedItems = new ArrayList(); } - public IRule getRule() { - return rule; + public Rule getRule() { + return myRule; } /** @@ -63,8 +64,8 @@ public abstract class CommonRuleInstance * @param entry */ public void addEntry(RangeEntry entry) { - if (rule instanceof CommonAttributes) { - SortOptions sortOptions = ((CommonAttributes)rule).getSortAttr(); + if (myRule instanceof CommonAttributes) { + SortOptions sortOptions = ((CommonAttributes)myRule).getSortAttr(); insertionSort(entry, sortOptions); } else { diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java index deda68b4c640..c19f1c08e899 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/DefaultRuleInstance.java @@ -21,11 +21,11 @@ */ package com.wrq.rearranger.ruleinstance; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; /** Collects any remaining RangeEntries after all explicit rule matching is done. */ public class DefaultRuleInstance extends CommonRuleInstance { - public DefaultRuleInstance(IRule defaultRule) { + public DefaultRuleInstance(Rule defaultRule) { super(defaultRule); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java index 77f53e911e07..dfa9ce4802a6 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/EmitAlwaysCommentRuleInstance.java @@ -37,7 +37,7 @@ public class EmitAlwaysCommentRuleInstance * Determine if this comment, in this instance, should be emitted. * For an "Emit Always" type of comment, it should always be emitted. */ - public void determineEmit(List resultRuleInstances, int startIndex) { + public void determineEmit(List resultRuleInstances, int startIndex) { setEmit(true); } } diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java index 098215166840..677740beea2b 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/HeaderTrailerRuleInstance.java @@ -25,7 +25,7 @@ import com.wrq.rearranger.entry.ClassContentsEntry; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.settings.RearrangerSettings; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import javax.swing.tree.DefaultMutableTreeNode; import java.util.ArrayList; @@ -33,13 +33,13 @@ import java.util.List; /** Instance to pick up header text. */ public class HeaderTrailerRuleInstance - implements IRuleInstance + implements RuleInstance { - private final IRule rule; - private RangeEntry entry; + private final Rule myRule; + private RangeEntry myEntry; - public HeaderTrailerRuleInstance(IRule rule) { - this.rule = rule; + public HeaderTrailerRuleInstance(Rule rule) { + myRule = rule; } public boolean hasMatches() { @@ -48,34 +48,31 @@ public class HeaderTrailerRuleInstance public List getMatches() { List list = null; - if (entry != null) { + if (myEntry != null) { list = new ArrayList(); - list.add(entry); + list.add(myEntry); } return list; } - public IRule getRule() { - return rule; + public Rule getRule() { + return myRule; } public void addEntry(RangeEntry entry) { - this.entry = entry; // a header only has one entry + this.myEntry = entry; // a header only has one entry } public void emit(Emitter emitter) { - if (entry != null) { - entry.emit(emitter); + if (myEntry != null) { + myEntry.emit(emitter); } } - public void rearrangeRuleItems(List entries, - RearrangerSettings settings) - { - return; + public void rearrangeRuleItems(List entries, RearrangerSettings settings) { } public void addRuleInstanceToPopupTree(DefaultMutableTreeNode node, RearrangerSettings settings) { - return; // don't show header/trailer junk in popup tree + // don't show header/trailer junk in popup tree } } diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java index c227c5829fcd..a5c7b79cb9b9 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceInstance.java @@ -22,7 +22,7 @@ package com.wrq.rearranger.ruleinstance; import com.wrq.rearranger.entry.MethodEntry; -import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.FilePopupEntry; import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.settings.CommentRule; import com.wrq.rearranger.settings.RearrangerSettings; @@ -36,7 +36,7 @@ import java.util.List; /** Corresponds to a single interface with one or more implementing methods. */ public class InterfaceInstance - implements IFilePopupEntry + implements FilePopupEntry { // ------------------------------------------------------- FIELDS ------------------------------------------------------ diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java index db5ee379cdd2..6d084195fc03 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/InterfaceRuleInstance.java @@ -26,7 +26,7 @@ import com.wrq.rearranger.entry.MethodEntry; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.settings.RearrangerSettings; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import com.wrq.rearranger.settings.attributeGroups.InterfaceAttributes; import javax.swing.tree.DefaultMutableTreeNode; @@ -44,7 +44,7 @@ public class InterfaceRuleInstance // --------------------------- CONSTRUCTORS --------------------------- - public InterfaceRuleInstance(IRule rule) { + public InterfaceRuleInstance(Rule rule) { super(rule); interfaceInstances = new ArrayList(); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java index ba31eaf0c85a..5dea4fbd84d6 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/PrecedingCommentRuleInstance.java @@ -35,7 +35,7 @@ public class PrecedingCommentRuleInstance } /** Determine if this comment, in this instance, should be emitted. */ - public void determineEmit(List resultRuleInstances, int startIndex) { + public void determineEmit(List resultRuleInstances, int startIndex) { if (match( resultRuleInstances, commentRule.getnPrecedingRulesToMatch(), diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/IRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/RuleInstance.java similarity index 94% rename from plugins/rearranger/src/com/wrq/rearranger/ruleinstance/IRuleInstance.java rename to plugins/rearranger/src/com/wrq/rearranger/ruleinstance/RuleInstance.java index fd681e3cb13f..ab2e5772431d 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/IRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/RuleInstance.java @@ -25,7 +25,8 @@ import com.wrq.rearranger.entry.ClassContentsEntry; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.rearrangement.Emitter; import com.wrq.rearranger.settings.RearrangerSettings; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; +import org.jetbrains.annotations.Nullable; import javax.swing.tree.DefaultMutableTreeNode; import java.util.List; @@ -34,11 +35,12 @@ import java.util.List; * One RuleInstance exists for every execution of every rule. An execution of a rule is the process by which * items are matched to a rule. */ -public interface IRuleInstance { +public interface RuleInstance { /** @return true if one or more items matched the rule in this instance. */ boolean hasMatches(); /** @return list of items matching the rule in this instance. */ + @Nullable List getMatches(); /** @@ -49,7 +51,7 @@ public interface IRuleInstance { void emit(Emitter emitter); /** @return the rule associated with this instance. */ - IRule getRule(); + Rule getRule(); /** * Adds an item to the list of items matching the rule in this instance. Order is preserved. diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java index 89ddb0e99e3a..267706698450 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SubsequentCommentRuleInstance.java @@ -35,7 +35,7 @@ public class SubsequentCommentRuleInstance } /** Determine if this comment, in this instance, should be emitted. */ - public void determineEmit(List resultRuleInstances, int startIndex) { + public void determineEmit(List resultRuleInstances, int startIndex) { if (match( resultRuleInstances, commentRule.getnSubsequentRulesToMatch(), diff --git a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java index b5e379b9a3f6..33e90ff12e0a 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java +++ b/plugins/rearranger/src/com/wrq/rearranger/ruleinstance/SurroundingCommentRuleInstance.java @@ -35,7 +35,7 @@ public class SurroundingCommentRuleInstance } /** Determine if this comment, in this instance, should be emitted. */ - public void determineEmit(List resultRuleInstances, int startIndex) { + public void determineEmit(List resultRuleInstances, int startIndex) { if (match( resultRuleInstances, commentRule.getnPrecedingRulesToMatch(), diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java index dd871c0c69b7..4e8710cb489e 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/CommentRule.java @@ -23,10 +23,10 @@ package com.wrq.rearranger.settings; import com.wrq.rearranger.entry.IPopupTreeRangeEntry; import com.wrq.rearranger.entry.RangeEntry; -import com.wrq.rearranger.popup.IFilePopupEntry; +import com.wrq.rearranger.popup.FilePopupEntry; import com.wrq.rearranger.popup.RearrangerTreeNode; import com.wrq.rearranger.ruleinstance.CommentRuleInstanceFactory; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; import com.wrq.rearranger.settings.attributeGroups.RegexUtil; import com.wrq.rearranger.util.Constraints; @@ -51,7 +51,7 @@ import java.util.List; public final class CommentRule implements AttributeGroup, IPopupTreeRangeEntry, - IFilePopupEntry + FilePopupEntry { // ------------------------------------------------------- FIELDS ------------------------------------------------------ @@ -464,7 +464,7 @@ public final class CommentRule // -------------------------------------------------- Interface IRule -------------------------------------------------- - public IRuleInstance createRuleInstance() { + public RuleInstance createRuleInstance() { return CommentRuleInstanceFactory.buildCommentRuleInstance(this); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java index dc1bd8e3d3c9..3b39e9c046c8 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/AttributeGroup.java @@ -25,7 +25,7 @@ import org.jdom.Element; /** Methods implemented by rule objects, which are saved in configuration. */ public interface AttributeGroup - extends IRule + extends Rule { // -------------------------- OTHER METHODS -------------------------- diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java index d0f14db787e1..db6e98c257d5 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java @@ -23,7 +23,7 @@ package com.wrq.rearranger.settings.attributeGroups; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.ruleinstance.DefaultRuleInstance; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.settings.atomicAttributes.*; import org.jdom.Element; @@ -116,7 +116,7 @@ public abstract class CommonAttributes // --------------------- Interface IRule --------------------- - public IRuleInstance createRuleInstance() { + public RuleInstance createRuleInstance() { return new DefaultRuleInstance(this); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java index b33bbd6157e5..5310def3f88e 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/DefaultRule.java @@ -23,7 +23,7 @@ package com.wrq.rearranger.settings.attributeGroups; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.ruleinstance.DefaultRuleInstance; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import java.util.ArrayList; import java.util.List; @@ -33,9 +33,9 @@ import java.util.List; * constant (unparsed) text. */ public class DefaultRule - implements IRule + implements Rule { - public IRuleInstance createRuleInstance() { + public RuleInstance createRuleInstance() { return new DefaultRuleInstance(this); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java index 0d6f759ea2de..fe32d118e50f 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/HeaderRule.java @@ -23,16 +23,16 @@ package com.wrq.rearranger.settings.attributeGroups; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.ruleinstance.HeaderTrailerRuleInstance; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import java.util.ArrayList; import java.util.List; /** A rule to match header text (text which does not constitute a matchable item such as a field or method.) */ public class HeaderRule - implements IRule + implements Rule { - public IRuleInstance createRuleInstance() { + public RuleInstance createRuleInstance() { return new HeaderTrailerRuleInstance(this); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java index 78eb7e4ca1bd..afd6f5a09f73 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java @@ -23,7 +23,7 @@ package com.wrq.rearranger.settings.attributeGroups; import com.wrq.rearranger.entry.MethodEntry; import com.wrq.rearranger.entry.RangeEntry; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import com.wrq.rearranger.ruleinstance.InterfaceRuleInstance; import com.wrq.rearranger.settings.CommentFillString; import com.wrq.rearranger.settings.CommentRule; @@ -136,7 +136,7 @@ public class InterfaceAttributes return priority; } - public IRuleInstance createRuleInstance() { + public RuleInstance createRuleInstance() { return new InterfaceRuleInstance(this); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/Rule.java similarity index 95% rename from plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRule.java rename to plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/Rule.java index c6ff7952e6b8..7cffb45bad01 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IRule.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/Rule.java @@ -22,13 +22,13 @@ package com.wrq.rearranger.settings.attributeGroups; import com.wrq.rearranger.entry.RangeEntry; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import java.util.List; /** Interface which all rules implement. */ -public interface IRule { - IRuleInstance createRuleInstance(); +public interface Rule { + RuleInstance createRuleInstance(); // all rules have a priority; but some are not settable by the user. Those that are user settable implement // the marker interface IPrioritizableRule. diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java index 388c92f79896..b7d42af98487 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/TrailerRule.java @@ -23,16 +23,16 @@ package com.wrq.rearranger.settings.attributeGroups; import com.wrq.rearranger.entry.RangeEntry; import com.wrq.rearranger.ruleinstance.HeaderTrailerRuleInstance; -import com.wrq.rearranger.ruleinstance.IRuleInstance; +import com.wrq.rearranger.ruleinstance.RuleInstance; import java.util.ArrayList; import java.util.List; /** A rule to match header text (text which does not constitute a matchable item such as a field or method.) */ public class TrailerRule - implements IRule + implements Rule { - public IRuleInstance createRuleInstance() { + public RuleInstance createRuleInstance() { return new HeaderTrailerRuleInstance(this); } diff --git a/plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java b/plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java index 64ade9ae3e29..2ba03562ded4 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java +++ b/plugins/rearranger/src/com/wrq/rearranger/util/CommentUtil.java @@ -22,7 +22,7 @@ package com.wrq.rearranger.util; import com.wrq.rearranger.settings.RearrangerSettings; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import java.util.ArrayList; import java.util.List; @@ -123,10 +123,10 @@ public class CommentUtil { private void createCommentPatternList() { commentStrings = new ArrayList(); - for (IRule rule : settings.getClassOrderAttributeList()) { + for (Rule rule : settings.getClassOrderAttributeList()) { rule.addCommentPatternsToList(commentStrings); } - for (IRule rule : settings.getItemOrderAttributeList()) { + for (Rule rule : settings.getItemOrderAttributeList()) { rule.addCommentPatternsToList(commentStrings); } settings.getExtractedMethodsSettings().addCommentPatternsToList(commentStrings); diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java b/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java index a8c6653d1ad2..39504e136a23 100644 --- a/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java +++ b/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java @@ -28,7 +28,7 @@ import com.intellij.testFramework.LightCodeInsightTestCase; import com.wrq.rearranger.configuration.RearrangerSettingsPanel; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.settings.attributeGroups.IPrioritizableRule; -import com.wrq.rearranger.settings.attributeGroups.IRule; +import com.wrq.rearranger.settings.attributeGroups.Rule; import com.wrq.rearranger.util.Constraints; import org.apache.log4j.Level; import org.apache.log4j.Logger; @@ -143,7 +143,7 @@ public class InteractiveTest ListIterator li; for (Object o : object.settings.getClassOrderAttributeList()) { if (o instanceof IPrioritizableRule) { - System.out.println(o + ", pri=" + ((IRule)o).getPriority()); + System.out.println(o + ", pri=" + ((Rule)o).getPriority()); } else { System.out.println(o); @@ -152,7 +152,7 @@ public class InteractiveTest System.out.println("Item order"); for (Object o : object.settings.getItemOrderAttributeList()) { if (o instanceof IPrioritizableRule) { - System.out.println(o + ", pri=" + ((IRule)o).getPriority()); + System.out.println(o + ", pri=" + ((Rule)o).getPriority()); } else { System.out.println(o); From 32e9e62430b70b7ff12d22d04fad3defdcd137f9 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 14 May 2012 13:09:05 +0400 Subject: [PATCH 35/67] IDEA-19061 Integrate the Rearranger-plugin into core-IDEA *) green code policy; *) naming convention for the RearrangerSettings fields; --- .../rearranger/configuration/SpacingPane.java | 2 +- .../wrq/rearranger/rearrangement/Spacer.java | 4 +- .../settings/RearrangerSettings.java | 487 ++++++++++-------- .../rearranger/util/RearrangerConstants.java | 16 + 4 files changed, 279 insertions(+), 230 deletions(-) create mode 100644 plugins/rearranger/src/com/wrq/rearranger/util/RearrangerConstants.java diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java index 1e92633e5ec5..070b511ce1d6 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/SpacingPane.java @@ -70,7 +70,7 @@ public class SpacingPane { constraints.newRow(); panel.add(getForceBlankLinePanel(settings.getAfterMethodRBrace()), constraints.weightedLastCol()); constraints.newRow(); - panel.add(getForceBlankLinePanel(settings.getNewlinesAtEOF()), constraints.weightedLastCol()); + panel.add(getForceBlankLinePanel(settings.getNewLinesAtEOF()), constraints.weightedLastCol()); constraints.weightedLastRow(); final JCheckBox insideBlockBox = new JCheckBox("Remove initial and final blank lines inside code block"); insideBlockBox.setSelected(settings.isRemoveBlanksInsideCodeBlocks()); diff --git a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java index b8d5c0f11872..0158aff9e423 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java +++ b/plugins/rearranger/src/com/wrq/rearranger/rearrangement/Spacer.java @@ -106,12 +106,12 @@ public class Spacer { public void visitFile(PsiFile psiFile) { super.visitFile(psiFile); - if (settings.getNewlinesAtEOF().isForce()) { + if (settings.getNewLinesAtEOF().isForce()) { // remove all newlines at end of file, then append as many as are declared in configuration. while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '\n') { sb.setLength(sb.length() - 1); } - for (int count = 0; count < settings.getNewlinesAtEOF().getnBlankLines(); count++) { + for (int count = 0; count < settings.getNewLinesAtEOF().getnBlankLines(); count++) { sb.append('\n'); } } diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java b/plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java index e302e62076c2..6474abaed387 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/RearrangerSettings.java @@ -27,6 +27,7 @@ import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; import com.wrq.rearranger.settings.attributeGroups.ClassAttributes; import com.wrq.rearranger.settings.attributeGroups.GetterSetterDefinition; import com.wrq.rearranger.settings.attributeGroups.ItemAttributes; +import com.wrq.rearranger.util.RearrangerConstants; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; @@ -34,6 +35,7 @@ import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; +import org.jetbrains.annotations.Nullable; import java.io.*; import java.net.URL; @@ -51,39 +53,39 @@ public final class RearrangerSettings { // ------------------------------ FIELDS ------------------------------ // BEGINNING OF FIELDS - private static final Logger logger = Logger.getInstance("#" + RearrangerSettings.class.getName()); + private static final Logger LOG = Logger.getInstance("#" + RearrangerSettings.class.getName()); public static final int OVERLOADED_ORDER_RETAIN_ORIGINAL = 0; public static final int OVERLOADED_ORDER_ASCENDING_PARAMETERS = 1; public static final int OVERLOADED_ORDER_DESCENDING_PARAMETERS = 2; - private final List itemOrderAttributeList; - private final List classOrderAttributeList; - private RelatedMethodsSettings relatedMethodsSettings; - private boolean keepGettersSettersTogether; - private boolean keepGettersSettersWithProperty; - private boolean keepOverloadedMethodsTogether; - private String globalCommentPattern; - private boolean askBeforeRearranging; - private boolean rearrangeInnerClasses; - private boolean showParameterTypes; - private boolean showParameterNames; - private boolean showFields; - private boolean showTypeAfterMethod; - private boolean showRules; - private boolean showMatchedRules; - private boolean showComments; - private ForceBlankLineSetting afterClassLBrace; - private ForceBlankLineSetting afterClassRBrace; - private ForceBlankLineSetting beforeClassRBrace; - private ForceBlankLineSetting beforeMethodLBrace; - private ForceBlankLineSetting afterMethodLBrace; - private ForceBlankLineSetting afterMethodRBrace; - private ForceBlankLineSetting beforeMethodRBrace; - private boolean removeBlanksInsideCodeBlocks; - private ForceBlankLineSetting newlinesAtEOF; - private int overloadedOrder; - private GetterSetterDefinition defaultGSDefinition; - private List primaryMethodList; + private final List myItemOrderAttributeList; + private final List myClassOrderAttributeList; + private RelatedMethodsSettings myRelatedMethodsSettings; + private boolean myKeepGettersSettersTogether; + private boolean myKeepGettersSettersWithProperty; + private boolean myKeepOverloadedMethodsTogether; + private String myGlobalCommentPattern; + private boolean myAskBeforeRearranging; + private boolean myRearrangeInnerClasses; + private boolean myShowParameterTypes; + private boolean myShowParameterNames; + private boolean myShowFields; + private boolean myShowTypeAfterMethod; + private boolean myShowRules; + private boolean myShowMatchedRules; + private boolean myShowComments; + private ForceBlankLineSetting myAfterClassLBrace; + private ForceBlankLineSetting myAfterClassRBrace; + private ForceBlankLineSetting myBeforeClassRBrace; + private ForceBlankLineSetting beforeMethodLBrace; + private ForceBlankLineSetting myAfterMethodLBrace; + private ForceBlankLineSetting myAfterMethodRBrace; + private ForceBlankLineSetting myBeforeMethodRBrace; + private boolean myRemoveBlanksInsideCodeBlocks; + private ForceBlankLineSetting myNewLinesAtEOF; + private int myOverloadedOrder; + private GetterSetterDefinition myDefaultGSDefinition; + private List myPrimaryMethodList; // -------------------------- STATIC METHODS -------------------------- @@ -95,20 +97,28 @@ public final class RearrangerSettings { return getBooleanAttribute(me, attr, false); } - public static RearrangerSettings getDefaultSettings() { - logger.debug("enter loadDefaultSettings"); - URL settingsURL = Rearranger.class.getClassLoader().getResource("com/wrq/rearranger/defaultConfiguration.xml"); - logger.debug("settings URL=" + settingsURL.getFile()); + @Nullable + public static RearrangerSettings getDefaultSettings() throws IllegalStateException { + LOG.debug("enter loadDefaultSettings"); + URL settingsURL = Rearranger.class.getClassLoader().getResource(RearrangerConstants.DEFAULT_CONFIG_PATH); + if (settingsURL == null) { + throw new IllegalStateException(String.format( + "Can't find default configuration (tried path '%s'", + RearrangerConstants.DEFAULT_CONFIG_PATH + )); + } + LOG.debug("settings URL=" + settingsURL.getFile()); try { InputStream is = settingsURL.openStream(); return getSettingsFromStream(is); } catch (IOException e) { - logger.debug("getDefaultSettings:" + e); + LOG.debug("getDefaultSettings:" + e); return null; } } - + + @Nullable public static RearrangerSettings getSettingsFromStream(InputStream is) { Document document = null; try { @@ -116,34 +126,32 @@ public final class RearrangerSettings { document = builder.build(is); } catch (JDOMException jde) { - logger.debug("JDOM exception building document:" + jde); + LOG.debug("JDOM exception building document:" + jde); return null; } catch (IOException e) { - logger.debug("I/O exception building document:" + e); + LOG.debug("I/O exception building document:" + e); return null; } finally { + if (is != null) { try { is.close(); } catch (IOException e) { + // Do nothing } } } Element app = document.getRootElement(); Element component = null; if (app.getName().equals("application")) { - ListIterator li = app.getChildren().listIterator(); - while (li.hasNext()) -// for (Element child : (List)((java.util.List)app.getChildren())) - { - Element child = (Element)li.next(); + for (Object o : app.getChildren()) { + Element child = (Element)o; if (child.getName().equals("component") && child.getAttribute("name") != null && - child.getAttribute("name").getValue().equals(Rearranger.COMPONENT_NAME)) - { + child.getAttribute("name").getValue().equals(Rearranger.COMPONENT_NAME)) { component = child; break; } @@ -184,46 +192,47 @@ public final class RearrangerSettings { // for (Element element : itemList) { Element element = (Element)li.next(); - itemOrderAttributeList.add(((com.wrq.rearranger.settings.attributeGroups.AttributeGroup)ItemAttributes.readExternal(element))); + myItemOrderAttributeList.add(ItemAttributes.readExternal(element)); } li = classList.listIterator(); // for (Element element : classList) while (li.hasNext()) { Element element = (Element)li.next(); - classOrderAttributeList.add(((com.wrq.rearranger.settings.attributeGroups.AttributeGroup)ClassAttributes.readExternal(element))); + myClassOrderAttributeList.add(ClassAttributes.readExternal(element)); } final Element gsd = entry.getChild("DefaultGetterSetterDefinition"); - defaultGSDefinition = GetterSetterDefinition.readExternal(gsd); + myDefaultGSDefinition = GetterSetterDefinition.readExternal(gsd); final Element relatedItems = entry.getChild("RelatedMethods"); - relatedMethodsSettings = RelatedMethodsSettings.readExternal(relatedItems); - keepGettersSettersTogether = getBooleanAttribute(entry, "KeepGettersSettersTogether", true); - keepGettersSettersWithProperty = getBooleanAttribute(entry, "KeepGettersSettersWithProperty", false); - keepOverloadedMethodsTogether = getBooleanAttribute(entry, "KeepOverloadedMethodsTogether", true); - final Attribute attr = RearrangerSettings.getAttribute(entry, "globalCommentPattern"); - askBeforeRearranging = getBooleanAttribute(entry, "ConfirmBeforeRearranging", false); - rearrangeInnerClasses = getBooleanAttribute(entry, "RearrangeInnerClasses", false); - globalCommentPattern = (attr == null ? "" : ((java.lang.String)attr.getValue())); - overloadedOrder = getIntAttribute(entry, "overloadedOrder", OVERLOADED_ORDER_RETAIN_ORIGINAL); - showParameterTypes = getBooleanAttribute(entry, "ShowParameterTypes", true); - showParameterNames = getBooleanAttribute(entry, "ShowParameterNames", true); - showFields = getBooleanAttribute(entry, "ShowFields", true); - showRules = getBooleanAttribute(entry, "ShowRules", false); - showMatchedRules = getBooleanAttribute(entry, "ShowMatchedRules", false); - showComments = getBooleanAttribute(entry, "ShowComments", false); - showTypeAfterMethod = getBooleanAttribute(entry, "ShowTypeAfterMethod", true); - removeBlanksInsideCodeBlocks = getBooleanAttribute(entry, "RemoveBlanksInsideCodeBlocks", false); - afterClassLBrace = ForceBlankLineSetting.readExternal(entry, false, true, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassLBrace"); - afterClassRBrace = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassRBrace"); - beforeClassRBrace = ForceBlankLineSetting.readExternal(entry, true, false, ForceBlankLineSetting.CLASS_OBJECT, "BeforeClassRBrace"); + myRelatedMethodsSettings = RelatedMethodsSettings.readExternal(relatedItems); + myKeepGettersSettersTogether = getBooleanAttribute(entry, "KeepGettersSettersTogether", true); + myKeepGettersSettersWithProperty = getBooleanAttribute(entry, "KeepGettersSettersWithProperty", false); + myKeepOverloadedMethodsTogether = getBooleanAttribute(entry, "KeepOverloadedMethodsTogether", true); + final Attribute attr = getAttribute(entry, "globalCommentPattern"); + myAskBeforeRearranging = getBooleanAttribute(entry, "ConfirmBeforeRearranging", false); + myRearrangeInnerClasses = getBooleanAttribute(entry, "RearrangeInnerClasses", false); + myGlobalCommentPattern = (attr == null ? "" : attr.getValue()); + myOverloadedOrder = getIntAttribute(entry, "overloadedOrder", OVERLOADED_ORDER_RETAIN_ORIGINAL); + myShowParameterTypes = getBooleanAttribute(entry, "ShowParameterTypes", true); + myShowParameterNames = getBooleanAttribute(entry, "ShowParameterNames", true); + myShowFields = getBooleanAttribute(entry, "ShowFields", true); + myShowRules = getBooleanAttribute(entry, "ShowRules", false); + myShowMatchedRules = getBooleanAttribute(entry, "ShowMatchedRules", false); + myShowComments = getBooleanAttribute(entry, "ShowComments", false); + myShowTypeAfterMethod = getBooleanAttribute(entry, "ShowTypeAfterMethod", true); + myRemoveBlanksInsideCodeBlocks = getBooleanAttribute(entry, "RemoveBlanksInsideCodeBlocks", false); + myAfterClassLBrace = ForceBlankLineSetting.readExternal(entry, false, true, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassLBrace"); + myAfterClassRBrace = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassRBrace"); + myBeforeClassRBrace = ForceBlankLineSetting.readExternal(entry, true, false, ForceBlankLineSetting.CLASS_OBJECT, "BeforeClassRBrace"); beforeMethodLBrace = ForceBlankLineSetting.readExternal(entry, true, true, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodLBrace"); - afterMethodLBrace = ForceBlankLineSetting.readExternal(entry, false, true, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodLBrace"); - afterMethodRBrace = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodRBrace"); - beforeMethodRBrace = ForceBlankLineSetting.readExternal(entry, true, false, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodRBrace"); - newlinesAtEOF = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.EOF_OBJECT, "NewlinesAtEOF"); + myAfterMethodLBrace = ForceBlankLineSetting.readExternal(entry, false, true, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodLBrace"); + myAfterMethodRBrace = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodRBrace"); + myBeforeMethodRBrace = ForceBlankLineSetting.readExternal(entry, true, false, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodRBrace"); + myNewLinesAtEOF = ForceBlankLineSetting.readExternal(entry, false, false, ForceBlankLineSetting.EOF_OBJECT, "NewlinesAtEOF"); } // Level 2 methods + @Nullable static public Attribute getAttribute(Element element, String attributeName) { if (element == null) return null; return element.getAttribute(attributeName); @@ -248,12 +257,24 @@ public final class RearrangerSettings { return (r.equalsIgnoreCase("true")); } + @Nullable public static RearrangerSettings getSettingsFromFile(File f) { try { - return getSettingsFromStream(new FileInputStream(f)); + final FileInputStream stream = new FileInputStream(f); + try { + return getSettingsFromStream(stream); + } + finally { + try { + stream.close(); + } + catch (IOException e) { + // Ignore. + } + } } catch (FileNotFoundException e) { - logger.debug("getSettingsFromFile:" + e); + LOG.debug("getSettingsFromFile:" + e); } return null; } @@ -262,44 +283,44 @@ public final class RearrangerSettings { // END OF ALL FIELDS public RearrangerSettings() { - itemOrderAttributeList = new ArrayList(); - classOrderAttributeList = new ArrayList(); - relatedMethodsSettings = new RelatedMethodsSettings(); - keepGettersSettersTogether = false; - keepGettersSettersWithProperty = false; - keepOverloadedMethodsTogether = false; - globalCommentPattern = ""; - overloadedOrder = OVERLOADED_ORDER_RETAIN_ORIGINAL; - askBeforeRearranging = false; - rearrangeInnerClasses = false; - showParameterTypes = true; - showParameterNames = false; - showFields = true; - showTypeAfterMethod = true; - showRules = false; - showMatchedRules = false; - showComments = false; - removeBlanksInsideCodeBlocks = false; - afterClassLBrace = new ForceBlankLineSetting(false, true, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassLBrace"); - afterClassRBrace = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassRBrace"); - beforeClassRBrace = new ForceBlankLineSetting(true, false, ForceBlankLineSetting.CLASS_OBJECT, "BeforeClassRBrace"); + myItemOrderAttributeList = new ArrayList(); + myClassOrderAttributeList = new ArrayList(); + myRelatedMethodsSettings = new RelatedMethodsSettings(); + myKeepGettersSettersTogether = false; + myKeepGettersSettersWithProperty = false; + myKeepOverloadedMethodsTogether = false; + myGlobalCommentPattern = ""; + myOverloadedOrder = OVERLOADED_ORDER_RETAIN_ORIGINAL; + myAskBeforeRearranging = false; + myRearrangeInnerClasses = false; + myShowParameterTypes = true; + myShowParameterNames = false; + myShowFields = true; + myShowTypeAfterMethod = true; + myShowRules = false; + myShowMatchedRules = false; + myShowComments = false; + myRemoveBlanksInsideCodeBlocks = false; + myAfterClassLBrace = new ForceBlankLineSetting(false, true, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassLBrace"); + myAfterClassRBrace = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.CLASS_OBJECT, "AfterClassRBrace"); + myBeforeClassRBrace = new ForceBlankLineSetting(true, false, ForceBlankLineSetting.CLASS_OBJECT, "BeforeClassRBrace"); beforeMethodLBrace = new ForceBlankLineSetting(true, true, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodLBrace"); - afterMethodLBrace = new ForceBlankLineSetting(false, true, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodLBrace"); - beforeMethodRBrace = new ForceBlankLineSetting(true, false, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodRBrace"); - afterMethodRBrace = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodRBrace"); - newlinesAtEOF = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.EOF_OBJECT, "NewlinesAtEOF"); - defaultGSDefinition = new GetterSetterDefinition(); - primaryMethodList = new LinkedList(); + myAfterMethodLBrace = new ForceBlankLineSetting(false, true, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodLBrace"); + myBeforeMethodRBrace = new ForceBlankLineSetting(true, false, ForceBlankLineSetting.METHOD_OBJECT, "BeforeMethodRBrace"); + myAfterMethodRBrace = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.METHOD_OBJECT, "AfterMethodRBrace"); + myNewLinesAtEOF = new ForceBlankLineSetting(false, false, ForceBlankLineSetting.EOF_OBJECT, "NewlinesAtEOF"); + myDefaultGSDefinition = new GetterSetterDefinition(); + myPrimaryMethodList = new LinkedList(); } // --------------------- GETTER / SETTER METHODS --------------------- public ForceBlankLineSetting getAfterClassLBrace() { - return afterClassLBrace; + return myAfterClassLBrace; } public ForceBlankLineSetting getAfterClassRBrace() { - return afterClassRBrace; + return myAfterClassRBrace; } public ForceBlankLineSetting getBeforeMethodLBrace() { @@ -307,123 +328,123 @@ public final class RearrangerSettings { } public ForceBlankLineSetting getAfterMethodLBrace() { - return afterMethodLBrace; + return myAfterMethodLBrace; } public ForceBlankLineSetting getAfterMethodRBrace() { - return afterMethodRBrace; + return myAfterMethodRBrace; } public ForceBlankLineSetting getBeforeClassRBrace() { - return beforeClassRBrace; + return myBeforeClassRBrace; } public ForceBlankLineSetting getBeforeMethodRBrace() { - return beforeMethodRBrace; + return myBeforeMethodRBrace; } public final List getClassOrderAttributeList() { - return classOrderAttributeList; + return myClassOrderAttributeList; } public GetterSetterDefinition getDefaultGSDefinition() { - return defaultGSDefinition; + return myDefaultGSDefinition; } // Level 1 methods public String getGlobalCommentPattern() { - return globalCommentPattern; + return myGlobalCommentPattern; } // Level 2 methods public void setGlobalCommentPattern(String globalCommentPattern) { - this.globalCommentPattern = globalCommentPattern; + this.myGlobalCommentPattern = globalCommentPattern; } // end of Level 2 methods // end of Level 1 methods public final List getItemOrderAttributeList() { - return itemOrderAttributeList; + return myItemOrderAttributeList; } - public ForceBlankLineSetting getNewlinesAtEOF() { - return newlinesAtEOF; + public ForceBlankLineSetting getNewLinesAtEOF() { + return myNewLinesAtEOF; } // Level 1 methods public int getOverloadedOrder() { - return overloadedOrder; + return myOverloadedOrder; } // Level 2 methods public void setOverloadedOrder(int overloadedOrder) { - this.overloadedOrder = overloadedOrder; + this.myOverloadedOrder = overloadedOrder; } // end of Level 2 methods // end of Level 1 methods public RelatedMethodsSettings getExtractedMethodsSettings() { - return relatedMethodsSettings; + return myRelatedMethodsSettings; } // Level 1 methods public boolean isAskBeforeRearranging() { - return askBeforeRearranging; + return myAskBeforeRearranging; } // Level 2 methods public void setAskBeforeRearranging(boolean askBeforeRearranging) { - this.askBeforeRearranging = askBeforeRearranging; + this.myAskBeforeRearranging = askBeforeRearranging; } public boolean isKeepGettersSettersTogether() { - return keepGettersSettersTogether; + return myKeepGettersSettersTogether; } // Level 2 methods public void setKeepGettersSettersTogether(boolean keepGettersSettersTogether) { - this.keepGettersSettersTogether = keepGettersSettersTogether; + this.myKeepGettersSettersTogether = keepGettersSettersTogether; } public boolean isKeepGettersSettersWithProperty() { - return keepGettersSettersWithProperty; + return myKeepGettersSettersWithProperty; } public void setKeepGettersSettersWithProperty(boolean keepGettersSettersWithProperty) { - this.keepGettersSettersWithProperty = keepGettersSettersWithProperty; + this.myKeepGettersSettersWithProperty = keepGettersSettersWithProperty; } // end of Level 2 methods // end of Level 1 methods // Level 1 methods public boolean isKeepOverloadedMethodsTogether() { - return keepOverloadedMethodsTogether; + return myKeepOverloadedMethodsTogether; } // Level 2 methods public void setKeepOverloadedMethodsTogether(boolean keepOverloadedMethodsTogether) { - this.keepOverloadedMethodsTogether = keepOverloadedMethodsTogether; + this.myKeepOverloadedMethodsTogether = keepOverloadedMethodsTogether; } // end of Level 2 methods // end of Level 1 methods // Level 1 methods public boolean isRearrangeInnerClasses() { - return rearrangeInnerClasses; + return myRearrangeInnerClasses; } public void setRearrangeInnerClasses(boolean rearrangeInnerClasses) { - this.rearrangeInnerClasses = rearrangeInnerClasses; + this.myRearrangeInnerClasses = rearrangeInnerClasses; } // end of Level 2 methods @@ -431,21 +452,21 @@ public final class RearrangerSettings { // Level 1 methods public boolean isRemoveBlanksInsideCodeBlocks() { - return removeBlanksInsideCodeBlocks; + return myRemoveBlanksInsideCodeBlocks; } // Level 2 methods public void setRemoveBlanksInsideCodeBlocks(boolean removeBlanksInsideCodeBlocks) { - this.removeBlanksInsideCodeBlocks = removeBlanksInsideCodeBlocks; + this.myRemoveBlanksInsideCodeBlocks = removeBlanksInsideCodeBlocks; } public boolean isShowComments() { - return showComments; + return myShowComments; } public void setShowComments(boolean showComments) { - this.showComments = showComments; + this.myShowComments = showComments; } // end of Level 2 methods @@ -453,31 +474,31 @@ public final class RearrangerSettings { // Level 1 methods public boolean isShowFields() { - return showFields; + return myShowFields; } // Level 2 methods public void setShowFields(boolean showFields) { - this.showFields = showFields; + this.myShowFields = showFields; } public boolean isShowMatchedRules() { - return showMatchedRules; + return myShowMatchedRules; } public void setShowMatchedRules(boolean showMatchedRules) { - this.showMatchedRules = showMatchedRules; + this.myShowMatchedRules = showMatchedRules; } public boolean isShowParameterNames() { - return showParameterNames; + return myShowParameterNames; } // Level 2 methods public void setShowParameterNames(boolean showParameterNames) { - this.showParameterNames = showParameterNames; + this.myShowParameterNames = showParameterNames; } // end of Level 2 methods @@ -485,34 +506,34 @@ public final class RearrangerSettings { // Level 1 methods public boolean isShowParameterTypes() { - return showParameterTypes; + return myShowParameterTypes; } // Level 2 methods public void setShowParameterTypes(boolean showParameterTypes) { - this.showParameterTypes = showParameterTypes; + this.myShowParameterTypes = showParameterTypes; } // end of Level 2 methods // end of Level 1 methods // Level 1 methods public boolean isShowRules() { - return showRules; + return myShowRules; } public void setShowRules(boolean showRules) { - this.showRules = showRules; + this.myShowRules = showRules; } // end of Level 2 methods // end of Level 1 methods public boolean isShowTypeAfterMethod() { - return showTypeAfterMethod; + return myShowTypeAfterMethod; } public void setShowTypeAfterMethod(boolean showTypeAfterMethod) { - this.showTypeAfterMethod = showTypeAfterMethod; + this.myShowTypeAfterMethod = showTypeAfterMethod; } // ------------------------ CANONICAL METHODS ------------------------ @@ -532,31 +553,31 @@ public final class RearrangerSettings { if (rs.isKeepGettersSettersTogether() != isKeepGettersSettersTogether()) return false; if (rs.isKeepGettersSettersWithProperty() != isKeepGettersSettersWithProperty()) return false; if (rs.isKeepOverloadedMethodsTogether() != isKeepOverloadedMethodsTogether()) return false; - if (rs.overloadedOrder != overloadedOrder) return false; - if (!rs.globalCommentPattern.equals(globalCommentPattern)) return false; - if (rs.askBeforeRearranging != askBeforeRearranging) return false; - if (rs.rearrangeInnerClasses != rearrangeInnerClasses) return false; - if (rs.showParameterTypes != showParameterTypes) return false; - if (rs.showParameterNames != showParameterNames) return false; - if (rs.showFields != showFields) return false; - if (rs.showTypeAfterMethod != showTypeAfterMethod) return false; - if (rs.showRules != showRules) return false; - if (rs.showMatchedRules != showMatchedRules) return false; - if (rs.showComments != showComments) return false; - if (rs.removeBlanksInsideCodeBlocks != removeBlanksInsideCodeBlocks) return false; - if (!rs.afterClassLBrace.equals(afterClassLBrace)) return false; - if (!rs.afterClassRBrace.equals(afterClassRBrace)) return false; - if (!rs.beforeClassRBrace.equals(beforeClassRBrace)) return false; + if (rs.myOverloadedOrder != myOverloadedOrder) return false; + if (!rs.myGlobalCommentPattern.equals(myGlobalCommentPattern)) return false; + if (rs.myAskBeforeRearranging != myAskBeforeRearranging) return false; + if (rs.myRearrangeInnerClasses != myRearrangeInnerClasses) return false; + if (rs.myShowParameterTypes != myShowParameterTypes) return false; + if (rs.myShowParameterNames != myShowParameterNames) return false; + if (rs.myShowFields != myShowFields) return false; + if (rs.myShowTypeAfterMethod != myShowTypeAfterMethod) return false; + if (rs.myShowRules != myShowRules) return false; + if (rs.myShowMatchedRules != myShowMatchedRules) return false; + if (rs.myShowComments != myShowComments) return false; + if (rs.myRemoveBlanksInsideCodeBlocks != myRemoveBlanksInsideCodeBlocks) return false; + if (!rs.myAfterClassLBrace.equals(myAfterClassLBrace)) return false; + if (!rs.myAfterClassRBrace.equals(myAfterClassRBrace)) return false; + if (!rs.myBeforeClassRBrace.equals(myBeforeClassRBrace)) return false; if (!rs.beforeMethodLBrace.equals(beforeMethodLBrace)) return false; - if (!rs.afterMethodLBrace.equals(afterMethodLBrace)) return false; - if (!rs.afterMethodRBrace.equals(afterMethodRBrace)) return false; - if (!rs.beforeMethodRBrace.equals(beforeMethodRBrace)) return false; - if (!rs.newlinesAtEOF.equals(newlinesAtEOF)) return false; - if (!rs.defaultGSDefinition.equals(defaultGSDefinition)) return false; - if (primaryMethodList.size() != rs.primaryMethodList.size()) return false; - for (int i = 0; i < primaryMethodList.size(); i++) { - PrimaryMethodSetting pms = primaryMethodList.get(i); - PrimaryMethodSetting rspms = rs.primaryMethodList.get(i); + if (!rs.myAfterMethodLBrace.equals(myAfterMethodLBrace)) return false; + if (!rs.myAfterMethodRBrace.equals(myAfterMethodRBrace)) return false; + if (!rs.myBeforeMethodRBrace.equals(myBeforeMethodRBrace)) return false; + if (!rs.myNewLinesAtEOF.equals(myNewLinesAtEOF)) return false; + if (!rs.myDefaultGSDefinition.equals(myDefaultGSDefinition)) return false; + if (myPrimaryMethodList.size() != rs.myPrimaryMethodList.size()) return false; + for (int i = 0; i < myPrimaryMethodList.size(); i++) { + PrimaryMethodSetting pms = myPrimaryMethodList.get(i); + PrimaryMethodSetting rspms = rs.myPrimaryMethodList.get(i); if (!rspms.equals(pms)) return false; } return true; @@ -565,59 +586,60 @@ public final class RearrangerSettings { // -------------------------- OTHER METHODS -------------------------- public final void addClass(final AttributeGroup ca, final int index) { - if (classOrderAttributeList.size() < index) { - classOrderAttributeList.add(ca); + if (myClassOrderAttributeList.size() < index) { + myClassOrderAttributeList.add(ca); } else { - classOrderAttributeList.add(index, ca); + myClassOrderAttributeList.add(index, ca); } } public final void addItem(final AttributeGroup ia, final int index) { - if (itemOrderAttributeList.size() < index) { - itemOrderAttributeList.add(ia); + if (myItemOrderAttributeList.size() < index) { + myItemOrderAttributeList.add(ia); } else { - itemOrderAttributeList.add(index, ia); + myItemOrderAttributeList.add(index, ia); } } public final RearrangerSettings deepCopy() { final RearrangerSettings result = new RearrangerSettings(); - for (AttributeGroup itemAttributes : itemOrderAttributeList) { - result.itemOrderAttributeList.add(itemAttributes.deepCopy()); + for (AttributeGroup itemAttributes : myItemOrderAttributeList) { + result.myItemOrderAttributeList.add(itemAttributes.deepCopy()); } - for (AttributeGroup classAttributes : classOrderAttributeList) { - result.classOrderAttributeList.add(classAttributes.deepCopy()); + for (AttributeGroup classAttributes : myClassOrderAttributeList) { + result.myClassOrderAttributeList.add(classAttributes.deepCopy()); } - result.relatedMethodsSettings = relatedMethodsSettings.deepCopy(); - result.keepGettersSettersTogether = keepGettersSettersTogether; - result.keepGettersSettersWithProperty = keepGettersSettersWithProperty; - result.keepOverloadedMethodsTogether = keepOverloadedMethodsTogether; - result.globalCommentPattern = globalCommentPattern; - result.overloadedOrder = overloadedOrder; - result.askBeforeRearranging = askBeforeRearranging; - result.rearrangeInnerClasses = rearrangeInnerClasses; - result.showParameterNames = showParameterNames; - result.showParameterTypes = showParameterTypes; - result.showFields = showFields; - result.showTypeAfterMethod = showTypeAfterMethod; - result.showRules = showRules; - result.showMatchedRules = showMatchedRules; - result.showComments = showComments; - result.removeBlanksInsideCodeBlocks = removeBlanksInsideCodeBlocks; - result.afterClassLBrace = afterClassLBrace.deepCopy(); - result.afterClassRBrace = afterClassRBrace.deepCopy(); - result.beforeClassRBrace = beforeClassRBrace.deepCopy(); + result.myRelatedMethodsSettings = myRelatedMethodsSettings.deepCopy(); + result.myKeepGettersSettersTogether = myKeepGettersSettersTogether; + result.myKeepGettersSettersWithProperty = myKeepGettersSettersWithProperty; + result.myKeepOverloadedMethodsTogether = myKeepOverloadedMethodsTogether; + result.myGlobalCommentPattern = myGlobalCommentPattern; + result.myOverloadedOrder = myOverloadedOrder; + result.myAskBeforeRearranging = myAskBeforeRearranging; + result.myRearrangeInnerClasses = myRearrangeInnerClasses; + result.myShowParameterNames = myShowParameterNames; + result.myShowParameterTypes = myShowParameterTypes; + result.myShowFields = myShowFields; + result.myShowTypeAfterMethod = myShowTypeAfterMethod; + result.myShowRules = myShowRules; + result.myShowMatchedRules = myShowMatchedRules; + result.myShowComments = myShowComments; + result.myRemoveBlanksInsideCodeBlocks = myRemoveBlanksInsideCodeBlocks; + result.myAfterClassLBrace = myAfterClassLBrace.deepCopy(); + result.myAfterClassRBrace = myAfterClassRBrace.deepCopy(); + result.myBeforeClassRBrace = myBeforeClassRBrace.deepCopy(); result.beforeMethodLBrace = beforeMethodLBrace.deepCopy(); - result.afterMethodLBrace = afterMethodLBrace.deepCopy(); - result.afterMethodRBrace = afterMethodRBrace.deepCopy(); - result.beforeMethodRBrace = beforeMethodRBrace.deepCopy(); - result.newlinesAtEOF = newlinesAtEOF.deepCopy(); - result.defaultGSDefinition = defaultGSDefinition.deepCopy(); + result.myAfterMethodLBrace = myAfterMethodLBrace.deepCopy(); + result.myAfterMethodRBrace = myAfterMethodRBrace.deepCopy(); + result.myBeforeMethodRBrace = myBeforeMethodRBrace.deepCopy(); + result.myNewLinesAtEOF = myNewLinesAtEOF.deepCopy(); + result.myDefaultGSDefinition = myDefaultGSDefinition.deepCopy(); return result; } + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") public void writeSettingsToFile(File f) { Element component = new Element("component"); component.setAttribute("name", Rearranger.COMPONENT_NAME); @@ -626,14 +648,25 @@ public final class RearrangerSettings { writeExternal(r); Format format = Format.getPrettyFormat(); XMLOutputter outputter = new XMLOutputter(format); + FileOutputStream fileOutputStream = null; try { - final FileOutputStream fileOutputStream = new FileOutputStream(f); + fileOutputStream = new FileOutputStream(f); outputter.output(component, fileOutputStream); fileOutputStream.close(); } catch (IOException e) { throw new RuntimeException(e); } + finally { + if (fileOutputStream != null) { + try { + fileOutputStream.close(); + } + catch (IOException e) { + // Ignore + } + } + } } // end of Level 2 methods @@ -644,40 +677,40 @@ public final class RearrangerSettings { final Element classes = new Element("Classes"); entry.getChildren().add(items); entry.getChildren().add(classes); - for (AttributeGroup item : itemOrderAttributeList) { + for (AttributeGroup item : myItemOrderAttributeList) { item.writeExternal(items); } - for (AttributeGroup attributes : classOrderAttributeList) { + for (AttributeGroup attributes : myClassOrderAttributeList) { attributes.writeExternal(classes); } final Element gsd = new Element("DefaultGetterSetterDefinition"); entry.getChildren().add(gsd); - defaultGSDefinition.writeExternal(gsd); + myDefaultGSDefinition.writeExternal(gsd); final Element relatedItems = new Element("RelatedMethods"); entry.getChildren().add(relatedItems); - entry.setAttribute("KeepGettersSettersTogether", Boolean.valueOf(keepGettersSettersTogether).toString()); - entry.setAttribute("KeepGettersSettersWithProperty", Boolean.valueOf(keepGettersSettersWithProperty).toString()); - entry.setAttribute("KeepOverloadedMethodsTogether", Boolean.valueOf(keepOverloadedMethodsTogether).toString()); - entry.setAttribute("ConfirmBeforeRearranging", Boolean.valueOf(askBeforeRearranging).toString()); - entry.setAttribute("RearrangeInnerClasses", Boolean.valueOf(rearrangeInnerClasses).toString()); - entry.setAttribute("globalCommentPattern", globalCommentPattern); - entry.setAttribute("overloadedOrder", "" + overloadedOrder); - entry.setAttribute("ShowParameterTypes", Boolean.valueOf(showParameterTypes).toString()); - entry.setAttribute("ShowParameterNames", Boolean.valueOf(showParameterNames).toString()); - entry.setAttribute("ShowFields", Boolean.valueOf(showFields).toString()); - entry.setAttribute("ShowTypeAfterMethod", Boolean.valueOf(showTypeAfterMethod).toString()); - entry.setAttribute("ShowRules", Boolean.valueOf(showRules).toString()); - entry.setAttribute("ShowMatchedRules", Boolean.valueOf(showMatchedRules).toString()); - entry.setAttribute("ShowComments", Boolean.valueOf(showComments).toString()); - entry.setAttribute("RemoveBlanksInsideCodeBlocks", Boolean.valueOf(removeBlanksInsideCodeBlocks).toString()); - relatedMethodsSettings.writeExternal(relatedItems); - afterClassLBrace.writeExternal(entry); - afterClassRBrace.writeExternal(entry); - beforeClassRBrace.writeExternal(entry); + entry.setAttribute("KeepGettersSettersTogether", Boolean.valueOf(myKeepGettersSettersTogether).toString()); + entry.setAttribute("KeepGettersSettersWithProperty", Boolean.valueOf(myKeepGettersSettersWithProperty).toString()); + entry.setAttribute("KeepOverloadedMethodsTogether", Boolean.valueOf(myKeepOverloadedMethodsTogether).toString()); + entry.setAttribute("ConfirmBeforeRearranging", Boolean.valueOf(myAskBeforeRearranging).toString()); + entry.setAttribute("RearrangeInnerClasses", Boolean.valueOf(myRearrangeInnerClasses).toString()); + entry.setAttribute("globalCommentPattern", myGlobalCommentPattern); + entry.setAttribute("overloadedOrder", "" + myOverloadedOrder); + entry.setAttribute("ShowParameterTypes", Boolean.valueOf(myShowParameterTypes).toString()); + entry.setAttribute("ShowParameterNames", Boolean.valueOf(myShowParameterNames).toString()); + entry.setAttribute("ShowFields", Boolean.valueOf(myShowFields).toString()); + entry.setAttribute("ShowTypeAfterMethod", Boolean.valueOf(myShowTypeAfterMethod).toString()); + entry.setAttribute("ShowRules", Boolean.valueOf(myShowRules).toString()); + entry.setAttribute("ShowMatchedRules", Boolean.valueOf(myShowMatchedRules).toString()); + entry.setAttribute("ShowComments", Boolean.valueOf(myShowComments).toString()); + entry.setAttribute("RemoveBlanksInsideCodeBlocks", Boolean.valueOf(myRemoveBlanksInsideCodeBlocks).toString()); + myRelatedMethodsSettings.writeExternal(relatedItems); + myAfterClassLBrace.writeExternal(entry); + myAfterClassRBrace.writeExternal(entry); + myBeforeClassRBrace.writeExternal(entry); beforeMethodLBrace.writeExternal(entry); - afterMethodLBrace.writeExternal(entry); - afterMethodRBrace.writeExternal(entry); - beforeMethodRBrace.writeExternal(entry); - newlinesAtEOF.writeExternal(entry); + myAfterMethodLBrace.writeExternal(entry); + myAfterMethodRBrace.writeExternal(entry); + myBeforeMethodRBrace.writeExternal(entry); + myNewLinesAtEOF.writeExternal(entry); } } diff --git a/plugins/rearranger/src/com/wrq/rearranger/util/RearrangerConstants.java b/plugins/rearranger/src/com/wrq/rearranger/util/RearrangerConstants.java new file mode 100644 index 000000000000..48784fb9a58b --- /dev/null +++ b/plugins/rearranger/src/com/wrq/rearranger/util/RearrangerConstants.java @@ -0,0 +1,16 @@ +package com.wrq.rearranger.util; + +import org.jetbrains.annotations.NonNls; + +/** + * @author Denis Zhdanov + * @since 5/14/12 12:57 PM + */ +public class RearrangerConstants { + + @NonNls + public static final String DEFAULT_CONFIG_PATH = "com/wrq/rearranger/defaultConfiguration.xml"; + + private RearrangerConstants() { + } +} From 913cfb3572bf789ada3ecfe42f3842e913cd6877 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 14 May 2012 13:18:20 +0400 Subject: [PATCH 36/67] IDEA-19061 Integrate the Rearranger-plugin into core-IDEA Refactoring --- .../configuration/SettingsPane.java | 6 +- .../attributeGroups/CommonAttributes.java | 2 +- .../attributeGroups/InterfaceAttributes.java | 2 +- ...itizableRule.java => PrioritizedRule.java} | 2 +- .../com/wrq/rearranger/InteractiveTest.java | 214 ++++++++---------- 5 files changed, 102 insertions(+), 124 deletions(-) rename plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/{IPrioritizableRule.java => PrioritizedRule.java} (97%) diff --git a/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java b/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java index 4a72bcb11a66..4b91940c052a 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java +++ b/plugins/rearranger/src/com/wrq/rearranger/configuration/SettingsPane.java @@ -23,7 +23,7 @@ package com.wrq.rearranger.configuration; import com.wrq.rearranger.settings.RearrangerSettings; import com.wrq.rearranger.settings.attributeGroups.AttributeGroup; -import com.wrq.rearranger.settings.attributeGroups.IPrioritizableRule; +import com.wrq.rearranger.settings.attributeGroups.PrioritizedRule; import com.wrq.rearranger.settings.attributeGroups.Rule; import com.wrq.rearranger.util.Constraints; @@ -139,7 +139,7 @@ public abstract class SettingsPane { if (columnIndex == PRIORITY_COLUMN && rowIndex >= 0) { ChoicePanel cp = (modelData.get(rowIndex)); Rule rule = cp.getChoice().getChoiceObject(); - if (rule instanceof IPrioritizableRule) { + if (rule instanceof PrioritizedRule) { return true; } } @@ -150,7 +150,7 @@ public abstract class SettingsPane { if (columnIndex == PRIORITY_COLUMN) { ChoicePanel cp = (modelData.get(rowIndex)); Rule rule = cp.getChoice().getChoiceObject(); - if (rule instanceof IPrioritizableRule) { + if (rule instanceof PrioritizedRule) { int priority; try { priority = (new Integer((String)aValue)); diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java index db6e98c257d5..341378944a7b 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/CommonAttributes.java @@ -37,7 +37,7 @@ import java.util.List; * expression is also supported. */ public abstract class CommonAttributes - implements AttributeGroup, IPrioritizableRule + implements AttributeGroup, PrioritizedRule { // ------------------------------ FIELDS ------------------------------ diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java index afd6f5a09f73..910c0c0d2dfb 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/InterfaceAttributes.java @@ -45,7 +45,7 @@ import java.util.List; /** Rule and attributes to support grouping of methods that implement interface methods. */ public class InterfaceAttributes - implements AttributeGroup, IRestrictMethodExtraction, IPrioritizableRule + implements AttributeGroup, IRestrictMethodExtraction, PrioritizedRule { private boolean noExtractedMethods; NameAttribute nameAttr; diff --git a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IPrioritizableRule.java b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/PrioritizedRule.java similarity index 97% rename from plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IPrioritizableRule.java rename to plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/PrioritizedRule.java index 29668d76448f..38bec49e6f76 100644 --- a/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/IPrioritizableRule.java +++ b/plugins/rearranger/src/com/wrq/rearranger/settings/attributeGroups/PrioritizedRule.java @@ -25,5 +25,5 @@ package com.wrq.rearranger.settings.attributeGroups; * Marker interface for rules which have a user-assignable priority. This excludes comment rules, and invisible * header and trailer rules. */ -public interface IPrioritizableRule { +public interface PrioritizedRule { } diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java b/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java index 39504e136a23..09beffce623b 100644 --- a/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java +++ b/plugins/rearranger/test/src/com/wrq/rearranger/InteractiveTest.java @@ -21,143 +21,121 @@ */ package com.wrq.rearranger; -import com.intellij.openapi.editor.Document; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.testFramework.LightCodeInsightTestCase; -import com.wrq.rearranger.configuration.RearrangerSettingsPanel; +import com.intellij.testFramework.SkipInHeadlessEnvironment; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.wrq.rearranger.settings.RearrangerSettings; -import com.wrq.rearranger.settings.attributeGroups.IPrioritizableRule; -import com.wrq.rearranger.settings.attributeGroups.Rule; -import com.wrq.rearranger.util.Constraints; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jdom.input.SAXBuilder; - -import javax.swing.*; -import java.awt.*; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ListIterator; /** * @author davek * Date: Mar 30, 2004 */ +@SkipInHeadlessEnvironment public class InteractiveTest - extends LightCodeInsightTestCase + extends LightCodeInsightFixtureTestCase { - private RearrangerSettings rs; public static final String DEFAULT_CONFIGURATION_ROOT = ".."; // up one level from test public static final String DEFAULT_CONFIGURATION = DEFAULT_CONFIGURATION_ROOT + "/src/com/wrq/rearranger/defaultConfiguration.xml"; + private RearrangerSettings mySettings; @Override - protected String getTestDataPath() { - return "testData"; // run unit tests with effective working directory of "C:\Rearranger\test" + protected String getBasePath() { + return "/plugins/rearranger/test/testData/com/wrq/rearranger"; } protected final void setUp() throws Exception { super.setUp(); - Logger logger = Logger.getLogger("com.wrq.rearranger"); -// logger.setAdditivity(false); -// logger.addAppender(new ConsoleAppender(new PatternLayout("[%7r] %6p - %30.30c - %m \n"))); -// logger.setLevel(Level.DEBUG); - logger.setLevel(Level.INFO); - rs = new RearrangerSettings(); - rs.setAskBeforeRearranging(true); - rs.setRearrangeInnerClasses(true); + + mySettings = new RearrangerSettings(); + mySettings.setAskBeforeRearranging(true); + mySettings.setRearrangeInnerClasses(true); } public final void testLiveRearrangerDialog() throws Exception { - configureByFile("/com/wrq/rearranger/RearrangementTest28.java"); - final PsiFile file = getFile(); - final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); - final LiveRearrangerActionHandler rah = new LiveRearrangerActionHandler(); - rah.liveRearrangeDocument(getProject(), file, rs, doc, 0); - super.checkResultByFile("/com/wrq/rearranger/RearrangementTest28.java"); + //configureByFile("/com/wrq/rearranger/RearrangementTest28.java"); + //final PsiFile file = getFile(); + //final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); + //final LiveRearrangerActionHandler rah = new LiveRearrangerActionHandler(); + //rah.liveRearrangeDocument(getProject(), file, mySettings, doc, 0); + //super.checkResultByFile("/com/wrq/rearranger/RearrangementTest28.java"); } - public final void testSettingsPanel() throws Exception { - Rearranger rearranger = new Rearranger(); - SAXBuilder builder = new SAXBuilder(); - org.jdom.Document doc = null; - try { - FileInputStream f = new FileInputStream(new File(DEFAULT_CONFIGURATION)); - doc = builder.build(f); - f.close(); - } - catch (JDOMException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - catch (FileNotFoundException e) { - File f = new File(DEFAULT_CONFIGURATION); - System.out.println(f.getAbsolutePath()); - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - catch (IOException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - Element appElement = doc.getRootElement(); - java.util.List componentList = appElement.getChildren(); - Element rearrangerElement = null; - if (appElement.getName().equals("component") && - appElement.getAttributeValue("name").equals(Rearranger.COMPONENT_NAME)) - { - rearrangerElement = appElement; - } - else { - ListIterator li = componentList.listIterator(); - while (li.hasNext()) -// for (Element e : componentList) - { - Element e = (Element)li.next(); - if (e.getAttributeValue("name").equals(Rearranger.COMPONENT_NAME)) { - rearrangerElement = e; - break; - } - } - } - if (rearrangerElement != null) { - rearranger.readExternal(rearrangerElement); - } - final JDialog frame = new JDialog((Frame)null, "SwingApplication"); - final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); - constraints.fill = GridBagConstraints.BOTH; - constraints.weightedLastRow(); - RearrangerSettings settings = rearranger.getSettings(); - final RearrangerSettingsPanel object = new RearrangerSettingsPanel(settings); - frame.getContentPane().setLayout(new GridBagLayout()); - frame.getContentPane().add(object, constraints.weightedLastCol()); - //Finish setting up the frame, and show it. - frame.pack(); - frame.setResizable(true); - frame.setModal(true); - frame.setVisible(true); - final RearrangerSettings rs = object.settings.deepCopy(); - assertTrue("Settings are unequal", rs.equals(object.settings)); - System.out.println("Class Order"); - ListIterator li; - for (Object o : object.settings.getClassOrderAttributeList()) { - if (o instanceof IPrioritizableRule) { - System.out.println(o + ", pri=" + ((Rule)o).getPriority()); - } - else { - System.out.println(o); - } - } - System.out.println("Item order"); - for (Object o : object.settings.getItemOrderAttributeList()) { - if (o instanceof IPrioritizableRule) { - System.out.println(o + ", pri=" + ((Rule)o).getPriority()); - } - else { - System.out.println(o); - } - } - object.checkCommentsAgainstGlobalPattern(object.settings); - } + //public final void testSettingsPanel() throws Exception { + // Rearranger rearranger = new Rearranger(); + // SAXBuilder builder = new SAXBuilder(); + // org.jdom.Document doc = null; + // FileInputStream in = new FileInputStream(new File(DEFAULT_CONFIGURATION)); + // try { + // doc = builder.build(in); + // } + // catch (JDOMException e) { + // e.printStackTrace(); + // } + // catch (FileNotFoundException e) { + // File f = new File(DEFAULT_CONFIGURATION); + // System.out.println(f.getAbsolutePath()); + // e.printStackTrace(); + // } + // catch (IOException e) { + // e.printStackTrace(); + // } + // finally { + // in.close(); + // } + // + // assert doc != null; + // Element appElement = doc.getRootElement(); + // java.util.List componentList = appElement.getChildren(); + // Element rearrangerElement = null; + // if (appElement.getName().equals("component") && + // appElement.getAttributeValue("name").equals(Rearranger.COMPONENT_NAME)) + // { + // rearrangerElement = appElement; + // } + // else { + // for (Object aComponentList : componentList) { + // Element e = (Element)aComponentList; + // if (e.getAttributeValue("name").equals(Rearranger.COMPONENT_NAME)) { + // rearrangerElement = e; + // break; + // } + // } + // } + // if (rearrangerElement != null) { + // rearranger.readExternal(rearrangerElement); + // } + // final JDialog frame = new JDialog((Frame)null, "SwingApplication"); + // final Constraints constraints = new Constraints(GridBagConstraints.NORTHWEST); + // constraints.fill = GridBagConstraints.BOTH; + // constraints.weightedLastRow(); + // RearrangerSettings settings = rearranger.getSettings(); + // final RearrangerSettingsPanel object = new RearrangerSettingsPanel(settings); + // frame.getContentPane().setLayout(new GridBagLayout()); + // frame.getContentPane().add(object, constraints.weightedLastCol()); + // //Finish setting up the frame, and show it. + // frame.pack(); + // frame.setResizable(true); + // frame.setModal(true); + // frame.setVisible(true); + // final RearrangerSettings rs = object.settings.deepCopy(); + // assertTrue("Settings are unequal", rs.equals(object.settings)); + // System.out.println("Class Order"); + // for (Object o : object.settings.getClassOrderAttributeList()) { + // if (o instanceof Rule && o instanceof PrioritizedRule) { + // System.out.println(o + ", pri=" + ((Rule)o).getPriority()); + // } + // else { + // System.out.println(o); + // } + // } + // System.out.println("Item order"); + // for (Object o : object.settings.getItemOrderAttributeList()) { + // if (o instanceof Rule && o instanceof PrioritizedRule) { + // System.out.println(o + ", pri=" + ((Rule)o).getPriority()); + // } + // else { + // System.out.println(o); + // } + // } + // object.checkCommentsAgainstGlobalPattern(object.settings); + //} } From d2f6b5ed726ddee3f9326d08ef77b391f3f36f98 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Mon, 14 May 2012 11:36:10 +0200 Subject: [PATCH 37/67] indexing-impl added to utils.gant --- build/scripts/utils.gant | 1 + 1 file changed, 1 insertion(+) diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index af1934b4e9a6..56dea509d8bc 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -237,6 +237,7 @@ binding.setVariable("platformApiModules", [ binding.setVariable("platformImplementationModules", [ "core-impl", + "indexing-impl", "platform-impl", "vcs-impl", "lang-impl", From c583fbbeb687c83ee9c72a2a02c2858db04df420 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 14 May 2012 13:18:15 +0400 Subject: [PATCH 38/67] Deprecate duplicate token sets; cleanup --- .../ide/highlighter/JavaFileHighlighter.java | 13 ++++++------- .../impl/cache/impl/idCache/JavaFilterLexer.java | 7 ++++--- .../src/com/intellij/psi/JavaTokenType.java | 15 +++++++++------ .../psi/impl/source/tree/ElementType.java | 9 +++++++-- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java b/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java index 866e90051289..a2c2fde1d155 100644 --- a/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java +++ b/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -25,6 +25,8 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.JavaDocTokenType; import com.intellij.psi.JavaTokenType; import com.intellij.psi.StringEscapesTokenTypes; +import com.intellij.psi.TokenType; +import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaDocElementType; import com.intellij.psi.tree.IElementType; import com.intellij.psi.xml.XmlTokenType; @@ -51,9 +53,8 @@ public class JavaFileHighlighter extends SyntaxHighlighterBase { ourMap1 = new HashMap(); ourMap2 = new HashMap(); - fillMap(ourMap1, JavaTokenType.KEYWORD_BIT_SET, SyntaxHighlighterColors.KEYWORD); - fillMap(ourMap1, JavaTokenType.OPERATION_BIT_SET, SyntaxHighlighterColors.OPERATION_SIGN); - fillMap(ourMap1, JavaTokenType.OPERATION_BIT_SET, SyntaxHighlighterColors.OPERATION_SIGN); + fillMap(ourMap1, ElementType.KEYWORD_BIT_SET, SyntaxHighlighterColors.KEYWORD); + fillMap(ourMap1, ElementType.OPERATION_BIT_SET, SyntaxHighlighterColors.OPERATION_SIGN); for (IElementType type : JavaDocTokenType.ALL_JAVADOC_TOKENS.getTypes()) { ourMap1.put(type, SyntaxHighlighterColors.DOC_COMMENT); @@ -86,12 +87,10 @@ public class JavaFileHighlighter extends SyntaxHighlighterBase { ourMap1.put(JavaTokenType.DOT, SyntaxHighlighterColors.DOT); ourMap1.put(JavaTokenType.SEMICOLON, SyntaxHighlighterColors.JAVA_SEMICOLON); - //ourMap1[JavaTokenType.BOOLEAN_LITERAL] = HighlighterColors.JAVA_KEYWORD; - //ourMap1[JavaTokenType.NULL_LITERAL] = HighlighterColors.JAVA_KEYWORD; ourMap1.put(JavaTokenType.C_STYLE_COMMENT, SyntaxHighlighterColors.JAVA_BLOCK_COMMENT); ourMap1.put(JavaDocElementType.DOC_COMMENT, SyntaxHighlighterColors.DOC_COMMENT); ourMap1.put(JavaTokenType.END_OF_LINE_COMMENT, SyntaxHighlighterColors.LINE_COMMENT); - ourMap1.put(JavaTokenType.BAD_CHARACTER, HighlighterColors.BAD_CHARACTER); + ourMap1.put(TokenType.BAD_CHARACTER, HighlighterColors.BAD_CHARACTER); ourMap1.put(JavaDocTokenType.DOC_TAG_NAME, SyntaxHighlighterColors.DOC_COMMENT); ourMap2.put(JavaDocTokenType.DOC_TAG_NAME, SyntaxHighlighterColors.DOC_COMMENT_TAG); diff --git a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java index 4ecc16fc6986..44207d32b640 100644 --- a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java +++ b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -17,6 +17,7 @@ package com.intellij.psi.impl.cache.impl.idCache; import com.intellij.lexer.Lexer; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.TokenType; import com.intellij.psi.impl.cache.impl.BaseFilterLexer; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; import com.intellij.psi.impl.source.tree.ElementType; @@ -30,7 +31,7 @@ import com.intellij.psi.tree.TokenSet; public class JavaFilterLexer extends BaseFilterLexer { private static final TokenSet ourSkipWordsScanSet = TokenSet.orSet( TokenSet.create( - JavaTokenType.WHITE_SPACE, + TokenType.WHITE_SPACE, JavaTokenType.LPARENTH, JavaTokenType.RPARENTH, JavaTokenType.LBRACE, @@ -43,7 +44,7 @@ public class JavaFilterLexer extends BaseFilterLexer { JavaTokenType.ELLIPSIS, JavaTokenType.AT ), - JavaTokenType.OPERATION_BIT_SET + ElementType.OPERATION_BIT_SET ); public JavaFilterLexer(final Lexer originalLexer, final OccurrenceConsumer table) { diff --git a/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java b/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java index 81db31947f2b..9e17f7e6be04 100644 --- a/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java +++ b/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java @@ -20,8 +20,7 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.java.IJavaElementType; import com.intellij.psi.tree.java.IKeywordElementType; - -public interface JavaTokenType extends TokenType{ +public interface JavaTokenType extends TokenType { IElementType IDENTIFIER = new IJavaElementType("IDENTIFIER"); IElementType C_STYLE_COMMENT = new IJavaElementType("C_STYLE_COMMENT"); IElementType END_OF_LINE_COMMENT = new IJavaElementType("END_OF_LINE_COMMENT"); @@ -143,13 +142,15 @@ public interface JavaTokenType extends TokenType{ IElementType DOUBLE_COLON = new IJavaElementType("DOUBLE_COLON"); IElementType ARROW = new IJavaElementType("ARROW"); - TokenSet OPERATION_BIT_SET = TokenSet.create( + /** @deprecated use {@linkplain com.intellij.psi.impl.source.tree.ElementType#OPERATION_BIT_SET} (to remove in IDEA 13) */ + @SuppressWarnings("UnusedDeclaration") TokenSet OPERATION_BIT_SET = TokenSet.create( EQ, GT, LT, EXCL, TILDE, QUEST, COLON, PLUS, MINUS, ASTERISK, DIV, AND, OR, XOR, PERC, EQEQ, LE, GE, NE, ANDAND, OROR, PLUSPLUS, MINUSMINUS, LTLT, GTGT, GTGTGT, PLUSEQ, MINUSEQ, ASTERISKEQ, DIVEQ, ANDEQ, OREQ, XOREQ, PERCEQ, LTLTEQ, GTGTEQ, GTGTGTEQ ); - TokenSet KEYWORD_BIT_SET = TokenSet.create( + /** @deprecated use {@linkplain com.intellij.psi.impl.source.tree.ElementType#KEYWORD_BIT_SET} (to remove in IDEA 13) */ + @SuppressWarnings("UnusedDeclaration") TokenSet KEYWORD_BIT_SET = TokenSet.create( ABSTRACT_KEYWORD, ASSERT_KEYWORD, BOOLEAN_KEYWORD, BREAK_KEYWORD, BYTE_KEYWORD, CASE_KEYWORD, CATCH_KEYWORD, CHAR_KEYWORD, CLASS_KEYWORD, CONST_KEYWORD, CONTINUE_KEYWORD, DEFAULT_KEYWORD, DO_KEYWORD, DOUBLE_KEYWORD, ELSE_KEYWORD, ENUM_KEYWORD, EXTENDS_KEYWORD, @@ -159,10 +160,12 @@ public interface JavaTokenType extends TokenType{ PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, RETURN_KEYWORD, SHORT_KEYWORD, SUPER_KEYWORD, STATIC_KEYWORD, STRICTFP_KEYWORD, SWITCH_KEYWORD, SYNCHRONIZED_KEYWORD, THIS_KEYWORD, THROW_KEYWORD, THROWS_KEYWORD, TRANSIENT_KEYWORD, TRY_KEYWORD, - VOID_KEYWORD, VOLATILE_KEYWORD, WHILE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NULL_KEYWORD + VOID_KEYWORD, VOLATILE_KEYWORD, WHILE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NULL_KEYWORD, + NONE_KEYWORD ); - TokenSet MODIFIER_BIT_SET = TokenSet.create( + /** @deprecated use {@linkplain com.intellij.psi.impl.source.tree.ElementType#MODIFIER_BIT_SET} (to remove in IDEA 13) */ + @SuppressWarnings("UnusedDeclaration") TokenSet MODIFIER_BIT_SET = TokenSet.create( PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, STATIC_KEYWORD, ABSTRACT_KEYWORD, FINAL_KEYWORD, NATIVE_KEYWORD, STRICTFP_KEYWORD, SYNCHRONIZED_KEYWORD, TRANSIENT_KEYWORD, VOLATILE_KEYWORD diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java index e0c480eba592..1eaeecc8c8f4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -38,7 +38,12 @@ public interface ElementType extends JavaTokenType, JavaDocTokenType, INT_KEYWORD, INTERFACE_KEYWORD, LONG_KEYWORD, NATIVE_KEYWORD, NEW_KEYWORD, PACKAGE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, SHORT_KEYWORD, SUPER_KEYWORD, SWITCH_KEYWORD, STRICTFP_KEYWORD, SYNCHRONIZED_KEYWORD, THIS_KEYWORD, THROW_KEYWORD, PROTECTED_KEYWORD, TRANSIENT_KEYWORD, RETURN_KEYWORD, VOID_KEYWORD, STATIC_KEYWORD, WHILE_KEYWORD, TRY_KEYWORD, VOLATILE_KEYWORD, THROWS_KEYWORD, - ENUM_KEYWORD); + ENUM_KEYWORD, NONE_KEYWORD); + + TokenSet OPERATION_BIT_SET = TokenSet.create( + EQ, GT, LT, EXCL, TILDE, QUEST, COLON, PLUS, MINUS, ASTERISK, DIV, AND, OR, XOR, + PERC, EQEQ, LE, GE, NE, ANDAND, OROR, PLUSPLUS, MINUSMINUS, LTLT, GTGT, GTGTGT, + PLUSEQ, MINUSEQ, ASTERISKEQ, DIVEQ, ANDEQ, OREQ, XOREQ, PERCEQ, LTLTEQ, GTGTEQ, GTGTGTEQ); TokenSet MODIFIER_BIT_SET = TokenSet.create( PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, STATIC_KEYWORD, ABSTRACT_KEYWORD, FINAL_KEYWORD, NATIVE_KEYWORD, SYNCHRONIZED_KEYWORD, From 70470e66f790b69e02941ffedac6fab722ea585a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 14 May 2012 13:25:18 +0400 Subject: [PATCH 39/67] Java 8: 'none' isn't a keyword yet --- .../src/com/intellij/psi/JavaTokenType.java | 4 +- .../src/com/intellij/lexer/JavaLexer.java | 4 - .../src/com/intellij/lexer/_JavaLexer.flex | 3 - .../src/com/intellij/lexer/_JavaLexer.java | 1038 ++++++++--------- .../psi/impl/source/tree/ElementType.java | 2 +- .../lang/java/lexer/JavaLexerTest.java | 2 +- 6 files changed, 517 insertions(+), 536 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java b/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java index 9e17f7e6be04..e9a5f0a8ee54 100644 --- a/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java +++ b/java/java-psi-api/src/com/intellij/psi/JavaTokenType.java @@ -86,7 +86,6 @@ public interface JavaTokenType extends TokenType { IElementType TRY_KEYWORD = new IKeywordElementType("TRY_KEYWORD"); IElementType VOLATILE_KEYWORD = new IKeywordElementType("VOLATILE_KEYWORD"); IElementType THROWS_KEYWORD = new IKeywordElementType("THROWS_KEYWORD"); - IElementType NONE_KEYWORD = new IKeywordElementType("NONE_KEYWORD"); IElementType LPARENTH = new IJavaElementType("LPARENTH"); IElementType RPARENTH = new IJavaElementType("RPARENTH"); @@ -160,8 +159,7 @@ public interface JavaTokenType extends TokenType { PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, RETURN_KEYWORD, SHORT_KEYWORD, SUPER_KEYWORD, STATIC_KEYWORD, STRICTFP_KEYWORD, SWITCH_KEYWORD, SYNCHRONIZED_KEYWORD, THIS_KEYWORD, THROW_KEYWORD, THROWS_KEYWORD, TRANSIENT_KEYWORD, TRY_KEYWORD, - VOID_KEYWORD, VOLATILE_KEYWORD, WHILE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NULL_KEYWORD, - NONE_KEYWORD + VOID_KEYWORD, VOLATILE_KEYWORD, WHILE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NULL_KEYWORD ); /** @deprecated use {@linkplain com.intellij.psi.impl.source.tree.ElementType#MODIFIER_BIT_SET} (to remove in IDEA 13) */ diff --git a/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java b/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java index cf47bdcb772c..13dd70775356 100644 --- a/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java +++ b/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java @@ -30,7 +30,6 @@ import java.util.Set; public class JavaLexer extends LexerBase { private static final HashTable[] TABLES = new HashTable[]{ - new HashTable(LanguageLevel.JDK_1_8), new HashTable(LanguageLevel.JDK_1_5), new HashTable(LanguageLevel.JDK_1_4), new HashTable(LanguageLevel.JDK_1_3) @@ -118,9 +117,6 @@ public class JavaLexer extends LexerBase { add("assert", JavaTokenType.ASSERT_KEYWORD); if (level.isAtLeast(LanguageLevel.JDK_1_5)) { add("enum", JavaTokenType.ENUM_KEYWORD); - if (level.isAtLeast(LanguageLevel.JDK_1_8)) { - add("none", JavaTokenType.NONE_KEYWORD); - } } } add("abstract", JavaTokenType.ABSTRACT_KEYWORD); diff --git a/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.flex b/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.flex index a1335e5ba747..5b62d45a8f4a 100644 --- a/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.flex +++ b/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.flex @@ -12,13 +12,11 @@ import com.intellij.psi.tree.IElementType; %{ private boolean myAssertKeyword; private boolean myEnumKeyword; - private boolean myNoneKeyword; public _JavaLexer(LanguageLevel level) { this((java.io.Reader)null); myAssertKeyword = level.isAtLeast(LanguageLevel.JDK_1_4); myEnumKeyword = level.isAtLeast(LanguageLevel.JDK_1_5); - myNoneKeyword = level.isAtLeast(LanguageLevel.JDK_1_8); } public void goTo(int offset) { @@ -154,7 +152,6 @@ ESCAPE_SEQUENCE=\\[^\r\n] "try" { return JavaTokenType.TRY_KEYWORD; } "volatile" { return JavaTokenType.VOLATILE_KEYWORD; } "throws" { return JavaTokenType.THROWS_KEYWORD; } - "none" { return myNoneKeyword ? JavaTokenType.NONE_KEYWORD : JavaTokenType.IDENTIFIER; } {IDENTIFIER} { return JavaTokenType.IDENTIFIER; } diff --git a/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.java b/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.java index 6f9733947fd3..702d3f66f20a 100644 --- a/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.java +++ b/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -/* The following code was generated by JFlex 1.4.3 on 5/11/12 9:41 PM */ +/* The following code was generated by JFlex 1.4.3 on 5/14/12 1:21 PM */ /* It's an automatically generated code. Do not modify it. */ package com.intellij.lexer; @@ -29,7 +29,7 @@ import com.intellij.psi.tree.IElementType; /** * This class is a scanner generated by * JFlex 1.4.3 - * on 5/11/12 9:41 PM from the specification file + * on 5/14/12 1:21 PM from the specification file * /home/sher/Projects/IDEA/tools/lexer/../../community/java/java-psi-impl/src/com/intellij/lexer/_JavaLexer.flex */ class _JavaLexer implements FlexLexer { @@ -161,26 +161,26 @@ class _JavaLexer implements FlexLexer { "\1\27\1\30\1\31\1\32\1\33\1\34\1\35\1\36"+ "\1\37\1\40\1\41\1\42\1\43\1\0\1\44\1\45"+ "\3\46\2\0\3\6\1\46\1\0\1\47\1\50\1\51"+ - "\2\11\2\12\35\3\1\52\3\3\1\53\6\3\1\54"+ + "\2\11\2\12\34\3\1\52\3\3\1\53\6\3\1\54"+ "\1\55\1\56\1\57\1\60\1\61\1\62\1\63\1\64"+ "\1\65\1\66\1\67\1\70\1\41\1\71\2\46\2\0"+ "\1\6\1\44\1\0\1\6\1\0\1\72\2\3\1\73"+ - "\10\3\1\74\13\3\1\75\12\3\1\76\14\3\1\77"+ + "\10\3\1\74\13\3\1\75\11\3\1\76\14\3\1\77"+ "\1\0\2\71\4\0\1\46\2\0\1\100\2\3\1\101"+ - "\1\3\1\102\1\103\6\3\1\104\6\3\1\105\1\3"+ - "\1\106\2\3\1\107\1\3\1\110\3\3\1\111\6\3"+ - "\1\112\5\3\1\113\1\3\1\41\4\0\1\45\1\46"+ - "\1\3\1\114\2\3\1\115\1\116\1\117\4\3\1\120"+ - "\1\3\1\121\2\3\1\122\1\3\1\123\1\124\1\3"+ - "\1\125\13\3\1\126\1\3\1\127\1\130\2\3\1\131"+ - "\2\3\1\132\1\3\1\133\1\134\5\3\1\135\1\3"+ - "\1\136\2\3\1\137\3\3\1\140\1\141\3\3\1\142"+ - "\4\3\1\143\1\3\1\144\1\145\2\3\1\146\1\147"+ - "\1\3\1\150\4\3\1\151\1\152\1\3\1\153\2\3"+ - "\1\154\1\3\1\155\1\156\1\3\1\157"; + "\1\3\1\102\1\103\6\3\1\104\6\3\1\105\3\3"+ + "\1\106\1\3\1\107\3\3\1\110\6\3\1\111\5\3"+ + "\1\112\1\3\1\41\4\0\1\45\1\46\1\3\1\113"+ + "\2\3\1\114\1\115\1\116\4\3\1\117\1\3\1\120"+ + "\2\3\1\121\1\3\1\122\1\123\1\3\1\124\13\3"+ + "\1\125\1\3\1\126\1\127\2\3\1\130\2\3\1\131"+ + "\1\3\1\132\1\133\5\3\1\134\1\3\1\135\2\3"+ + "\1\136\3\3\1\137\1\140\3\3\1\141\4\3\1\142"+ + "\1\3\1\143\1\144\2\3\1\145\1\146\1\3\1\147"+ + "\4\3\1\150\1\151\1\3\1\152\2\3\1\153\1\3"+ + "\1\154\1\155\1\3\1\156"; private static int [] zzUnpackAction() { - int [] result = new int[345]; + int [] result = new int[342]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -217,41 +217,40 @@ class _JavaLexer implements FlexLexer { "\0\107\0\u0e25\0\u0e6c\0\u0eb3\0\u0efa\0\u0f41\0\u0f88\0\u0fcf"+ "\0\u1016\0\u105d\0\u10a4\0\u10eb\0\u1132\0\u1179\0\u11c0\0\u1207"+ "\0\u124e\0\u1295\0\u12dc\0\u1323\0\u136a\0\u13b1\0\u13f8\0\u143f"+ - "\0\u1486\0\u14cd\0\u1514\0\u155b\0\u15a2\0\u15e9\0\325\0\u1630"+ + "\0\u1486\0\u14cd\0\u1514\0\u155b\0\u15a2\0\325\0\u15e9\0\u1630"+ "\0\u1677\0\u16be\0\u1705\0\u174c\0\u1793\0\u17da\0\u1821\0\u1868"+ - "\0\u18af\0\107\0\107\0\107\0\107\0\107\0\107\0\107"+ - "\0\u18f6\0\107\0\107\0\107\0\107\0\107\0\u193d\0\u1984"+ - "\0\u19cb\0\u1a12\0\u1a59\0\u1aa0\0\u1ae7\0\u1aa0\0\u1b2e\0\u1b75"+ - "\0\u1bbc\0\107\0\u1c03\0\u1c4a\0\325\0\u1c91\0\u1cd8\0\u1d1f"+ - "\0\u1d66\0\u1dad\0\u1df4\0\u1e3b\0\u1e82\0\325\0\u1ec9\0\u1f10"+ + "\0\107\0\107\0\107\0\107\0\107\0\107\0\107\0\u18af"+ + "\0\107\0\107\0\107\0\107\0\107\0\u18f6\0\u193d\0\u1984"+ + "\0\u19cb\0\u1a12\0\u1a59\0\u1aa0\0\u1a59\0\u1ae7\0\u1b2e\0\u1b75"+ + "\0\107\0\u1bbc\0\u1c03\0\325\0\u1c4a\0\u1c91\0\u1cd8\0\u1d1f"+ + "\0\u1d66\0\u1dad\0\u1df4\0\u1e3b\0\325\0\u1e82\0\u1ec9\0\u1f10"+ "\0\u1f57\0\u1f9e\0\u1fe5\0\u202c\0\u2073\0\u20ba\0\u2101\0\u2148"+ - "\0\u218f\0\325\0\u21d6\0\u221d\0\u2264\0\u22ab\0\u22f2\0\u2339"+ + "\0\325\0\u218f\0\u21d6\0\u221d\0\u2264\0\u22ab\0\u22f2\0\u2339"+ "\0\u2380\0\u23c7\0\u240e\0\u2455\0\u249c\0\u24e3\0\u252a\0\u2571"+ - "\0\u25b8\0\u25ff\0\u2646\0\u268d\0\u26d4\0\u271b\0\u2762\0\u27a9"+ - "\0\u27f0\0\107\0\u2837\0\u287e\0\107\0\u28c5\0\u290c\0\u2953"+ - "\0\u299a\0\u29e1\0\u2a28\0\u2a6f\0\325\0\u2ab6\0\u2afd\0\325"+ - "\0\u2b44\0\325\0\325\0\u2b8b\0\u2bd2\0\u2c19\0\u2c60\0\u2ca7"+ - "\0\u2cee\0\325\0\u2d35\0\u2d7c\0\u2dc3\0\u2e0a\0\u2e51\0\u2e98"+ - "\0\325\0\u2edf\0\325\0\u2f26\0\u2f6d\0\325\0\u2fb4\0\325"+ - "\0\u2ffb\0\u3042\0\u3089\0\325\0\u30d0\0\u3117\0\u315e\0\u31a5"+ - "\0\u31ec\0\u3233\0\325\0\u327a\0\u32c1\0\u3308\0\u334f\0\u3396"+ - "\0\325\0\u33dd\0\107\0\u3424\0\u346b\0\u34b2\0\u34f9\0\u290c"+ - "\0\u290c\0\u3540\0\u3587\0\u35ce\0\u3615\0\325\0\325\0\u365c"+ - "\0\u36a3\0\u36ea\0\u3731\0\u3778\0\325\0\u37bf\0\325\0\u3806"+ - "\0\u384d\0\325\0\u3894\0\325\0\325\0\u38db\0\325\0\u3922"+ - "\0\u3969\0\u39b0\0\u39f7\0\u3a3e\0\u3a85\0\u3acc\0\u3b13\0\u3b5a"+ - "\0\u3ba1\0\u3be8\0\325\0\u3c2f\0\325\0\325\0\u3c76\0\u3cbd"+ - "\0\325\0\u3d04\0\u3d4b\0\325\0\u3d92\0\325\0\325\0\u3dd9"+ - "\0\u3e20\0\u3e67\0\u3eae\0\u3ef5\0\325\0\u3f3c\0\325\0\u3f83"+ - "\0\u3fca\0\325\0\u4011\0\u4058\0\u409f\0\325\0\325\0\u40e6"+ - "\0\u412d\0\u4174\0\325\0\u41bb\0\u4202\0\u4249\0\u4290\0\325"+ - "\0\u42d7\0\325\0\325\0\u431e\0\u4365\0\325\0\325\0\u43ac"+ - "\0\325\0\u43f3\0\u443a\0\u4481\0\u44c8\0\325\0\325\0\u450f"+ - "\0\325\0\u4556\0\u459d\0\325\0\u45e4\0\325\0\325\0\u462b"+ - "\0\325"; + "\0\u25b8\0\u25ff\0\u2646\0\u268d\0\u26d4\0\u271b\0\u2762\0\107"+ + "\0\u27a9\0\u27f0\0\107\0\u2837\0\u287e\0\u28c5\0\u290c\0\u2953"+ + "\0\u299a\0\u29e1\0\325\0\u2a28\0\u2a6f\0\325\0\u2ab6\0\325"+ + "\0\325\0\u2afd\0\u2b44\0\u2b8b\0\u2bd2\0\u2c19\0\u2c60\0\325"+ + "\0\u2ca7\0\u2cee\0\u2d35\0\u2d7c\0\u2dc3\0\u2e0a\0\325\0\u2e51"+ + "\0\u2e98\0\u2edf\0\325\0\u2f26\0\325\0\u2f6d\0\u2fb4\0\u2ffb"+ + "\0\325\0\u3042\0\u3089\0\u30d0\0\u3117\0\u315e\0\u31a5\0\325"+ + "\0\u31ec\0\u3233\0\u327a\0\u32c1\0\u3308\0\325\0\u334f\0\107"+ + "\0\u3396\0\u33dd\0\u3424\0\u346b\0\u287e\0\u287e\0\u34b2\0\u34f9"+ + "\0\u3540\0\u3587\0\325\0\325\0\u35ce\0\u3615\0\u365c\0\u36a3"+ + "\0\u36ea\0\325\0\u3731\0\325\0\u3778\0\u37bf\0\325\0\u3806"+ + "\0\325\0\325\0\u384d\0\325\0\u3894\0\u38db\0\u3922\0\u3969"+ + "\0\u39b0\0\u39f7\0\u3a3e\0\u3a85\0\u3acc\0\u3b13\0\u3b5a\0\325"+ + "\0\u3ba1\0\325\0\325\0\u3be8\0\u3c2f\0\325\0\u3c76\0\u3cbd"+ + "\0\325\0\u3d04\0\325\0\325\0\u3d4b\0\u3d92\0\u3dd9\0\u3e20"+ + "\0\u3e67\0\325\0\u3eae\0\325\0\u3ef5\0\u3f3c\0\325\0\u3f83"+ + "\0\u3fca\0\u4011\0\325\0\325\0\u4058\0\u409f\0\u40e6\0\325"+ + "\0\u412d\0\u4174\0\u41bb\0\u4202\0\325\0\u4249\0\325\0\325"+ + "\0\u4290\0\u42d7\0\325\0\325\0\u431e\0\325\0\u4365\0\u43ac"+ + "\0\u43f3\0\u443a\0\325\0\325\0\u4481\0\325\0\u44c8\0\u450f"+ + "\0\325\0\u4556\0\325\0\325\0\u459d\0\325"; private static int [] zzUnpackRowMap() { - int [] result = new int[345]; + int [] result = new int[342]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -308,349 +307,346 @@ class _JavaLexer implements FlexLexer { "\1\0\1\4\1\0\1\4\4\0\1\127\1\4\1\130"+ "\12\4\1\131\1\132\7\4\1\133\1\4\27\0\2\4"+ "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\2\4"+ - "\1\134\1\135\1\4\1\136\5\4\1\137\14\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\1\4\1\140\11\4\1\141\1\4\1\142\12\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\5\4\1\143\1\144\4\4\1\145\2\4\1\146\11\4"+ + "\1\134\1\135\1\4\1\136\22\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\1\4\1\137"+ + "\11\4\1\140\1\4\1\141\12\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\5\4\1\142"+ + "\1\143\4\4\1\144\2\4\1\145\11\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\4\4"+ + "\1\146\3\4\1\147\10\4\1\150\6\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ + "\1\151\7\4\1\152\14\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\13\4\1\153\14\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\4\4\1\147\3\4\1\150\10\4\1\151\6\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\3\4\1\152\7\4\1\153\14\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\13\4"+ - "\1\154\14\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\1\4\1\155\1\156\2\4\1\157"+ - "\22\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\13\4\1\160\14\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\16\4\1\161"+ - "\11\4\107\0\1\162\106\0\1\163\106\0\1\164\1\0"+ - "\1\165\104\0\1\166\2\0\1\167\103\0\1\170\3\0"+ - "\1\171\102\0\1\172\5\0\1\173\100\0\1\174\106\0"+ - "\1\175\131\0\1\176\1\0\6\62\1\0\17\62\1\0"+ - "\60\62\5\177\1\200\101\177\7\0\1\7\1\66\1\7"+ - "\1\0\2\7\101\0\1\101\1\0\1\101\1\0\2\101"+ - "\3\0\1\70\1\71\1\0\1\73\11\0\1\73\1\70"+ - "\13\0\1\71\43\0\1\201\1\0\1\201\1\0\2\201"+ - "\3\0\1\70\1\71\2\0\1\202\11\0\1\70\13\0"+ - "\1\71\12\0\1\202\30\0\1\74\1\203\1\74\1\0"+ - "\2\74\3\0\1\70\1\71\1\72\1\73\11\0\1\73"+ - "\1\70\13\0\1\71\43\0\1\74\1\75\1\76\1\0"+ - "\2\76\101\0\1\74\1\75\1\76\1\0\2\76\2\0"+ - "\1\67\1\70\1\71\1\72\1\73\11\0\1\73\1\70"+ - "\1\0\1\67\11\0\1\71\34\0\7\204\1\205\1\204"+ - "\4\205\1\204\1\205\1\206\2\205\1\204\1\205\1\204"+ - "\1\207\1\0\6\204\3\205\1\206\2\204\2\205\5\204"+ - "\1\205\3\204\1\207\30\204\13\0\2\210\2\0\1\67"+ - "\20\0\1\67\55\0\1\101\1\211\1\101\1\0\2\101"+ - "\3\0\1\70\1\71\1\0\1\73\11\0\1\73\1\70"+ - "\13\0\1\71\56\0\1\212\64\0\6\13\1\0\17\13"+ - "\1\0\60\13\6\14\1\0\17\14\1\0\60\14\2\0"+ + "\4\0\1\4\1\154\1\155\2\4\1\156\22\4\27\0"+ "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\2\4\1\213\2\4\1\214\7\4\1\215\12\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\1\4\1\216\15\4\1\217\10\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\1\220\27\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\7\4\1\221\20\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\2\4\1\222\25\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\1\223\27\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\6\4\1\224\21\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\13\4\1\225\14\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\1\4\1\226\26\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\10\4\1\227\17\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\7\4\1\230\20\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\7\4\1\231\20\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\10\4\1\232\17\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\1\4\1\233\3\4\1\234\22\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\24\4\1\235"+ - "\3\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\10\4\1\236\17\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\13\4\1\237"+ + "\13\4\1\157\14\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\16\4\1\160\11\4\107\0"+ + "\1\161\106\0\1\162\106\0\1\163\1\0\1\164\104\0"+ + "\1\165\2\0\1\166\103\0\1\167\3\0\1\170\102\0"+ + "\1\171\5\0\1\172\100\0\1\173\106\0\1\174\131\0"+ + "\1\175\1\0\6\62\1\0\17\62\1\0\60\62\5\176"+ + "\1\177\101\176\7\0\1\7\1\66\1\7\1\0\2\7"+ + "\101\0\1\101\1\0\1\101\1\0\2\101\3\0\1\70"+ + "\1\71\1\0\1\73\11\0\1\73\1\70\13\0\1\71"+ + "\43\0\1\200\1\0\1\200\1\0\2\200\3\0\1\70"+ + "\1\71\2\0\1\201\11\0\1\70\13\0\1\71\12\0"+ + "\1\201\30\0\1\74\1\202\1\74\1\0\2\74\3\0"+ + "\1\70\1\71\1\72\1\73\11\0\1\73\1\70\13\0"+ + "\1\71\43\0\1\74\1\75\1\76\1\0\2\76\101\0"+ + "\1\74\1\75\1\76\1\0\2\76\2\0\1\67\1\70"+ + "\1\71\1\72\1\73\11\0\1\73\1\70\1\0\1\67"+ + "\11\0\1\71\34\0\7\203\1\204\1\203\4\204\1\203"+ + "\1\204\1\205\2\204\1\203\1\204\1\203\1\206\1\0"+ + "\6\203\3\204\1\205\2\203\2\204\5\203\1\204\3\203"+ + "\1\206\30\203\13\0\2\207\2\0\1\67\20\0\1\67"+ + "\55\0\1\101\1\210\1\101\1\0\2\101\3\0\1\70"+ + "\1\71\1\0\1\73\11\0\1\73\1\70\13\0\1\71"+ + "\56\0\1\211\64\0\6\13\1\0\17\13\1\0\60\13"+ + "\6\14\1\0\17\14\1\0\60\14\2\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\2\4\1\212"+ + "\2\4\1\213\7\4\1\214\12\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\1\4\1\215"+ + "\15\4\1\216\10\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\1\217\27\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\7\4"+ + "\1\220\20\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\2\4\1\221\25\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\222"+ + "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\6\4\1\223\21\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\13\4\1\224"+ "\14\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\17\4\1\240\10\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\6\4\1\241"+ - "\21\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\26\4\1\242\1\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\1\243\27\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\10\4\1\244\17\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\3\4\1\245\24\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\13\4\1\246\14\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\1\247\27\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\1\250\6\4\1\251\20\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\5\4\1\252\22\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\10\4\1\253\17\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\5\4\1\254\22\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\1\255\6\4\1\256\20\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\24\4\1\257"+ - "\3\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\4\4\1\260\23\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\2\4\1\261"+ - "\25\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\1\262\27\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\13\4\1\263\3\4"+ - "\1\264\10\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\11\4\1\265\16\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\12\4"+ - "\1\266\15\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\6\4\1\267\10\4\1\270\10\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\17\4\1\271\10\4\107\0\1\272\24\0\5\177"+ - "\1\273\101\177\4\274\1\275\1\200\101\274\7\0\1\201"+ - "\1\276\1\201\1\0\2\201\3\0\1\70\1\71\14\0"+ - "\1\70\13\0\1\71\43\0\1\201\1\0\1\201\1\0"+ - "\2\201\3\0\1\70\1\71\14\0\1\70\13\0\1\71"+ - "\43\0\1\74\1\203\1\74\1\0\2\74\101\0\1\277"+ - "\1\0\4\277\1\0\1\277\1\0\2\277\1\0\1\277"+ - "\1\0\1\300\7\0\3\277\3\0\2\277\5\0\1\277"+ - "\3\0\1\300\30\0\7\204\1\205\1\301\4\205\1\204"+ - "\1\205\1\206\2\205\1\204\1\205\1\204\1\207\1\0"+ - "\6\204\3\205\1\206\2\204\2\205\5\204\1\205\3\204"+ - "\1\207\30\204\7\0\1\302\1\0\1\302\1\277\2\302"+ - "\1\0\1\277\1\0\2\277\1\0\1\277\1\303\1\300"+ - "\7\0\3\277\3\0\2\277\5\0\1\277\3\0\1\300"+ - "\6\0\1\303\31\0\1\304\2\0\2\210\2\0\1\67"+ - "\20\0\1\67\55\0\1\101\1\211\1\101\1\0\2\101"+ - "\74\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\3\4\1\305\24\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\10\4\1\306\17\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\13\4\1\307\14\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\7\4\1\310\20\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\2\4\1\311\25\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\3\4\1\312\24\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\21\4\1\313\6\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\3\4\1\314\24\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\7\4\1\315\20\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\5\4\1\316\22\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\5\4\1\317\22\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\3\4\1\320\24\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\1\321\27\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\23\4\1\322\4\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\17\4\1\323\10\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\1\324\27\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ - "\1\325\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\12\4\1\326\15\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\4"+ - "\1\327\26\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\1\330\27\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\6\4\1\331"+ - "\21\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\17\4\1\332\10\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\3\4\1\333"+ - "\24\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\5\4\1\334\22\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\6\4\1\335"+ - "\21\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\3\4\1\336\24\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\12\4\1\337"+ - "\15\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\3\4\1\340\24\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\7\4\1\341"+ - "\20\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\1\342\6\4\1\343\20\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\4"+ - "\1\344\26\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\3\4\1\345\24\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\346"+ - "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\6\4\1\347\4\4\1\350\14\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\5\4\1\351\22\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\11\4\1\352\16\4\27\0"+ - "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\13\4\1\353\14\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\1\354\27\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\25\4"+ - "\1\355\2\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\6\4\1\356\21\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\14\4"+ - "\1\357\13\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\5\4\1\360\22\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\20\4"+ - "\1\361\7\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\6\4\1\362\21\4\25\0\4\177"+ - "\1\363\1\273\101\177\5\274\1\364\101\274\7\0\1\201"+ - "\1\276\1\201\1\0\2\201\101\0\1\277\1\365\4\277"+ - "\1\0\1\277\1\0\2\277\1\0\1\277\1\0\1\300"+ - "\7\0\3\277\3\0\2\277\5\0\1\277\3\0\1\300"+ - "\37\0\1\201\1\0\1\201\1\0\2\201\7\0\1\303"+ - "\40\0\1\303\30\0\1\205\1\366\4\205\1\0\1\205"+ - "\1\0\2\205\1\0\1\205\1\0\1\300\7\0\3\205"+ - "\3\0\2\205\5\0\1\205\3\0\1\300\37\0\1\302"+ - "\1\367\1\302\1\277\2\302\1\0\1\277\1\0\1\370"+ - "\1\371\1\0\1\277\1\0\1\300\7\0\1\277\1\370"+ - "\1\277\3\0\2\277\5\0\1\371\3\0\1\300\37\0"+ - "\1\201\1\0\1\201\1\0\2\201\102\0\1\304\2\0"+ - "\2\210\74\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\7\4\1\372\20\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\26\4\1\373"+ - "\1\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\1\4\1\374\26\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\10\4\1\375"+ + "\1\4\4\0\1\4\1\225\26\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\10\4\1\226"+ "\17\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\3\4\1\376\24\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\1\377\27\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\6\4\1\u0100\21\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\1\4\1\u0101\26\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\1\4\1\u0102\26\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\12\4\1\u0103\15\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\17\4\1\u0104\10\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\1\4\1\u0105\26\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\16\4\1\u0106\11\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\1\u0107\27\4\27\0"+ + "\1\4\4\0\7\4\1\227\20\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\7\4\1\230"+ + "\20\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\10\4\1\231\17\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\1\4\1\232"+ + "\3\4\1\233\22\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\24\4\1\234\3\4\27\0"+ "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\12\4\1\u0108\15\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\25\4\1\u0109\2\4\27\0"+ + "\10\4\1\235\17\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\13\4\1\236\14\4\27\0"+ "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\14\4\1\u010a\13\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\3\4\1\u010b\24\4\27\0"+ + "\17\4\1\237\10\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\6\4\1\240\21\4\27\0"+ "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\16\4\1\u010c\11\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\7\4\1\u010d\20\4\27\0"+ + "\26\4\1\241\1\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\1\242\27\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ + "\1\243\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\13\4\1\244\14\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\245"+ + "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\1\246\6\4\1\247\20\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\5\4"+ + "\1\250\22\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\10\4\1\251\17\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\5\4"+ + "\1\252\22\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\1\253\6\4\1\254\20\4\27\0"+ "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\17\4\1\u010e\10\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\1\u010f\27\4\27\0\2\4"+ + "\24\4\1\255\3\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\4\4\1\256\23\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\2\4\1\257\25\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\1\260\27\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\13\4"+ + "\1\261\3\4\1\262\10\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\11\4\1\263\16\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\12\4\1\264\15\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\6\4\1\265\10\4"+ + "\1\266\10\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\17\4\1\267\10\4\107\0\1\270"+ + "\24\0\5\176\1\271\101\176\4\272\1\273\1\177\101\272"+ + "\7\0\1\200\1\274\1\200\1\0\2\200\3\0\1\70"+ + "\1\71\14\0\1\70\13\0\1\71\43\0\1\200\1\0"+ + "\1\200\1\0\2\200\3\0\1\70\1\71\14\0\1\70"+ + "\13\0\1\71\43\0\1\74\1\202\1\74\1\0\2\74"+ + "\101\0\1\275\1\0\4\275\1\0\1\275\1\0\2\275"+ + "\1\0\1\275\1\0\1\276\7\0\3\275\3\0\2\275"+ + "\5\0\1\275\3\0\1\276\30\0\7\203\1\204\1\277"+ + "\4\204\1\203\1\204\1\205\2\204\1\203\1\204\1\203"+ + "\1\206\1\0\6\203\3\204\1\205\2\203\2\204\5\203"+ + "\1\204\3\203\1\206\30\203\7\0\1\300\1\0\1\300"+ + "\1\275\2\300\1\0\1\275\1\0\2\275\1\0\1\275"+ + "\1\301\1\276\7\0\3\275\3\0\2\275\5\0\1\275"+ + "\3\0\1\276\6\0\1\301\31\0\1\302\2\0\2\207"+ + "\2\0\1\67\20\0\1\67\55\0\1\101\1\210\1\101"+ + "\1\0\2\101\74\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\3\4\1\303\24\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\10\4"+ + "\1\304\17\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\13\4\1\305\14\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\7\4"+ + "\1\306\20\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\2\4\1\307\25\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ + "\1\310\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\21\4\1\311\6\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ + "\1\312\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\7\4\1\313\20\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\5\4"+ + "\1\314\22\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\5\4\1\315\22\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ + "\1\316\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\1\317\27\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\23\4\1\320"+ + "\4\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\17\4\1\321\10\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\1\322\27\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\3\4\1\323\24\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\12\4\1\324\15\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\1\4\1\325\26\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\326\27\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\6\4\1\327\21\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\17\4\1\330\10\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\5\4\1\331\22\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\6\4\1\332\21\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\3\4\1\333\24\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\12\4\1\334\15\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\3\4\1\335\24\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\7\4\1\336\20\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\1\337\6\4\1\340\20\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\4\1\341\26\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\3\4\1\342\24\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\343\27\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\6\4\1\344\4\4\1\345\14\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\5\4\1\346"+ + "\22\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\11\4\1\347\16\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\13\4\1\350"+ + "\14\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\1\351\27\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\25\4\1\352\2\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\6\4\1\353\21\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\14\4\1\354\13\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\5\4\1\355\22\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\20\4\1\356\7\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\6\4\1\357\21\4\25\0\4\176\1\360\1\271"+ + "\101\176\5\272\1\361\101\272\7\0\1\200\1\274\1\200"+ + "\1\0\2\200\101\0\1\275\1\362\4\275\1\0\1\275"+ + "\1\0\2\275\1\0\1\275\1\0\1\276\7\0\3\275"+ + "\3\0\2\275\5\0\1\275\3\0\1\276\37\0\1\200"+ + "\1\0\1\200\1\0\2\200\7\0\1\301\40\0\1\301"+ + "\30\0\1\204\1\363\4\204\1\0\1\204\1\0\2\204"+ + "\1\0\1\204\1\0\1\276\7\0\3\204\3\0\2\204"+ + "\5\0\1\204\3\0\1\276\37\0\1\300\1\364\1\300"+ + "\1\275\2\300\1\0\1\275\1\0\1\365\1\366\1\0"+ + "\1\275\1\0\1\276\7\0\1\275\1\365\1\275\3\0"+ + "\2\275\5\0\1\366\3\0\1\276\37\0\1\200\1\0"+ + "\1\200\1\0\2\200\102\0\1\302\2\0\2\207\74\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\7\4\1\367\20\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\26\4\1\370\1\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\1\4\1\371\26\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\10\4\1\372\17\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\3\4\1\373\24\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\1\374\27\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\6\4"+ + "\1\375\21\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\1\4\1\376\26\4\27\0\2\4"+ "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\4"+ - "\1\u0110\26\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\5\4\1\u0111\22\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ - "\1\u0112\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\1\4\1\u0113\26\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\2\4"+ - "\1\u0114\25\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\6\4\1\u0115\21\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ - "\1\u0116\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\5\4\1\u0117\22\4\27\0\2\4"+ + "\1\377\26\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\12\4\1\u0100\15\4\27\0\2\4"+ "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\17\4"+ - "\1\u0118\10\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\5\4\1\u0119\22\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\u011a"+ - "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\3\4\1\u011b\24\4\25\0\4\274\1\275"+ - "\1\364\101\274\7\0\1\277\1\365\4\277\1\0\1\277"+ - "\1\0\2\277\1\0\1\277\11\0\3\277\3\0\2\277"+ - "\5\0\1\277\43\0\1\205\1\366\4\205\1\0\1\205"+ - "\1\0\2\205\1\0\1\205\11\0\3\205\3\0\2\205"+ - "\5\0\1\205\43\0\1\302\1\367\1\302\1\277\2\302"+ - "\1\0\1\277\1\0\2\277\1\0\1\277\11\0\3\277"+ - "\3\0\2\277\5\0\1\277\36\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\17\4\1\u011c\10\4"+ + "\1\u0101\10\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\1\4\1\u0102\26\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\16\4"+ + "\1\u0103\11\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\1\u0104\27\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\12\4\1\u0105"+ + "\15\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\25\4\1\u0106\2\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\14\4\1\u0107"+ + "\13\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\3\4\1\u0108\24\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\16\4\1\u0109"+ + "\11\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\7\4\1\u010a\20\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\17\4\1\u010b"+ + "\10\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\1\u010c\27\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\4\1\u010d\26\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\7\4\1\u011d\20\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\10\4\1\u011e\17\4"+ + "\4\0\5\4\1\u010e\22\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\3\4\1\u010f\24\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\20\4\1\u011f\7\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\6\4\1\u0120\21\4"+ + "\4\0\1\4\1\u0110\26\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\2\4\1\u0111\25\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\1\u0121\27\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\5\4\1\u0122\22\4\27\0"+ + "\4\0\6\4\1\u0112\21\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\3\4\1\u0113\24\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\5\4\1\u0114\22\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\17\4\1\u0115\10\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\5\4\1\u0116\22\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\u0117\27\4\27\0"+ "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\1\u0123\27\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\12\4\1\u0124\15\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\4"+ - "\1\u0125\26\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\16\4\1\u0126\11\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ - "\1\u0127\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\5\4\1\u0128\22\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\10\4"+ - "\1\u0129\17\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\4\4\1\u012a\23\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\10\4"+ - "\1\u012b\17\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\21\4\1\u012c\6\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\u012d"+ + "\3\4\1\u0118\24\4\25\0\4\272\1\273\1\361\101\272"+ + "\7\0\1\275\1\362\4\275\1\0\1\275\1\0\2\275"+ + "\1\0\1\275\11\0\3\275\3\0\2\275\5\0\1\275"+ + "\43\0\1\204\1\363\4\204\1\0\1\204\1\0\2\204"+ + "\1\0\1\204\11\0\3\204\3\0\2\204\5\0\1\204"+ + "\43\0\1\300\1\364\1\300\1\275\2\300\1\0\1\275"+ + "\1\0\2\275\1\0\1\275\11\0\3\275\3\0\2\275"+ + "\5\0\1\275\36\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\17\4\1\u0119\10\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\7\4"+ + "\1\u011a\20\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\10\4\1\u011b\17\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\20\4"+ + "\1\u011c\7\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\6\4\1\u011d\21\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\u011e"+ "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\6\4\1\u012e\21\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\3\4\1\u012f"+ - "\24\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\12\4\1\u0130\15\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\1\u0131\27\4"+ + "\1\4\4\0\5\4\1\u011f\22\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\1\u0120\27\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\12\4\1\u0132\15\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\23\4\1\u0133\4\4"+ + "\4\0\12\4\1\u0121\15\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\4\1\u0122\26\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\17\4\1\u0134\10\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\3\4\1\u0135\24\4"+ + "\4\0\16\4\1\u0123\11\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\3\4\1\u0124\24\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\7\4\1\u0136\20\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\15\4\1\u0137\12\4"+ + "\4\0\5\4\1\u0125\22\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\10\4\1\u0126\17\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\12\4\1\u0138\15\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\4\4\1\u0139\23\4"+ + "\4\0\4\4\1\u0127\23\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\10\4\1\u0128\17\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\13\4\1\u013a\14\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\10\4\1\u013b\17\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\2\4\1\u013c\25\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\5\4\1\u013d\22\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\12\4\1\u013e\15\4\27\0\2\4\3\0\13\4"+ + "\4\0\21\4\1\u0129\6\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\u012a\27\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\6\4\1\u012b\21\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\3\4\1\u012c\24\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\12\4\1\u012d\15\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\1\u012e\27\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\12\4"+ + "\1\u012f\15\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\23\4\1\u0130\4\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\17\4"+ + "\1\u0131\10\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\3\4\1\u0132\24\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\7\4"+ + "\1\u0133\20\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\15\4\1\u0134\12\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\12\4"+ + "\1\u0135\15\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\4\4\1\u0136\23\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\13\4"+ + "\1\u0137\14\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\10\4\1\u0138\17\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\2\4"+ + "\1\u0139\25\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\5\4\1\u013a\22\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\12\4"+ + "\1\u013b\15\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\3\4\1\u013c\24\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\u013d"+ + "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\1\u013e\27\4\27\0\2\4\3\0\13\4"+ "\1\0\1\4\1\0\1\4\4\0\3\4\1\u013f\24\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\1\u0140\27\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\1\u0141\27\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ - "\1\u0142\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\3\4\1\u0143\24\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\6\4"+ - "\1\u0144\21\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\10\4\1\u0145\17\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\u0146"+ - "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\24\4\1\u0147\3\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\10\4\1\u0148"+ - "\17\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\3\4\1\u0149\24\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\12\4\1\u014a"+ - "\15\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\3\4\1\u014b\24\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\10\4\1\u014c"+ - "\17\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\3\4\1\u014d\24\4\27\0\2\4\3\0"+ - "\13\4\1\0\1\4\1\0\1\4\4\0\3\4\1\u014e"+ - "\24\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ - "\1\4\4\0\1\u014f\27\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\17\4\1\u0150\10\4"+ + "\4\0\3\4\1\u0140\24\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\6\4\1\u0141\21\4"+ "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\3\4\1\u0151\24\4\27\0\2\4\3\0\13\4"+ - "\1\0\1\4\1\0\1\4\4\0\13\4\1\u0152\14\4"+ - "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ - "\4\0\1\u0153\27\4\27\0\2\4\3\0\13\4\1\0"+ - "\1\4\1\0\1\4\4\0\20\4\1\u0154\7\4\27\0"+ + "\4\0\10\4\1\u0142\17\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\1\u0143\27\4\27\0"+ "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ - "\27\4\1\u0155\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\4\4\1\u0156\23\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\7\4"+ - "\1\u0157\20\4\27\0\2\4\3\0\13\4\1\0\1\4"+ - "\1\0\1\4\4\0\3\4\1\u0158\24\4\27\0\2\4"+ - "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\20\4"+ - "\1\u0159\7\4\25\0"; + "\24\4\1\u0144\3\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\10\4\1\u0145\17\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\3\4\1\u0146\24\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\12\4\1\u0147\15\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\3\4\1\u0148\24\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\10\4\1\u0149\17\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\3\4\1\u014a\24\4\27\0\2\4\3\0\13\4\1\0"+ + "\1\4\1\0\1\4\4\0\3\4\1\u014b\24\4\27\0"+ + "\2\4\3\0\13\4\1\0\1\4\1\0\1\4\4\0"+ + "\1\u014c\27\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\17\4\1\u014d\10\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\3\4"+ + "\1\u014e\24\4\27\0\2\4\3\0\13\4\1\0\1\4"+ + "\1\0\1\4\4\0\13\4\1\u014f\14\4\27\0\2\4"+ + "\3\0\13\4\1\0\1\4\1\0\1\4\4\0\1\u0150"+ + "\27\4\27\0\2\4\3\0\13\4\1\0\1\4\1\0"+ + "\1\4\4\0\20\4\1\u0151\7\4\27\0\2\4\3\0"+ + "\13\4\1\0\1\4\1\0\1\4\4\0\27\4\1\u0152"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\4\4\1\u0153\23\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\7\4\1\u0154\20\4"+ + "\27\0\2\4\3\0\13\4\1\0\1\4\1\0\1\4"+ + "\4\0\3\4\1\u0155\24\4\27\0\2\4\3\0\13\4"+ + "\1\0\1\4\1\0\1\4\4\0\20\4\1\u0156\7\4"+ + "\25\0"; private static int [] zzUnpackTrans() { - int [] result = new int[18034]; + int [] result = new int[17892]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -693,13 +689,13 @@ class _JavaLexer implements FlexLexer { private static final String ZZ_ATTRIBUTE_PACKED_0 = "\1\0\1\11\37\1\1\11\3\1\12\11\1\1\1\11"+ "\2\1\2\11\1\0\3\11\2\1\2\0\4\1\1\0"+ - "\4\11\2\1\1\11\50\1\7\11\1\1\5\11\4\1"+ - "\2\0\2\1\1\0\1\1\1\0\1\11\57\1\1\11"+ - "\1\0\1\1\1\11\4\0\1\1\2\0\56\1\1\11"+ + "\4\11\2\1\1\11\47\1\7\11\1\1\5\11\4\1"+ + "\2\0\2\1\1\0\1\1\1\0\1\11\56\1\1\11"+ + "\1\0\1\1\1\11\4\0\1\1\2\0\55\1\1\11"+ "\4\0\142\1"; private static int [] zzUnpackAttribute() { - int [] result = new int[345]; + int [] result = new int[342]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -760,13 +756,11 @@ class _JavaLexer implements FlexLexer { /* user code: */ private boolean myAssertKeyword; private boolean myEnumKeyword; - private boolean myNoneKeyword; public _JavaLexer(LanguageLevel level) { this((java.io.Reader)null); myAssertKeyword = level.isAtLeast(LanguageLevel.JDK_1_4); myEnumKeyword = level.isAtLeast(LanguageLevel.JDK_1_5); - myNoneKeyword = level.isAtLeast(LanguageLevel.JDK_1_8); } public void goTo(int offset) { @@ -1025,447 +1019,443 @@ class _JavaLexer implements FlexLexer { case 68: { return JavaTokenType.LONG_KEYWORD; } - case 112: break; - case 100: + case 111: break; + case 99: { return JavaTokenType.PRIVATE_KEYWORD; } - case 113: break; + case 112: break; case 27: { return JavaTokenType.COMMA; } - case 114: break; + case 113: break; case 23: { return JavaTokenType.RBRACE; } - case 115: break; + case 114: break; case 22: { return JavaTokenType.LBRACE; } - case 116: break; + case 115: break; case 65: { return JavaTokenType.THIS_KEYWORD; } - case 117: break; - case 84: + case 116: break; + case 83: { return JavaTokenType.CLASS_KEYWORD; } - case 118: break; + case 117: break; case 14: { return JavaTokenType.PLUS; } - case 119: break; + case 118: break; case 54: { return JavaTokenType.XOREQ; } - case 120: break; + case 119: break; case 62: { return JavaTokenType.INT_KEYWORD; } - case 121: break; - case 81: + case 120: break; + case 80: { return JavaTokenType.SHORT_KEYWORD; } - case 122: break; + case 121: break; case 44: { return JavaTokenType.EQEQ; } - case 123: break; + case 122: break; case 67: { return myEnumKeyword ? JavaTokenType.ENUM_KEYWORD : JavaTokenType.IDENTIFIER; } - case 124: break; - case 102: + case 123: break; + case 101: { return JavaTokenType.ABSTRACT_KEYWORD; } - case 125: break; + case 124: break; case 69: { return JavaTokenType.NULL_KEYWORD; } - case 126: break; - case 96: + case 125: break; + case 95: { return JavaTokenType.EXTENDS_KEYWORD; } - case 127: break; + case 126: break; case 51: { return JavaTokenType.LTLT; } - case 128: break; + case 127: break; case 20: { return JavaTokenType.LPARENTH; } - case 129: break; + case 128: break; case 12: { return JavaTokenType.EXCL; } - case 130: break; - case 103: + case 129: break; + case 102: { return JavaTokenType.STRICTFP_KEYWORD; } - case 131: break; + case 130: break; case 34: { return JavaTokenType.DIVEQ; } - case 132: break; - case 90: + case 131: break; + case 89: { return JavaTokenType.STATIC_KEYWORD; } - case 133: break; + case 132: break; case 39: { return JavaTokenType.MINUSMINUS; } - case 134: break; - case 77: + case 133: break; + case 76: { return JavaTokenType.FALSE_KEYWORD; } - case 135: break; + case 134: break; case 1: { return JavaTokenType.BAD_CHARACTER; } - case 136: break; - case 91: + case 135: break; + case 90: { return JavaTokenType.SWITCH_KEYWORD; } - case 137: break; + case 136: break; case 26: { return JavaTokenType.SEMICOLON; } - case 138: break; + case 137: break; case 18: { return JavaTokenType.XOR; } - case 139: break; + case 138: break; case 38: { return JavaTokenType.DOUBLE_LITERAL; } - case 140: break; + case 139: break; case 46: { return JavaTokenType.OREQ; } - case 141: break; + case 140: break; case 11: { return JavaTokenType.EQ; } - case 142: break; + case 141: break; case 4: { return JavaTokenType.DIV; } - case 143: break; + case 142: break; case 66: { return JavaTokenType.ELSE_KEYWORD; } - case 144: break; + case 143: break; case 61: { return JavaTokenType.NEW_KEYWORD; } - case 145: break; + case 144: break; case 58: { return JavaTokenType.ELLIPSIS; } - case 146: break; + case 145: break; case 53: { return JavaTokenType.ANDAND; } - case 147: break; - case 82: + case 146: break; + case 81: { return JavaTokenType.BREAK_KEYWORD; } - case 148: break; + case 147: break; case 9: { return JavaTokenType.CHARACTER_LITERAL; } - case 149: break; + case 148: break; case 52: { return JavaTokenType.ANDEQ; } - case 150: break; + case 149: break; case 6: { return JavaTokenType.INTEGER_LITERAL; } - case 151: break; - case 78: + case 150: break; + case 77: { return JavaTokenType.FLOAT_KEYWORD; } - case 152: break; + case 151: break; case 10: { return JavaTokenType.STRING_LITERAL; } - case 153: break; - case 73: + case 152: break; + case 72: { return JavaTokenType.CHAR_KEYWORD; } - case 154: break; - case 92: + case 153: break; + case 91: { return JavaTokenType.NATIVE_KEYWORD; } - case 155: break; + case 154: break; case 43: { return JavaTokenType.DO_KEYWORD; } - case 156: break; + case 155: break; case 7: { return JavaTokenType.DOT; } - case 157: break; + case 156: break; case 28: { return JavaTokenType.TILDE; } - case 158: break; - case 111: + case 157: break; + case 110: { return JavaTokenType.SYNCHRONIZED_KEYWORD; } - case 159: break; + case 158: break; case 32: { return JavaTokenType.END_OF_LINE_COMMENT; } - case 160: break; + case 159: break; case 35: { return JavaTokenType.ASTERISKEQ; } - case 161: break; - case 80: + case 160: break; + case 79: { return JavaTokenType.SUPER_KEYWORD; } - case 162: break; + case 161: break; case 40: { return JavaTokenType.MINUSEQ; } - case 163: break; + case 162: break; case 63: { return JavaTokenType.LTLTEQ; } - case 164: break; - case 74: + case 163: break; + case 73: { return JavaTokenType.GOTO_KEYWORD; } - case 165: break; + case 164: break; case 25: { return JavaTokenType.RBRACKET; } - case 166: break; + case 165: break; case 33: { return JavaTokenType.C_STYLE_COMMENT; } - case 167: break; + case 166: break; case 15: { return JavaTokenType.LT; } - case 168: break; + case 167: break; case 42: { return JavaTokenType.IF_KEYWORD; } - case 169: break; + case 168: break; case 8: { return JavaTokenType.MINUS; } - case 170: break; - case 86: + case 169: break; + case 85: { return JavaTokenType.WHILE_KEYWORD; } - case 171: break; - case 71: + case 170: break; + case 70: { return JavaTokenType.BYTE_KEYWORD; } - case 172: break; - case 97: + case 171: break; + case 96: { return JavaTokenType.FINALLY_KEYWORD; } - case 173: break; - case 75: + case 172: break; + case 74: { return JavaTokenType.VOID_KEYWORD; } - case 174: break; + case 173: break; case 29: { return JavaTokenType.QUEST; } - case 175: break; + case 174: break; case 19: { return JavaTokenType.PERC; } - case 176: break; - case 110: + case 175: break; + case 109: { return JavaTokenType.IMPLEMENTS_KEYWORD; } - case 177: break; - case 87: + case 176: break; + case 86: { return JavaTokenType.THROWS_KEYWORD; } - case 178: break; + case 177: break; case 41: { return JavaTokenType.ARROW; } - case 179: break; - case 79: + case 178: break; + case 78: { return JavaTokenType.FINAL_KEYWORD; } - case 180: break; - case 94: + case 179: break; + case 93: { return JavaTokenType.DOUBLE_KEYWORD; } - case 181: break; - case 89: + case 180: break; + case 88: { return myAssertKeyword ? JavaTokenType.ASSERT_KEYWORD : JavaTokenType.IDENTIFIER; } - case 182: break; - case 108: + case 181: break; + case 107: { return JavaTokenType.PROTECTED_KEYWORD; } - case 183: break; - case 104: + case 182: break; + case 103: { return JavaTokenType.CONTINUE_KEYWORD; } - case 184: break; - case 101: + case 183: break; + case 100: { return JavaTokenType.PACKAGE_KEYWORD; } - case 185: break; - case 70: - { return myNoneKeyword ? JavaTokenType.NONE_KEYWORD : JavaTokenType.IDENTIFIER; - } - case 186: break; + case 184: break; case 16: { return JavaTokenType.GT; } - case 187: break; + case 185: break; case 24: { return JavaTokenType.LBRACKET; } - case 188: break; + case 186: break; case 36: { return JavaTokenType.LONG_LITERAL; } - case 189: break; + case 187: break; case 60: { return JavaTokenType.FOR_KEYWORD; } - case 190: break; - case 99: + case 188: break; + case 98: { return JavaTokenType.DEFAULT_KEYWORD; } - case 191: break; + case 189: break; case 48: { return JavaTokenType.PLUSEQ; } - case 192: break; - case 88: + case 190: break; + case 87: { return JavaTokenType.RETURN_KEYWORD; } - case 193: break; + case 191: break; case 64: { return JavaTokenType.TRUE_KEYWORD; } - case 194: break; + case 192: break; case 49: { return JavaTokenType.PLUSPLUS; } - case 195: break; + case 193: break; case 47: { return JavaTokenType.OROR; } - case 196: break; + case 194: break; case 13: { return JavaTokenType.OR; } - case 197: break; + case 195: break; case 3: { return JavaTokenType.IDENTIFIER; } - case 198: break; + case 196: break; case 55: { return JavaTokenType.PERCEQ; } - case 199: break; + case 197: break; case 30: { return JavaTokenType.COLON; } - case 200: break; - case 105: + case 198: break; + case 104: { return JavaTokenType.VOLATILE_KEYWORD; } - case 201: break; - case 107: + case 199: break; + case 106: { return JavaTokenType.INTERFACE_KEYWORD; } - case 202: break; - case 109: + case 200: break; + case 108: { return JavaTokenType.INSTANCEOF_KEYWORD; } - case 203: break; - case 106: + case 201: break; + case 105: { return JavaTokenType.TRANSIENT_KEYWORD; } - case 204: break; - case 98: + case 202: break; + case 97: { return JavaTokenType.BOOLEAN_KEYWORD; } - case 205: break; - case 72: + case 203: break; + case 71: { return JavaTokenType.CASE_KEYWORD; } - case 206: break; + case 204: break; case 5: { return JavaTokenType.ASTERISK; } - case 207: break; - case 93: + case 205: break; + case 92: { return JavaTokenType.IMPORT_KEYWORD; } - case 208: break; + case 206: break; case 31: { return JavaTokenType.AT; } - case 209: break; + case 207: break; case 45: { return JavaTokenType.NE; } - case 210: break; + case 208: break; case 59: { return JavaTokenType.TRY_KEYWORD; } - case 211: break; - case 83: + case 209: break; + case 82: { return JavaTokenType.CATCH_KEYWORD; } - case 212: break; + case 210: break; case 37: { return JavaTokenType.FLOAT_LITERAL; } - case 213: break; + case 211: break; case 17: { return JavaTokenType.AND; } - case 214: break; - case 76: + case 212: break; + case 75: { return JavaTokenType.THROW_KEYWORD; } - case 215: break; + case 213: break; case 57: { return JavaDocElementType.DOC_COMMENT; } - case 216: break; + case 214: break; case 56: { return JavaTokenType.DOUBLE_COLON; } - case 217: break; + case 215: break; case 21: { return JavaTokenType.RPARENTH; } - case 218: break; + case 216: break; case 2: { return JavaTokenType.WHITE_SPACE; } - case 219: break; - case 95: + case 217: break; + case 94: { return JavaTokenType.PUBLIC_KEYWORD; } - case 220: break; + case 218: break; case 50: { return JavaTokenType.LE; } - case 221: break; - case 85: + case 219: break; + case 84: { return JavaTokenType.CONST_KEYWORD; } - case 222: break; + case 220: break; default: if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java index 1eaeecc8c8f4..b506fd85e094 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java @@ -38,7 +38,7 @@ public interface ElementType extends JavaTokenType, JavaDocTokenType, INT_KEYWORD, INTERFACE_KEYWORD, LONG_KEYWORD, NATIVE_KEYWORD, NEW_KEYWORD, PACKAGE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, SHORT_KEYWORD, SUPER_KEYWORD, SWITCH_KEYWORD, STRICTFP_KEYWORD, SYNCHRONIZED_KEYWORD, THIS_KEYWORD, THROW_KEYWORD, PROTECTED_KEYWORD, TRANSIENT_KEYWORD, RETURN_KEYWORD, VOID_KEYWORD, STATIC_KEYWORD, WHILE_KEYWORD, TRY_KEYWORD, VOLATILE_KEYWORD, THROWS_KEYWORD, - ENUM_KEYWORD, NONE_KEYWORD); + ENUM_KEYWORD); TokenSet OPERATION_BIT_SET = TokenSet.create( EQ, GT, LT, EXCL, TILDE, QUEST, COLON, PLUS, MINUS, ASTERISK, DIV, AND, OR, XOR, diff --git a/java/java-tests/testSrc/com/intellij/lang/java/lexer/JavaLexerTest.java b/java/java-tests/testSrc/com/intellij/lang/java/lexer/JavaLexerTest.java index 0f5080857a4f..b1639bc4b4be 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/lexer/JavaLexerTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/lexer/JavaLexerTest.java @@ -136,7 +136,7 @@ public class JavaLexerTest extends LexerTestCase { public void testJava8Tokens() { doTest("none :: ->", - "NONE_KEYWORD ('none')\nWHITE_SPACE (' ')\nDOUBLE_COLON ('::')\nWHITE_SPACE (' ')\nARROW ('->')"); + "IDENTIFIER ('none')\nWHITE_SPACE (' ')\nDOUBLE_COLON ('::')\nWHITE_SPACE (' ')\nARROW ('->')"); } @Override From dd1d52b2f6f4b95edc6b9209e7ec3e4f5c4d46d5 Mon Sep 17 00:00:00 2001 From: Danila Ponomarenko Date: Mon, 14 May 2012 13:54:32 +0400 Subject: [PATCH 40/67] IDEA-86016 False positive 'Recursive call' line marker fix --- .../daemon/impl/JavaLineMarkerProvider.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java index a351c62ddcb4..9c5646dd62ed 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java @@ -180,10 +180,21 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { } private static boolean isRecursiveMethodCall(@NotNull PsiMethodCallExpression methodCall){ - PsiMethod referencedMethod = methodCall.resolveMethod(); + final PsiMethod referencedMethod = methodCall.resolveMethod(); - TextRange rmRange = referencedMethod == null ? null : referencedMethod.getTextRange(); - int mcOffset = methodCall.getTextRange().getStartOffset(); + if (referencedMethod == null || !referencedMethod.isValid() || !methodCall.isValid()){ + return false; + } + + final PsiFile methodCallFile = methodCall.getContainingFile(); + final PsiFile methodFile = referencedMethod.getContainingFile(); + + if (methodCallFile == null || methodFile == null || !methodCallFile.equals(methodFile)){ + return false; + } + + final TextRange rmRange = referencedMethod.getTextRange(); + final int mcOffset = methodCall.getTextRange().getStartOffset(); return rmRange != null && rmRange.contains(mcOffset); } From a6e32320d69034515b65efffbdc4702145ae4570 Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Mon, 14 May 2012 13:58:31 +0400 Subject: [PATCH 41/67] Storage dum utility (compile server). --- .../org/jetbrains/ether/StorageDumper.java | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java b/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java new file mode 100644 index 000000000000..7d4c39b96112 --- /dev/null +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java @@ -0,0 +1,156 @@ +package org.jetbrains.ether; + +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.ether.dependencyView.Mappings; +import org.jetbrains.jps.Project; +import org.jetbrains.jps.Sdk; +import org.jetbrains.jps.idea.IdeaProjectLoader; +import org.jetbrains.jps.incremental.Utils; +import org.jetbrains.jps.server.ClasspathBootstrap; + +import java.io.File; +import java.io.PrintStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: db + * Date: 14.05.12 + * Time: 13:02 + * To change this template use File | Settings | File Templates. + */ +public class StorageDumper { + private static class Env { + final String myProjectPath; + final String myOutputPath; + final String myErrors; + final boolean myHelp; + + Env(final String[] args) { + int s = 0; + + String projectPath = null; + String outputPath = null; + boolean help = false; + + final StringBuilder errors = new StringBuilder(); + + for (final String arg : args) { + switch (s) { + case 0: // Initial state + if (arg.equals("-o")) { + s = 1; + } + else if (arg.equals("-h")) { + help = true; + } + else if (arg.startsWith("-")) { + errors.append("Unrecognized option: "); + errors.append(arg); + errors.append("\n"); + } + else { + if (projectPath != null) { + errors.append("Multiple projects specified, skipping "); + errors.append(arg); + errors.append("\n"); + } + else { + projectPath = arg; + } + } + break; + + case 1: // -o + if (arg.startsWith("-")) { + errors.append("Output path expected after \"-o\", but found: "); + errors.append(arg); + errors.append("\n"); + } + else { + if (outputPath != null) { + errors.append("Multiple output paths specified, skipping "); + errors.append(arg); + errors.append("\n"); + } + else { + outputPath = arg; + } + } + s = 0; + } + } + + myOutputPath = outputPath; + myProjectPath = projectPath; + myHelp = help; + + myErrors = errors.toString(); + } + + String getProjectPath() { + return myProjectPath; + } + + String getOutputPath() { + return myOutputPath; + } + + String getErrors() { + return myErrors; + } + + void report() { + if (myHelp) { + System.out.println("Usage: [-o | -h ] "); + System.out.println(); + } + + System.err.println(myErrors); + } + } + + public static void main(final String[] args) { + final Env env = new Env(args); + + env.report(); + + final String path = env.getProjectPath(); + final String oath = env.getOutputPath(); + + if (path == null) { + System.err.println("No project path specified."); + } + else { + try { + final String projectPath = path + File.separator + ".idea"; + final String outputPath = (oath == null ? "" : oath) + File.separator + "snapshot-" + new SimpleDateFormat("dd-MM-yy(hh:mm:ss)").format(new Date()) + ".log"; + final Project project = new Project(); + + final Sdk jdk = project.createSdk("JavaSDK", "IDEA jdk", "1.6", System.getProperty("java.home"), null); + final List paths = new LinkedList(); + + paths.add(FileUtil.toSystemIndependentName(ClasspathBootstrap.getResourcePath(Object.class).getCanonicalPath())); + + jdk.setClasspath(paths); + + IdeaProjectLoader.loadFromPath(project, projectPath, ""); + + final File dataStorageRoot = Utils.getDataStorageRoot(project); + + final Mappings mappings = new Mappings(dataStorageRoot, true); + final PrintStream p = new PrintStream(outputPath); + + mappings.toStream(p); + + p.close(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + } +} From 58dce1256eca069920f97d460a1cf71dbe8f0cfb Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Mon, 14 May 2012 13:50:12 +0400 Subject: [PATCH 42/67] fix npe --- .../groovy/lang/completion/GroovyDocCompletionProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyDocCompletionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyDocCompletionProvider.java index ee03b9d85586..c010d8216641 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyDocCompletionProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyDocCompletionProvider.java @@ -52,6 +52,8 @@ public class GroovyDocCompletionProvider extends CompletionProvider Date: Mon, 14 May 2012 14:13:28 +0400 Subject: [PATCH 43/67] reusing method from PsiTestUtil in tests --- .../intellij/testFramework/PsiTestUtil.java | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java index 78f95bd52d1a..d8dc84b67e6f 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java @@ -46,8 +46,10 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.List; @NonNls public class PsiTestUtil { public static VirtualFile createTestProjectStructure(Project project, @@ -215,12 +217,16 @@ import java.util.Collection; } public static void removeContentEntry(final Module module, final ContentEntry e) { - new WriteCommandAction.Simple(module.getProject()) { + ModuleRootManager rootModel = ModuleRootManager.getInstance(module); + final ModifiableRootModel model = rootModel.getModifiableModel(); + model.removeContentEntry(e); + commitModel(model); + } + + private static void commitModel(final ModifiableRootModel model) { + new WriteCommandAction.Simple(model.getProject()) { @Override protected void run() throws Throwable { - ModuleRootManager rootModel = ModuleRootManager.getInstance(module); - ModifiableRootModel model = rootModel.getModifiableModel(); - model.removeContentEntry(e); model.commit(); } }.execute().throwException(); @@ -234,7 +240,6 @@ import java.util.Collection; } public static void addLibrary(final Module module, final String libName, final String libPath, final String... jarArr) { - assert ModuleRootManager.getInstance(module).getContentRoots().length > 0 : "content roots must not be empty"; new WriteCommandAction(module.getProject()) { @Override protected void run(Result result) throws Throwable { @@ -245,40 +250,52 @@ import java.util.Collection; }.execute().throwException(); } - public static void addLibrary(final Module module, final ModifiableRootModel model, final String libName, final String libPath, final String... jarArr) { + public static void addProjectLibrary(Module module, String libName, VirtualFile... classesRoots) { + final ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(module).getModifiableModel(); + addProjectLibrary(module, modifiableModel, libName, classesRoots); + commitModel(modifiableModel); + } + + private static void addProjectLibrary(final Module module, final ModifiableRootModel model, final String libName, final VirtualFile... classesRoots) { new WriteCommandAction.Simple(module.getProject()) { @Override protected void run() throws Throwable { final LibraryTable libraryTable = ProjectLibraryTable.getInstance(module.getProject()); final Library library = libraryTable.createLibrary(libName); final Library.ModifiableModel libraryModel = library.getModifiableModel(); - for (String jar : jarArr) { - if (!libPath.endsWith("/") && !jar.startsWith("/")) { - jar = "/" + jar; - } - final String path = libPath + jar; - VirtualFile root; - if (path.endsWith(".jar")) { - root = JarFileSystem.getInstance().refreshAndFindFileByPath(path + "!/"); - } else { - root = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); - } - assert root != null : "Library root folder not found: " + path + "!/"; + for (VirtualFile root : classesRoots) { libraryModel.addRoot(root, OrderRootType.CLASSES); } libraryModel.commit(); model.addLibraryEntry(library); final OrderEntry[] orderEntries = model.getOrderEntries(); OrderEntry last = orderEntries[orderEntries.length - 1]; - for (int i = orderEntries.length - 2; i > -1; i--) { - orderEntries[i + 1] = orderEntries[i]; - } + System.arraycopy(orderEntries, 0, orderEntries, 1, orderEntries.length - 1); orderEntries[0] = last; model.rearrangeOrderEntries(orderEntries); } }.execute().throwException(); } + public static void addLibrary(final Module module, final ModifiableRootModel model, final String libName, final String libPath, final String... jarArr) { + List classesRoots = new ArrayList(); + for (String jar : jarArr) { + if (!libPath.endsWith("/") && !jar.startsWith("/")) { + jar = "/" + jar; + } + final String path = libPath + jar; + VirtualFile root; + if (path.endsWith(".jar")) { + root = JarFileSystem.getInstance().refreshAndFindFileByPath(path + "!/"); + } else { + root = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); + } + assert root != null : "Library root folder not found: " + path + "!/"; + classesRoots.add(root); + } + addProjectLibrary(module, model, libName, VfsUtil.toVirtualFileArray(classesRoots)); + } + public static void addLibrary(final Module module, final String libName, final String libDir, final String[] classRoots, From f48d454efea34c35dd2659259a76607fd0075d74 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Sat, 12 May 2012 19:20:11 +0400 Subject: [PATCH 44/67] always close jar builder --- .../compiler/tools/AndroidApkBuilder.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index 9465c698cfe2..f4ac855c0e3d 100644 --- a/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -156,6 +156,7 @@ public class AndroidApkBuilder { result.put(WARNING, new ArrayList()); FileOutputStream fos = null; + SignedJarBuilder builder = null; try { String keyStoreOsPath = customKeystorePath != null && customKeystorePath.length() > 0 @@ -212,7 +213,7 @@ public class AndroidApkBuilder { } fos = new FileOutputStream(outputApk); - SignedJarBuilder builder = new SignedJarBuilder(fos, key, certificate); + builder = new SignedJarBuilder(fos, key, certificate); FileInputStream fis = new FileInputStream(apkPath); try { @@ -265,7 +266,6 @@ public class AndroidApkBuilder { } } } - builder.close(); } catch (IOException e) { return addExceptionMessage(e, result); @@ -292,6 +292,18 @@ public class AndroidApkBuilder { return addExceptionMessage(e, result); } finally { + if (builder != null) { + try { + builder.close(); + } + catch (IOException e) { + addExceptionMessage(e, result); + } + catch (GeneralSecurityException e) { + addExceptionMessage(e, result); + } + } + if (fos != null) { try { fos.close(); From e0870a52370a8ce12b1f7b42e7b779230724cad7 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Sat, 12 May 2012 22:08:51 +0400 Subject: [PATCH 45/67] do not filter list of attributes by context, because passed tag may have other namespace (ex. jspx tag) --- .../relaxNG/model/descriptors/CompositeDescriptor.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/CompositeDescriptor.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/CompositeDescriptor.java index 8e5c75894595..153374e5ce12 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/CompositeDescriptor.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/CompositeDescriptor.java @@ -74,11 +74,7 @@ public class CompositeDescriptor extends RngElementDescriptor { } protected XmlAttributeDescriptor[] collectAttributeDescriptors(@Nullable XmlTag context) { - - final QName qName = context == null ? - null : - new QName(context.getNamespace(), context.getLocalName()); - + final QName qName = null; final DPattern[] patterns; if (qName == null) { patterns = myPatterns; From bd706a1cdaee12cb3eb0817f438cd2f9888ca0c4 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Mon, 14 May 2012 12:25:29 +0200 Subject: [PATCH 46/67] AbstractFileType fixes --- .../impl/CustomSyntaxTableFileType.java | 26 +++++++++++++++++++ .../impl/cache/impl/id/IdTableBuilding.java | 15 ++++------- .../CommentByBlockCommentHandler.java | 7 ++--- .../CommentByLineCommentHandler.java | 5 ++-- .../CustomFileTypeHighlighterProvider.java | 3 ++- .../impl/StandardFileTypeRegistrator.java | 5 ++-- .../psi/impl/cache/impl/id/IdIndex.java | 4 +-- .../impl/id/PlatformIdTableBuilding.java | 17 +++++++----- .../psi/impl/cache/impl/todo/TodoIndex.java | 4 +-- .../psi/impl/search/IndexPatternSearcher.java | 4 +-- .../fileTypes/impl/AbstractFileType.java | 6 +++-- plugins/rearranger/rearranger.iml | 1 + 12 files changed, 65 insertions(+), 32 deletions(-) create mode 100644 platform/indexing-impl/src/com/intellij/openapi/fileTypes/impl/CustomSyntaxTableFileType.java rename platform/{lang-impl => indexing-impl}/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java (94%) diff --git a/platform/indexing-impl/src/com/intellij/openapi/fileTypes/impl/CustomSyntaxTableFileType.java b/platform/indexing-impl/src/com/intellij/openapi/fileTypes/impl/CustomSyntaxTableFileType.java new file mode 100644 index 000000000000..445f369131bb --- /dev/null +++ b/platform/indexing-impl/src/com/intellij/openapi/fileTypes/impl/CustomSyntaxTableFileType.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2012 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.fileTypes.impl; + +import com.intellij.ide.highlighter.custom.SyntaxTable; +import com.intellij.openapi.fileTypes.FileType; + +/** + * Author: dmitrylomov + */ +public interface CustomSyntaxTableFileType extends FileType { + SyntaxTable getSyntaxTable(); +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java similarity index 94% rename from platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java rename to platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java index 7d61c806e49d..dda845796bd0 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java @@ -23,7 +23,7 @@ import com.intellij.lang.findUsages.FindUsagesProvider; import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.LanguageFileType; -import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.psi.CustomHighlighterTokenType; import com.intellij.psi.impl.cache.impl.IndexPatternUtil; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; @@ -116,11 +116,6 @@ public class IdTableBuilding { ourIdIndexers.put(fileType, indexer); } - @Deprecated - public static void registerTodoIndexer(FileType fileType, DataIndexer indexer) { - PlatformIdTableBuilding.ourTodoIndexers.put(fileType, indexer); - } - public static boolean isIdIndexerRegistered(FileType fileType) { return ourIdIndexers.containsKey(fileType) || IdIndexers.INSTANCE.forFileType(fileType) != null; } @@ -159,15 +154,15 @@ public class IdTableBuilding { return new WordsScannerFileTypeIdIndexerAdapter(scanner); } - if (fileType instanceof AbstractFileType) { - return new WordsScannerFileTypeIdIndexerAdapter(createWordScanner((AbstractFileType)fileType)); + if (fileType instanceof CustomSyntaxTableFileType) { + return new WordsScannerFileTypeIdIndexerAdapter(createWordScanner((CustomSyntaxTableFileType)fileType)); } return null; } - private static WordsScanner createWordScanner(final AbstractFileType abstractFileType) { - return new DefaultWordsScanner(new CustomFileTypeLexer(abstractFileType.getSyntaxTable(), true), + private static WordsScanner createWordScanner(final CustomSyntaxTableFileType customSyntaxTableFileType) { + return new DefaultWordsScanner(new CustomFileTypeLexer(customSyntaxTableFileType.getSyntaxTable(), true), TokenSet.create(CustomHighlighterTokenType.IDENTIFIER), TokenSet.create(CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.MULTI_LINE_COMMENT), diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java index 39ba70a41730..fe09c10d5f18 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java @@ -29,6 +29,7 @@ import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -223,8 +224,8 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler { private TextRange findCommentedRange(final Commenter commenter) { final CharSequence text = myDocument.getCharsSequence(); final FileType fileType = myFile.getFileType(); - if (fileType instanceof AbstractFileType) { - Lexer lexer = new CustomFileTypeLexer(((AbstractFileType)fileType).getSyntaxTable()); + if (fileType instanceof CustomSyntaxTableFileType) { + Lexer lexer = new CustomFileTypeLexer(((CustomSyntaxTableFileType)fileType).getSyntaxTable()); final int caretOffset = myEditor.getCaretModel().getOffset(); int commentStart = CharArrayUtil.lastIndexOf(text, commenter.getBlockCommentPrefix(), caretOffset); if (commentStart == -1) return null; @@ -312,7 +313,7 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler { @Nullable private static Commenter findCommenter(PsiFile file, Editor editor) { final FileType fileType = file.getFileType(); - if (fileType instanceof AbstractFileType) { + if (fileType instanceof CustomSyntaxTableFileType) { return ((AbstractFileType)fileType).getCommenter(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java index c90b15b822a8..1120ed03e1a0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java @@ -31,6 +31,7 @@ import com.intellij.openapi.editor.*; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; @@ -210,9 +211,9 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { Commenter blockSuitableCommenter = languageSuitableForCompleteFragment == null ? LanguageCommenters.INSTANCE.forLanguage(myFile.getLanguage()) : null; - if (blockSuitableCommenter == null && myFile.getFileType() instanceof AbstractFileType) { + if (blockSuitableCommenter == null && myFile.getFileType() instanceof CustomSyntaxTableFileType) { blockSuitableCommenter = new Commenter() { - final SyntaxTable mySyntaxTable = ((AbstractFileType)myFile.getFileType()).getSyntaxTable(); + final SyntaxTable mySyntaxTable = ((CustomSyntaxTableFileType)myFile.getFileType()).getSyntaxTable(); @Nullable public String getLineCommentPrefix() { diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeHighlighterProvider.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeHighlighterProvider.java index 3b3208aff5d1..03d312c50c81 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeHighlighterProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeHighlighterProvider.java @@ -20,6 +20,7 @@ import com.intellij.openapi.fileTypes.SyntaxHighlighterProvider; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ide.highlighter.custom.CustomFileHighlighter; @@ -32,7 +33,7 @@ public class CustomFileTypeHighlighterProvider implements SyntaxHighlighterProvi @Nullable public SyntaxHighlighter create(final FileType fileType, @Nullable final Project project, @Nullable final VirtualFile file) { if (fileType instanceof AbstractFileType) { - return new CustomFileHighlighter(((AbstractFileType) fileType).getSyntaxTable()); + return new CustomFileHighlighter(((CustomSyntaxTableFileType) fileType).getSyntaxTable()); } return null; } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/StandardFileTypeRegistrator.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/StandardFileTypeRegistrator.java index 603bd0278270..a7f7d0da14b3 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/StandardFileTypeRegistrator.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/StandardFileTypeRegistrator.java @@ -25,6 +25,7 @@ import com.intellij.ide.highlighter.custom.SyntaxTable; import com.intellij.lang.Commenter; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; public class StandardFileTypeRegistrator implements FileTypeRegistrator { public void initFileType(final FileType fileType) { @@ -51,9 +52,9 @@ public class StandardFileTypeRegistrator implements FileTypeRegistrator { } private static class MyCommenter implements Commenter { - private final AbstractFileType myAbstractFileType; + private final CustomSyntaxTableFileType myAbstractFileType; - public MyCommenter(final AbstractFileType abstractFileType) { + public MyCommenter(final CustomSyntaxTableFileType abstractFileType) { myAbstractFileType = abstractFileType; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java index fa9b7aa17391..f486918aa398 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java @@ -19,7 +19,7 @@ package com.intellij.psi.impl.cache.impl.id; import com.intellij.lang.cacheBuilder.CacheBuilderRegistry; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.LanguageFileType; -import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.indexing.*; @@ -126,7 +126,7 @@ public class IdIndex extends FileBasedIndexExtension { private static boolean isIndexable(FileType fileType) { return fileType instanceof LanguageFileType || - fileType instanceof AbstractFileType || + fileType instanceof CustomSyntaxTableFileType || IdTableBuilding.isIdIndexerRegistered(fileType) || CacheBuilderRegistry.getInstance().getCacheBuilder(fileType) != null; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java index 80c6f558cd85..c190dbb7fa82 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java @@ -27,7 +27,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.CustomHighlighterTokenType; import com.intellij.psi.impl.cache.impl.BaseFilterLexer; @@ -92,7 +92,7 @@ public abstract class PlatformIdTableBuilding { } } - if (fileType instanceof AbstractFileType) { + if (fileType instanceof CustomSyntaxTableFileType) { return new TokenSetTodoIndexer(ABSTRACT_FILE_COMMENT_TOKENS, virtualFile); } @@ -109,6 +109,11 @@ public abstract class PlatformIdTableBuilding { return b; } + @Deprecated + public static void registerTodoIndexer(FileType fileType, DataIndexer indexer) { + ourTodoIndexers.put(fileType, indexer); + } + private static class CompositeTodoIndexer implements DataIndexer { @@ -198,14 +203,14 @@ public abstract class PlatformIdTableBuilding { static { IdTableBuilding.registerIdIndexer(FileTypes.PLAIN_TEXT, new IdTableBuilding.PlainTextIndexer()); - IdTableBuilding.registerTodoIndexer(FileTypes.PLAIN_TEXT, new IdTableBuilding.PlainTextTodoIndexer()); + registerTodoIndexer(FileTypes.PLAIN_TEXT, new IdTableBuilding.PlainTextTodoIndexer()); IdTableBuilding.registerIdIndexer(StdFileTypes.IDEA_MODULE, null); IdTableBuilding.registerIdIndexer(StdFileTypes.IDEA_WORKSPACE, null); IdTableBuilding.registerIdIndexer(StdFileTypes.IDEA_PROJECT, null); - IdTableBuilding.registerTodoIndexer(StdFileTypes.IDEA_MODULE, null); - IdTableBuilding.registerTodoIndexer(StdFileTypes.IDEA_WORKSPACE, null); - IdTableBuilding.registerTodoIndexer(StdFileTypes.IDEA_PROJECT, null); + registerTodoIndexer(StdFileTypes.IDEA_MODULE, null); + registerTodoIndexer(StdFileTypes.IDEA_WORKSPACE, null); + registerTodoIndexer(StdFileTypes.IDEA_PROJECT, null); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index 19809f52fa41..890cc1ebbfbd 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -21,7 +21,7 @@ import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.LanguageFileType; -import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -131,7 +131,7 @@ public class TodoIndex extends FileBasedIndexExtension } return IdTableBuilding.isTodoIndexerRegistered(fileType) || - fileType instanceof AbstractFileType; + fileType instanceof CustomSyntaxTableFileType; } }; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/IndexPatternSearcher.java b/platform/lang-impl/src/com/intellij/psi/impl/search/IndexPatternSearcher.java index 7b233a67d86b..4f1c94e33001 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/IndexPatternSearcher.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/IndexPatternSearcher.java @@ -24,7 +24,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; -import com.intellij.openapi.fileTypes.impl.AbstractFileType; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; @@ -111,7 +111,7 @@ public class IndexPatternSearcher implements QueryExecutor implements ExternalizableFileType, ExternalizableScheme { +public class AbstractFileType extends UserFileType implements ExternalizableFileType, ExternalizableScheme, + CustomSyntaxTableFileType { protected SyntaxTable mySyntaxTable; private SyntaxTable myDefaultSyntaxTable; protected Commenter myCommenter = null; @@ -76,6 +77,7 @@ public class AbstractFileType extends UserFileType implements } } + @Override public SyntaxTable getSyntaxTable() { return mySyntaxTable; } @@ -95,7 +97,7 @@ public class AbstractFileType extends UserFileType implements public void copyFrom(UserFileType newType) { super.copyFrom(newType); if (newType instanceof AbstractFileType) { - mySyntaxTable = ((AbstractFileType)newType).getSyntaxTable(); + mySyntaxTable = ((CustomSyntaxTableFileType)newType).getSyntaxTable(); myExternalInfo.copy(((AbstractFileType)newType).myExternalInfo); } } diff --git a/plugins/rearranger/rearranger.iml b/plugins/rearranger/rearranger.iml index a4214d4850e2..7adfe3aca0d2 100644 --- a/plugins/rearranger/rearranger.iml +++ b/plugins/rearranger/rearranger.iml @@ -8,6 +8,7 @@ + From 49f674d6a381c0925599f22c7772fe441d7b65aa Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 14 May 2012 14:29:33 +0400 Subject: [PATCH 47/67] Fix @NotNull assertion in GitVcsPanel in tests --- plugins/git4idea/src/git4idea/config/GitVcsPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/git4idea/src/git4idea/config/GitVcsPanel.java b/plugins/git4idea/src/git4idea/config/GitVcsPanel.java index d031d595c1d1..acf24e6403ab 100644 --- a/plugins/git4idea/src/git4idea/config/GitVcsPanel.java +++ b/plugins/git4idea/src/git4idea/config/GitVcsPanel.java @@ -16,12 +16,12 @@ package git4idea.config; import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.ui.components.JBCheckBox; -import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.i18n.GitBundle; import git4idea.repo.GitRepositoryManager; @@ -76,7 +76,7 @@ public class GitVcsPanel { myConvertTextFilesComboBox.setSelectedItem(CRLF_ASK); myGitField.addBrowseFolderListener(GitBundle.getString("find.git.title"), GitBundle.getString("find.git.description"), project, FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()); - final GitRepositoryManager repositoryManager = GitUtil.getRepositoryManager(myProject); + final GitRepositoryManager repositoryManager = ServiceManager.getService(myProject, GitRepositoryManager.class); mySyncBranchControl.setVisible(repositoryManager != null && repositoryManager.moreThanOneRoot()); } From 9d25d530fbce3d0801fb7f2151f3656847d46830 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 13:51:19 +0400 Subject: [PATCH 48/67] refactorings api: ability to define changed places (IDEA-85953) --- .../intellij/refactoring/BaseRefactoringProcessor.java | 6 +++++- .../refactoring/safeDelete/SafeDeleteProcessor.java | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index d5cb1d5dd353..091e4f9bc0e5 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -415,7 +415,7 @@ public abstract class BaseRefactoringProcessor { for (Iterator iterator = usageInfoSet.iterator(); iterator.hasNext();) { UsageInfo usageInfo = iterator.next(); final PsiElement element = usageInfo.getElement(); - if (element == null || !element.isWritable()) { + if (element == null || !isToBeChanged(usageInfo)) { iterator.remove(); } } @@ -473,6 +473,10 @@ public abstract class BaseRefactoringProcessor { } } + protected boolean isToBeChanged(UsageInfo usageInfo) { + return usageInfo.isWritable(); + } + /** * Refactorings that spoil PSI (write something directly to documents etc.) should * do that in this method.
diff --git a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java index b2382fd586a9..bbadc0c06cc0 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java @@ -405,6 +405,14 @@ public class SafeDeleteProcessor extends BaseRefactoringProcessor { } } + @Override + protected boolean isToBeChanged(UsageInfo usageInfo) { + if (usageInfo instanceof SafeDeleteReferenceUsageInfo) { + return ((SafeDeleteReferenceUsageInfo)usageInfo).isSafeDelete() && super.isToBeChanged(usageInfo); + } + return super.isToBeChanged(usageInfo); + } + public static boolean validElement(PsiElement element) { if (element instanceof PsiFile) return true; if (!element.isPhysical()) return false; From 4879868fefcb1a5a403f1f73ee416eb5f85932cd Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 14:39:33 +0400 Subject: [PATCH 49/67] package scope when package is inside package prefix should contain classes with "subnames" (IDEA-82937) --- .../com/intellij/psi/search/PackageScope.java | 20 ++++++++++++++++++- .../intellij/execution/ConfigurationUtil.java | 4 ++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/search/PackageScope.java b/java/java-psi-api/src/com/intellij/psi/search/PackageScope.java index e0571b284682..22f7f066b520 100644 --- a/java/java-psi-api/src/com/intellij/psi/search/PackageScope.java +++ b/java/java-psi-api/src/com/intellij/psi/search/PackageScope.java @@ -25,6 +25,9 @@ import com.intellij.openapi.roots.PackageIndex; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClassOwner; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiPackage; import org.jetbrains.annotations.NotNull; @@ -35,6 +38,9 @@ public class PackageScope extends GlobalSearchScope { private final PsiPackage myPackage; private final boolean myIncludeSubpackages; private final boolean myIncludeLibraries; + protected final boolean myPartOfPackagePrefix; + protected final String myPackageQualifiedName; + protected final String myPackageQNamePrefix; public PackageScope(@NotNull PsiPackage aPackage, boolean includeSubpackages, final boolean includeLibraries) { super(aPackage.getProject()); @@ -42,8 +48,12 @@ public class PackageScope extends GlobalSearchScope { myIncludeSubpackages = includeSubpackages; Project project = myPackage.getProject(); - myDirs = PackageIndex.getInstance(project).getDirsByPackageName(myPackage.getQualifiedName(), true).findAll(); + myPackageQualifiedName = myPackage.getQualifiedName(); + myDirs = PackageIndex.getInstance(project).getDirsByPackageName(myPackageQualifiedName, true).findAll(); myIncludeLibraries = includeLibraries; + + myPartOfPackagePrefix = JavaPsiFacade.getInstance(getProject()).isPartOfPackagePrefix(myPackageQualifiedName); + myPackageQNamePrefix = myPackageQualifiedName + "."; } @Override @@ -54,6 +64,14 @@ public class PackageScope extends GlobalSearchScope { : Comparing.equal(file.getParent(), scopeDir); if (inDir) return true; } + if (myPartOfPackagePrefix && myIncludeSubpackages) { + final PsiFile psiFile = myPackage.getManager().findFile(file); + if (psiFile instanceof PsiClassOwner) { + final String packageName = ((PsiClassOwner)psiFile).getPackageName(); + if (myPackageQualifiedName.equals(packageName) || + packageName.startsWith(myPackageQNamePrefix)) return true; + } + } return false; } diff --git a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java index 82e7e6e9d8a1..4d1b6adc05a7 100644 --- a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java +++ b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java @@ -29,7 +29,7 @@ import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.searches.AnnotatedMembersSearch; import com.intellij.psi.search.searches.ClassInheritorsSearch; -import com.intellij.psi.util.PsiUtilBase; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -102,7 +102,7 @@ public class ConfigurationUtil { new Computable() { @Override public Boolean compute() { - return scope.contains(PsiUtilBase.getVirtualFile(containingClass)) && testClassFilter.isAccepted(containingClass); + return scope.contains(PsiUtilCore.getVirtualFile(containingClass)) && testClassFilter.isAccepted(containingClass); } })) { found.add(containingClass); From d56caeb5a31c401a0a2a7410efb93c5078f9d7a3 Mon Sep 17 00:00:00 2001 From: Vassiliy Kudryashov Date: Mon, 14 May 2012 15:06:39 +0400 Subject: [PATCH 50/67] IDEA-85148 'Commit' dialog merged button tooltip is hard to invoke --- .../src/com/intellij/ui/components/JBOptionButton.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBOptionButton.java b/platform/platform-api/src/com/intellij/ui/components/JBOptionButton.java index 4acee12346c8..db80798b0ac3 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBOptionButton.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBOptionButton.java @@ -135,7 +135,7 @@ public class JBOptionButton extends JButton implements MouseMotionListener { @Override public String getToolTipText(MouseEvent event) { - if (myMoreRec.contains(event.getPoint())) { + if (myMoreRec.x < event.getX()) { return myOptionTooltipText; } else { return super.getToolTipText(event); From 7ab954ab1ffaedb8c9be58d484f77a395da5feb0 Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Mon, 14 May 2012 15:11:14 +0400 Subject: [PATCH 51/67] Storage dum utility artifact (compile server). --- .../org/jetbrains/ether/dependencyView/ClassfileAnalyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/ClassfileAnalyzer.java b/jps/model/src/org/jetbrains/ether/dependencyView/ClassfileAnalyzer.java index f45e8fa2e304..864c1033fe71 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/ClassfileAnalyzer.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/ClassfileAnalyzer.java @@ -155,7 +155,7 @@ class ClassfileAnalyzer { final int methodName = context.get(name); if (value instanceof Type) { - final String className = ((Type)value).getClassName(); + final String className = ((Type)value).getClassName().replace('.', '/'); if (className != null) { usages.addUsage(residence, UsageRepr.createClassUsage(context, context.get(className))); From 8b0924027c883452d36bca40a9eeee5ce9948b57 Mon Sep 17 00:00:00 2001 From: Danila Ponomarenko Date: Mon, 14 May 2012 15:22:06 +0400 Subject: [PATCH 52/67] Recursive call markers temporary turned off --- .../daemon/impl/JavaLineMarkerProvider.java | 59 ------------------- 1 file changed, 59 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java index 9c5646dd62ed..4a26b2c25866 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java @@ -32,7 +32,6 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.search.searches.AllOverridingMethodsSearch; import com.intellij.psi.search.searches.ClassInheritorsSearch; @@ -61,8 +60,6 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { private static final Icon IMPLEMENTED_INTERFACE_MARKER_RENDERER = IMPLEMENTED_METHOD_MARKER_RENDERER; private static final Icon SUBCLASSED_CLASS_MARKER_RENDERER = OVERRIDEN_METHOD_MARKER_RENDERER; - private static final Icon RECURSIVE_METHOD_ICON = IconLoader.getIcon("/gutter/recursiveMethod.png"); - protected final DaemonCodeAnalyzerSettings myDaemonSettings; protected final EditorColorsManager myColorsManager; @@ -167,11 +164,6 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { } else if (element instanceof PsiClass && !(element instanceof PsiTypeParameter)) { collectInheritingClasses((PsiClass)element, result); - } else if(element instanceof PsiMethodCallExpression){ - final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)element; - if (isRecursiveMethodCall(methodCall)){ - result.add(new RecursiveMethodCallMarkerInfo(methodCall)); - } } } if (!methods.isEmpty()) { @@ -179,25 +171,6 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { } } - private static boolean isRecursiveMethodCall(@NotNull PsiMethodCallExpression methodCall){ - final PsiMethod referencedMethod = methodCall.resolveMethod(); - - if (referencedMethod == null || !referencedMethod.isValid() || !methodCall.isValid()){ - return false; - } - - final PsiFile methodCallFile = methodCall.getContainingFile(); - final PsiFile methodFile = referencedMethod.getContainingFile(); - - if (methodCallFile == null || methodFile == null || !methodCallFile.equals(methodFile)){ - return false; - } - - final TextRange rmRange = referencedMethod.getTextRange(); - final int mcOffset = methodCall.getTextRange().getStartOffset(); - return rmRange != null && rmRange.contains(mcOffset); - } - private static void collectInheritingClasses(PsiClass aClass, Collection result) { if (aClass.hasModifierProperty(PsiModifier.FINAL)) { return; @@ -303,36 +276,4 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { }; } } - - private static class RecursiveMethodCallMarkerInfo extends MergeableLineMarkerInfo { - private RecursiveMethodCallMarkerInfo(@NotNull PsiMethodCallExpression methodCall) { - super(methodCall, - methodCall.getTextRange(), - RECURSIVE_METHOD_ICON, - Pass.UPDATE_OVERRIDEN_MARKERS, - FunctionUtil.constant("Recursive call"), - null, - GutterIconRenderer.Alignment.RIGHT - ); - } - - @Override - public boolean canMergeWith(@NotNull MergeableLineMarkerInfo info) { - if (!(info instanceof RecursiveMethodCallMarkerInfo)) return false; - PsiElement otherElement = info.getElement(); - PsiElement myElement = getElement(); - return otherElement != null && myElement != null; - } - - - @Override - public Icon getCommonIcon(@NotNull List infos) { - return myIcon; - } - - @Override - public Function getCommonTooltip(@NotNull List infos) { - return FunctionUtil.constant("Multiple recursive calls"); - } - } } From 34f3d5c4867885aeaad2a848663901b814a1f80c Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Mon, 14 May 2012 13:35:23 +0200 Subject: [PATCH 53/67] IDEA-85898 --- .../intellij/images/index/ImageInfoIndex.java | 4 +-- .../util/indexing/FileBasedIndex.java | 7 ++++++ .../indexing/FileBasedIndexExtension.java | 2 +- .../intellij/util/indexing/InputFilter.java | 25 ------------------- .../intellij/find/ngrams/TrigramIndex.java | 6 ++--- .../impl/FrameworkDetectionIndex.java | 4 +-- .../psi/impl/cache/impl/id/IdIndex.java | 4 +-- .../psi/impl/cache/impl/todo/TodoIndex.java | 4 +-- .../psi/impl/include/FileIncludeIndex.java | 4 +-- .../intellij/psi/search/FileTypeIndex.java | 4 +-- .../intellij/psi/search/FilenameIndex.java | 4 +-- .../intellij/psi/stubs/StubUpdatingIndex.java | 4 +-- .../org/jetbrains/android/AndroidIdIndex.java | 4 +-- .../android/AndroidValueResourcesIndex.java | 4 +-- .../lang/ant/psi/impl/AntImportsIndex.java | 4 +-- .../groovy/dsl/GroovyDslFileIndex.java | 4 +-- .../properties/xml/XmlPropertiesIndex.java | 4 +-- .../uiDesigner/binding/FormClassIndex.java | 4 +-- .../lang/xpath/xslt/impl/XsltSymbolIndex.java | 4 +-- .../com/intellij/util/xml/DomFileIndex.java | 4 +-- .../index/Html5CustomAttributesIndex.java | 4 +-- .../src/com/intellij/xml/index/XmlIndex.java | 6 ++--- .../model/resolve/RelaxSymbolIndex.java | 4 +-- 23 files changed, 50 insertions(+), 68 deletions(-) delete mode 100644 platform/indexing-api/src/com/intellij/util/indexing/InputFilter.java diff --git a/images/src/org/intellij/images/index/ImageInfoIndex.java b/images/src/org/intellij/images/index/ImageInfoIndex.java index 472fb9545f4c..ec1ee69b8384 100644 --- a/images/src/org/intellij/images/index/ImageInfoIndex.java +++ b/images/src/org/intellij/images/index/ImageInfoIndex.java @@ -36,7 +36,7 @@ import java.io.IOException; public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension { public static final ID INDEX_ID = ID.create("ImageFileInfoIndex"); - private final InputFilter myInputFilter = new InputFilter() { + private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) && @@ -89,7 +89,7 @@ public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension { public abstract DataExternalizer getValueExternalizer(); - public abstract InputFilter getInputFilter(); + public abstract FileBasedIndex.InputFilter getInputFilter(); public abstract boolean dependsOnFileContent(); diff --git a/platform/indexing-api/src/com/intellij/util/indexing/InputFilter.java b/platform/indexing-api/src/com/intellij/util/indexing/InputFilter.java deleted file mode 100644 index eeddca80a61a..000000000000 --- a/platform/indexing-api/src/com/intellij/util/indexing/InputFilter.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2000-2012 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.util.indexing; - -import com.intellij.openapi.vfs.VirtualFile; - -/** -* Author: dmitrylomov -*/ -public interface InputFilter { - boolean acceptInput(VirtualFile file); -} diff --git a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java index bcafd8f4c29d..9fdc87e70686 100644 --- a/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java +++ b/platform/lang-impl/src/com/intellij/find/ngrams/TrigramIndex.java @@ -36,13 +36,13 @@ public class TrigramIndex extends ScalarIndexExtension { public static final ID INDEX_ID = ID.create("Trigram.Index"); - private static final InputFilter INPUT_FILTER = new InputFilter() { + private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(VirtualFile file) { return !file.getFileType().isBinary(); } }; - private static final InputFilter NO_FILES = new InputFilter() { + private static final FileBasedIndex.InputFilter NO_FILES = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(VirtualFile file) { return false; @@ -82,7 +82,7 @@ public class TrigramIndex extends ScalarIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { if (ENABLED) { return INPUT_FILTER; } diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java index 957921ae7316..4c648d3a3ed9 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectionIndex.java @@ -98,7 +98,7 @@ public class FrameworkDetectionIndex extends ScalarIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { if (myInputFilter == null) { final Set acceptedTypes = new HashSet(); for (FrameworkDetector detector : FrameworkDetector.EP_NAME.getExtensions()) { @@ -119,7 +119,7 @@ public class FrameworkDetectionIndex extends ScalarIndexExtension { return myRegistry.getDetectorsVersion(); } - private static class FileTypesInputFilter implements InputFilter { + private static class FileTypesInputFilter implements FileBasedIndex.InputFilter { private final Set myAcceptedTypes; public FileTypesInputFilter(Set acceptedTypes) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java index f486918aa398..62706a9764b3 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java @@ -42,7 +42,7 @@ import java.util.Map; public class IdIndex extends FileBasedIndexExtension { @NonNls public static final ID NAME = ID.create("IdIndex"); - private final InputFilter myInputFilter = new InputFilter() { + private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { final FileType fileType = file.getFileType(); @@ -120,7 +120,7 @@ public class IdIndex extends FileBasedIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index 890cc1ebbfbd..6488c6636892 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -111,7 +111,7 @@ public class TodoIndex extends FileBasedIndexExtension } }; - private final InputFilter myInputFilter = new InputFilter() { + private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { if (!(file.getFileSystem() instanceof LocalFileSystem)) { @@ -168,7 +168,7 @@ public class TodoIndex extends FileBasedIndexExtension } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java index 45fc9b448b2c..f11d1fc871b8 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeIndex.java @@ -159,8 +159,8 @@ public class FileIncludeIndex extends FileBasedIndexExtension - implements InputFilter, KeyDescriptor, DataIndexer { + implements FileBasedIndex.InputFilter, KeyDescriptor, DataIndexer { public static Collection getFiles(FileType fileType, GlobalSearchScope scope) { @@ -52,7 +52,7 @@ public class FileTypeIndex extends ScalarIndexExtension } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return this; } diff --git a/platform/lang-impl/src/com/intellij/psi/search/FilenameIndex.java b/platform/lang-impl/src/com/intellij/psi/search/FilenameIndex.java index 25e603f2c894..387612fff350 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/FilenameIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/search/FilenameIndex.java @@ -57,7 +57,7 @@ public class FilenameIndex extends ScalarIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } @@ -102,7 +102,7 @@ public class FilenameIndex extends ScalarIndexExtension { } } - private static class MyInputFilter implements InputFilter { + private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override public boolean acceptInput(final VirtualFile file) { return true; diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 428f29dd556e..cfb2be18ee98 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -63,7 +63,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi } }; - private static final InputFilter INPUT_FILTER = new InputFilter() { + private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(@NotNull final VirtualFile file) { return canHaveStub(file); @@ -144,7 +144,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi @NotNull @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } diff --git a/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java b/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java index f705ee42322b..e68a3ec9ea4b 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java +++ b/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java @@ -41,7 +41,7 @@ public class AndroidIdIndex extends ScalarIndexExtension { public static final ID INDEX_ID = ID.create("android.id.index"); public static final String MARKER = "$"; - private static final InputFilter INPUT_FILTER = new InputFilter() { + private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) && @@ -98,7 +98,7 @@ public class AndroidIdIndex extends ScalarIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } diff --git a/plugins/android/src/org/jetbrains/android/AndroidValueResourcesIndex.java b/plugins/android/src/org/jetbrains/android/AndroidValueResourcesIndex.java index 97f42753f450..f40f1a0d024e 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidValueResourcesIndex.java +++ b/plugins/android/src/org/jetbrains/android/AndroidValueResourcesIndex.java @@ -29,7 +29,7 @@ import java.util.Set; public class AndroidValueResourcesIndex extends FileBasedIndexExtension> { public static final ID> INDEX_ID = ID.create("android.value.resources.index"); - private final InputFilter myInputFilter = new InputFilter() { + private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) && @@ -152,7 +152,7 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension{ return map; } }; - private static final InputFilter INPUT_FILTER = new InputFilter() { + private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { return file.getFileType() instanceof XmlFileType; @@ -111,7 +111,7 @@ public class AntImportsIndex extends ScalarIndexExtension{ } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index 81856246328f..0ff1054751e4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -132,7 +132,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } @@ -410,7 +410,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } } - private static class MyInputFilter implements InputFilter { + private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override public boolean acceptInput(final VirtualFile file) { return "gdsl".equals(file.getExtension()); diff --git a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java index d68e30bcbf3c..1f576524002e 100644 --- a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java +++ b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesIndex.java @@ -22,7 +22,7 @@ import java.util.Map; * Date: 7/25/11 */ public class XmlPropertiesIndex extends FileBasedIndexExtension - implements InputFilter, DataIndexer, + implements FileBasedIndex.InputFilter, DataIndexer, KeyDescriptor { public final static Key MARKER_KEY = new Key(); @@ -53,7 +53,7 @@ public class XmlPropertiesIndex extends FileBasedIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } @@ -94,7 +94,7 @@ public class FormClassIndex extends ScalarIndexExtension { } } - private static class MyInputFilter implements InputFilter { + private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override public boolean acceptInput(final VirtualFile file) { return file.getFileType() == StdFileTypes.GUI_DESIGNER_FORM; diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java index 668838c554bb..fb62ec3f0fcb 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltSymbolIndex.java @@ -143,8 +143,8 @@ public class XsltSymbolIndex extends FileBasedIndexExtension{ public static final ID NAME = ID.create("DomFileIndex"); - private static final InputFilter INPUT_FILTER = new InputFilter() { + private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { return file.getFileType() == StdFileTypes.XML; @@ -97,7 +97,7 @@ public class DomFileIndex extends ScalarIndexExtension{ } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } diff --git a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java index 97f4f1927a98..152018cb1281 100644 --- a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java +++ b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java @@ -75,7 +75,7 @@ public class Html5CustomAttributesIndex extends ScalarIndexExtension { } }; - private final InputFilter myInputFilter = new InputFilter() { + private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) && @@ -101,7 +101,7 @@ public class Html5CustomAttributesIndex extends ScalarIndexExtension { } @Override - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } diff --git a/xml/impl/src/com/intellij/xml/index/XmlIndex.java b/xml/impl/src/com/intellij/xml/index/XmlIndex.java index 2e211feeafad..d466188c5ca0 100644 --- a/xml/impl/src/com/intellij/xml/index/XmlIndex.java +++ b/xml/impl/src/com/intellij/xml/index/XmlIndex.java @@ -23,8 +23,8 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileFilter; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.indexing.FileBasedIndex; import com.intellij.util.indexing.FileBasedIndexExtension; -import com.intellij.util.indexing.InputFilter; import com.intellij.util.io.EnumeratorStringDescriptor; import com.intellij.util.io.KeyDescriptor; import org.jetbrains.annotations.NonNls; @@ -39,7 +39,7 @@ public abstract class XmlIndex extends FileBasedIndexExtension { protected static final EnumeratorStringDescriptor KEY_DESCRIPTOR = new EnumeratorStringDescriptor(); - private static final InputFilter INPUT_FILTER = new InputFilter() { + private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { public boolean acceptInput(final VirtualFile file) { @NonNls final String extension = file.getExtension(); return extension != null && extension.equals("xsd"); @@ -105,7 +105,7 @@ public abstract class XmlIndex extends FileBasedIndexExtension { return KEY_DESCRIPTOR; } - public InputFilter getInputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java index ca55a0546682..e92869d41b9a 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java @@ -135,8 +135,8 @@ public class RelaxSymbolIndex extends ScalarIndexExtension { } @Override - public InputFilter getInputFilter() { - return new InputFilter() { + public FileBasedIndex.InputFilter getInputFilter() { + return new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(VirtualFile file) { if (file.getFileSystem() instanceof JarFileSystem) { From 398b0709196d37fa2261b612756247f7ed255ce3 Mon Sep 17 00:00:00 2001 From: Evgeny Zakrevsky Date: Fri, 11 May 2012 17:19:51 +0400 Subject: [PATCH 54/67] Indents in OptionsGroup --- .../options/CodeStyleImportsPanel.java | 2 +- .../printing/ExportToHTMLDialog.java | 1 - .../src/com/intellij/ui/OptionGroup.java | 28 ++++++++----------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java b/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java index 7a890c7081bc..56399a3f7dde 100644 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java +++ b/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java @@ -120,7 +120,7 @@ public class CodeStyleImportsPanel extends JPanel { } private JPanel createGeneralOptionsPanel() { - OptionGroup group = new OptionGroup(ApplicationBundle.message("title.general"), true); + OptionGroup group = new OptionGroup(ApplicationBundle.message("title.general")); myCbUseSingleClassImports = new JCheckBox(ApplicationBundle.message("checkbox.use.single.class.import")); group.add(myCbUseSingleClassImports); diff --git a/platform/lang-impl/src/com/intellij/codeEditor/printing/ExportToHTMLDialog.java b/platform/lang-impl/src/com/intellij/codeEditor/printing/ExportToHTMLDialog.java index fa54e202ebf8..70449b615abd 100644 --- a/platform/lang-impl/src/com/intellij/codeEditor/printing/ExportToHTMLDialog.java +++ b/platform/lang-impl/src/com/intellij/codeEditor/printing/ExportToHTMLDialog.java @@ -112,7 +112,6 @@ public class ExportToHTMLDialog extends DialogWrapper { CodeEditorBundle.message("export.to.html.select.output.directory.description"), project, FileChooserDescriptorFactory.createSingleFolderDescriptor()); labeledComponent.setComponent(targetDirectoryField); - labeledComponent.setBorder(BorderFactory.createEmptyBorder(5, 4, 0, 0)); return labeledComponent; } diff --git a/platform/platform-api/src/com/intellij/ui/OptionGroup.java b/platform/platform-api/src/com/intellij/ui/OptionGroup.java index 2d90ebb51ba2..337fb7d29bc9 100644 --- a/platform/platform-api/src/com/intellij/ui/OptionGroup.java +++ b/platform/platform-api/src/com/intellij/ui/OptionGroup.java @@ -17,6 +17,7 @@ package com.intellij.ui; import com.intellij.openapi.util.Pair; import com.intellij.ui.border.IdeaTitledBorder; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -30,19 +31,13 @@ import java.util.List; public class OptionGroup implements PanelWithAnchor { private String myTitle; private List myOptions; - private List myIsShifted; - private boolean boldTitle; + private List myIsShifted; private JComponent anchor; - public OptionGroup(String title) { - this(title, false); - } - - public OptionGroup(String title, boolean boldTitle) { + public OptionGroup(@Nullable String title) { myTitle = title; myOptions = new ArrayList(); - myIsShifted = new ArrayList(); - this.boldTitle = boldTitle; + myIsShifted = new ArrayList(); } /** @@ -75,27 +70,26 @@ public class OptionGroup implements PanelWithAnchor { panel.setLayout(new GridBagLayout()); for (int i = 0; i < myOptions.size(); i++) { - int leftInset = Boolean.TRUE.equals(myIsShifted.get(i)) ? 15 : 5; - Object option = myOptions.get(i); + final int leftInset = Boolean.TRUE.equals(myIsShifted.get(i)) ? IdeBorderFactory.TITLED_BORDER_INDENT : 0; + final int topInset = i == 0 ? 0 : UIUtil.DEFAULT_VGAP; + final int rightInset = UIUtil.DEFAULT_HGAP; + final Object option = myOptions.get(i); if (option instanceof JComponent) { JComponent component = (JComponent)option; - int verticalInset = component instanceof JLabel || component instanceof JTextField ? 2 : 0; panel.add(component, new GridBagConstraints(0, i, GridBagConstraints.REMAINDER, 1, 1, 0, GridBagConstraints.WEST, getFill(component), - new Insets(verticalInset, leftInset, verticalInset, 5), 0, 0)); + new Insets(topInset, leftInset, 0, 0), 0, 0)); } else { Pair pair = (Pair)option; JComponent firstComponent = (JComponent)pair.first; - int verticalInset = firstComponent instanceof JLabel || firstComponent instanceof JTextField ? 1 : 0; panel.add(firstComponent, new GridBagConstraints(0, i, 1, 1, 1, 0, GridBagConstraints.WEST, getFill(firstComponent), - new Insets(verticalInset, leftInset, verticalInset, 5), 0, 0)); + new Insets(topInset, leftInset, 0, 0), 0, 0)); JComponent secondComponent = (JComponent)pair.second; - verticalInset = secondComponent instanceof JLabel || secondComponent instanceof JTextField ? 2 : 0; panel.add(secondComponent, new GridBagConstraints(1, i, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, - new Insets(verticalInset, 5, verticalInset, 5), 0, 0)); + new Insets(topInset, rightInset, 0, 0), 0, 0)); } } JPanel p = new JPanel(); From dd795f87f8f9dd28bfb3476e9bbf15f6cb0745bd Mon Sep 17 00:00:00 2001 From: Evgeny Zakrevsky Date: Mon, 14 May 2012 15:32:39 +0400 Subject: [PATCH 55/67] git integration. removing panel with "Git: Update". Tree of changes is busy during updating. --- .../intellij/openapi/vcs/changes/ChangeListManagerImpl.java | 2 +- .../src/com/intellij/openapi/vcs/changes/ChangesViewI.java | 1 + .../intellij/openapi/vcs/changes/ChangesViewManager.java | 6 ++++++ .../com/intellij/openapi/vcs/changes/DummyChangesView.java | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index 925063cf5682..c307fae99d32 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -530,7 +530,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec scope.setWasEverythingDirty(wasEverythingDirty); final VcsModifiableDirtyScope adjustedScope = vcs.adjustDirtyScope((VcsModifiableDirtyScope) scope); - myChangesViewManager.updateProgressText(VcsBundle.message("changes.update.progress.message", vcs.getDisplayName()), false); + myChangesViewManager.setBusy(true); dataHolder.notifyStartProcessingChanges(adjustedScope); actualUpdate(builder, adjustedScope, vcs, dataHolder, gate); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewI.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewI.java index 6663169b9669..f5bbd9f9a338 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewI.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewI.java @@ -25,4 +25,5 @@ public interface ChangesViewI { void selectFile(VirtualFile vFile); void refreshChangesViewNodeAsync(VirtualFile file); void updateProgressText(final String text, final boolean isError); + void setBusy(boolean b); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java index 86f5a297fd5f..72abed47be0a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java @@ -358,6 +358,11 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro updateProgressComponent(createTextStatusFactory(text, isError)); } + @Override + public void setBusy(boolean b) { + myView.setPaintBusy(b); + } + public static Factory createTextStatusFactory(final String text, final boolean isError) { return new Factory() { @Override @@ -488,6 +493,7 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro VcsException updateException = changeListManager.getUpdateException(); if (updateException == null) { updateProgressText("", false); + setBusy(false); final Factory additionalUpdateInfo = changeListManager.getAdditionalUpdateInfo(); if (additionalUpdateInfo != null) { updateProgressComponent(additionalUpdateInfo); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DummyChangesView.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DummyChangesView.java index 79552f116eeb..7679eeba0a96 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DummyChangesView.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DummyChangesView.java @@ -40,4 +40,8 @@ class DummyChangesView implements ChangesViewI { @Override public void updateProgressText(String text, boolean isError) { } + + @Override + public void setBusy(boolean b) { + } } From 4114fcc49da864775a25fd86268efcded28ef730 Mon Sep 17 00:00:00 2001 From: Vassiliy Kudryashov Date: Mon, 14 May 2012 16:12:08 +0400 Subject: [PATCH 56/67] IDEA-85611 Run configurations: impossible to delete the default Make 'before launch' goal --- .../BuildArtifactsBeforeRunTaskProvider.java | 2 +- .../ApplicationConfigurationType.java | 6 - .../com/intellij/execution/BeforeRunTask.java | 2 + .../com/intellij/execution/RunManagerEx.java | 10 +- .../execution/actions/CreateAction.java | 5 +- .../impl/BaseExecuteBeforeRunDialog.java | 2 +- .../execution/impl/BeforeRunStepsPanel.java | 8 +- .../ConfigurationSettingsEditorWrapper.java | 4 +- .../execution/impl/ExecutionManagerImpl.java | 7 +- .../execution/impl/RunConfigurable.java | 9 +- .../execution/impl/RunManagerImpl.java | 137 +++++++++--------- .../com/intellij/ui/CollectionListModel.java | 5 + .../src/com/intellij/mock/MockRunManager.java | 13 +- .../explorer/AntTargetNodeDescriptor.java | 2 +- .../ant/config/impl/AntBeforeRunTask.java | 3 - .../config/impl/AntBeforeRunTaskProvider.java | 4 +- .../junit/JUnitConfigurationType.java | 6 - .../tasks/MavenBeforeRunTasksProvider.java | 6 +- .../idea/maven/tasks/MavenTasksManager.java | 2 +- .../actions/ToggleBeforeRunTaskAction.java | 4 +- .../TestNGConfigurationType.java | 7 - 21 files changed, 105 insertions(+), 139 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java index 667bd73ea91e..c7bab6b06867 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java @@ -109,7 +109,7 @@ public class BuildArtifactsBeforeRunTaskProvider extends BeforeRunTaskProvider pointers = task.getArtifactPointers(); - if (!task.isEnabled() || pointers.isEmpty()) { + if (pointers.isEmpty()) { return CompilerBundle.message("build.artifacts.before.run.description.empty"); } if (pointers.size() == 1) { diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java index 7d1ea6033393..032d56d85e1e 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java @@ -16,7 +16,6 @@ package com.intellij.execution.application; import com.intellij.execution.ExecutionBundle; -import com.intellij.execution.RunConfigurationExtension; import com.intellij.execution.configuration.ConfigurationFactoryEx; import com.intellij.execution.configurations.ConfigurationFactory; import com.intellij.execution.configurations.ConfigurationType; @@ -48,11 +47,6 @@ public class ApplicationConfigurationType implements ConfigurationType { return new ApplicationConfiguration("", project, ApplicationConfigurationType.this); } - @Override - public Icon getIcon(@NotNull final RunConfiguration configuration) { - return getIcon(); - } - @Override public void onNewConfigurationCreated(@NotNull RunConfiguration configuration) { ((ModuleBasedConfiguration)configuration).onNewConfigurationCreated(); diff --git a/platform/lang-api/src/com/intellij/execution/BeforeRunTask.java b/platform/lang-api/src/com/intellij/execution/BeforeRunTask.java index fad6015d02f0..5eb1ed114b42 100644 --- a/platform/lang-api/src/com/intellij/execution/BeforeRunTask.java +++ b/platform/lang-api/src/com/intellij/execution/BeforeRunTask.java @@ -55,6 +55,8 @@ public abstract class BeforeRunTask implements Cloneabl if (attribValue == null) { attribValue = element.getAttributeValue("value"); // maintain compatibility with old format } + if (attribValue == null) + attribValue = "true"; myIsEnabled = Boolean.valueOf(attribValue).booleanValue(); } diff --git a/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java b/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java index db6ea1442367..13a16c6fd8f2 100644 --- a/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java +++ b/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java @@ -53,7 +53,10 @@ public abstract class RunManagerEx extends RunManager { @NotNull public abstract RunnerAndConfigurationSettings createConfiguration(String name, ConfigurationFactory type); - public abstract void addConfiguration(RunnerAndConfigurationSettings settings, boolean isShared, List tasks); + public abstract void addConfiguration(RunnerAndConfigurationSettings settings, + boolean isShared, + List tasks, + boolean addTemplateTasksIfAbsent); public abstract void addConfiguration(final RunnerAndConfigurationSettings settings, final boolean isShared); @@ -62,14 +65,11 @@ public abstract class RunManagerEx extends RunManager { @NotNull public abstract List getBeforeRunTasks(RunConfiguration settings); - @NotNull - public abstract List getBeforeRunTasks(RunConfiguration settings, boolean includeOnlyActiveTasks); - @NotNull public abstract List getBeforeRunTasks(RunConfiguration settings, Key taskProviderID); @NotNull - public abstract List getBeforeRunTasks(Key taskProviderID, boolean includeOnlyActiveTasks); + public abstract List getBeforeRunTasks(Key taskProviderID); public abstract RunnerAndConfigurationSettings findConfigurationByName(@Nullable final String name); diff --git a/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java b/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java index af9ce1aed324..d7fd9e783393 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java @@ -122,7 +122,8 @@ public class CreateAction extends BaseRunConfigurationAction { final RunnerAndConfigurationSettings configuration = context.getConfiguration(); final RunnerAndConfigurationSettings template = runManager.getConfigurationTemplate(configuration.getFactory()); final RunConfiguration templateConfiguration = template.getConfiguration(); - runManager.addConfiguration(configuration, runManager.isConfigurationShared(template), runManager.getBeforeRunTasks( templateConfiguration)); + runManager.addConfiguration(configuration, runManager.isConfigurationShared(template), runManager.getBeforeRunTasks( templateConfiguration), + false); runManager.setActiveConfiguration(configuration); } } @@ -139,7 +140,7 @@ public class CreateAction extends BaseRunConfigurationAction { final RunManagerImpl runManager = (RunManagerImpl)context.getRunManager(); runManager.addConfiguration(configuration, runManager.isConfigurationShared(configuration), - runManager.getBeforeRunTasks(configuration.getConfiguration())); + runManager.getBeforeRunTasks(configuration.getConfiguration()), false); runManager.setActiveConfiguration(configuration); } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java b/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java index fe59622cc785..31284e67419a 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java @@ -235,7 +235,7 @@ public abstract class BaseExecuteBeforeRunDialog extend tasks.remove(task); } } - runManager.setBeforeRunTasks(config, tasks); + runManager.setBeforeRunTasks(config, tasks, false); } protected abstract void update(T task); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java b/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java index cc2b4687ea0f..29e34c124e0a 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java @@ -120,7 +120,7 @@ class BeforeRunStepsPanel extends JPanel { myRunConfiguration = settings.getConfiguration(); originalTasks.clear(); - originalTasks.addAll(RunManagerImpl.getInstanceImpl(myRunConfiguration.getProject()).getBeforeRunTasks(myRunConfiguration, true)); + originalTasks.addAll(RunManagerImpl.getInstanceImpl(myRunConfiguration.getProject()).getBeforeRunTasks(myRunConfiguration)); myModel.replaceAll(originalTasks); myShowSettingsBeforeRunCheckBox.setSelected(settings.isEditBeforeRun()); myShowSettingsBeforeRunCheckBox.setEnabled(!(myRunConfiguration instanceof UnknownRunConfiguration)); @@ -205,11 +205,11 @@ class BeforeRunStepsPanel extends JPanel { = (RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask)task; RunConfiguration configuration = runTask.getSettings().getConfiguration(); - List tasks = RunManagerImpl.getInstanceImpl(configuration.getProject()).getBeforeRunTasks(configuration, true); + List tasks = RunManagerImpl.getInstanceImpl(configuration.getProject()).getBeforeRunTasks(configuration); for (BeforeRunTask beforeRunTask : tasks) { if (beforeRunTask instanceof RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask) { - configurationSet.add(((RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask)beforeRunTask).getSettings().getConfiguration()); - getAllRunBeforeRuns(beforeRunTask, configurationSet); + if (configurationSet.add(((RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask)beforeRunTask).getSettings().getConfiguration())) + getAllRunBeforeRuns(beforeRunTask, configurationSet); } } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java index 7d1d7a436db0..61835db7f5b3 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java @@ -114,7 +114,7 @@ public class ConfigurationSettingsEditorWrapper extends SettingsEditor getStepsBeforeLaunch() { - return Collections.unmodifiableList(myBeforeRunStepsPanel.getTasks(false)); + return Collections.unmodifiableList(myBeforeRunStepsPanel.getTasks(true)); } public boolean isStoreProjectConfiguration() { diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java index f15e9fa2c222..484cb35ac961 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java @@ -97,12 +97,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject); final List activeTasks = new ArrayList(); - final List tasks = runManager.getBeforeRunTasks(runConfiguration); - for (BeforeRunTask task : tasks) { - if (task != null && task.isEnabled()) { - activeTasks.add(task); - } - } + activeTasks.addAll(runManager.getBeforeRunTasks(runConfiguration)); ConfigurationPerRunnerSettings configurationSettings = state != null ? state.getConfigurationSettings() : null; final DataContext projectContext = SimpleDataContext.getProjectContext(myProject); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java index f462ba509a22..75a880070fbd 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java @@ -164,12 +164,7 @@ class RunConfigurable extends BaseConfigurable { if (userObject instanceof SingleConfigurationConfigurable) { final SingleConfigurationConfigurable settings = (SingleConfigurationConfigurable)userObject; RunnerAndConfigurationSettings snapshot; - try { - snapshot = settings.getSnapshot(); - } - catch (ConfigurationException e) { - snapshot = settings.getSettings(); - } + snapshot = settings.getSettings(); configuration = settings.getConfiguration(); name = settings.getNameText(); setIcon(ProgramRunnerUtil.getConfigurationIcon(snapshot, !settings.isValid(), runManager.isTemporary(configuration))); @@ -645,7 +640,7 @@ class RunConfigurable extends BaseConfigurable { for (RunConfigurationBean each : stableConfigurations) { toDeleteSettings.remove(each.getSettings()); - manager.addConfiguration(each.getSettings(), each.isShared(), each.getStepsBeforeLaunch()); + manager.addConfiguration(each.getSettings(), each.isShared(), each.getStepsBeforeLaunch(), false); } RunnerAndConfigurationSettings selected = manager.getSelectedConfiguration(); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java index 25555d1ee971..cc09148e22af 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java @@ -67,7 +67,6 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, protected static final String SELECTED_ATTR = "selected"; @NonNls private static final String METHOD = "method"; @NonNls private static final String OPTION = "option"; - @NonNls private static final String VALUE = "value"; private List myUnknownElements = null; private JDOMExternalizableStringList myOrder = new JDOMExternalizableStringList(); @@ -240,7 +239,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, public void addConfiguration(RunnerAndConfigurationSettings settings, boolean shared, - List tasks) { + List tasks, boolean addEnabledTemplateTasksIfAbsent) { final RunConfiguration configuration = settings.getConfiguration(); Integer existingId = findConfigurationIdByUniqueName(getUniqueName(settings)); @@ -257,7 +256,8 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, checkRecentsLimit(); mySharedConfigurations.put(newId, shared); - setBeforeRunTasks(configuration, tasks); + getTemplateBeforeRunTask(configuration); + setBeforeRunTasks(configuration, tasks, addEnabledTemplateTasksIfAbsent); if (existingSettings == settings) { myDispatcher.getMulticaster().runConfigurationChanged(settings); @@ -455,13 +455,30 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, if (!settings.isTemplate()) { List beforeRunTasks = getBeforeRunTasks(getConfigurationTemplate(settings.getFactory()).getConfiguration()); templateTasks = new HashMap, BeforeRunTask>(); - for (BeforeRunTask task : beforeRunTasks) { - templateTasks.put(task.getProviderId(), task); + for (BeforeRunTask templateTask : beforeRunTasks) { + templateTasks.put(templateTask.getProviderId(), templateTask); + if (templateTask.isEnabled()) { + boolean found = false; + for (BeforeRunTask realTask : tasks) { + if (realTask.getProviderId() == templateTask.getProviderId()) { + found = true; + break; + } + } + if (!found) { + BeforeRunTask clone = templateTask.clone(); + clone.setEnabled(false); + tasks.add(0, clone); + } + } } } for (BeforeRunTask task : tasks) { - if (templateTasks != null && task.equals(templateTasks.get(task.getProviderId()))) - continue; // not neccesary saving if the task is the same as template + if (templateTasks != null) { + BeforeRunTask templateTask = templateTasks.get(task.getProviderId()); + if (task.equals(templateTask)) + continue; // not neccesary saving if the task is the same as template + } final Element child = new Element(OPTION); child.setAttribute(NAME_ATTR, task.getProviderId().toString()); task.writeExternal(child); @@ -471,6 +488,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, } } + public void readExternal(final Element parentNode) throws InvalidDataException { clear(); @@ -573,10 +591,10 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, final List tasks = readStepsBeforeRun(methodsElement, settings); if (settings.isTemplate()) { myTemplateConfigurationsMap.put(factory.getType().getId() + "." + factory.getName(), settings); - setBeforeRunTasks(settings.getConfiguration(), tasks); + setBeforeRunTasks(settings.getConfiguration(), tasks, true); } else { - addConfiguration(settings, isShared, tasks); + addConfiguration(settings, isShared, tasks, true); if (Boolean.valueOf(element.getAttributeValue(SELECTED_ATTR)).booleanValue()) { //to support old style setSelectedConfiguration(settings); } @@ -657,7 +675,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, invalidateConfigurationIcon(tempConfiguration); addConfiguration(tempConfiguration, isConfigurationShared(tempConfiguration), - getBeforeRunTasks(tempConfiguration.getConfiguration())); + getBeforeRunTasks(tempConfiguration.getConfiguration()), false); setActiveConfiguration(tempConfiguration); } @@ -720,48 +738,30 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, } @NotNull - public List getBeforeRunTasks(Key taskProviderID, boolean includeOnlyActiveTasks) { + public List getBeforeRunTasks(Key taskProviderID) { final List tasks = new ArrayList(); - if (includeOnlyActiveTasks) { - final List checkedTemplates = new ArrayList(); - List settingsList = new ArrayList(myConfigurations.values()); - for (RunnerAndConfigurationSettings settings : settingsList) { - final List runTasks = getBeforeRunTasks(settings.getConfiguration()); - for (BeforeRunTask task : runTasks) { - if (task != null && task.isEnabled() && task.getProviderId() == taskProviderID) { - tasks.add((T)task); - } - else { - final RunnerAndConfigurationSettings template = getConfigurationTemplate(settings.getFactory()); - if (!checkedTemplates.contains(template)) { - checkedTemplates.add(template); - final List templateTasks = getBeforeRunTasks(template.getConfiguration()); - for (BeforeRunTask templateTask : templateTasks) { - if (templateTask != null && templateTask.isEnabled() && templateTask.getProviderId() == taskProviderID) { - tasks.add((T)templateTask); - } + final List checkedTemplates = new ArrayList(); + List settingsList = new ArrayList(myConfigurations.values()); + for (RunnerAndConfigurationSettings settings : settingsList) { + final List runTasks = getBeforeRunTasks(settings.getConfiguration()); + for (BeforeRunTask task : runTasks) { + if (task != null && task.isEnabled() && task.getProviderId() == taskProviderID) { + tasks.add((T)task); + } + else { + final RunnerAndConfigurationSettings template = getConfigurationTemplate(settings.getFactory()); + if (!checkedTemplates.contains(template)) { + checkedTemplates.add(template); + final List templateTasks = getBeforeRunTasks(template.getConfiguration()); + for (BeforeRunTask templateTask : templateTasks) { + if (templateTask != null && templateTask.isEnabled() && templateTask.getProviderId() == taskProviderID) { + tasks.add((T)templateTask); } } } } } } - else { - for (RunnerAndConfigurationSettings settings : myTemplateConfigurationsMap.values()) { - final List tasks_ = getBeforeRunTasks(settings.getConfiguration()); - for (BeforeRunTask task : tasks_) { - if (task != null && task.getProviderId() == taskProviderID) - tasks.add((T)task); - } - } - for (RunnerAndConfigurationSettings settings : myConfigurations.values()) { - final List tasks_ = getBeforeRunTasks(settings.getConfiguration()); - for (BeforeRunTask task : tasks_) { - if (task != null && task.getProviderId() == taskProviderID) - tasks.add((T)task); - } - } - } return tasks; } @@ -826,32 +826,25 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, @NotNull public List getBeforeRunTasks(final RunConfiguration settings) { - return getBeforeRunTasks(settings, false); - } - @NotNull - @Override - public List getBeforeRunTasks(RunConfiguration settings, boolean includeOnlyActiveTasks) { final List tasks = myConfigurationToBeforeTasksMap.get(settings); if (tasks != null) { - return getCopies(tasks, includeOnlyActiveTasks); + return getCopies(tasks); } - return getTemplateBeforeRunTask(settings, includeOnlyActiveTasks); + return getTemplateBeforeRunTask(settings); } - private List getTemplateBeforeRunTask(RunConfiguration settings, boolean includeOnlyActiveTasks) { + private List getTemplateBeforeRunTask(RunConfiguration settings) { final RunnerAndConfigurationSettings template = getConfigurationTemplate(settings.getFactory()); final List templateTasks = myConfigurationToBeforeTasksMap.get(template.getConfiguration()); if (templateTasks != null) { - return getCopies(templateTasks, includeOnlyActiveTasks); + return getCopies(templateTasks); } final List _tasks = new ArrayList(); for (BeforeRunTaskProvider provider : Extensions .getExtensions(BeforeRunTaskProvider.EXTENSION_POINT_NAME, myProject)) { BeforeRunTask task = provider.createTask(settings); - if (task != null) { - if (includeOnlyActiveTasks && !task.isEnabled()) - continue; + if (task != null && task.isEnabled()) { Key providerID = provider.getId(); _tasks.add(task); settings.getFactory().configureBeforeRunTaskDefaults(providerID, task); @@ -861,11 +854,11 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, } @NotNull - private static List getCopies(List original, boolean includeOnlyActiveTasks) { + private static List getCopies(List original) { List result = new ArrayList(); if (original != null) { for (BeforeRunTask task : original) { - if (includeOnlyActiveTasks && !task.isEnabled()) + if (!task.isEnabled()) continue; result.add(task.clone()); } @@ -883,18 +876,20 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, if (shouldFire) fireRunConfigurationChanged(settings); } - public final void setBeforeRunTasks(final RunConfiguration runConfiguration, List tasks) { - List templates = getTemplateBeforeRunTask(runConfiguration, false); - Set> idsToSet = new HashSet>(); + public final void setBeforeRunTasks(final RunConfiguration runConfiguration, @NotNull List tasks, boolean addEnabledTemplateTasksIfAbsent) { List result = new ArrayList(tasks); - for (BeforeRunTask task : tasks) { - idsToSet.add(task.getProviderId()); - } - int i = 0; - for (BeforeRunTask template : templates) { - if (!idsToSet.contains(template.getProviderId())) { - result.add(i, template); - i++; + if (addEnabledTemplateTasksIfAbsent) { + List templates = getTemplateBeforeRunTask(runConfiguration); + Set> idsToSet = new HashSet>(); + for (BeforeRunTask task : tasks) { + idsToSet.add(task.getProviderId()); + } + int i = 0; + for (BeforeRunTask template : templates) { + if (!idsToSet.contains(template.getProviderId())) { + result.add(i, template); + i++; + } } } myConfigurationToBeforeTasksMap.put(runConfiguration, result); @@ -907,7 +902,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, } public void addConfiguration(final RunnerAndConfigurationSettings settings, final boolean isShared) { - addConfiguration(settings, isShared, new ArrayList()); + addConfiguration(settings, isShared, new ArrayList(), false); } public static RunManagerImpl getInstanceImpl(final Project project) { diff --git a/platform/platform-api/src/com/intellij/ui/CollectionListModel.java b/platform/platform-api/src/com/intellij/ui/CollectionListModel.java index 161529538472..12ddaa9bff41 100644 --- a/platform/platform-api/src/com/intellij/ui/CollectionListModel.java +++ b/platform/platform-api/src/com/intellij/ui/CollectionListModel.java @@ -98,4 +98,9 @@ public class CollectionListModel extends AbstractListModel { removeAll(); add(elements); } + + @Override + public String toString() { + return getClass().getName() + " (" + getSize() + " elements)"; + } } diff --git a/platform/testFramework/src/com/intellij/mock/MockRunManager.java b/platform/testFramework/src/com/intellij/mock/MockRunManager.java index 4f47bbd45014..8cb22fd675be 100644 --- a/platform/testFramework/src/com/intellij/mock/MockRunManager.java +++ b/platform/testFramework/src/com/intellij/mock/MockRunManager.java @@ -96,7 +96,10 @@ public class MockRunManager extends RunManagerEx { } @Override - public void addConfiguration(RunnerAndConfigurationSettings settings, boolean isShared, List tasks) { + public void addConfiguration(RunnerAndConfigurationSettings settings, + boolean isShared, + List tasks, + boolean addTemplateTasksIfAbsent) { } @Override @@ -111,18 +114,12 @@ public class MockRunManager extends RunManagerEx { @NotNull @Override public List getBeforeRunTasks(RunConfiguration settings) { - return null; - } - - @NotNull - @Override - public List getBeforeRunTasks(RunConfiguration settings, boolean includeOnlyActiveTasks) { return Collections.emptyList(); } @NotNull @Override - public List getBeforeRunTasks(Key taskProviderID, boolean includeOnlyActiveTasks) { + public List getBeforeRunTasks(Key taskProviderID) { return Collections.emptyList(); } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntTargetNodeDescriptor.java b/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntTargetNodeDescriptor.java index b5fe79ba9959..12450fafdb4b 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntTargetNodeDescriptor.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntTargetNodeDescriptor.java @@ -97,7 +97,7 @@ final class AntTargetNodeDescriptor extends AntNodeDescriptor { final RunManagerEx runManager = RunManagerEx.getInstanceEx(myProject); final VirtualFile vFile = buildFile.getVirtualFile(); if (vFile != null) { - for (AntBeforeRunTask task : runManager.getBeforeRunTasks(AntBeforeRunTaskProvider.ID, true)) { + for (AntBeforeRunTask task : runManager.getBeforeRunTasks(AntBeforeRunTaskProvider.ID)) { if (task.isRunningTarget(myTarget)) { myHighlightedText.getEnding().addText(" (Before Run/Debug)", ourPostfixAttributes); break; diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTask.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTask.java index da5fe11c2bc6..9612ca7417f2 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTask.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTask.java @@ -69,9 +69,6 @@ public class AntBeforeRunTask extends BeforeRunTask{ } public boolean isRunningTarget(AntBuildTarget target) { - if (!isEnabled()) { - return false; - } final VirtualFile vFile = target.getModel().getBuildFile().getVirtualFile(); if (vFile == null) { return false; diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTaskProvider.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTaskProvider.java index 96dffca033d0..d1b589dba850 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTaskProvider.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBeforeRunTaskProvider.java @@ -66,7 +66,7 @@ public class AntBeforeRunTaskProvider extends BeforeRunTaskProvider"); @@ -144,7 +144,7 @@ public class AntBeforeRunTaskProvider extends BeforeRunTaskProvider projectAndGoal = getProjectAndGoalChecked(task); - if (projectAndGoal != null) desc = projectAndGoal.first.getDisplayName() + ":" + projectAndGoal.second; - } + Pair projectAndGoal = getProjectAndGoalChecked(task); + if (projectAndGoal != null) desc = projectAndGoal.first.getDisplayName() + ":" + projectAndGoal.second; return desc == null ? TasksBundle.message("maven.tasks.before.run.empty") : TasksBundle.message("maven.tasks.before.run", desc); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java index 55cdc3ae5d16..303d91189726 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java @@ -162,7 +162,7 @@ public class MavenTasksManager extends MavenSimpleProjectComponent implements Pe } } RunManagerEx runManager = RunManagerEx.getInstanceEx(myProject); - for (MavenBeforeRunTask each : runManager.getBeforeRunTasks(MavenBeforeRunTasksProvider.ID, true)) { + for (MavenBeforeRunTask each : runManager.getBeforeRunTasks(MavenBeforeRunTasksProvider.ID)) { if (each.isFor(project, goal)) { result.add(TasksBundle.message("maven.tasks.goal.before.run")); break; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/ToggleBeforeRunTaskAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/ToggleBeforeRunTaskAction.java index 62949c591b88..cbbf24fc8c6a 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/ToggleBeforeRunTaskAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/ToggleBeforeRunTaskAction.java @@ -40,8 +40,8 @@ public class ToggleBeforeRunTaskAction extends MavenToggleAction { final DataContext context = e.getDataContext(); final Pair desc = getTaskDesc(context); if (desc != null) { - for (MavenBeforeRunTask each : getRunManager(context).getBeforeRunTasks(MavenBeforeRunTasksProvider.ID, true)) { - if (each.isEnabled() && each.isFor(desc.first, desc.second)) return true; + for (MavenBeforeRunTask each : getRunManager(context).getBeforeRunTasks(MavenBeforeRunTasksProvider.ID)) { + if (each.isFor(desc.first, desc.second)) return true; } } return false; diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationType.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationType.java index 08cb9c134888..7dfc48dfa35b 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationType.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationType.java @@ -23,9 +23,7 @@ package com.theoryinpractice.testng.configuration; import com.intellij.execution.Location; -import com.intellij.execution.RunConfigurationExtension; import com.intellij.execution.RunManagerEx; -import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.configuration.ConfigurationFactoryEx; import com.intellij.execution.configurations.*; import com.intellij.execution.impl.RunManagerImpl; @@ -57,11 +55,6 @@ public class TestNGConfigurationType implements ConfigurationType return new TestNGConfiguration("", project, this); } - @Override - public Icon getIcon(@NotNull final RunConfiguration configuration) { - return ICON; - } - @Override public void onNewConfigurationCreated(@NotNull RunConfiguration configuration) { ((ModuleBasedConfiguration)configuration).onNewConfigurationCreated(); From f6953ac8436ad6b91442ebb0fdf46c37a3df0f95 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Mon, 14 May 2012 16:25:50 +0400 Subject: [PATCH 57/67] RelativeLayout --- .../layout/RelativeLayoutOperation.java | 3 + .../layout/relative/AutoSnapPoint.java | 4 + .../layout/relative/RelativeDecorator.java | 163 +++++++++++++++++- .../relative/SnapPointFeedbackHost.java | 54 +++++- .../relative/RadRelativeLayoutComponent.java | 15 ++ .../model/layout/relative/RelativeInfo.java | 8 + .../designSurface/DecorationLayer.java | 8 + 7 files changed, 250 insertions(+), 5 deletions(-) diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/RelativeLayoutOperation.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/RelativeLayoutOperation.java index 15911f11c360..227325b5b684 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/RelativeLayoutOperation.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/RelativeLayoutOperation.java @@ -56,6 +56,8 @@ public class RelativeLayoutOperation extends AbstractEditOperation { private void createFeedback() { if (mySnapFeedback == null) { + myContainer.setClientProperty(SnapPointFeedbackHost.KEY, Boolean.TRUE); + FeedbackLayer layer = myContext.getArea().getFeedbackLayer(); myHorizontalTextFeedback = new TextFeedback(); @@ -171,6 +173,7 @@ public class RelativeLayoutOperation extends AbstractEditOperation { @Override public void eraseFeedback() { if (mySnapFeedback != null) { + myContainer.extractClientProperty(SnapPointFeedbackHost.KEY); FeedbackLayer layer = myContext.getArea().getFeedbackLayer(); layer.remove(myHorizontalTextFeedback); layer.remove(myVerticalTextFeedback); diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/AutoSnapPoint.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/AutoSnapPoint.java index 1d257de52125..ef4823af47db 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/AutoSnapPoint.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/AutoSnapPoint.java @@ -53,9 +53,13 @@ public class AutoSnapPoint extends SnapPoint { if (myHorizontal) { myMargin = bounds.x - myBounds.x; + feedback.addVerticalLine(myBounds.x, myBounds.y, myBounds.height); + feedback.addHorizontalArrow(myBounds.x, bounds.y + bounds.height / 2, myMargin); } else { myMargin = bounds.y - myBounds.y; + feedback.addHorizontalLine(myBounds.x, myBounds.y, myBounds.width); + feedback.addVerticalArrow(bounds.x + bounds.width / 2, myBounds.y, myMargin); } return true; diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/RelativeDecorator.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/RelativeDecorator.java index 431eb49b05e3..d7b371990cd0 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/RelativeDecorator.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/RelativeDecorator.java @@ -15,22 +15,183 @@ */ package com.intellij.android.designer.designSurface.layout.relative; +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.android.designer.model.layout.relative.RelativeInfo; import com.intellij.designer.designSurface.DecorationLayer; import com.intellij.designer.designSurface.StaticDecorator; import com.intellij.designer.model.RadComponent; import java.awt.*; +import java.util.List; +import java.util.Map; /** * @author Alexander Lobas */ public class RelativeDecorator extends StaticDecorator { + private static final int TOP = 0; + private static final int BOTTOM = 1; + private static final int BASELINE = 2; + private static final int LEFT = 3; + private static final int RIGHT = 4; + public RelativeDecorator(RadComponent container) { super(container); } @Override protected void paint(DecorationLayer layer, Graphics2D g, RadComponent container) { - // TODO: Auto-generated method stub + if (!layer.showSelection() || container.getClientProperty(SnapPointFeedbackHost.KEY) != null) { + return; + } + + Stroke stroke = g.getStroke(); + g.setStroke(SnapPointFeedbackHost.STROKE); + g.setColor(SnapPointFeedbackHost.COLOR); + + Rectangle bounds = container.getBounds(layer); + Map relativeInfos = container.getClientProperty(RelativeInfo.KEY); + List selection = layer.getArea().getSelection(); + + for (RadComponent component : selection) { + RelativeInfo info = relativeInfos.get(component); + if (info != null) { + paintOutRelative(layer, g, component, info); + paintContainerRelative(g, bounds, info); + } + } + + g.setStroke(stroke); + g.setColor(Color.orange); + + for (RadComponent component : selection) { + RelativeInfo info = relativeInfos.get(component); + if (info != null) { + paintContainerMarginRelative(layer, g, bounds, (RadViewComponent)component, info); + } + } + } + + private static void paintOutRelative(DecorationLayer layer, Graphics2D g, RadComponent component, RelativeInfo info) { + Rectangle bounds = component.getBounds(layer); + + paintHorizontal(layer, g, bounds, info.alignTop, TOP); + paintHorizontal(layer, g, bounds, info.alignBottom, BOTTOM); + paintHorizontal(layer, g, bounds, info.below, TOP); + paintHorizontal(layer, g, bounds, info.above, BOTTOM); + + paintHorizontal(layer, g, bounds, info.alignBaseline, BASELINE); + + paintVertical(layer, g, bounds, info.alignLeft, LEFT); + paintVertical(layer, g, bounds, info.alignRight, RIGHT); + paintVertical(layer, g, bounds, info.toRightOf, LEFT); + paintVertical(layer, g, bounds, info.toLeftOf, RIGHT); + } + + private static void paintContainerRelative(Graphics2D g, Rectangle bounds, RelativeInfo info) { + if (info.parentTop) { + g.drawLine(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y); + } + if (info.parentBottom) { + g.drawLine(bounds.x, bounds.y + bounds.height, bounds.x + bounds.width, bounds.y + bounds.height); + } + if (info.parentLeft) { + g.drawLine(bounds.x, bounds.y, bounds.x, bounds.y + bounds.height); + } + if (info.parentRight) { + g.drawLine(bounds.x + bounds.width, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height); + } + if (info.parentCenterHorizontal) { + int centerX = bounds.x + bounds.width / 2 - 1; + g.drawLine(centerX, bounds.y, centerX, bounds.y + bounds.height); + } + if (info.parentCenterVertical) { + int centerY = bounds.y + bounds.height / 2 - 1; + g.drawLine(bounds.x, centerY, bounds.x + bounds.width, centerY); + } + } + + private static void paintContainerMarginRelative(DecorationLayer layer, + Graphics2D g, + Rectangle containerBounds, + RadViewComponent component, + RelativeInfo info) { + Rectangle componentBounds = component.getBounds(layer); + Rectangle margins = component.getMargins(); + + if (info.parentTop && margins.y > 0) { + int x = componentBounds.x + componentBounds.width / 2; + SnapPointFeedbackHost.paintArrowVertical(g, x, containerBounds.y, x, componentBounds.y); + } + if (info.parentBottom && margins.height > 0) { + int x = componentBounds.x + componentBounds.width / 2; + SnapPointFeedbackHost.paintArrowVertical(g, x, componentBounds.y + componentBounds.height, x, containerBounds.y); + } + if (info.parentLeft && margins.x > 0) { + int y = componentBounds.y + componentBounds.height / 2; + SnapPointFeedbackHost.paintArrowHorizontal(g, containerBounds.x, y, componentBounds.x, y); + } + if (info.parentRight && margins.width > 0) { + int y = componentBounds.y + componentBounds.height / 2; + SnapPointFeedbackHost.paintArrowHorizontal(g, componentBounds.x + componentBounds.width, y, containerBounds.x, y); + } + } + + private static void paintHorizontal(DecorationLayer layer, Graphics2D g, Rectangle from, RadComponent toComponent, int yType) { + if (toComponent == null) { + return; + } + + Rectangle to = toComponent.getBounds(layer); + + int x1, x2; + if (from.x < to.x) { + x1 = from.x - SnapPointFeedbackHost.EXPAND_SIZE; + x2 = to.x + to.width + SnapPointFeedbackHost.EXPAND_SIZE; + } + else { + x1 = to.x - SnapPointFeedbackHost.EXPAND_SIZE; + x2 = from.x + from.width + SnapPointFeedbackHost.EXPAND_SIZE; + } + + int y; + if (yType == TOP) { + y = from.y; + } + else if (yType == BOTTOM) { + y = from.y + from.height; + } + else { + y = to.y; + + int baseline = ((RadViewComponent)toComponent).getBaseline(); + if (baseline != -1) { + y += baseline; + } + } + + g.drawLine(x1, y, x2, y); + } + + private static void paintVertical(DecorationLayer layer, Graphics2D g, Rectangle from, RadComponent toComponent, int xType) { + if (toComponent == null) { + return; + } + + Rectangle to = toComponent.getBounds(layer); + + int y1, y2; + if (from.y < to.y) { + y1 = from.y - SnapPointFeedbackHost.EXPAND_SIZE; + y2 = to.y + to.height + SnapPointFeedbackHost.EXPAND_SIZE; + } + else { + y1 = to.y - SnapPointFeedbackHost.EXPAND_SIZE; + y2 = from.y + from.height + SnapPointFeedbackHost.EXPAND_SIZE; + } + + int x = xType == LEFT ? from.x : from.x + from.width; + + g.drawLine(x, y1, x, y2); } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/SnapPointFeedbackHost.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/SnapPointFeedbackHost.java index 911a7ca6e8b7..fdce2e7040bc 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/SnapPointFeedbackHost.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/relative/SnapPointFeedbackHost.java @@ -26,13 +26,15 @@ import java.util.List; * @author Alexander Lobas */ public class SnapPointFeedbackHost extends JComponent { - private static final BasicStroke STROKE = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[]{3, 1}, 0); - private static final Color COLOR = new Color(60, 139, 186); - private static final int EXPAND_SIZE = 10; + public static final BasicStroke STROKE = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[]{3, 1}, 0); + public static final Color COLOR = new Color(60, 139, 186); + public static final int EXPAND_SIZE = 10; + public static final String KEY = "SnapPointFeedbackHost"; public static SimpleTextAttributes SNAP_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, COLOR); private final List myLines = new ArrayList(); + private final List myArrows = new ArrayList(); public void addHorizontalLine(int x, int y, int length) { myLines.add(new Rectangle(x, y, length, -1)); @@ -42,8 +44,17 @@ public class SnapPointFeedbackHost extends JComponent { myLines.add(new Rectangle(x, y, -1, length)); } + public void addHorizontalArrow(int x, int y, int length) { + myArrows.add(new Rectangle(x, y, length, -1)); + } + + public void addVerticalArrow(int x, int y, int length) { + myArrows.add(new Rectangle(x, y, -1, length)); + } + public void clearAll() { myLines.clear(); + myArrows.clear(); } @Override @@ -54,8 +65,12 @@ public class SnapPointFeedbackHost extends JComponent { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); + Graphics2D g2d = (Graphics2D)g; + Stroke stroke = g2d.getStroke(); + g.setColor(COLOR); - ((Graphics2D)g).setStroke(STROKE); + g2d.setStroke(STROKE); + Rectangle bounds = getBounds(); for (Rectangle line : myLines) { @@ -69,5 +84,36 @@ public class SnapPointFeedbackHost extends JComponent { g.drawLine(x, y, x + line.width, y); } } + + g.setColor(Color.orange); + g2d.setStroke(stroke); + + for (Rectangle line : myArrows) { + int x = line.x - bounds.x; + int y = line.y - bounds.y; + + if (line.width == -1) { + paintArrowVertical(g, x, y, x, y + line.height); + } + else { + paintArrowHorizontal(g, x, y, x + line.width, y); + } + } + } + + public static void paintArrowHorizontal(Graphics g, int x1, int y1, int x2, int y2) { + g.drawLine(x1, y1, x2, y2); + g.drawLine(x1 + 5, y1 - 5, x1, y1); + g.drawLine(x1 + 5, y1 + 5, x1, y1); + g.drawLine(x2 - 5, y2 - 5, x2, y2); + g.drawLine(x2 - 5, y2 + 5, x2, y2); + } + + public static void paintArrowVertical(Graphics g, int x1, int y1, int x2, int y2) { + g.drawLine(x1, y1, x2, y2); + g.drawLine(x1 - 5, y1 + 5, x1, y1); + g.drawLine(x1 + 5, y1 + 5, x1, y1); + g.drawLine(x2 - 5, y2 - 5, x2, y2); + g.drawLine(x2 + 5, y2 - 5, x2, y2); } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayoutComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayoutComponent.java index 46d6505ead28..cb64bf469c7f 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayoutComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RadRelativeLayoutComponent.java @@ -19,6 +19,7 @@ import com.android.ide.common.rendering.api.ViewInfo; import com.intellij.android.designer.model.RadViewComponent; import com.intellij.android.designer.model.RadViewContainer; import com.intellij.designer.model.RadComponent; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.xml.XmlTag; import org.jetbrains.annotations.Nullable; @@ -50,6 +51,7 @@ public class RadRelativeLayoutComponent extends RadViewContainer { relativeInfos.put(child, info); XmlTag tag = ((RadViewComponent)child).getTag(); + info.alignTop = getComponent(idToComponent, tag, "android:layout_alignTop"); info.alignBottom = getComponent(idToComponent, tag, "android:layout_alignBottom"); info.alignLeft = getComponent(idToComponent, tag, "android:layout_alignLeft"); @@ -59,6 +61,19 @@ public class RadRelativeLayoutComponent extends RadViewContainer { info.below = getComponent(idToComponent, tag, "android:layout_below"); info.toLeftOf = getComponent(idToComponent, tag, "android:layout_toLeftOf"); info.toRightOf = getComponent(idToComponent, tag, "android:layout_toRightOf"); + + info.parentTop = "true".equals(tag.getAttributeValue("android:layout_alignParentTop")); + info.parentBottom = "true".equals(tag.getAttributeValue("android:layout_alignParentBottom")); + info.parentLeft = "true".equals(tag.getAttributeValue("android:layout_alignParentLeft")); + info.parentRight = "true".equals(tag.getAttributeValue("android:layout_alignParentRight")); + + info.parentCenterHorizontal = "true".equals(tag.getAttributeValue("android:layout_centerHorizontal")); + info.parentCenterVertical = "true".equals(tag.getAttributeValue("android:layout_centerVertical")); + + String center = tag.getAttributeValue("android:layout_centerInParent"); + if (!StringUtil.isEmpty(center)) { + info.parentCenterHorizontal = info.parentCenterVertical = "true".equals(center); + } } } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RelativeInfo.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RelativeInfo.java index 4375158f7ac7..472802e335a0 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RelativeInfo.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/relative/RelativeInfo.java @@ -34,6 +34,14 @@ public class RelativeInfo { public RadViewComponent toLeftOf; public RadViewComponent toRightOf; + public boolean parentTop; + public boolean parentBottom; + public boolean parentLeft; + public boolean parentRight; + + public boolean parentCenterHorizontal; + public boolean parentCenterVertical; + public boolean contains(RadComponent component) { return component == alignTop || component == alignBottom || diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DecorationLayer.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DecorationLayer.java index 4d04dec4ff4e..d82ebae61dbb 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DecorationLayer.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DecorationLayer.java @@ -36,6 +36,14 @@ public class DecorationLayer extends JComponent { myArea = area; } + public EditableArea getArea() { + return myArea; + } + + public boolean showSelection() { + return myShowSelection; + } + public void showSelection(boolean value) { if (myShowSelection != value) { myShowSelection = value; From 3cc5137367e79cc95d5a20e90857e7f3dcec2d73 Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Mon, 14 May 2012 17:30:33 +0400 Subject: [PATCH 58/67] Storage dum utility final commit (compile server). --- jps/jps-builders/src/META-INF/MANIFEST.MF | 3 +++ .../org/jetbrains/ether/StorageDumper.java | 19 ++++--------------- 2 files changed, 7 insertions(+), 15 deletions(-) create mode 100644 jps/jps-builders/src/META-INF/MANIFEST.MF diff --git a/jps/jps-builders/src/META-INF/MANIFEST.MF b/jps/jps-builders/src/META-INF/MANIFEST.MF new file mode 100644 index 000000000000..63c029fd45be --- /dev/null +++ b/jps/jps-builders/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: org.jetbrains.ether.StorageDumper + diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java b/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java index 7d4c39b96112..bd7049c0a1ce 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java @@ -1,5 +1,6 @@ package org.jetbrains.ether; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.ether.dependencyView.Mappings; import org.jetbrains.jps.Project; @@ -54,7 +55,7 @@ public class StorageDumper { } else { if (projectPath != null) { - errors.append("Multiple projects specified, skipping "); + errors.append("Multiple storage paths specified, skipping "); errors.append(arg); errors.append("\n"); } @@ -105,7 +106,7 @@ public class StorageDumper { void report() { if (myHelp) { - System.out.println("Usage: [-o | -h ] "); + System.out.println("Usage: [-o | -h ] "); System.out.println(); } @@ -126,20 +127,8 @@ public class StorageDumper { } else { try { - final String projectPath = path + File.separator + ".idea"; final String outputPath = (oath == null ? "" : oath) + File.separator + "snapshot-" + new SimpleDateFormat("dd-MM-yy(hh:mm:ss)").format(new Date()) + ".log"; - final Project project = new Project(); - - final Sdk jdk = project.createSdk("JavaSDK", "IDEA jdk", "1.6", System.getProperty("java.home"), null); - final List paths = new LinkedList(); - - paths.add(FileUtil.toSystemIndependentName(ClasspathBootstrap.getResourcePath(Object.class).getCanonicalPath())); - - jdk.setClasspath(paths); - - IdeaProjectLoader.loadFromPath(project, projectPath, ""); - - final File dataStorageRoot = Utils.getDataStorageRoot(project); + final File dataStorageRoot = new File(path + File.separator + "mappings"); final Mappings mappings = new Mappings(dataStorageRoot, true); final PrintStream p = new PrintStream(outputPath); From dae40c57b38c81d5b3619c2f99a02cc509912cd2 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 14 May 2012 17:46:41 +0400 Subject: [PATCH 59/67] #RUBY-10825 fixed --- .../com/intellij/indentation/IndentationAnnotatorVisitor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/indentation/IndentationAnnotatorVisitor.java b/platform/lang-impl/src/com/intellij/indentation/IndentationAnnotatorVisitor.java index facb47a68a3a..dc42077a1e67 100644 --- a/platform/lang-impl/src/com/intellij/indentation/IndentationAnnotatorVisitor.java +++ b/platform/lang-impl/src/com/intellij/indentation/IndentationAnnotatorVisitor.java @@ -83,8 +83,8 @@ public class IndentationAnnotatorVisitor extends PsiElementVisitor { final int delta = currentIndentLength - lastIndent; if (currentIndentLength % indentInfoLength != 0 || delta > indentInfoLength) { final String message = useTab - ? currentIndentLength + " tabs were used for indentation. Must be indented using " + indentInfoLength + " tabs" - : currentIndentLength + " spaces were used for indentation. Must be indented using " + indentInfoLength + " spaces"; + ? delta + " tabs were used for indentation. Must be indented using " + indentInfoLength + " tabs" + : delta + " spaces were used for indentation. Must be indented using " + indentInfoLength + " spaces"; myHolder.createErrorAnnotation(leaf, message); } lastIndent = currentIndentLength / indentInfoLength * indentInfoLength; From bc977662224a8b762206eae7af8bb02960df1b86 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 14 May 2012 15:55:41 +0200 Subject: [PATCH 60/67] better fix for IDEA-85620 --- .../style/StringBufferReplaceableByStringInspection.java | 5 +++-- .../style/replace_with_string/Precedence3.after.java | 8 ++++++++ .../igfixes/style/replace_with_string/Precedence3.java | 8 ++++++++ .../style/StringBufferReplaceableWithStringFixTest.java | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.after.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java index a209bae56e24..d642e1831b8b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java @@ -152,9 +152,11 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { return null; } final PsiExpression argument = arguments[0]; + final PsiType type = argument.getType(); if (result.length() != 0) { result.append('+'); - if (ParenthesesUtils.getPrecedence(argument) >= ParenthesesUtils.ADDITIVE_PRECEDENCE) { + if (ParenthesesUtils.getPrecedence(argument) > ParenthesesUtils.ADDITIVE_PRECEDENCE || + (type instanceof PsiPrimitiveType && ParenthesesUtils.getPrecedence(argument) == ParenthesesUtils.ADDITIVE_PRECEDENCE)) { result.append('(').append(argument.getText()).append(')'); } else { @@ -162,7 +164,6 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { } } else { - final PsiType type = argument.getType(); if (type instanceof PsiPrimitiveType) { result.append("String.valueOf(").append(argument.getText()).append(")"); } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.after.java new file mode 100644 index 000000000000..cbb701918117 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.after.java @@ -0,0 +1,8 @@ +package com.siyeh.igfixes.style.replace_with_string; + +class Precedence3 { + void foo() { + String start = "0", end = "0"; + String string = "Time: " + end + start + "."; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.java new file mode 100644 index 000000000000..b2cc1c54e8a0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/Precedence3.java @@ -0,0 +1,8 @@ +package com.siyeh.igfixes.style.replace_with_string; + +class Precedence3 { + void foo() { + String start = "0", end = "0"; + String string = new StringBuilder().append("Time: ").append(end + start).append(".").toString(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableWithStringFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableWithStringFixTest.java index 1e3acbc4e549..bbcd239687cc 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableWithStringFixTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableWithStringFixTest.java @@ -36,4 +36,5 @@ public class StringBufferReplaceableWithStringFixTest extends IGQuickFixesTestCa public void testStartsWithPrimitive() { doTest(); } public void testPrecedence() { doTest("Precedence", InspectionGadgetsBundle.message("string.builder.replaceable.by.string.quickfix")); } public void testPrecedence2() { doTest("Precedence2", InspectionGadgetsBundle.message("string.builder.replaceable.by.string.quickfix")); } + public void testPrecedence3() { doTest("Precedence3", InspectionGadgetsBundle.message("string.builder.replaceable.by.string.quickfix")); } } From 7c6fc9901e146b91358192875fbd96d1f075c234 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 15:58:59 +0400 Subject: [PATCH 61/67] do not reformat during undo --- .../refactoring/rename/inplace/InplaceRefactoring.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java index 19ce3bfd0d4e..d6015a1ed694 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java @@ -748,11 +748,6 @@ public abstract class InplaceRefactoring { documentManager.commitAllDocuments(); finish(false); moveOffsetAfter(false); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - documentManager.doPostponedOperationsAndUnblockDocument(myEditor.getDocument()); - } - }); } finally { try { From 6711dfcac14e91f28b8605b079b0895b9c015dcd Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 17:03:09 +0400 Subject: [PATCH 62/67] unused return value: ignore simple setters (IDEA-85981) --- .../unusedReturnValue/UnusedReturnValue.java | 26 ++++++++++++++++--- .../simpleSetter/expected.xml | 2 ++ .../simpleSetter/src/Test.java | 13 ++++++++++ .../codeInspection/UnusedReturnValueTest.java | 10 +++++++ 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/expected.xml create mode 100644 java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/src/Test.java diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java index bbe8b5f463b8..89aa34787572 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java @@ -19,18 +19,22 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInspection.*; import com.intellij.codeInspection.reference.*; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; import com.intellij.psi.search.searches.OverridingMethodsSearch; +import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; import com.intellij.util.IncorrectOperationException; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.util.ArrayList; import java.util.List; @@ -40,6 +44,8 @@ import java.util.List; public class UnusedReturnValue extends GlobalJavaInspectionTool{ private MakeVoidQuickFix myQuickFix; + public boolean IGNORE_BUILDER_PATTERN = false; + @Nullable public CommonProblemDescriptor[] checkElement(RefEntity refEntity, AnalysisScope scope, @@ -54,8 +60,11 @@ public class UnusedReturnValue extends GlobalJavaInspectionTool{ if (refMethod.getInReferences().size() == 0) return null; if (!refMethod.isReturnValueUsed()) { - return new ProblemDescriptor[]{manager.createProblemDescriptor(refMethod.getElement().getNavigationElement(), - InspectionsBundle.message("inspection.unused.return.value.problem.descriptor"), + final PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); + if (IGNORE_BUILDER_PATTERN && PropertyUtil.isSimplePropertySetter(psiMethod)) return null; + return new ProblemDescriptor[]{manager.createProblemDescriptor(psiMethod.getNavigationElement(), + InspectionsBundle + .message("inspection.unused.return.value.problem.descriptor"), getFix(processor), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)}; } @@ -64,6 +73,17 @@ public class UnusedReturnValue extends GlobalJavaInspectionTool{ return null; } + @Override + public void writeSettings(Element node) throws WriteExternalException { + if (IGNORE_BUILDER_PATTERN) { + super.writeSettings(node); + } + } + + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore simple setters", this, "IGNORE_BUILDER_PATTERN"); + } protected boolean queryExternalUsagesRequests(final RefManager manager, final GlobalJavaInspectionContext globalContext, final ProblemDescriptionsProcessor processor) { diff --git a/java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/expected.xml b/java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/expected.xml new file mode 100644 index 000000000000..4704d91e891d --- /dev/null +++ b/java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/expected.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/src/Test.java b/java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/src/Test.java new file mode 100644 index 000000000000..8df38c124d67 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedReturnValue/simpleSetter/src/Test.java @@ -0,0 +1,13 @@ +class Test { + private String myStr; + + public Test setStr(String str) { + myStr = str; + return this; + } + + public static void main(String[] args) { + final Test test = new Test(); + test.setStr(""); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java index 4e086f0e7a14..0fcd2ef1a07e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java @@ -35,4 +35,14 @@ public class UnusedReturnValueTest extends InspectionTestCase { doTest(); } + + public void testSimpleSetter() throws Exception { + try { + myTool.IGNORE_BUILDER_PATTERN = true; + doTest(); + } + finally { + myTool.IGNORE_BUILDER_PATTERN = false; + } + } } \ No newline at end of file From 9fde6251865606f0c4f535e530d4872a551e1708 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 17:20:50 +0400 Subject: [PATCH 63/67] do not suggest to move to library (IDEA-86011) --- .../move/moveMembers/MoveMembersDialog.java | 2 +- .../ReferenceEditorComboWithBrowseButton.java | 18 +++++++++++++++--- .../src/com/intellij/psi/JavaCodeFragment.java | 7 +++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersDialog.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersDialog.java index a69df03db346..8f5a4e1e69de 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersDialog.java @@ -121,7 +121,7 @@ public class MoveMembersDialog extends RefactoringDialog implements MoveMembersO } myMemberInfos = memberList; String fqName = initialTargetClass != null && !sourceClass.equals(initialTargetClass) ? initialTargetClass.getQualifiedName() : ""; - myTfTargetClassName = new ReferenceEditorComboWithBrowseButton(new ChooseClassAction(), fqName, myProject, true, RECENTS_KEY); + myTfTargetClassName = new ReferenceEditorComboWithBrowseButton(new ChooseClassAction(), fqName, myProject, true, JavaCodeFragment.VisibilityChecker.PROJECT_SCOPE_VISIBLE, RECENTS_KEY); init(); } diff --git a/java/java-impl/src/com/intellij/ui/ReferenceEditorComboWithBrowseButton.java b/java/java-impl/src/com/intellij/ui/ReferenceEditorComboWithBrowseButton.java index eef311a5b05c..286e897e82ec 100644 --- a/java/java-impl/src/com/intellij/ui/ReferenceEditorComboWithBrowseButton.java +++ b/java/java-impl/src/com/intellij/ui/ReferenceEditorComboWithBrowseButton.java @@ -34,7 +34,16 @@ public class ReferenceEditorComboWithBrowseButton extends ComponentWithBrowseBut final String text, @NotNull final Project project, boolean toAcceptClasses, final String recentsKey) { - super(new EditorComboBox(createDocument(text, project, toAcceptClasses), project, StdFileTypes.JAVA), browseActionListener); + this(browseActionListener, text, project, toAcceptClasses, JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE, recentsKey); + } + + public ReferenceEditorComboWithBrowseButton(final ActionListener browseActionListener, + final String text, + @NotNull final Project project, + boolean toAcceptClasses, + final JavaCodeFragment.VisibilityChecker visibilityChecker, final String recentsKey) { + super(new EditorComboBox(createDocument(text, project, toAcceptClasses, visibilityChecker), project, StdFileTypes.JAVA), + browseActionListener); final List recentEntries = RecentsManager.getInstance(project).getRecentEntries(recentsKey); if (recentEntries != null) { setHistory(ArrayUtil.toStringArray(recentEntries)); @@ -44,10 +53,13 @@ public class ReferenceEditorComboWithBrowseButton extends ComponentWithBrowseBut } } - private static Document createDocument(final String text, Project project, boolean isClassesAccepted) { + private static Document createDocument(final String text, + Project project, + boolean isClassesAccepted, + final JavaCodeFragment.VisibilityChecker visibilityChecker) { PsiPackage defaultPackage = JavaPsiFacade.getInstance(project).findPackage(""); final JavaCodeFragment fragment = JavaCodeFragmentFactory.getInstance(project).createReferenceCodeFragment(text, defaultPackage, true, isClassesAccepted); - fragment.setVisibilityChecker(JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE); + fragment.setVisibilityChecker(visibilityChecker); return PsiDocumentManager.getInstance(project).getDocument(fragment); } diff --git a/java/java-psi-api/src/com/intellij/psi/JavaCodeFragment.java b/java/java-psi-api/src/com/intellij/psi/JavaCodeFragment.java index 8c99369179bf..25f4ad4c60c4 100644 --- a/java/java-psi-api/src/com/intellij/psi/JavaCodeFragment.java +++ b/java/java-psi-api/src/com/intellij/psi/JavaCodeFragment.java @@ -139,6 +139,13 @@ public interface JavaCodeFragment extends PsiImportHolder, PsiCodeFragment { return Visibility.VISIBLE; } }; + + VisibilityChecker PROJECT_SCOPE_VISIBLE = new VisibilityChecker() { + @Override + public Visibility isDeclarationVisible(PsiElement declaration, PsiElement place) { + return declaration.getManager().isInProject(declaration) ? Visibility.VISIBLE : Visibility.NOT_VISIBLE; + } + }; } /** From fbd775fc8bdcbbedccfab7a112a9cef67d831101 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 17:35:43 +0400 Subject: [PATCH 64/67] do not include automatic renamer factories when they would be added automatically --- .../refactoring/rename/inplace/MemberInplaceRenamer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java index 8eedbe64a682..baa446d0025f 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java @@ -223,7 +223,7 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { elementProcessor.isToSearchInComments(element), elementProcessor.isToSearchForTextOccurrences(element)); for (AutomaticRenamerFactory factory : Extensions.getExtensions(AutomaticRenamerFactory.EP_NAME)) { - if (factory.isApplicable(element)) { + if (factory.getOptionName() != null && factory.isApplicable(element)) { renameProcessor.addRenamerFactory(factory); } } From 2a03100cb30764b2904f1a1e5d96f37dc1fb7d72 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 18:09:42 +0400 Subject: [PATCH 65/67] suggest to rename constructor params when property name is the same (IDEA-85979) --- .../naming/ConstructorParameterOnFieldRenameRenamer.java | 4 +++- .../RenameFieldWithConstructorParamAutomatic.java | 7 +++++++ .../RenameFieldWithConstructorParamAutomatic_after.java | 7 +++++++ .../testSrc/com/intellij/refactoring/RenameLocalTest.java | 4 ++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic.java create mode 100644 java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic_after.java diff --git a/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java b/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java index b2517c4a586e..345b3129defb 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java @@ -60,7 +60,9 @@ public class ConstructorParameterOnFieldRenameRenamer extends AutomaticRenamer { if (constructor instanceof LightElement) continue; final PsiParameter[] parameters = constructor.getParameterList().getParameters(); for (final PsiParameter parameter : parameters) { - if (paramName.equals(parameter.getName())) { + final String parameterName = parameter.getName(); + if (paramName.equals(parameterName) || + propertyName.equals(styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER))) { toRename.add(parameter); } } diff --git a/java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic.java b/java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic.java new file mode 100644 index 000000000000..578b24b5739f --- /dev/null +++ b/java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic.java @@ -0,0 +1,7 @@ +class Test { + private boolean isFlag = false; + + public Test(boolean isFlag) { + this.isFlag = isFlag; + } +} diff --git a/java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic_after.java b/java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic_after.java new file mode 100644 index 000000000000..3474332bf3be --- /dev/null +++ b/java/java-tests/testData/refactoring/renameLocal/RenameFieldWithConstructorParamAutomatic_after.java @@ -0,0 +1,7 @@ +class Test { + private boolean pp = false; + + public Test(boolean pp) { + this.pp = pp; + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameLocalTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameLocalTest.java index ed98dc27a235..3aeefbe1459d 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameLocalTest.java @@ -78,6 +78,10 @@ public class RenameLocalTest extends LightRefactoringTestCase { public void testRenameInPlaceParamInOverriderAutomaticRenamer() throws Exception { doTestInplaceRename("pp"); } + + public void testRenameFieldWithConstructorParamAutomatic() throws Exception { + doTest("pp"); + } public void testRenameInPlaceParamInOverriderAutomaticRenamerConflict() throws Exception { doTestInplaceRename("pp"); From 11e3c21180f8877da161a4210b1dd2155834d8f0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 14 May 2012 18:19:08 +0400 Subject: [PATCH 66/67] force initial name in rename dialog --- .../src/com/intellij/refactoring/rename/RenameDialog.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java index 64fbfa6c5348..00a7d80e3a66 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java @@ -135,7 +135,8 @@ public class RenameDialog extends RefactoringDialog { } public String[] getSuggestedNames() { - LinkedHashSet result = new LinkedHashSet(); + final LinkedHashSet result = new LinkedHashSet(); + result.add(UsageViewUtil.getShortName(myPsiElement)); final NameSuggestionProvider[] providers = Extensions.getExtensions(NameSuggestionProvider.EP_NAME); for(NameSuggestionProvider provider: providers) { SuggestedNameInfo info = provider.getSuggestedNames(myPsiElement, myNameSuggestionContext, result); @@ -144,9 +145,6 @@ public class RenameDialog extends RefactoringDialog { if (provider instanceof PreferrableNameSuggestionProvider && !((PreferrableNameSuggestionProvider)provider).shouldCheckOthers()) break; } } - if (result.size() == 0) { - result.add(UsageViewUtil.getShortName(myPsiElement)); - } return ArrayUtil.toStringArray(result); } From 1fd99e39f869759b7d4675f95610406482c65b75 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 14 May 2012 18:28:02 +0400 Subject: [PATCH 67/67] IDEA-85700 Can't save settings in Inspections --- .../SingleInspectionProfilePanelTest.java | 79 +++++++++++++++++++ .../ui/SingleInspectionProfilePanel.java | 1 + .../testFramework/LightPlatformTestCase.java | 2 +- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testSrc/com/intellij/codeInspection/SingleInspectionProfilePanelTest.java diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/SingleInspectionProfilePanelTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/SingleInspectionProfilePanelTest.java new file mode 100644 index 000000000000..9a45fd5817a2 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInspection/SingleInspectionProfilePanelTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2012 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.codeInspection; + +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; +import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; +import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; +import com.intellij.testFramework.LightIdeaTestCase; + +/** + * @author Dmitry Avdeev + * Date: 5/10/12 + */ +public class SingleInspectionProfilePanelTest extends LightIdeaTestCase { + + // see IDEA-85700 + public void testSettingsModification() throws Exception { + + Project project = ProjectManager.getInstance().getDefaultProject(); + InspectionProjectProfileManager profileManager = InspectionProjectProfileManager.getInstance(project); + InspectionProfileImpl profile = (InspectionProfileImpl)profileManager.getProfile(PROFILE); + profile.initInspectionTools(project); + + InspectionProfileImpl model = (InspectionProfileImpl)profile.getModifiableModel(); + SingleInspectionProfilePanel panel = new SingleInspectionProfilePanel(profileManager, PROFILE, model); + panel.setVisible(true); + panel.reset(); + + LocalInspectionToolWrapper wrapper = (LocalInspectionToolWrapper)model.getInspectionTool(myInspection.getShortName()); + assert wrapper != null; + JavaDocLocalInspection tool = (JavaDocLocalInspection)wrapper.getTool(); + assertEquals("", tool.myAdditionalJavadocTags); + tool.myAdditionalJavadocTags = "foo"; + model.setModified(true); + panel.apply(); + + + wrapper = (LocalInspectionToolWrapper)profile.getInspectionTool(myInspection.getShortName()); + assert wrapper != null; + tool = (JavaDocLocalInspection)wrapper.getTool(); + assertEquals("foo", tool.myAdditionalJavadocTags); + } + + @Override + public void setUp() throws Exception { + InspectionProfileImpl.INIT_INSPECTIONS = true; + super.setUp(); + } + + @Override + public void tearDown() throws Exception { + InspectionProfileImpl.INIT_INSPECTIONS = false; + super.tearDown(); + } + + private final JavaDocLocalInspection myInspection = new JavaDocLocalInspection(); + + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[] {myInspection}; + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index c49b1ecbc643..39efab431bb4 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -842,6 +842,7 @@ public class SingleInspectionProfilePanel extends JPanel { } private void setSelectedProfile(final ModifiableModel modifiableModel) { + if (mySelectedProfile == modifiableModel) return; mySelectedProfile = (InspectionProfileImpl)modifiableModel; if (mySelectedProfile != null) { myInitialProfile = mySelectedProfile.getName(); diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 2078af288a71..b3df4e20de88 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -343,7 +343,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da enableInspectionTool(availableInspectionTools, new LocalInspectionToolWrapper(tool)); } - final InspectionProfileImpl profile = new InspectionProfileImpl("Configurable") { + final InspectionProfileImpl profile = new InspectionProfileImpl(PROFILE) { @Override @NotNull public InspectionProfileEntry[] getInspectionTools(PsiElement element) {