@Nullable private LookupFile getClosestParent(final String typed) { if (typed == null) return null; LookupFile lastFound = myFinder.find(typed); if (lastFound == null) return null; if (lastFound.exists()) { if (typed.charAt(typed.length() - 1) != File.separatorChar) return lastFound.getParent(); return lastFound; } final String[] splits = myFinder.normalize(typed).split(myFileSpitRegExp); StringBuilder fullPath = new StringBuilder(); for (int i = 0; i < splits.length; i++) { String each = splits[i]; fullPath.append(each); if (i < splits.length - 1) { fullPath.append(myFinder.getSeparator()); } final LookupFile file = myFinder.find(fullPath.toString()); if (file == null || !file.exists()) return lastFound; lastFound = file; } return lastFound; }
private void setTextToFile(final LookupFile file) { String text = file.getAbsolutePath(); if (file.isDirectory() && !text.endsWith(myFinder.getSeparator())) { text += myFinder.getSeparator(); } myPathTextField.setText(text); }
/** * Replace the path component under the caret with the file selected from the completion list. * * @param file the selected file. * @param caretPos * @param start the start offset of the path component under the caret. * @param end the end offset of the path component under the caret. * @throws BadLocationException */ private void replacePathComponent(LookupFile file, int caretPos, int start, int end) throws BadLocationException { final Document doc = myPathTextField.getDocument(); myPathTextField.setSelectionStart(0); myPathTextField.setSelectionEnd(0); final String name = file.getName(); boolean toRemoveExistingName; String prefix = ""; if (caretPos >= start) { prefix = doc.getText(start, caretPos - start); if (prefix.length() == 0) { prefix = doc.getText(start, end - start); } if (SystemInfo.isFileSystemCaseSensitive) { toRemoveExistingName = name.startsWith(prefix) && prefix.length() > 0; } else { toRemoveExistingName = name.toUpperCase().startsWith(prefix.toUpperCase()) && prefix.length() > 0; } } else { toRemoveExistingName = true; } int newPos; if (toRemoveExistingName) { doc.remove(start, end - start); doc.insertString(start, name, doc.getDefaultRootElement().getAttributes()); newPos = start + name.length(); } else { doc.insertString(caretPos, name, doc.getDefaultRootElement().getAttributes()); newPos = caretPos + name.length(); } if (file.isDirectory()) { if (!myFinder.getSeparator().equals(doc.getText(newPos, 1))) { doc.insertString( newPos, myFinder.getSeparator(), doc.getDefaultRootElement().getAttributes()); newPos++; } } if (newPos < doc.getLength()) { if (myFinder.getSeparator().equals(doc.getText(newPos, 1))) { newPos++; } } myPathTextField.setCaretPosition(newPos); }
private void processChosenFromCompletion(boolean nameOnly) { final LookupFile file = getSelectedFileFromCompletionPopup(); if (file == null) return; if (nameOnly) { try { final Document doc = myPathTextField.getDocument(); int caretPos = myPathTextField.getCaretPosition(); if (myFinder.getSeparator().equals(doc.getText(caretPos, 1))) { for (; caretPos < doc.getLength(); caretPos++) { final String eachChar = doc.getText(caretPos, 1); if (!myFinder.getSeparator().equals(eachChar)) break; } } int start = caretPos > 0 ? caretPos - 1 : caretPos; while (start >= 0) { final String each = doc.getText(start, 1); if (myFinder.getSeparator().equals(each)) { start++; break; } start--; } int end = start < caretPos ? caretPos : start; while (end <= doc.getLength()) { final String each = doc.getText(end, 1); if (myFinder.getSeparator().equals(each)) { break; } end++; } if (end > doc.getLength()) { end = doc.getLength(); } if (start > end || start < 0 || end > doc.getLength()) { setTextToFile(file); } else { replacePathComponent(file, caretPos, start, end); } } catch (BadLocationException e) { LOG.error(e); } } else { setTextToFile(file); } }
private void addMacroPaths(final CompletionResult result, final String typedText) { result.myMacros = new ArrayList<LookupFile>(); final Iterator<String> macros = myMacroMap.keySet().iterator(); while (macros.hasNext()) { String eachMacro = macros.next(); if (eachMacro.toUpperCase().startsWith(typedText.toUpperCase())) { final String eachPath = myMacroMap.get(eachMacro); if (eachPath != null) { final LookupFile macroFile = myFinder.find(eachPath); if (macroFile != null && macroFile.exists()) { result.myMacros.add(macroFile); result.myToComplete.add(macroFile); macroFile.setMacro(eachMacro); } } } } }
public FileTextFieldImpl( final JTextField field, Finder finder, LookupFilter filter, Map<String, String> macroMap, final Disposable parent) { myPathTextField = field; myMacroMap = new TreeMap<String, String>(); myMacroMap.putAll(macroMap); final InputMap listMap = (InputMap) UIManager.getDefaults().get("List.focusInputMap"); final KeyStroke[] listKeys = listMap.keys(); myDisabledTextActions = new HashSet<Action>(); for (KeyStroke eachListStroke : listKeys) { final String listActionID = (String) listMap.get(eachListStroke); if ("selectNextRow".equals(listActionID) || "selectPreviousRow".equals(listActionID)) { final Object textActionID = field.getInputMap().get(eachListStroke); if (textActionID != null) { final Action textAction = field.getActionMap().get(textActionID); if (textAction != null) { myDisabledTextActions.add(textAction); } } } } final FileTextFieldImpl assigned = (FileTextFieldImpl) myPathTextField.getClientProperty(KEY); if (assigned != null) { assigned.myFinder = finder; assigned.myFilter = filter; return; } myPathTextField.putClientProperty(KEY, this); final boolean headless = ApplicationManager.getApplication().isUnitTestMode(); myUiUpdater = new MergingUpdateQueue("FileTextField.UiUpdater", 200, false, myPathTextField); if (!headless) { new UiNotifyConnector(myPathTextField, myUiUpdater); } myFinder = finder; myFilter = filter; myFileSpitRegExp = myFinder.getSeparator().replaceAll("\\\\", "\\\\\\\\"); myPathTextField .getDocument() .addDocumentListener( new DocumentListener() { public void insertUpdate(final DocumentEvent e) { processTextChanged(); } public void removeUpdate(final DocumentEvent e) { processTextChanged(); } public void changedUpdate(final DocumentEvent e) { processTextChanged(); } }); myPathTextField.addKeyListener( new KeyAdapter() { public void keyPressed(final KeyEvent e) { processListSelection(e); } }); myPathTextField.addFocusListener( new FocusAdapter() { public void focusLost(final FocusEvent e) { closePopup(); } }); myCancelAction = new CancelAction(); new LazyUiDisposable<FileTextFieldImpl>(parent, field, this) { protected void initialize( @NotNull Disposable parent, @NotNull FileTextFieldImpl child, @Nullable Project project) { Disposer.register(child, myUiUpdater); } }; }
@Nullable public LookupFile getFile() { String text = getTextFieldText(); if (text == null) return null; return myFinder.find(text); }
public void processCompletion(final CompletionResult result) { result.myToComplete = new ArrayList<LookupFile>(); result.mySiblings = new ArrayList<LookupFile>(); result.myKidsAfterSeparator = new ArrayList<LookupFile>(); String typed = result.myCompletionBase; if (typed == null || typed.length() == 0) return; addMacroPaths(result, typed); final String typedText = myFinder.normalize(typed); result.current = getClosestParent(typed); result.myClosestParent = result.current; if (result.current != null) { result.currentParentMatch = SystemInfo.isFileSystemCaseSensitive ? typedText.equals(result.current.getAbsolutePath()) : typedText.equalsIgnoreCase(result.current.getAbsolutePath()); result.closedPath = typed.endsWith(myFinder.getSeparator()) && typedText.length() > myFinder.getSeparator().length(); final String currentParentText = result.current.getAbsolutePath(); if (!typedText.toUpperCase().startsWith(currentParentText.toUpperCase())) return; String prefix = typedText.substring(currentParentText.length()); if (prefix.startsWith(myFinder.getSeparator())) { prefix = prefix.substring(myFinder.getSeparator().length()); } else if (typed.endsWith(myFinder.getSeparator())) { prefix = ""; } result.effectivePrefix = prefix.toUpperCase(); result.currentGrandparent = result.current.getParent(); if (result.currentGrandparent != null && result.currentParentMatch && !result.closedPath) { final String currentGrandparentText = result.currentGrandparent.getAbsolutePath(); if (StringUtil.startsWithConcatenationOf( typedText, currentGrandparentText, myFinder.getSeparator())) { result.grandparentPrefix = currentParentText .substring(currentGrandparentText.length() + myFinder.getSeparator().length()) .toUpperCase(); } } } else { result.effectivePrefix = typedText.toUpperCase(); } ApplicationManager.getApplication() .runReadAction( new Runnable() { public void run() { if (result.current != null) { result.myToComplete.addAll( result.current.getChildren( new LookupFilter() { public boolean isAccepted(final LookupFile file) { return myFilter.isAccepted(file) && file.getName() .toUpperCase() .startsWith(result.effectivePrefix); } })); if (result.currentParentMatch && !result.closedPath) { result.myKidsAfterSeparator.addAll(result.myToComplete); } if (result.grandparentPrefix != null) { final List<LookupFile> siblings = result.currentGrandparent.getChildren( new LookupFilter() { public boolean isAccepted(final LookupFile file) { return !file.equals(result.current) && myFilter.isAccepted(file) && file.getName() .toUpperCase() .startsWith(result.grandparentPrefix); } }); result.myToComplete.addAll(0, siblings); result.mySiblings.addAll(siblings); } } int currentDiff = Integer.MIN_VALUE; LookupFile toPreselect = result.myPreselected; if (toPreselect == null || !result.myToComplete.contains(toPreselect)) { boolean toPreselectFixed = false; if (result.effectivePrefix.length() > 0) { for (LookupFile each : result.myToComplete) { String eachName = each.getName().toUpperCase(); if (!eachName.startsWith(result.effectivePrefix)) continue; int diff = result.effectivePrefix.compareTo(eachName); currentDiff = Math.max(diff, currentDiff); if (currentDiff == diff) { toPreselect = each; toPreselectFixed = true; break; } } if (!toPreselectFixed) { toPreselect = null; } } else { toPreselect = null; } if (toPreselect == null) { if (result.myToComplete.size() == 1) { toPreselect = result.myToComplete.get(0); } else if (result.effectivePrefix.length() == 0) { if (result.mySiblings.size() > 0) { toPreselect = result.mySiblings.get(0); } } if (toPreselect == null && !result.myToComplete.contains(toPreselect) && result.myToComplete.size() > 0) { toPreselect = result.myToComplete.get(0); } } } if (result.currentParentMatch && result.mySiblings.size() > 0) { toPreselect = null; } result.myPreselected = toPreselect; } }); }