mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
IDEA-19061 Integrate the Rearranger-plugin into core-IDEA
1. Arrangement API provides 'dependent entries' concept now; 2. Java static and instance initialization blocks are defined to be 'dependent arrangement entries'; 3. Corresponding tests are added; 4. Default java arrangement rules are expanded in order to preserve old 'generated class members order'; 5. Test data is corrected;
This commit is contained in:
+40
-8
@@ -45,7 +45,8 @@ public class JavaArrangementVisitor extends JavaElementVisitor {
|
||||
MODIFIERS.put(PsiModifier.ABSTRACT, ArrangementModifier.ABSTRACT);
|
||||
}
|
||||
|
||||
private final Stack<JavaElementArrangementEntry> myStack = new Stack<JavaElementArrangementEntry>();
|
||||
@NotNull private final Stack<JavaElementArrangementEntry> myStack = new Stack<JavaElementArrangementEntry>();
|
||||
@NotNull private final Map<PsiElement, JavaElementArrangementEntry> myEntries = new HashMap<PsiElement, JavaElementArrangementEntry>();
|
||||
|
||||
@NotNull private final List<JavaElementArrangementEntry> myRootEntries;
|
||||
@NotNull private Collection<TextRange> myRanges;
|
||||
@@ -69,13 +70,13 @@ public class JavaArrangementVisitor extends JavaElementVisitor {
|
||||
else if (aClass.isInterface()) {
|
||||
type = ArrangementEntryType.INTERFACE;
|
||||
}
|
||||
JavaElementArrangementEntry entry = createNewEntry(aClass.getTextRange(), type, aClass.getName(), true);
|
||||
JavaElementArrangementEntry entry = createNewEntry(aClass, type, aClass.getName(), true);
|
||||
processEntry(entry, aClass, aClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnonymousClass(PsiAnonymousClass aClass) {
|
||||
JavaElementArrangementEntry entry = createNewEntry(aClass.getTextRange(), ArrangementEntryType.CLASS, aClass.getName(), false);
|
||||
JavaElementArrangementEntry entry = createNewEntry(aClass, ArrangementEntryType.CLASS, aClass.getName(), false);
|
||||
processEntry(entry, null, aClass);
|
||||
}
|
||||
|
||||
@@ -88,14 +89,43 @@ public class JavaArrangementVisitor extends JavaElementVisitor {
|
||||
|
||||
@Override
|
||||
public void visitField(PsiField field) {
|
||||
JavaElementArrangementEntry entry = createNewEntry(field.getTextRange(), ArrangementEntryType.FIELD, field.getName(), true);
|
||||
JavaElementArrangementEntry entry = createNewEntry(field, ArrangementEntryType.FIELD, field.getName(), true);
|
||||
processEntry(entry, field, field.getInitializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassInitializer(PsiClassInitializer initializer) {
|
||||
JavaElementArrangementEntry entry = createNewEntry(initializer, ArrangementEntryType.FIELD, null, true);
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiElement classLBrace = null;
|
||||
PsiClass clazz = initializer.getContainingClass();
|
||||
if (clazz != null) {
|
||||
classLBrace = clazz.getLBrace();
|
||||
}
|
||||
for (PsiElement e = initializer.getPrevSibling(); e != null; e = e.getPrevSibling()) {
|
||||
JavaElementArrangementEntry prevEntry;
|
||||
if (e == classLBrace) {
|
||||
prevEntry = myEntries.get(clazz);
|
||||
}
|
||||
else {
|
||||
prevEntry = myEntries.get(e);
|
||||
}
|
||||
if (prevEntry != null) {
|
||||
entry.addDependency(prevEntry);
|
||||
}
|
||||
if (!(e instanceof PsiWhiteSpace)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
ArrangementEntryType type = method.isConstructor() ? ArrangementEntryType.CONSTRUCTOR : ArrangementEntryType.METHOD;
|
||||
JavaElementArrangementEntry entry = createNewEntry(method.getTextRange(), type, method.getName(), true);
|
||||
JavaElementArrangementEntry entry = createNewEntry(method, type, method.getName(), true);
|
||||
processEntry(entry, method, method.getBody());
|
||||
}
|
||||
|
||||
@@ -111,7 +141,7 @@ public class JavaArrangementVisitor extends JavaElementVisitor {
|
||||
return;
|
||||
}
|
||||
JavaElementArrangementEntry entry =
|
||||
createNewEntry(anonymousClass.getTextRange(), ArrangementEntryType.CLASS, anonymousClass.getName(), false);
|
||||
createNewEntry(anonymousClass, ArrangementEntryType.CLASS, anonymousClass.getName(), false);
|
||||
processEntry(entry, null, anonymousClass);
|
||||
}
|
||||
|
||||
@@ -152,11 +182,12 @@ public class JavaArrangementVisitor extends JavaElementVisitor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JavaElementArrangementEntry createNewEntry(@NotNull TextRange range,
|
||||
private JavaElementArrangementEntry createNewEntry(@NotNull PsiElement element,
|
||||
@NotNull ArrangementEntryType type,
|
||||
@Nullable String name,
|
||||
boolean canArrange)
|
||||
{
|
||||
TextRange range = element.getTextRange();
|
||||
if (!isWithinBounds(range)) {
|
||||
return null;
|
||||
}
|
||||
@@ -170,13 +201,14 @@ public class JavaArrangementVisitor extends JavaElementVisitor {
|
||||
else {
|
||||
entry = new JavaElementArrangementEntry(current, range, type, name, false);
|
||||
}
|
||||
myEntries.put(element, entry);
|
||||
if (current == null) {
|
||||
myRootEntries.add(entry);
|
||||
}
|
||||
else {
|
||||
current.addChild(entry);
|
||||
}
|
||||
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -26,6 +26,8 @@ import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Not thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 7/20/12 4:50 PM
|
||||
*/
|
||||
|
||||
@@ -88,9 +88,11 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
|
||||
and(FIELD, modifier);
|
||||
}
|
||||
and(CONSTRUCTOR);
|
||||
and(METHOD, STATIC);
|
||||
and(METHOD);
|
||||
and(ENUM);
|
||||
and(INTERFACE);
|
||||
and(CLASS, STATIC);
|
||||
and(CLASS);
|
||||
}
|
||||
|
||||
|
||||
@@ -183,8 +183,14 @@ public class JavaPsiImplementationHelperImpl extends JavaPsiImplementationHelper
|
||||
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(aClass.getProject());
|
||||
MemberOrderService service = ServiceManager.getService(MemberOrderService.class);
|
||||
PsiElement anchor = service.getAnchor(member, settings.getCommonSettings(JavaLanguage.INSTANCE), aClass);
|
||||
|
||||
if (anchor != null && anchor.getNextSibling() == aClass.getRBrace()) {
|
||||
// Given member should be inserted as the last child.
|
||||
return aClass.getRBrace();
|
||||
}
|
||||
|
||||
if (anchor != null && anchor != aClass) {
|
||||
anchor = anchor.getNextSibling();
|
||||
while (anchor instanceof PsiJavaToken && (anchor.getText().equals(",") || anchor.getText().equals(";"))) {
|
||||
anchor = anchor.getNextSibling();
|
||||
}
|
||||
@@ -194,7 +200,7 @@ public class JavaPsiImplementationHelperImpl extends JavaPsiImplementationHelper
|
||||
}
|
||||
|
||||
// The main idea is to avoid to anchor to 'white space' element because that causes reformatting algorithm
|
||||
// to perform incorrectly. The algorithm is encapsulated at PostprocessReformattingAspect.doPostponedFormattingInner().
|
||||
// to perform incorrectly. The algorithm is encapsulated at the PostprocessReformattingAspect.doPostponedFormattingInner().
|
||||
final PsiElement lBrace = aClass.getLBrace();
|
||||
if (lBrace != null) {
|
||||
PsiElement result = lBrace.getNextSibling();
|
||||
@@ -207,7 +213,7 @@ public class JavaPsiImplementationHelperImpl extends JavaPsiImplementationHelper
|
||||
return aClass.getRBrace();
|
||||
}
|
||||
|
||||
// TODO remove as soon as arrangement sub-system is provided for groovy.
|
||||
// TODO remove as soon as an arrangement sub-system is provided for groovy.
|
||||
public static int getMemberOrderWeight(PsiElement member, CodeStyleSettings settings) {
|
||||
if (member instanceof PsiField) {
|
||||
if (member instanceof PsiEnumConstant) {
|
||||
|
||||
+17
-1
@@ -1,9 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// "Create Inner Class 'MyCollection'" "true"
|
||||
public class Test {
|
||||
public static void main() {
|
||||
Collection[] cc = new MyCollection[10];
|
||||
}
|
||||
<caret>
|
||||
|
||||
private static class MyCollection {
|
||||
}
|
||||
}
|
||||
+17
-1
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// "Create Inner Class 'MyTableModel'" "true"
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableModel;
|
||||
@@ -6,7 +22,7 @@ public class Test {
|
||||
public static void main() {
|
||||
JTable table = new JTable(new MyTableModel());
|
||||
}
|
||||
<caret>
|
||||
|
||||
private static class MyTableModel implements TableModel {
|
||||
}
|
||||
}
|
||||
+17
-1
@@ -1,9 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// "Create Inner Class 'Generic'" "true"
|
||||
class Test {
|
||||
void foo () {
|
||||
new Generic<String> ();
|
||||
}
|
||||
<caret>
|
||||
|
||||
private class Generic<T> {
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,6 @@ public class TestClass {
|
||||
return yearsTo( expiry );
|
||||
}
|
||||
return 0.0;
|
||||
|
||||
}
|
||||
|
||||
private double yearsTo( final Date endDate ) {
|
||||
|
||||
-1
@@ -41,7 +41,6 @@ public class TestClass {
|
||||
return yearsTo( expiry );
|
||||
}
|
||||
return 0.0;
|
||||
|
||||
}
|
||||
|
||||
private double riskFactor() {
|
||||
|
||||
+16
-2
@@ -1,7 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
public class X {
|
||||
A myField;
|
||||
private final Base myDelegate = new Base();
|
||||
|
||||
A myField;
|
||||
public void method(Test t) {
|
||||
myField = t.getA();
|
||||
myField.methodFromA();
|
||||
|
||||
+16
-1
@@ -1,6 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
class A {
|
||||
int fieldFromA;
|
||||
private final MyBase myDelegate = new MyBase();
|
||||
int fieldFromA;
|
||||
|
||||
public void firstMethodFromBase() {
|
||||
myDelegate.firstMethodFromBase();
|
||||
|
||||
+16
-1
@@ -1,6 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
class Test {
|
||||
private Foo myFoo;
|
||||
private final Foo foo;
|
||||
private Foo myFoo;
|
||||
|
||||
Test() {
|
||||
foo = new Foo();
|
||||
|
||||
+16
-1
@@ -1,6 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
class Test {
|
||||
private String myTimer;
|
||||
private final String string;
|
||||
private String myTimer;
|
||||
|
||||
Test() {
|
||||
string = "";<caret>
|
||||
|
||||
+16
-1
@@ -1,6 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
class Test {
|
||||
private String myTimer;
|
||||
private final String string;
|
||||
private String myTimer;
|
||||
|
||||
Test() {
|
||||
string = "";
|
||||
|
||||
+34
@@ -69,4 +69,38 @@ class Test {
|
||||
rule(CLASS)]
|
||||
)
|
||||
}
|
||||
|
||||
void testInstanceInitializationBlockBoundToField() {
|
||||
doTest('''\
|
||||
class Test {
|
||||
private int i;
|
||||
public int j;
|
||||
{ j = 1; }
|
||||
protected int k;
|
||||
}''', '''\
|
||||
class Test {
|
||||
public int j;
|
||||
{ j = 1; }
|
||||
protected int k;
|
||||
private int i;
|
||||
}''',
|
||||
[rule(FIELD, PUBLIC), rule(FIELD, PROTECTED), rule(FIELD, PRIVATE)])
|
||||
}
|
||||
|
||||
void testInstanceInitializationBlockAsFirstChild() {
|
||||
doTest('''\
|
||||
class Test {
|
||||
{ j = 1; }
|
||||
private int i;
|
||||
public int j;
|
||||
protected int k;
|
||||
}''', '''\
|
||||
class Test {
|
||||
{ j = 1; }
|
||||
public int j;
|
||||
protected int k;
|
||||
private int i;
|
||||
}''',
|
||||
[rule(FIELD, PUBLIC), rule(FIELD, PROTECTED), rule(FIELD, PRIVATE)])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,20 @@ public interface ArrangementEntry {
|
||||
@NotNull
|
||||
List<? extends ArrangementEntry> getChildren();
|
||||
|
||||
/**
|
||||
* There is a possible case that particular entry position depends on another entries positions. E.g. static initialization
|
||||
* block which uses static fields from the same class must be declared after them.
|
||||
* <p/>
|
||||
* This method allows to answer what sibling entries must be located before the current one at the resulting arrangement algorithm.
|
||||
* <p/>
|
||||
* There is also a special case when a list with the single entry which is the current's entry {@link #getParent() parent}
|
||||
* is returned - that means that current entry should be arranged to be the first child.
|
||||
*
|
||||
* @return current entry's dependencies (if any)
|
||||
*/
|
||||
@Nullable
|
||||
List<? extends ArrangementEntry> getDependencies();
|
||||
|
||||
/**
|
||||
* @return start offset of the current entry (inclusive) within the target document. Rearranger engine uses this information
|
||||
* to move rearranged entries
|
||||
|
||||
+18
-2
@@ -22,13 +22,16 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Not thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 7/20/12 4:53 PM
|
||||
*/
|
||||
public class DefaultArrangementEntry implements ArrangementEntry {
|
||||
|
||||
@NotNull private final List<ArrangementEntry> myChildren = new ArrayList<ArrangementEntry>();
|
||||
|
||||
private final List<ArrangementEntry> myChildren = new ArrayList<ArrangementEntry>();
|
||||
|
||||
@Nullable private List<ArrangementEntry> myDependencies;
|
||||
@Nullable ArrangementEntry myParent;
|
||||
private final int myStartOffset;
|
||||
private final int myEndOffset;
|
||||
@@ -58,6 +61,19 @@ public class DefaultArrangementEntry implements ArrangementEntry {
|
||||
myChildren.add(entry);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<? extends ArrangementEntry> getDependencies() {
|
||||
return myDependencies;
|
||||
}
|
||||
|
||||
public void addDependency(@NotNull ArrangementEntry dependency) {
|
||||
if (myDependencies == null) {
|
||||
myDependencies = new ArrayList<ArrangementEntry>();
|
||||
}
|
||||
myDependencies.add(dependency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartOffset() {
|
||||
return myStartOffset;
|
||||
|
||||
+7
-2
@@ -112,7 +112,12 @@ public class MemberOrderService {
|
||||
if (anchorEntry == null) {
|
||||
return context;
|
||||
}
|
||||
|
||||
return context.findElementAt(anchorEntry.getEndOffset() - context.getTextRange().getStartOffset());
|
||||
|
||||
int offset = anchorEntry.getEndOffset() - 1 - context.getTextRange().getStartOffset();
|
||||
PsiElement element = context.findElementAt(offset);
|
||||
for (PsiElement e = element; e != null && e.getTextRange().getStartOffset() >= anchorEntry.getStartOffset(); e = e.getParent()) {
|
||||
element = e;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
+44
-6
@@ -18,6 +18,7 @@ package com.intellij.psi.codeStyle.arrangement.engine;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
@@ -30,6 +31,7 @@ import com.intellij.psi.codeStyle.arrangement.ArrangementRule;
|
||||
import com.intellij.psi.codeStyle.arrangement.Rearranger;
|
||||
import com.intellij.psi.codeStyle.arrangement.StdArrangementRule;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import gnu.trove.TIntArrayList;
|
||||
@@ -200,22 +202,58 @@ public class ArrangementEngine {
|
||||
* @param <E> arrangement entry type
|
||||
* @return arranged list of the given rules
|
||||
*/
|
||||
@SuppressWarnings("AssignmentToForLoopParameter")
|
||||
@NotNull
|
||||
public static <E extends ArrangementEntry> List<E> arrange(@NotNull Collection<E> entries,
|
||||
@NotNull List<? extends ArrangementRule> rules)
|
||||
{
|
||||
List<E> arranged = new ArrayList<E>();
|
||||
Set<E> unprocessed = new LinkedHashSet<E>(entries);
|
||||
|
||||
for (ArrangementRule rule : rules) {
|
||||
for (E entry : entries) {
|
||||
if (entry.canBeMatched() && unprocessed.contains(entry) && rule.getMatcher().isMatched(entry)) {
|
||||
Set<E> unprocessed = new LinkedHashSet<E>();
|
||||
List<Pair<Set<ArrangementEntry>, E>> dependent = new ArrayList<Pair<Set<ArrangementEntry>, E>>();
|
||||
for (E entry : entries) {
|
||||
List<? extends ArrangementEntry> dependencies = entry.getDependencies();
|
||||
if (dependencies == null) {
|
||||
unprocessed.add(entry);
|
||||
}
|
||||
else {
|
||||
if (dependencies.size() == 1 && dependencies.get(0) == entry.getParent()) {
|
||||
// Handle a situation when the entry is condifured to be at the first parent's children.
|
||||
arranged.add(entry);
|
||||
unprocessed.remove(entry);
|
||||
}
|
||||
else {
|
||||
Set<ArrangementEntry> first = new HashSet<ArrangementEntry>(dependencies);
|
||||
dependent.add(Pair.create(first, entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<E> matched = new HashSet<E>();
|
||||
|
||||
for (ArrangementRule rule : rules) {
|
||||
matched.clear();
|
||||
for (E entry : unprocessed) {
|
||||
if (entry.canBeMatched() && rule.getMatcher().isMatched(entry)) {
|
||||
arranged.add(entry);
|
||||
matched.add(entry);
|
||||
}
|
||||
}
|
||||
unprocessed.removeAll(matched);
|
||||
}
|
||||
arranged.addAll(unprocessed);
|
||||
|
||||
for (int i = 0; i < arranged.size() && !dependent.isEmpty(); i++) {
|
||||
E e = arranged.get(i);
|
||||
for (Iterator<Pair<Set<ArrangementEntry>, E>> iterator = dependent.iterator(); iterator.hasNext(); ) {
|
||||
Pair<Set<ArrangementEntry>, E> pair = iterator.next();
|
||||
pair.first.remove(e);
|
||||
if (pair.first.isEmpty()) {
|
||||
iterator.remove();
|
||||
arranged.add(i + 1, pair.second);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return arranged;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user