[J2EEStructure] typing UE impro: async tree builder. Part 1
[fedora-idea.git] / lang-impl / src / com / intellij / psi / impl / file / PsiDirectoryImpl.java
blobc83018e988090c6a8c6e0fddbcf9063bb227b985
1 package com.intellij.psi.impl.file;
3 import com.intellij.ide.util.EditSourceUtil;
4 import com.intellij.lang.ASTNode;
5 import com.intellij.lang.Language;
6 import com.intellij.openapi.diagnostic.Logger;
7 import com.intellij.openapi.editor.Document;
8 import com.intellij.openapi.fileEditor.FileDocumentManager;
9 import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
10 import com.intellij.openapi.util.Comparing;
11 import com.intellij.openapi.util.TextRange;
12 import com.intellij.openapi.util.text.StringUtil;
13 import com.intellij.openapi.vcs.FileStatus;
14 import com.intellij.openapi.vcs.FileStatusManager;
15 import com.intellij.openapi.vfs.VfsBundle;
16 import com.intellij.openapi.vfs.VfsUtil;
17 import com.intellij.openapi.vfs.VirtualFile;
18 import com.intellij.openapi.vfs.ex.dummy.DummyFileSystem;
19 import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
20 import com.intellij.openapi.progress.ProgressManager;
21 import com.intellij.psi.*;
22 import com.intellij.psi.impl.CheckUtil;
23 import com.intellij.psi.impl.PsiElementBase;
24 import com.intellij.psi.impl.PsiManagerImpl;
25 import com.intellij.psi.impl.source.PsiFileImpl;
26 import com.intellij.psi.search.PsiElementProcessor;
27 import com.intellij.psi.search.PsiFileSystemItemProcessor;
28 import com.intellij.util.ArrayUtil;
29 import com.intellij.util.Icons;
30 import com.intellij.util.IncorrectOperationException;
31 import org.jetbrains.annotations.NotNull;
33 import javax.swing.*;
34 import java.io.IOException;
35 import java.io.Writer;
36 import java.util.ArrayList;
38 public class PsiDirectoryImpl extends PsiElementBase implements PsiDirectory {
39 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.file.PsiDirectoryImpl");
41 private final PsiManagerImpl myManager;
42 private final VirtualFile myFile;
44 public PsiDirectoryImpl(PsiManagerImpl manager, VirtualFile file) {
45 myManager = manager;
46 myFile = file;
49 @NotNull
50 public VirtualFile getVirtualFile() {
51 return myFile;
54 public boolean isDirectory() {
55 return true;
58 public boolean isValid() {
59 return myFile.isValid();
62 @NotNull
63 public Language getLanguage() {
64 return Language.ANY;
67 public PsiManager getManager() {
68 return myManager;
71 @NotNull
72 public String getName() {
73 return myFile.getName();
76 @NotNull
77 public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
78 checkSetName(name);
81 final String oldName = myFile.getName();
82 PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
83 event.setElement(this);
84 event.setPropertyName(PsiTreeChangeEvent.PROP_DIRECTORY_NAME);
85 event.setOldValue(oldName);
86 myManager.beforePropertyChange(event);
89 try {
90 myFile.rename(myManager, name);
92 catch (IOException e) {
93 throw new IncorrectOperationException(e.toString());
97 PsiUndoableAction undoableAction = new PsiUndoableAction(){
98 public void undo() throws IncorrectOperationException {
99 if (!PsiDirectoryImpl.this.isValid()){
100 throw new IncorrectOperationException();
102 setName(oldName);
108 event = new PsiTreeChangeEventImpl(myManager);
109 event.setElement(this);
110 event.setPropertyName(PsiTreeChangeEvent.PROP_DIRECTORY_NAME);
111 event.setOldValue(oldName);
112 event.setNewValue(name);
113 event.setUndoableAction(undoableAction);
114 myManager.propertyChanged(event);
116 return this;
119 public void checkSetName(String name) throws IncorrectOperationException {
120 //CheckUtil.checkIsIdentifier(name);
121 CheckUtil.checkWritable(this);
122 VirtualFile parentFile = myFile.getParent();
123 if (parentFile == null) {
124 throw new IncorrectOperationException(VfsBundle.message("cannot.rename.root.directory"));
126 VirtualFile child = parentFile.findChild(name);
127 if (child != null && !child.equals(myFile)) {
128 throw new IncorrectOperationException(VfsBundle.message("file.already.exists.error", child.getPresentableUrl()));
132 public PsiDirectory getParentDirectory() {
133 VirtualFile parentFile = myFile.getParent();
134 if (parentFile == null) return null;
135 return myManager.findDirectory(parentFile);
138 @NotNull
139 public PsiDirectory[] getSubdirectories() {
140 VirtualFile[] files = myFile.getChildren();
141 ArrayList<PsiDirectory> dirs = new ArrayList<PsiDirectory>();
142 for (VirtualFile file : files) {
143 PsiDirectory dir = myManager.findDirectory(file);
144 if (dir != null) {
145 dirs.add(dir);
148 return dirs.toArray(new PsiDirectory[dirs.size()]);
151 @NotNull
152 public PsiFile[] getFiles() {
153 LOG.assertTrue(myFile.isValid());
154 VirtualFile[] files = myFile.getChildren();
155 ArrayList<PsiFile> psiFiles = new ArrayList<PsiFile>();
156 for (VirtualFile file : files) {
157 PsiFile psiFile = myManager.findFile(file);
158 if (psiFile != null) {
159 psiFiles.add(psiFile);
162 return psiFiles.toArray(new PsiFile[psiFiles.size()]);
165 public PsiDirectory findSubdirectory(@NotNull String name) {
166 VirtualFile childVFile = myFile.findChild(name);
167 if (childVFile == null) return null;
168 return myManager.findDirectory(childVFile);
171 public PsiFile findFile(@NotNull String name) {
172 VirtualFile childVFile = myFile.findChild(name);
173 if (childVFile == null) return null;
174 return myManager.findFile(childVFile);
177 public boolean processChildren(PsiElementProcessor<PsiFileSystemItem> processor) {
178 checkValid();
179 ProgressManager.getInstance().checkCanceled();
181 for (VirtualFile vFile : myFile.getChildren()) {
182 if (processor instanceof PsiFileSystemItemProcessor &&
183 !((PsiFileSystemItemProcessor)processor).acceptItem(vFile.getName(), vFile.isDirectory())) {
184 continue;
186 if (vFile.isDirectory()) {
187 PsiDirectory dir = myManager.findDirectory(vFile);
188 if (dir != null) {
189 if(!processor.execute(dir)) return false;
192 else {
193 PsiFile file = myManager.findFile(vFile);
194 if (file != null) {
195 if(!processor.execute(file)) return false;
199 return true;
202 @NotNull
203 public PsiElement[] getChildren() {
204 checkValid();
206 VirtualFile[] files = myFile.getChildren();
207 final ArrayList<PsiElement> children = new ArrayList<PsiElement>(files.length);
208 processChildren(new PsiElementProcessor<PsiFileSystemItem>() {
209 public boolean execute(final PsiFileSystemItem element) {
210 children.add(element);
211 return true;
215 return children.toArray(new PsiElement[children.size()]);
218 private void checkValid() {
219 if (!isValid()) {
220 throw new PsiInvalidElementAccessException(this);
224 public PsiDirectory getParent() {
225 return getParentDirectory();
228 public PsiFile getContainingFile() {
229 return null;
232 public TextRange getTextRange() {
233 return null;
236 public int getStartOffsetInParent() {
237 return -1;
240 public int getTextLength() {
241 return -1;
244 public PsiElement findElementAt(int offset) {
245 return null;
248 public int getTextOffset() {
249 return -1;
252 public String getText() {
253 return ""; // TODO throw new InsupportedOperationException()
256 @NotNull
257 public char[] textToCharArray() {
258 return ArrayUtil.EMPTY_CHAR_ARRAY; // TODO throw new InsupportedOperationException()
261 public boolean textMatches(@NotNull CharSequence text) {
262 return false;
265 public boolean textMatches(@NotNull PsiElement element) {
266 return false;
269 public final boolean isWritable() {
270 return myFile.isWritable();
273 public boolean isPhysical() {
274 return !(myFile.getFileSystem() instanceof DummyFileSystem) && !(myFile.getFileSystem() instanceof TempFileSystem);
278 * @not_implemented
280 public PsiElement copy() {
281 LOG.error("not implemented");
282 return null;
286 @NotNull
287 public PsiDirectory createSubdirectory(@NotNull String name) throws IncorrectOperationException {
288 checkCreateSubdirectory(name);
290 try {
291 VirtualFile file = getVirtualFile().createChildDirectory(myManager, name);
292 PsiDirectory directory = myManager.findDirectory(file);
293 if (directory == null) throw new IncorrectOperationException("Cannot find directory in '"+file.getPresentableUrl()+"'");
294 return directory;
296 catch (IOException e) {
297 throw new IncorrectOperationException(e.toString());
301 public void checkCreateSubdirectory(@NotNull String name) throws IncorrectOperationException {
302 // TODO : another check?
303 //CheckUtil.checkIsIdentifier(name);
304 VirtualFile existingFile = getVirtualFile().findChild(name);
305 if (existingFile != null) {
306 throw new IncorrectOperationException(VfsBundle.message("file.already.exists.error", existingFile.getPresentableUrl()));
308 CheckUtil.checkWritable(this);
311 @NotNull
312 public PsiFile createFile(@NotNull String name) throws IncorrectOperationException {
313 checkCreateFile(name);
315 try {
316 VirtualFile vFile = getVirtualFile().createChildData(myManager, name);
317 return myManager.findFile(vFile);
319 catch (IOException e) {
320 throw new IncorrectOperationException(e.toString());
324 @NotNull
325 public PsiFile copyFileFrom(@NotNull String newName, @NotNull PsiFile originalFile) throws IncorrectOperationException {
326 checkCreateFile(newName);
328 final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(originalFile);
329 if (document != null) {
330 FileDocumentManager.getInstance().saveDocument(document);
333 final VirtualFile parent = getVirtualFile();
334 try {
335 final VirtualFile vFile = originalFile.getVirtualFile();
336 if (vFile == null) throw new IncorrectOperationException("Cannot copy nonphysical file");
337 VirtualFile copyVFile;
338 if (parent.getFileSystem() == vFile.getFileSystem()) {
339 copyVFile = vFile.copy(this, parent, newName);
341 else {
342 copyVFile = VfsUtil.copyFile(this, vFile, parent, newName);
344 final PsiFile copyPsi = myManager.findFile(copyVFile);
345 if (copyPsi == null) {
346 LOG.error("Could not find file '"+copyVFile+"' after copying '"+vFile+"'");
348 updateAddedFile(copyPsi, originalFile);
349 return copyPsi;
351 catch (IOException e) {
352 throw new IncorrectOperationException(e.toString(),e);
357 private static void updateAddedFile(PsiFile copyPsi, PsiFile originalFile) throws IncorrectOperationException {
358 final UpdateAddedFileProcessor processor = UpdateAddedFileProcessor.forElement(copyPsi);
359 if (processor != null) {
360 processor.update(copyPsi, null);
364 public void checkCreateFile(@NotNull String name) throws IncorrectOperationException {
365 VirtualFile existingFile = getVirtualFile().findChild(name);
366 if (existingFile != null) {
367 throw new IncorrectOperationException(VfsBundle.message("file.already.exists.error", existingFile.getPresentableUrl()));
369 CheckUtil.checkWritable(this);
373 public PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException {
374 checkAdd(element);
375 if (element instanceof PsiDirectory) {
376 LOG.error("not implemented");
377 return null;
379 else if (element instanceof PsiFile) {
380 PsiFile originalFile = (PsiFile)element;
382 try {
383 VirtualFile newVFile;
384 final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(myManager.getProject());
385 if (originalFile instanceof PsiFileImpl) {
386 newVFile = myFile.createChildData(myManager, originalFile.getName());
387 String text = originalFile.getText();
388 final PsiFile psiFile = getManager().findFile(newVFile);
389 final Document document = psiFile == null ? null : psiDocumentManager.getDocument(psiFile);
390 final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
391 if (document != null) {
392 document.setText(text);
393 fileDocumentManager.saveDocument(document);
394 } else {
395 String lineSeparator = fileDocumentManager.getLineSeparator(newVFile, getProject());
396 if (!lineSeparator.equals("\n")) {
397 text = StringUtil.convertLineSeparators(text, lineSeparator);
400 final Writer writer = LoadTextUtil.getWriter(getProject(), newVFile, myManager, text, -1);
401 try {
402 writer.write(text);
404 finally {
405 writer.close();
409 else {
410 byte[] storedContents = ((PsiBinaryFileImpl)originalFile).getStoredContents();
411 if (storedContents != null) {
412 newVFile = myFile.createChildData(myManager, originalFile.getName());
413 newVFile.setBinaryContent(storedContents);
415 else {
416 newVFile = VfsUtil.copyFile(null, originalFile.getVirtualFile(), myFile);
419 psiDocumentManager.commitAllDocuments();
421 PsiFile newFile = myManager.findFile(newVFile);
422 updateAddedFile(newFile, null);
424 return newFile;
426 catch (IOException e) {
427 throw new IncorrectOperationException(e.toString(),e);
430 else {
431 LOG.assertTrue(false);
432 return null;
436 public void checkAdd(@NotNull PsiElement element) throws IncorrectOperationException {
437 CheckUtil.checkWritable(this);
438 if (element instanceof PsiDirectory) {
439 String name = ((PsiDirectory)element).getName();
440 PsiDirectory[] subpackages = getSubdirectories();
441 for (PsiDirectory dir : subpackages) {
442 if (Comparing.strEqual(dir.getName(),name)) {
443 throw new IncorrectOperationException(VfsBundle.message("dir.already.exists.error", dir.getVirtualFile().getPresentableUrl()));
447 else if (element instanceof PsiFile) {
448 String name = ((PsiFile)element).getName();
449 PsiFile[] files = getFiles();
450 for (PsiFile file : files) {
451 if (Comparing.strEqual(file.getName(),name)) {
452 throw new IncorrectOperationException(VfsBundle.message("file.already.exists.error", file.getVirtualFile().getPresentableUrl()));
456 else {
457 throw new IncorrectOperationException();
461 public PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException {
462 throw new IncorrectOperationException();
465 public PsiElement addAfter(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException {
466 throw new IncorrectOperationException();
469 public void delete() throws IncorrectOperationException {
470 checkDelete();
471 //PsiDirectory parent = getParentDirectory();
474 PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
475 event.setParent(parent);
476 event.setChild(this);
477 myManager.beforeChildRemoval(event);
480 try {
481 myFile.delete(myManager);
483 catch (IOException e) {
484 throw new IncorrectOperationException(e.toString(),e);
488 //TODO : allow undo
489 PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager);
490 treeEvent.setParent(parent);
491 treeEvent.setChild(this);
492 treeEvent.setUndoableAction(null);
493 myManager.childRemoved(treeEvent);
497 public void checkDelete() throws IncorrectOperationException {
498 CheckUtil.checkDelete(myFile);
502 * @not_implemented
504 public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException {
505 LOG.error("not implemented");
506 return null;
509 public void accept(@NotNull PsiElementVisitor visitor) {
510 visitor.visitDirectory(this);
513 public String toString() {
514 return "PsiDirectory:" + myFile.getPresentableUrl();
517 public ASTNode getNode() {
518 return null;
521 public boolean canNavigate() {
522 return EditSourceUtil.canNavigate(this);
525 public boolean canNavigateToSource() {
526 return false;
529 public void navigate(boolean requestFocus) {
532 public FileStatus getFileStatus() {
533 return myFile != null ? FileStatusManager.getInstance(getProject()).getStatus(myFile) : FileStatus.NOT_CHANGED;
536 protected Icon getElementIcon(final int flags) {
537 return Icons.DIRECTORY_CLOSED_ICON;