1 /* 2 * Copyright (c) 2008-2019 Emmanuel Dupuy. 3 * This project is distributed under the GPLv3 license. 4 * This is a Copyleft license that gives the user the right to use, 5 * copy and modify the code freely for non-commercial purposes. 6 */ 7 8 package org.jd.gui.controller; 9 10 import org.jd.gui.api.API; 11 import org.jd.gui.api.model.Container; 12 import org.jd.gui.api.model.Type; 13 import org.jd.gui.model.container.DelegatingFilterContainer; 14 import org.jd.gui.service.type.TypeFactoryService; 15 import org.jd.gui.spi.TypeFactory; 16 import org.jd.gui.view.SelectLocationView; 17 18 import javax.swing.*; 19 import java.awt.*; 20 import java.net.URI; 21 import java.util.*; 22 import java.util.function.Consumer; 23 24 public class SelectLocationController { 25 protected static final ContainerEntryComparator CONTAINER_ENTRY_COMPARATOR = new ContainerEntryComparator(); 26 27 protected API api; 28 protected SelectLocationView selectLocationView; 29 SelectLocationController(API api, JFrame mainFrame)30 public SelectLocationController(API api, JFrame mainFrame) { 31 this.api = api; 32 // Create UI 33 selectLocationView = new SelectLocationView(api, mainFrame); 34 } 35 36 @SuppressWarnings("unchecked") show(Point location, Collection<Container.Entry> entries, Consumer<Container.Entry> selectedLocationCallback, Runnable closeCallback)37 public void show(Point location, Collection<Container.Entry> entries, Consumer<Container.Entry> selectedLocationCallback, Runnable closeCallback) { 38 // Show UI 39 HashMap<Container, ArrayList<Container.Entry>> map = new HashMap<>(); 40 41 for (Container.Entry entry : entries) { 42 Container container = entry.getContainer(); 43 44 // Search root container 45 while (true) { 46 Container parentContainer = container.getRoot().getParent().getContainer(); 47 if (parentContainer.getRoot() == null) { 48 break; 49 } else { 50 container = parentContainer; 51 } 52 } 53 54 ArrayList<Container.Entry> list = map.get(container); 55 56 if (list == null) { 57 map.put(container, list=new ArrayList<>()); 58 } 59 60 list.add(entry); 61 } 62 63 HashSet<DelegatingFilterContainer> delegatingFilterContainers = new HashSet<>(); 64 65 for (Map.Entry<Container, ArrayList<Container.Entry>> mapEntry : map.entrySet()) { 66 Container container = mapEntry.getKey(); 67 // Create a filtered container 68 // TODO In a future release, display matching types and inner-types, not only matching files 69 delegatingFilterContainers.add(new DelegatingFilterContainer(container, getOuterEntries(mapEntry.getValue()))); 70 } 71 72 Consumer<URI> selectedEntryCallback = uri -> onLocationSelected(delegatingFilterContainers, uri, selectedLocationCallback); 73 74 selectLocationView.show(location, delegatingFilterContainers, entries.size(), selectedEntryCallback, closeCallback); 75 } 76 getOuterEntries(Collection<Container.Entry> entries)77 protected Collection<Container.Entry> getOuterEntries(Collection<Container.Entry> entries) { 78 HashMap<Container.Entry, Container.Entry> innerTypeEntryToOuterTypeEntry = new HashMap<>(); 79 HashSet<Container.Entry> outerEntriesSet = new HashSet<>(); 80 81 for (Container.Entry entry : entries) { 82 Container.Entry outerTypeEntry = null; 83 TypeFactory factory = TypeFactoryService.getInstance().get(entry); 84 85 if (factory != null) { 86 Type type = factory.make(api, entry, null); 87 88 if ((type != null) && (type.getOuterName() != null)) { 89 outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry); 90 91 if (outerTypeEntry == null) { 92 HashMap<String, Container.Entry> typeNameToEntry = new HashMap<>(); 93 HashMap<String, String> innerTypeNameToOuterTypeName = new HashMap<>(); 94 95 // Populate "typeNameToEntry" and "innerTypeNameToOuterTypeName" 96 for (Container.Entry e : entry.getParent().getChildren()) { 97 factory = TypeFactoryService.getInstance().get(e); 98 99 if (factory != null) { 100 type = factory.make(api, e, null); 101 102 if (type != null) { 103 typeNameToEntry.put(type.getName(), e); 104 if (type.getOuterName() != null) { 105 innerTypeNameToOuterTypeName.put(type.getName(), type.getOuterName()); 106 } 107 } 108 } 109 } 110 111 // Search outer type entries and populate "innerTypeEntryToOuterTypeEntry" 112 for (Map.Entry<String, String> e : innerTypeNameToOuterTypeName.entrySet()) { 113 Container.Entry innerTypeEntry = typeNameToEntry.get(e.getKey()); 114 115 if (innerTypeEntry != null) { 116 String outerTypeName = e.getValue(); 117 118 for (;;) { 119 String typeName = innerTypeNameToOuterTypeName.get(outerTypeName); 120 if (typeName != null) { 121 outerTypeName = typeName; 122 } else { 123 break; 124 } 125 } 126 127 outerTypeEntry = typeNameToEntry.get(outerTypeName); 128 129 if (outerTypeEntry != null) { 130 innerTypeEntryToOuterTypeEntry.put(innerTypeEntry, outerTypeEntry); 131 } 132 } 133 } 134 135 // Get outer type entry 136 outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry); 137 } 138 } 139 } 140 141 if (outerTypeEntry != null) { 142 outerEntriesSet.add(outerTypeEntry); 143 } else { 144 outerEntriesSet.add(entry); 145 } 146 } 147 148 // Return outer type entries sorted by path 149 ArrayList<Container.Entry> result = new ArrayList<>(outerEntriesSet); 150 151 result.sort(CONTAINER_ENTRY_COMPARATOR); 152 153 return result; 154 } 155 onLocationSelected(Set<DelegatingFilterContainer> delegatingFilterContainers, URI uri, Consumer<Container.Entry> selectedLocationCallback)156 protected void onLocationSelected(Set<DelegatingFilterContainer> delegatingFilterContainers, URI uri, Consumer<Container.Entry> selectedLocationCallback) { 157 // Open the single entry uri 158 Container.Entry entry = null; 159 160 for (DelegatingFilterContainer container : delegatingFilterContainers) { 161 entry = container.getEntry(uri); 162 if (entry != null) { 163 break; 164 } 165 } 166 167 if (entry != null) { 168 selectedLocationCallback.accept(entry); 169 } 170 } 171 172 protected static class ContainerEntryComparator implements Comparator<Container.Entry> { 173 @Override compare(Container.Entry e1, Container.Entry e2)174 public int compare(Container.Entry e1, Container.Entry e2) { 175 return e1.getPath().compareTo(e2.getPath()); 176 } 177 } 178 } 179