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
;
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
) {
50 public VirtualFile
getVirtualFile() {
54 public boolean isDirectory() {
58 public boolean isValid() {
59 return myFile
.isValid();
63 public Language
getLanguage() {
67 public PsiManager
getManager() {
72 public String
getName() {
73 return myFile
.getName();
77 public PsiElement
setName(@NotNull String name
) throws IncorrectOperationException
{
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);
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();
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);
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
);
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
);
148 return dirs
.toArray(new PsiDirectory
[dirs
.size()]);
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
) {
179 ProgressManager
.getInstance().checkCanceled();
181 for (VirtualFile vFile
: myFile
.getChildren()) {
182 if (processor
instanceof PsiFileSystemItemProcessor
&&
183 !((PsiFileSystemItemProcessor
)processor
).acceptItem(vFile
.getName(), vFile
.isDirectory())) {
186 if (vFile
.isDirectory()) {
187 PsiDirectory dir
= myManager
.findDirectory(vFile
);
189 if(!processor
.execute(dir
)) return false;
193 PsiFile file
= myManager
.findFile(vFile
);
195 if(!processor
.execute(file
)) return false;
203 public PsiElement
[] getChildren() {
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
);
215 return children
.toArray(new PsiElement
[children
.size()]);
218 private void checkValid() {
220 throw new PsiInvalidElementAccessException(this);
224 public PsiDirectory
getParent() {
225 return getParentDirectory();
228 public PsiFile
getContainingFile() {
232 public TextRange
getTextRange() {
236 public int getStartOffsetInParent() {
240 public int getTextLength() {
244 public PsiElement
findElementAt(int offset
) {
248 public int getTextOffset() {
252 public String
getText() {
253 return ""; // TODO throw new InsupportedOperationException()
257 public char[] textToCharArray() {
258 return ArrayUtil
.EMPTY_CHAR_ARRAY
; // TODO throw new InsupportedOperationException()
261 public boolean textMatches(@NotNull CharSequence text
) {
265 public boolean textMatches(@NotNull PsiElement element
) {
269 public final boolean isWritable() {
270 return myFile
.isWritable();
273 public boolean isPhysical() {
274 return !(myFile
.getFileSystem() instanceof DummyFileSystem
) && !(myFile
.getFileSystem() instanceof TempFileSystem
);
280 public PsiElement
copy() {
281 LOG
.error("not implemented");
287 public PsiDirectory
createSubdirectory(@NotNull String name
) throws IncorrectOperationException
{
288 checkCreateSubdirectory(name
);
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()+"'");
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);
312 public PsiFile
createFile(@NotNull String name
) throws IncorrectOperationException
{
313 checkCreateFile(name
);
316 VirtualFile vFile
= getVirtualFile().createChildData(myManager
, name
);
317 return myManager
.findFile(vFile
);
319 catch (IOException e
) {
320 throw new IncorrectOperationException(e
.toString());
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();
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
);
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
);
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
{
375 if (element
instanceof PsiDirectory
) {
376 LOG
.error("not implemented");
379 else if (element
instanceof PsiFile
) {
380 PsiFile originalFile
= (PsiFile
)element
;
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
);
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);
410 byte[] storedContents
= ((PsiBinaryFileImpl
)originalFile
).getStoredContents();
411 if (storedContents
!= null) {
412 newVFile
= myFile
.createChildData(myManager
, originalFile
.getName());
413 newVFile
.setBinaryContent(storedContents
);
416 newVFile
= VfsUtil
.copyFile(null, originalFile
.getVirtualFile(), myFile
);
419 psiDocumentManager
.commitAllDocuments();
421 PsiFile newFile
= myManager
.findFile(newVFile
);
422 updateAddedFile(newFile
, null);
426 catch (IOException e
) {
427 throw new IncorrectOperationException(e
.toString(),e
);
431 LOG
.assertTrue(false);
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()));
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
{
471 //PsiDirectory parent = getParentDirectory();
474 PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
475 event.setParent(parent);
476 event.setChild(this);
477 myManager.beforeChildRemoval(event);
481 myFile
.delete(myManager
);
483 catch (IOException e
) {
484 throw new IncorrectOperationException(e
.toString(),e
);
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
);
504 public PsiElement
replace(@NotNull PsiElement newElement
) throws IncorrectOperationException
{
505 LOG
.error("not implemented");
509 public void accept(@NotNull PsiElementVisitor visitor
) {
510 visitor
.visitDirectory(this);
513 public String
toString() {
514 return "PsiDirectory:" + myFile
.getPresentableUrl();
517 public ASTNode
getNode() {
521 public boolean canNavigate() {
522 return EditSourceUtil
.canNavigate(this);
525 public boolean canNavigateToSource() {
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
;