// Copyright 2006-2012 AdvancedTools. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.advancedtools.cpp; import com.advancedtools.cpp.build.BaseBuildHandler; import com.advancedtools.cpp.build.BuildTarget; import com.advancedtools.cpp.commands.ChangedCommand; import com.advancedtools.cpp.commands.FindSymbolsCommand; import com.advancedtools.cpp.commands.StringCommand; import com.advancedtools.cpp.communicator.BuildingCommandHelper; import com.advancedtools.cpp.communicator.Communicator; import com.advancedtools.cpp.facade.EnvironmentFacade; import com.advancedtools.cpp.facade.ExtendedPlatformServices; import com.advancedtools.cpp.makefile.MakefileLanguage; import com.advancedtools.cpp.navigation.CppSymbolContributor; import com.advancedtools.cpp.settings.*; import com.advancedtools.cpp.usages.OurUsage; import com.advancedtools.cpp.utils.StringTokenizerIterable; import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; import com.intellij.codeInsight.completion.CompletionType; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.event.DocumentListener; import com.intellij.openapi.editor.event.EditorFactoryEvent; import com.intellij.openapi.editor.event.EditorFactoryListener; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.ExtensionsArea; import com.intellij.openapi.extensions.LoadingOrder; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDialog; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.*; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.tree.IFileElementType; import com.intellij.util.Alarm; import com.intellij.util.Processor; import com.intellij.util.text.CharArrayUtil; import com.intellij.util.ui.ErrorTreeView; import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.table.AbstractTableModel; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.lang.reflect.Field; import java.util.*; import java.util.List; /** * @author maxim */ public class CppSupportLoader implements ProjectComponent, JDOMExternalizable { public static final @NonNls String HPP_EXTENSION = "hpp"; public static final @NonNls String HXX_EXTENSION = "hxx"; public static final @NonNls String TCC_EXTENSION = "tcc"; public static final @NonNls String INL_EXTENSION = "inl"; public static final @NonNls String INC_EXTENSION = "inc"; public static final @NonNls String HI_EXTENSION = "hi"; public static final @NonNls String CPP_EXTENSION = "cpp"; public static final @NonNls String CC_EXTENSION = "cc"; public static final @NonNls String C_EXTENSION = "c"; public static final @NonNls String H_EXTENSION = "h"; public static final @NonNls String INO_EXTENSION = "ino"; private static Key<DocumentListener> ourListenerKey = Key.create("cpp.document.listener"); public static final String[] extensions = new String[]{CPP_EXTENSION, CC_EXTENSION, C_EXTENSION, INO_EXTENSION, H_EXTENSION, HPP_EXTENSION, TCC_EXTENSION, INL_EXTENSION, HI_EXTENSION, INC_EXTENSION, HXX_EXTENSION}; private Project project; private DocumentListener myDocumentListener; private VirtualFileListener myFileListener; private EditorFactoryListener myEditorFactoryListener; private static CppSymbolContributor myConstantContributor; private static CppSymbolContributor myMacrosContributor; private static final @NonNls String JAVA_INCLUDES_KEY = "javaIncludes"; private static final @NonNls String FILE_KEY = "ignored-file"; private static final @NonNls String ADDITIONAL_INCLUDE_DIR_KEY = "include-dir"; private static final @NonNls String ADDITIONAL_SYSTEM_INCLUDE_DIR_KEY = "system-include-dir"; private static final @NonNls String WARNED_ABOUT_FILE_OUT_OF_SOURCE_ROOT_KEY = "warnedAboutFileOutOfSourceRoot"; private static final @NonNls String SETTINGS_VERSION_KEY = "version"; private Set<String> myIgnoredFiles = new TreeSet<String>(); private String myAdditionalIncludeDirs = ""; private String myAdditionalSystemIncludeDirs = ""; private boolean myWarnedAboutSourceFileOutOfSourceRoot; private final CppHighlightingSettings myHighlightingSettings = new CppHighlightingSettings(); private int mySettingsVersion = SETTINGS_VERSION; public static final int SETTINGS_VERSION = 3; private String myActiveConfiguration; private String myProjectFile; private String myAutomaticallyIncludedHeaderFiles = ""; private String myAdditionalPreprocessorDefines; private String myLastBuildAction = BuildTarget.DEFAULT_BUILD_ACTION; private String myAdditionalCommandLineBuildParameters; private boolean myIncludeJavaIncludes = true; private String myAdditionalCompileParameters; private boolean myIncludeProjectSettings; private long myReportedProblemAboutServerProblemStamp = -1; private static final @NonNls String FILE_PATH_KEY = "path"; private static final @NonNls String ACTIVE_CONFIGURATION_KEY = "activeConfiguration"; private static final @NonNls String LAST_BUILD_ACTION_KEY = "lastBuildAction"; private static final @NonNls String ADDITIONAL_COMMAND_LINE_BUILD_PARAMETERS_KEY = "additionalCommandLineBuildParameters"; private static final @NonNls String ADDITIONAL_COMPILE_PARAMETERS_KEY = "additionalCompileParameters"; private static final @NonNls String INCLUDE_PROJECT_SETTINGS_KEY = "includeProjectSettings"; private static final @NonNls String ADDITIONAL_PREPROCESSOR_DEFINITIONS_KEY = "additionalPreprocessorDefs"; private static final @NonNls String AUTOMATICALLY_INCLUDED_HEADER_FILES_KEY = "automaticallyIncludedHeaderFiles"; private static final @NonNls String PROJECT_FILE_KEY = "currentProject"; private static final @NonNls String SERVER_STAMP_ERROR_REPORTED = "serverStampWhenFatalErrorReported"; private static final @NonNls String SDK_ERROR_REPORTED = "sdkErrorReported"; private LinkedHashSet<VirtualFile> projectAndBuildFilesSet = new LinkedHashSet<VirtualFile>(); private static CppSupportLoader instance; private ErrorTreeView errorTreeView; private boolean errorViewIsFilling; public static final Icon ourCppIcon = IconLoader.findIcon("c_file_obj.gif"); public static final Icon ourIncludeIcon = IconLoader.findIcon("include_obj.gif"); public static final Icon ourMakefileIcon = IconLoader.findIcon("makefile.gif"); public static final Icon ourSdkIcon = ourCppIcon; public static final Icon ourModuleIcon = ourCppIcon; public static final Icon ourBigModuleIcon = ourCppIcon; private boolean complainedAboutGccOrMsVc; public boolean isComplainedAboutGccOrMsVc() { return complainedAboutGccOrMsVc; } public void setComplainedAboutGccOrMsVc(boolean complainedAboutGccOrMsVc) { this.complainedAboutGccOrMsVc = complainedAboutGccOrMsVc; } // Server problems // TODO: usage text contains new lines //------------ // find parent by no should give info on class context public CppSupportLoader(Project _project) { project = _project; } public void projectOpened() { initFileType(project); if (EnvironmentFacade.isJavaIde()) { ExtendedPlatformServices.registerCompilerStuff(project); } myDocumentListener = new MyDocumentListener(); EditorFactory.getInstance().addEditorFactoryListener( myEditorFactoryListener = new EditorFactoryListener() { public void editorCreated(EditorFactoryEvent event) { if (this != myEditorFactoryListener) return; // disposed final Editor editor = event.getEditor(); if (editor.getProject() != project) return; final Document document = editor.getDocument(); if (isAcceptableDocument(document) && document.getUserData(ourListenerKey) == null) { document.addDocumentListener(myDocumentListener); document.putUserData(ourListenerKey, myDocumentListener); } } public void editorReleased(EditorFactoryEvent event) { if (this != myEditorFactoryListener) return; // disposed final Editor editor = event.getEditor(); if (editor.getProject() != project) return; final Document document = editor.getDocument(); removeDocumentListener(document); } } ); VirtualFileManager.getInstance().addVirtualFileListener(myFileListener = new VirtualFileListener() { public void fileCreated(VirtualFileEvent virtualFileEvent) { if (this != myFileListener) return; // disposed VirtualFile file = virtualFileEvent.getFile(); doFileCreated(file); } public void fileDeleted(VirtualFileEvent virtualFileEvent) {} public void contentsChanged(VirtualFileEvent virtualFileEvent) { updateModificationCount(virtualFileEvent, true); } public void beforeFileDeletion(VirtualFileEvent virtualFileEvent) { VirtualFile file = virtualFileEvent.getFile(); doFileRemoved(file); if (isCppFile(file)) { myIgnoredFiles.remove(file.getPath()); } } public void beforePropertyChange(VirtualFilePropertyEvent virtualFilePropertyEvent) { VirtualFile file = virtualFilePropertyEvent.getFile(); if (isCppFile(file) && VirtualFile.PROP_NAME.equals(virtualFilePropertyEvent.getPropertyName())) { if(myIgnoredFiles.remove(file.getPath())) { myIgnoredFiles.add(file.getParent().getPath() + '/' + virtualFilePropertyEvent.getNewValue()); } } } public void beforeContentsChange(VirtualFileEvent virtualFileEvent) {} public void propertyChanged(VirtualFilePropertyEvent virtualFilePropertyEvent) { VirtualFile file = virtualFilePropertyEvent.getFile(); if (isCppFile(file) && VirtualFile.PROP_NAME.equals(virtualFilePropertyEvent.getPropertyName())) { if (!myIgnoredFiles.contains(file.getPath())) { Communicator.getInstance(project).onFileCreated(file); } } updateModificationCount(virtualFilePropertyEvent, false); } public void beforeFileMovement(VirtualFileMoveEvent virtualFileMoveEvent) { VirtualFile file = virtualFileMoveEvent.getFile(); doFileRemoved(file); if (isCppFile(file)) { if(myIgnoredFiles.remove(file.getPath())) { myIgnoredFiles.add(virtualFileMoveEvent.getNewParent().getPath() + '/' + file.getName()); } } } public void fileMoved(VirtualFileMoveEvent event) { doFileCreated(event.getFile()); } public void fileCopied(VirtualFileCopyEvent virtualFileCopyEvent) { //To change body of implemented methods use File | Settings | File Templates. } private void updateModificationCount(VirtualFileEvent event, boolean sendReload) { if (this != myFileListener) return; // disposed VirtualFile file = event.getFile(); if (isCppFile(file)) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile != null && isOurFile(psiFile)) { final Communicator communicator = Communicator.getInstance(project); communicator.incModificationCount(); if (sendReload) { communicator.sendCommand( new StringCommand( "reload -n " + communicator.getModificationCount() + " " + BuildingCommandHelper.quote(file.getPresentableUrl()) ) ); } } } } }); } private static boolean isCppFile(VirtualFile file) { return !file.isDirectory() && file.getFileType() == CPP_FILETYPE; } private void removeDocumentListener(Document document) { if (isAcceptableDocument(document) && document.getUserData(ourListenerKey) != null) { document.removeDocumentListener(myDocumentListener); document.putUserData(ourListenerKey, null); } } private void doFileCreated(VirtualFile file) { if (isCppFile(file)) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile != null && isOurFile(psiFile)) { Communicator.getInstance(project).onFileCreated(file); } } } private void doFileRemoved(VirtualFile file) { if (isCppFile(file)) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile != null && isOurFile(psiFile)) { Communicator.getInstance(project).onFileRemoved(file); } } } private boolean isAcceptableDocument(Document document) { final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); return psiFile != null && CPP_FILETYPE == psiFile.getFileType(); } private boolean isOurFile(PsiFile psiFile) { final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); return isInSource(psiFile.getVirtualFile(), index); } public static final Language CPP_LANGUAGE = new CppLanguage(); public static final Language MAKEFILE_LANGUAGE = new MakefileLanguage(); public static final LanguageFileType CPP_FILETYPE = new LanguageFileType(CPP_LANGUAGE) { @NotNull @NonNls public String getName() { return "C/C++"; } @NotNull public String getDescription() { return "Cpp file support"; } @NotNull @NonNls public String getDefaultExtension() { return CPP_EXTENSION; } @Nullable public Icon getIcon() { return ourCppIcon; } }; public static final LanguageFileType MAKE_FILETYPE = new LanguageFileType(MAKEFILE_LANGUAGE) { @NotNull @NonNls public String getName() { return "Makefile"; } @NotNull public String getDescription() { return "Traditional makefiles"; } @NotNull @NonNls public String getDefaultExtension() { return ""; } @Nullable public Icon getIcon() { return ourMakefileIcon; } }; public static final IFileElementType CPP_FILE = new IFileElementType(CPP_LANGUAGE); private final static Set<String> filesWithEmptyExtsKnownToBeCpp = new THashSet<String>(); static { final @NonNls String listOfKnownCppFiles = "algorithm\n" + "bitset\n" + "cassert\n" + "cctype\n" + "cerrno\n" + "cfloat\n" + "ciso646\n" + "climits\n" +"clocale\n" + "cmath\n" + "complex\n" + "csetjmp\n" + "csignal\n" + "cstdarg\n" + "cstddef\n" + "cstdio\n" + "cstdlib\n" + "cstring\n" + "ctime\n" + "cwchar\n" + "cwctype\n" + "deque\n" + "exception\n" + "fstream\n" + "functional\n" + "iomanip\n" + "ios\n" + "iosfwd\n" + "iostream\n" + "istream\n" + "iterator\n" + "limits\n" + "list\n" + "locale\n" + "map\n" + "memory\n" + "new\n" + "numeric\n" + "ostream\n" + "queue\n" + "set\n" + "sstream\n" + "stack\n" + "stdexcept\n" + "streambuf\n" + "string\n" + "typeinfo\n" + "utility\n" + "valarray\n" + "vector\n" + "hash_map\n" + "hash_set\n" + "memory\n" + "numeric\n" + "rb_tree\n" + "rope\n" + "slist\n" + "xcomplex\n" + "xdebug\n" + "xhash\n" + "xiosbase\n" + "xlocale\n" + "xlocinfo\n" + "xlocmes\n" + "xlocmon\n" + "xlocnum\n" + "xloctime\n" + "xmemory\n" + "xstddef\n" + "xstring\n" + "xtree\n" + "xutility"; final StringTokenizer tokenizer = new StringTokenizer(listOfKnownCppFiles, "\n"); while (tokenizer.hasMoreElements()) { filesWithEmptyExtsKnownToBeCpp.add(tokenizer.nextToken()); } } public static boolean isKnownEmptyExtensionFile(@NotNull String fileName) { return filesWithEmptyExtsKnownToBeCpp.contains(SystemInfo.isFileSystemCaseSensitive ?fileName:fileName.toLowerCase()); } public static Set<String> filesWithEmptyExtensions() { return filesWithEmptyExtsKnownToBeCpp; } public static final Key<OurUsage> ourUsageKey = Key.create("usage.key"); private static boolean initialized; private static void initFileType(Project project) { if (initialized) return; initialized = true; EnvironmentFacade.getInstance().runWriteActionFromComponentInstantiation(new Runnable() { public void run() { myConstantContributor = new CppSymbolContributor(FindSymbolsCommand.TargetTypes.CONSTANTS); myMacrosContributor = new CppSymbolContributor(FindSymbolsCommand.TargetTypes.MACROS); } }); Communicator.getInstance(project); } public void projectClosed() { EditorFactory.getInstance().removeEditorFactoryListener(myEditorFactoryListener); myEditorFactoryListener = null; VirtualFileManager.getInstance().removeVirtualFileListener(myFileListener); myFileListener = null; for(Editor editor:EditorFactory.getInstance().getAllEditors()) { if (editor.getProject() == project) { removeDocumentListener(editor.getDocument()); } } myDocumentListener = null; } @NonNls public String getComponentName() { return "CppTools.Loader"; } public void initComponent() { } public void disposeComponent() { } public static Editor findEditor(Project project, VirtualFile newFile) { final FileEditor selectedEditor = FileEditorManager.getInstance(project).getSelectedEditor(newFile); return selectedEditor instanceof TextEditor ? ((TextEditor)selectedEditor).getEditor() : null; } public void readExternal(Element element) throws InvalidDataException { myIgnoredFiles.clear(); // old compatibility code boolean usedCompatibility = false; for (Object anIgnoredFile : element.getChildren(FILE_KEY)) { if (!(anIgnoredFile instanceof Element)) continue; Element fileElement = (Element) anIgnoredFile; final String name = fileElement.getAttributeValue("name"); if (name != null && name.length() > 0) { myIgnoredFiles.add(name); usedCompatibility = true; } } String additionalIncludes = element.getAttributeValue(ADDITIONAL_INCLUDE_DIR_KEY); myAdditionalIncludeDirs = (additionalIncludes != null) ? additionalIncludes:""; usedCompatibility |= additionalIncludes != null; additionalIncludes = element.getAttributeValue(ADDITIONAL_SYSTEM_INCLUDE_DIR_KEY); myAdditionalSystemIncludeDirs = (additionalIncludes != null) ? additionalIncludes:""; usedCompatibility |= additionalIncludes != null; if (!usedCompatibility) { readChildren(element, FILE_KEY, FILE_PATH_KEY, new Processor<String>() { public boolean process(String s) { myIgnoredFiles.add(s); return true; } }); final StringBuilder builder = new StringBuilder(); Processor<String> collectingPathProcessor = new Processor<String>() { public boolean process(String s) { if (builder.length() > 0) builder.append(CppSupportSettings.PATH_SEPARATOR); builder.append(s); return true; } }; readChildren(element, ADDITIONAL_INCLUDE_DIR_KEY, FILE_PATH_KEY, collectingPathProcessor); myAdditionalIncludeDirs = builder.toString(); builder.setLength(0); readChildren(element, ADDITIONAL_SYSTEM_INCLUDE_DIR_KEY, FILE_PATH_KEY, collectingPathProcessor); myAdditionalSystemIncludeDirs = builder.toString(); } myHighlightingSettings.readExternal(element); String s = element.getAttributeValue(WARNED_ABOUT_FILE_OUT_OF_SOURCE_ROOT_KEY); if (s != null) myWarnedAboutSourceFileOutOfSourceRoot = Boolean.parseBoolean(s); s = element.getAttributeValue(SETTINGS_VERSION_KEY); if (s != null) { try { mySettingsVersion = Integer.parseInt(s); } catch (NumberFormatException e) {} } s = element.getAttributeValue(ACTIVE_CONFIGURATION_KEY); if (s != null) myActiveConfiguration = s; s = element.getAttributeValue(LAST_BUILD_ACTION_KEY); if (s != null) myLastBuildAction = s; s = element.getAttributeValue(ADDITIONAL_COMMAND_LINE_BUILD_PARAMETERS_KEY); if (s != null) myAdditionalCommandLineBuildParameters = s; s = element.getAttributeValue(ADDITIONAL_COMPILE_PARAMETERS_KEY); if (s != null) myAdditionalCompileParameters = s; else myAdditionalCompileParameters = null; s = element.getAttributeValue(INCLUDE_PROJECT_SETTINGS_KEY); if (s != null && Boolean.parseBoolean(s)) myIncludeProjectSettings = true; else myIncludeProjectSettings = false; s = element.getAttributeValue(ADDITIONAL_PREPROCESSOR_DEFINITIONS_KEY); if (s != null) myAdditionalPreprocessorDefines = s; s = element.getAttributeValue(AUTOMATICALLY_INCLUDED_HEADER_FILES_KEY); if (s != null) myAutomaticallyIncludedHeaderFiles = s; s = element.getAttributeValue(PROJECT_FILE_KEY); if (s != null) myProjectFile = s; s = element.getAttributeValue(SERVER_STAMP_ERROR_REPORTED); if (s != null) { try { myReportedProblemAboutServerProblemStamp = Long.parseLong(s); } catch (NumberFormatException ex) { myReportedProblemAboutServerProblemStamp = -1; } } s = element.getAttributeValue(SDK_ERROR_REPORTED); if (s != null) { complainedAboutGccOrMsVc = Boolean.parseBoolean(s); } s = element.getAttributeValue(COMPILER_SELECT_KEY); if (s != null) myCompilerOptions = CppSupportSettings.CompilerSelectOptions.valueOf(s); s = element.getAttributeValue(JAVA_INCLUDES_KEY); if (s != null) myIncludeJavaIncludes = Boolean.parseBoolean(s); } private void readChildren(Element element, String subTagName, String attrName, Processor<String> processor) { for (Object anIgnoredFile : element.getChildren(subTagName)) { if (!(anIgnoredFile instanceof Element)) continue; Element fileElement = (Element) anIgnoredFile; final String name = fileElement.getAttributeValue(attrName); if (name != null && name.length() > 0) processor.process(name); } } public void writeExternal(Element element) throws WriteExternalException { serializeFileList(myIgnoredFiles, element, FILE_KEY); if (myAdditionalIncludeDirs.length() > 0) { serializeFileList(new StringTokenizerIterable(myAdditionalIncludeDirs, CppSupportSettings.PATH_SEPARATOR), element, ADDITIONAL_INCLUDE_DIR_KEY); } if (myAdditionalSystemIncludeDirs.length() > 0) { serializeFileList(new StringTokenizerIterable(myAdditionalSystemIncludeDirs, CppSupportSettings.PATH_SEPARATOR), element, ADDITIONAL_SYSTEM_INCLUDE_DIR_KEY); } myHighlightingSettings.writeExternal(element); if (myWarnedAboutSourceFileOutOfSourceRoot) element.setAttribute(WARNED_ABOUT_FILE_OUT_OF_SOURCE_ROOT_KEY, "true"); element.setAttribute(SETTINGS_VERSION_KEY, Integer.toString(SETTINGS_VERSION)); if (myActiveConfiguration != null) element.setAttribute(ACTIVE_CONFIGURATION_KEY, myActiveConfiguration); if (myLastBuildAction != null && !BuildTarget.DEFAULT_BUILD_ACTION.equals(myLastBuildAction)) element.setAttribute(LAST_BUILD_ACTION_KEY, myLastBuildAction); if (myAdditionalCommandLineBuildParameters != null) element.setAttribute(ADDITIONAL_COMMAND_LINE_BUILD_PARAMETERS_KEY, myAdditionalCommandLineBuildParameters); if (myIncludeProjectSettings) element.setAttribute(INCLUDE_PROJECT_SETTINGS_KEY, "true"); if (myAdditionalCompileParameters != null) element.setAttribute(ADDITIONAL_COMPILE_PARAMETERS_KEY, myAdditionalCompileParameters); if (myProjectFile != null) element.setAttribute(PROJECT_FILE_KEY, myProjectFile); if (myReportedProblemAboutServerProblemStamp != -1) { element.setAttribute(SERVER_STAMP_ERROR_REPORTED,String.valueOf(myReportedProblemAboutServerProblemStamp)); } if (complainedAboutGccOrMsVc) { element.setAttribute(SDK_ERROR_REPORTED, "true"); } if (myAdditionalPreprocessorDefines != null) { element.setAttribute(ADDITIONAL_PREPROCESSOR_DEFINITIONS_KEY, myAdditionalPreprocessorDefines); } if (myAutomaticallyIncludedHeaderFiles.length() > 0) { element.setAttribute(AUTOMATICALLY_INCLUDED_HEADER_FILES_KEY, myAutomaticallyIncludedHeaderFiles); } element.setAttribute(COMPILER_SELECT_KEY, myCompilerOptions.toString()); if (!myIncludeJavaIncludes) element.setAttribute(JAVA_INCLUDES_KEY, "false"); } private static void serializeFileList(Iterable<String> myIgnoredFiles, Element element, String key) { for(String ignoredFile: myIgnoredFiles) { final Element fileElement = new Element(key); fileElement.setAttribute(FILE_PATH_KEY, ignoredFile); element.addContent(fileElement); } } public Set<String> getIgnoredFilesSet() { return myIgnoredFiles; } public String getAdditionalIncludeDirs() { return myAdditionalIncludeDirs; } public String getAdditionalSystemIncludeDirs() { return myAdditionalSystemIncludeDirs; } public boolean isWarnedAboutSourceFileOutOfSourceRoot() { return myWarnedAboutSourceFileOutOfSourceRoot; } public void setWarnedAboutSourceFileOutOfSourceRoot(boolean value) { myWarnedAboutSourceFileOutOfSourceRoot = value; } public static CppSupportLoader getInstance(Project project) { CppSupportLoader loader = project.getComponent(CppSupportLoader.class); if (loader == null && ApplicationManager.getApplication().isUnitTestMode() && instance != null) { loader = instance; } return loader; } public static void setInstance(CppSupportLoader loader) { assert ApplicationManager.getApplication().isUnitTestMode(); instance = loader; } public Set<VirtualFile> getProjectAndBuildFilesSet() { return projectAndBuildFilesSet; } public ErrorTreeView getErrorTreeView() { return errorTreeView; } public void setErrorTreeView(ErrorTreeView errorTreeView) { this.errorTreeView = errorTreeView; } public void setErrorViewIsFilling(boolean value) { errorViewIsFilling = value; } public boolean isErrorViewIsFilling() { return errorViewIsFilling; } public boolean isIncludeJavaIncludes() { return myIncludeJavaIncludes; } public static void doRegisterExtensionPoint(String extensionPointName, Object extension, Project project) { // Dynamic registering exp point for IDEA 7 ExtensionsArea area = project != null ? Extensions.getArea(project): Extensions.getRootArea(); if (area != null && area.hasExtensionPoint(extensionPointName)) { area.getExtensionPoint(extensionPointName).registerExtension(extension, LoadingOrder.ANY); } } public static String getQuickDoc(PsiElement psiElement) { OurUsage usage = psiElement.getUserData(ourUsageKey); if (usage == null) return null; StringBuilder result = new StringBuilder(); result.append (usage.fileUsage.getFileLocaton()).append("\n"); if (usage.context != null) result.append(usage.context); else result.append(usage.getText()); return result.toString(); } public static boolean isInSource(VirtualFile virtualFile, ProjectFileIndex fileIndex) { if (fileIndex.isInSourceContent(virtualFile)) { return !fileIndex.isInTestSourceContent(virtualFile) && fileIndex.getModuleForFile(virtualFile) != null; } else if (!EnvironmentFacade.isJavaIde()) { return fileIndex.getModuleForFile(virtualFile) != null; } return false; } class ProjectSettingsForm { private JPanel projectSettingsPanel; private JTable excludedFilesTable; private JButton removeFileButton; private JButton addFileButton; private TextFieldWithBrowseButton additionalIncludeDirectoriesTextField; private TextFieldWithBrowseButton additionalSystemIncludeDirectoriesTextField; private JComboBox activeConfiguration; private JComboBox projectFile; private TextFieldWithBrowseButton preprocessorDefines; private TextFieldWithBrowseButton autoIncludedHeaders; private JComboBox compilerSelector; private JCheckBox includeJavaIncludeDirs; private JPanel mySettingsContent; private List<String> excludedFileList = new ArrayList<String>(); ProjectSettingsForm() { compilerSelector.setModel(new DefaultComboBoxModel(CppSupportSettings.CompilerSelectOptions.values())); excludedFilesTable.setDefaultRenderer(String.class, new ValidatingFilePathCellRenderer()); addFileButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FileChooserDescriptor fileChooserDescriptor = new FileChooserDescriptor(true, false, false, false, false, false) { public boolean isFileSelectable(VirtualFile virtualFile) { return virtualFile.getFileType() == CPP_FILETYPE && !Communicator.isHeaderFile(virtualFile); } }; fileChooserDescriptor.setTitle("Choose File to Remove from Analysis Scope"); FileChooserDialog fileChooser = FileChooserFactory.getInstance().createFileChooser( fileChooserDescriptor, project, WindowManagerEx.getInstanceEx().suggestParentWindow(project) ); final VirtualFile[] virtualFiles = fileChooser.choose(null, project); if (virtualFiles != null && virtualFiles.length == 1) { excludedFileList.add(virtualFiles[0].getPresentableUrl().replace(File.separatorChar,'/')); final int atEnd = excludedFileList.size() - 1; ((AbstractTableModel)excludedFilesTable.getModel()).fireTableRowsInserted(atEnd, atEnd); } } }); removeFileButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int selectedRow = excludedFilesTable.getSelectedRow(); if (selectedRow == -1) return; excludedFileList.remove(selectedRow); ((AbstractTableModel)excludedFilesTable.getModel()).fireTableRowsDeleted(selectedRow,selectedRow); } }); setupEditIncludeDirectories("Edit Additional System Include Pathes",additionalSystemIncludeDirectoriesTextField); setupEditIncludeDirectories("Edit Additional User Include Pathes", additionalIncludeDirectoriesTextField); setupEditIncludeFiles("Edit Automatically Included Header Files", autoIncludedHeaders); setupEditPredefinesList("Edit Predefines", preprocessorDefines); mySettingsContent.setLayout(new BorderLayout()); mySettingsContent.add(myHighlightingSettings.createComponent(), BorderLayout.CENTER); } public void apply() { myIgnoredFiles.clear(); myIgnoredFiles.addAll(excludedFileList); myAdditionalIncludeDirs = additionalIncludeDirectoriesTextField.getText(); myAdditionalSystemIncludeDirs = additionalSystemIncludeDirectoriesTextField.getText(); myAutomaticallyIncludedHeaderFiles = autoIncludedHeaders.getText(); myCompilerOptions = CppSupportSettings.CompilerSelectOptions.valueOf(compilerSelector.getSelectedItem().toString()); myHighlightingSettings.apply(); myIncludeJavaIncludes = includeJavaIncludeDirs.isSelected(); myActiveConfiguration = (String) activeConfiguration.getSelectedItem(); myProjectFile = (String) projectFile.getSelectedItem(); myAdditionalPreprocessorDefines = preprocessorDefines.getText(); SwingUtilities.invokeLater(new Runnable() { public void run() { Communicator.getInstance(project).restartServer(); } }); } public boolean isModified() { return !excludedFileList.containsAll(myIgnoredFiles) || !myIgnoredFiles.containsAll(excludedFileList) || !myAdditionalIncludeDirs.equals(additionalIncludeDirectoriesTextField.getText()) || !myAutomaticallyIncludedHeaderFiles.equals(autoIncludedHeaders.getText()) || !myAdditionalSystemIncludeDirs.equals(additionalSystemIncludeDirectoriesTextField.getText()) || myHighlightingSettings.isModified() || !myCompilerOptions.equals(compilerSelector.getSelectedItem()) || ( myActiveConfiguration == null && activeConfiguration.getSelectedItem() != null) || ( myActiveConfiguration != null && !myActiveConfiguration.equals(activeConfiguration.getSelectedItem())) || (myProjectFile != null && !myProjectFile.equals(projectFile.getSelectedItem())) || (myProjectFile == null && projectFile.getSelectedItem() != null) || myIncludeJavaIncludes != includeJavaIncludeDirs.isSelected() || (myAdditionalPreprocessorDefines != null && !myAdditionalPreprocessorDefines.equals(preprocessorDefines.getText())) || (myAdditionalPreprocessorDefines == null && preprocessorDefines.getText().length() > 0) ; } public void init() { excludedFileList.clear(); excludedFileList.addAll(myIgnoredFiles); compilerSelector.setSelectedItem(myCompilerOptions); excludedFilesTable.setModel(new AbstractTableModel() { public int getRowCount() { return excludedFileList.size(); } public int getColumnCount() { return 1; } public Object getValueAt(int rowIndex, int columnIndex) { return excludedFileList.get(rowIndex); } public String getColumnName(int column) { return "File Name"; } public Class<?> getColumnClass(int columnIndex) { return String.class; } public void setValueAt(Object aValue, int rowIndex, int columnIndex) { excludedFileList.set(rowIndex, (String) aValue); } }); additionalIncludeDirectoriesTextField.setText(myAdditionalIncludeDirs); additionalSystemIncludeDirectoriesTextField.setText(myAdditionalSystemIncludeDirs); myHighlightingSettings.init(); final Object[] objects = new Object[]{BaseBuildHandler.DEBUG_CONFIGURATION_NAME, BaseBuildHandler.RELEASE_CONFIGURATION_NAME}; activeConfiguration.setModel(new DefaultComboBoxModel(objects)); activeConfiguration.setSelectedItem(myActiveConfiguration); LinkedHashSet<String> set = buildProjectAndBuildFilesSet(); projectFile.setModel(new DefaultComboBoxModel(set.toArray())); projectFile.setSelectedItem(myProjectFile); preprocessorDefines.setText(myAdditionalPreprocessorDefines != null ? myAdditionalPreprocessorDefines:""); autoIncludedHeaders.setText(myAutomaticallyIncludedHeaderFiles); includeJavaIncludeDirs.setSelected(myIncludeJavaIncludes); } public JPanel getProjectSettingsPanel() { return projectSettingsPanel; } } static void setupEditIncludeDirectories(final String title, final TextFieldWithBrowseButton includeDirectoriesTextField) { createEditIncludeDialog(title, includeDirectoriesTextField, true); } static void setupEditIncludeFiles(final String title, final TextFieldWithBrowseButton includeDirectoriesTextField) { createEditIncludeDialog(title, includeDirectoriesTextField, false); } private static void createEditIncludeDialog(final String title, final TextFieldWithBrowseButton includeDirectoriesTextField, final boolean directories) { includeDirectoriesTextField.getButton().setToolTipText(title); includeDirectoriesTextField.getButton().addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final StringListEditor pathesComponent = directories ? new IncludePathesListEditor(title, includeDirectoriesTextField.getText()): new IncludeFilesListEditor(title, includeDirectoriesTextField.getText() ); pathesComponent.show(); if (pathesComponent.isOK()) includeDirectoriesTextField.setText(pathesComponent.getText()); } }); } static void setupEditPredefinesList(final String title, final TextFieldWithBrowseButton editPredefinesList) { editPredefinesList.getButton().setToolTipText(title); editPredefinesList.getButton().addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { StringListEditor pathesComponent = new MacrosListEditor(title, editPredefinesList.getText()); pathesComponent.show(); if (pathesComponent.isOK()) editPredefinesList.setText(pathesComponent.getText()); } }); } public CppHighlightingSettings getHighlightingSettings() { return myHighlightingSettings; } public String getActiveConfiguration() { return myActiveConfiguration; } public long getReportedProblemAboutServerProblemStamp() { return myReportedProblemAboutServerProblemStamp; } public void setReportedProblemAboutServerProblemStamp(long reportedProblemAboutServerProblemStamp) { this.myReportedProblemAboutServerProblemStamp = reportedProblemAboutServerProblemStamp; } public void setActiveConfiguration(String activeConfiguration) { myActiveConfiguration = activeConfiguration; } public String getLastBuildAction() { return myLastBuildAction; } public void setLastBuildAction(String lastBuildAction) { myLastBuildAction = lastBuildAction; } public String getAdditionalCommandLineBuildParameters() { return myAdditionalCommandLineBuildParameters; } public void setAdditionalCommandLineBuildParameters(String additionalBuildOptions) { myAdditionalCommandLineBuildParameters = additionalBuildOptions; } public static CppSymbolContributor getConstantContributor() { return myConstantContributor; } public static CppSymbolContributor getMacrosContributor() { return myMacrosContributor; } public String getAdditionalCompileParameters() { return myAdditionalCompileParameters; } public boolean isIncludeProjectSettings() { return myIncludeProjectSettings; } public void setAdditionalCompileParameters(String additionalCompileParameters) { myAdditionalCompileParameters = additionalCompileParameters; } public void setIncludeProjectSettings(boolean includeProjectSettings) { myIncludeProjectSettings = includeProjectSettings; } public String getAdditionalPreprocessorDefines() { return myAdditionalPreprocessorDefines; } public String getProjectFile() { return myProjectFile; } public void setProjectFile(String _projectFile) { myProjectFile = _projectFile; } public LinkedHashSet<String> buildProjectAndBuildFilesSet() { LinkedHashSet<String> set = new LinkedHashSet<String>(); for(VirtualFile file:getProjectAndBuildFilesSet()) { set.add(file.getPath()); } return set; } public int getSettingsVersion() { return mySettingsVersion; } private CppSupportSettings.CompilerSelectOptions myCompilerOptions = CppSupportSettings.CompilerSelectOptions.AUTO; private static final @NonNls String COMPILER_SELECT_KEY = "compilerSelect"; public CppSupportSettings.CompilerSelectOptions getCompilerOptions() { return myCompilerOptions; } public void setCompilerOptions(CppSupportSettings.CompilerSelectOptions compilerOptions) { this.myCompilerOptions = compilerOptions; } public String getAutomaticallyIncludedHeaderFiles() { return myAutomaticallyIncludedHeaderFiles; } private class MyDocumentListener implements DocumentListener { private Field autoPopupControllerAlarmField; { try { final Field[] declaredFields = AutoPopupController.class.getDeclaredFields(); autoPopupControllerAlarmField = declaredFields[1]; autoPopupControllerAlarmField.setAccessible(true); } catch (Exception e) { e.printStackTrace(); } } public void beforeDocumentChange(DocumentEvent event) { } public void documentChanged(DocumentEvent event) { if (this != myDocumentListener) return; // disposed final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(event.getDocument()); final VirtualFile virtualFile = psiFile.getVirtualFile(); final Communicator communicator = Communicator.getInstance(project); final long stamp = communicator.incModificationCount(); final CharSequence newFragment = event.getNewFragment(); final int insertedAt = event.getOffset(); communicator.sendCommand( new ChangedCommand( virtualFile.getPath(), newFragment.toString(), insertedAt, insertedAt + event.getOldLength(), stamp ) ); final int len = newFragment.length(); if (len > 0) { char aChar = newFragment.charAt(len - 1); final Editor selectedEditor = FileEditorManager.getInstance(project).getSelectedTextEditor(); final Document document = selectedEditor.getDocument(); if (selectedEditor != null && document == event.getDocument()) { final CharSequence oldFragment = event.getOldFragment(); if ((aChar == '.' && !"->".equals(oldFragment.toString())) || (aChar == ':' && previousChar(selectedEditor) == ':') || ((aChar == '>' && previousChar(selectedEditor) == '-') && !".".equals(oldFragment.toString())) ) { CodeInsightSettings settings = CodeInsightSettings.getInstance(); final int lookupDelay = settings.AUTO_POPUP_COMPLETION_LOOKUP ? 0 : -1; if (lookupDelay >= 0) { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { try { ((Alarm)autoPopupControllerAlarmField.get(AutoPopupController.getInstance(project))).addRequest( new Runnable() { public void run() { PsiDocumentManager.getInstance(project).commitAllDocuments(); new CodeCompletionHandlerBase(CompletionType.BASIC).invokeCompletion(project, selectedEditor); } }, lookupDelay ); } catch (IllegalAccessException e) { e.printStackTrace(); } } }); } final AutoPopupController inst = AutoPopupController.getInstance(project); final Class[] paramClasses; final Object[] params; final int selena7_0_4_builds_start = 7800; int buildNumber = selena7_0_4_builds_start; try { buildNumber = Integer.parseInt(ApplicationInfo.getInstance().getBuildNumber()); } catch (NumberFormatException ex) {} if (buildNumber >= selena7_0_4_builds_start) { paramClasses = new Class[] { Editor.class, Condition.class }; params = new Object[] { selectedEditor, null }; } else { paramClasses = new Class[] { Editor.class }; params = new Object[] { selectedEditor }; } try { inst.getClass().getMethod("autoPopupMemberLookup", paramClasses).invoke(inst, params); } catch (Exception ex) { ex.printStackTrace(); } } else if (aChar == '}' && newFragment.length() == 2 && newFragment.charAt(0) == '\n' && oldFragment.length() == 0) { int i = insertedAt - 1; final CharSequence charsSequence = document.getCharsSequence(); i = CharArrayUtil.shiftBackwardUntil(charsSequence, i, "\n"); if (i >= 0) { int j = CharArrayUtil.shiftForward(charsSequence, i +1, " \t"); final String indent = charsSequence.subSequence(i + 1, j).toString(); if (indent.length() > 0) { SwingUtilities.invokeLater(new Runnable() { public void run() { CommandProcessor.getInstance().executeCommand( project, new Runnable() { public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { // document.insertString(insertedAt, " "); int lbracePos = CharArrayUtil.shiftForwardUntil(charsSequence, insertedAt, "}"); if (lbracePos != -1) document.insertString(lbracePos, indent); } }); } }, "Indent brace", this ); } }); } } } } } } private char previousChar(Editor editor) { final CharSequence charsSequence = editor.getDocument().getCharsSequence(); int offset = editor.getCaretModel().getOffset(); if (offset > 0) return charsSequence.charAt(offset - 1); return 0; } } }