Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2014-08-26 11:06:33 +02:00
41 changed files with 634 additions and 463 deletions
@@ -56,7 +56,7 @@ public class ShowStructureSettingsAction extends AnAction implements DumbAware {
protected JComponent createSouthPanel() {
JComponent panel = super.createSouthPanel();
assert panel != null;
CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153, Gray._80), 1, 0, 0, 0);
CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153.withAlpha(128), Gray._100.withAlpha(128)), 1, 0, 0, 0);
panel.setBorder(new CompoundBorder(line, new EmptyBorder(10, 5, 5, 5)));
return panel;
}
@@ -130,7 +130,8 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen
public boolean isAccepted(@NotNull VirtualFile rootCandidate, @NotNull ProgressIndicator progressIndicator) {
if (rootCandidate.isDirectory()) {
for (VirtualFile file : rootCandidate.getChildren()) {
if (NATIVE_LIBRARY_EXTENSIONS.contains(file.getExtension())) {
String extension = file.getExtension();
if (extension != null && NATIVE_LIBRARY_EXTENSIONS.contains(extension)) {
return true;
}
}
@@ -1300,7 +1300,7 @@ class Foo {{
type '.'
assert myFixture.lookupElementStrings == ['Util.bar', 'Util.CONSTANT', 'Util.foo']
def p = LookupElementPresentation.renderElement(myFixture.lookupElements[1])
def p = ApplicationManager.application.runReadAction ({ LookupElementPresentation.renderElement(myFixture.lookupElements[1]) } as Computable)
assert p.itemText == 'Util.CONSTANT'
assert p.tailText == ' (foo)'
assert p.typeText == 'int'
@@ -23,7 +23,13 @@ import java.util.EventListener;
* @see {@link com.intellij.openapi.editor.EditorFactory#addEditorFactoryListener(com.intellij.openapi.editor.event.EditorFactoryListener, com.intellij.openapi.Disposable)}
*/
public interface EditorFactoryListener extends EventListener {
/**
* Called after {@link com.intellij.openapi.editor.Editor} instance has been created.
*/
void editorCreated(@NotNull EditorFactoryEvent event);
/**
* Called before {@link com.intellij.openapi.editor.Editor} instance will be released.
*/
void editorReleased(@NotNull EditorFactoryEvent event);
}
@@ -856,6 +856,17 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
}
}
}
if (targetElement == null) {
for (Language language : Language.getRegisteredLanguages()) {
DocumentationProvider documentationProvider = LanguageDocumentation.INSTANCE.forLanguage(language);
if (documentationProvider != null) {
targetElement = documentationProvider.getDocumentationElementForLink(manager, refText, psiElement);
if (targetElement != null) {
break;
}
}
}
}
if (targetElement != null) {
fetchDocInfo(getDefaultCollector(targetElement, null), component);
}
@@ -22,7 +22,6 @@ import com.intellij.lang.parameterInfo.ParameterInfoUIContextEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
@@ -296,47 +295,50 @@ public class ParameterInfoComponent extends JPanel {
public String setup(final String[] texts, final EnumSet<ParameterInfoUIContextEx.Flag>[] flags, final Color background) {
StringBuilder buf = new StringBuilder();
removeAll();
final String[] lines = UIUtil.splitText(StringUtil.join(texts), getFontMetrics(BOLD_FONT), myWidthLimit, ',');
setBackground(background);
int index = 0;
int curOffset = 0;
myOneLineComponents = new OneLineComponent[lines.length];
final ArrayList<OneLineComponent> components = new ArrayList<OneLineComponent>();
Map<TextRange, ParameterInfoUIContextEx.Flag> flagsMap = new TreeMap<TextRange, ParameterInfoUIContextEx.Flag>(TEXT_RANGE_COMPARATOR);
int added = 0;
String line = "";
for (int i = 0; i < texts.length; i++) {
String line = escapeString(texts[i]);
if (lines.length <= index) break;
String text = lines[index];
final int paramCount = StringUtil.split(text, ", ").size();
String paramText = escapeString(texts[i]);
if (paramText == null) break;
line += texts[i];
final EnumSet<ParameterInfoUIContextEx.Flag> flag = flags[i];
if (flag.contains(ParameterInfoUIContextEx.Flag.HIGHLIGHT)) {
flagsMap.put(TextRange.create(curOffset, curOffset + line.trim().length()), ParameterInfoUIContextEx.Flag.HIGHLIGHT);
flagsMap.put(TextRange.create(curOffset, curOffset + paramText.trim().length()), ParameterInfoUIContextEx.Flag.HIGHLIGHT);
}
if (flag.contains(ParameterInfoUIContextEx.Flag.DISABLE)) {
flagsMap.put(TextRange.create(curOffset, curOffset + line.trim().length()), ParameterInfoUIContextEx.Flag.DISABLE);
flagsMap.put(TextRange.create(curOffset, curOffset + paramText.trim().length()), ParameterInfoUIContextEx.Flag.DISABLE);
}
if (flag.contains(ParameterInfoUIContextEx.Flag.STRIKEOUT)) {
flagsMap.put(TextRange.create(curOffset, curOffset + line.trim().length()), ParameterInfoUIContextEx.Flag.STRIKEOUT);
flagsMap.put(TextRange.create(curOffset, curOffset + paramText.trim().length()), ParameterInfoUIContextEx.Flag.STRIKEOUT);
}
curOffset += line.length();
if (i == paramCount + added - 1) {
myOneLineComponents[index] = new OneLineComponent();
setBackground(background);
buf.append(myOneLineComponents[index].setup(escapeString(text), flagsMap, background));
add(myOneLineComponents[index], new GridBagConstraints(0, index, 1, 1, 1, 0, GridBagConstraints.WEST,
curOffset += paramText.length();
if (line.length() >= 50) {
final OneLineComponent component = new OneLineComponent();
buf.append(component.setup(escapeString(line), flagsMap, background));
add(component, new GridBagConstraints(0, index, 1, 1, 1, 0, GridBagConstraints.WEST,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
index += 1;
flagsMap.clear();
curOffset = 1;
added += paramCount;
line = "";
components.add(component);
}
}
final OneLineComponent component = new OneLineComponent();
buf.append(component.setup(escapeString(line), flagsMap, background));
add(component, new GridBagConstraints(0, index, 1, 1, 1, 0, GridBagConstraints.WEST,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
components.add(component);
myOneLineComponents = components.toArray(new OneLineComponent[components.size()]);
return buf.toString();
}
}
@@ -203,14 +203,17 @@ public class EditorFactoryImpl extends EditorFactory implements ApplicationCompo
@Override
public void releaseEditor(@NotNull Editor editor) {
try {
((EditorImpl)editor).release();
myEditorFactoryEventDispatcher.getMulticaster().editorReleased(new EditorFactoryEvent(this, editor));
}
finally {
myEditors.remove(editor);
myEditorFactoryEventDispatcher.getMulticaster().editorReleased(new EditorFactoryEvent(this, editor));
if (LOG.isDebugEnabled()) {
LOG.debug("number of Editor's:" + myEditors.size());
try {
((EditorImpl)editor).release();
}
finally {
myEditors.remove(editor);
if (LOG.isDebugEnabled()) {
LOG.debug("number of Editor's:" + myEditors.size());
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,10 @@
package com.intellij.openapi.options.ex;
import com.intellij.ide.ui.search.SearchUtil;
import com.intellij.openapi.ui.GraphicsConfig;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
@@ -27,6 +30,7 @@ import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.Kernel;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -64,17 +68,19 @@ public class GlassPanel extends JComponent {
final Point leftPoint = SwingUtilities.convertPoint(myPanel, new Point(visibleRect.x, visibleRect.y), surfaceComponent);
Area innerPanel = new Area(new Rectangle2D.Double(leftPoint.x, leftPoint.y, visibleRect.width, visibleRect.height));
Area mask = new Area(screen);
ArrayList<JComponent> components = new ArrayList<JComponent>();
for (JComponent lightComponent : myLightComponents) {
final Area area = getComponentArea(surfaceComponent, lightComponent);
final Area area = getComponentArea(surfaceComponent, lightComponent, 1);
if (area == null) continue;
components.add(lightComponent);
if (lightComponent instanceof JLabel) {
final JLabel label = (JLabel)lightComponent;
final Component labelFor = label.getLabelFor();
if (labelFor instanceof JComponent) {
final Area labelForArea = getComponentArea(surfaceComponent, (JComponent)labelFor);
final Area labelForArea = getComponentArea(surfaceComponent, (JComponent)labelFor, 1);
if (labelForArea != null) {
components.add((JComponent)labelFor);
area.add(labelForArea);
}
}
@@ -86,19 +92,32 @@ public class GlassPanel extends JComponent {
Graphics2D g2 = (Graphics2D)g;
Color shieldColor = new Color(0.0f, 0.0f, 0.0f, 0.15f);
Color shieldColor = new Color(0.0f, 0.0f, 0.0f, 0.20f);
Color boundsColor = Color.gray;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(shieldColor);
g2.fill(mask);
g2.setColor(boundsColor);
g2.draw(mask);
g2.setColor(ColorUtil.toAlpha(Color.orange, 25));
GraphicsConfig config = GraphicsUtil.setupAAPainting(g2);
for (int i = 2; i > 0; i--) {
g2.setStroke(new BasicStroke(i));
Area arrr = new Area();
for (JComponent component : components) {
Area area = getComponentArea(surfaceComponent, component, i-1);
if (area != null) {
arrr.add(area);
}
}
g2.draw(arrr);
}
config.restore();
}
}
@Nullable
private Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent) {
private Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent, int offset) {
if (!lightComponent.isShowing()) return null;
final Point panelPoint = SwingUtilities.convertPoint(lightComponent, new Point(0, 0), surfaceComponent);
@@ -115,12 +134,17 @@ public class GlassPanel extends JComponent {
int hInset = isWithBorder ? 7 : isLabelFromTabbedPane ? 20 : 7;
int vInset = isWithBorder ? 1 : isLabelFromTabbedPane ? 10 : 5;
final Area area = new Area(new RoundRectangle2D.Double(x - hInset + insetsToIgnore.left,
y - vInset + insetsToIgnore.top,
lightComponent.getWidth() + hInset * 2 - insetsToIgnore.right - insetsToIgnore.left,
lightComponent.getHeight() + vInset * 2 - insetsToIgnore.top - insetsToIgnore.bottom,
6, 6));
return area;
hInset += offset;
vInset += offset;
int xCoord = x - hInset + insetsToIgnore.left;
int yCoord = y - vInset + insetsToIgnore.top;
int width = lightComponent.getWidth() + hInset * 2 - insetsToIgnore.right - insetsToIgnore.left;
int height = lightComponent.getHeight() + vInset * 2 - insetsToIgnore.top - insetsToIgnore.bottom;
return new Area(new RoundRectangle2D.Double(xCoord,
yCoord,
width,
height,
Math.min(height, 30), Math.min(height, 30)));
}
protected static Kernel getBlurKernel(int blurSize) {
@@ -128,7 +128,7 @@ public class IdeSettingsDialog extends DialogWrapper implements DataProvider {
@Override
protected JComponent createSouthPanel() {
final JComponent panel = super.createSouthPanel();
CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153, Gray._80), 1, 0, 0, 0);
CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153.withAlpha(128), Gray._100.withAlpha(128)), 1, 0, 0, 0);
panel.setBorder(new CompoundBorder(line, new EmptyBorder(8, 12, 8, 12)));
return panel;
}
@@ -1201,7 +1201,8 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
* @return default view for the specified configurable
*/
private JComponent createDefaultComponent(SearchableConfigurable searchable) {
Box box = Box.createVerticalBox();
JPanel box = new JPanel();
box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
try {
box.add(new JLabel(OptionsBundle.message(searchable.getId() + ".settings.description")));
}
@@ -37,6 +37,7 @@ import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.util.ui.tree.WideSelectionTreeUI;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.NotNull;
@@ -49,12 +50,14 @@ import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.TreeUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
@@ -403,6 +406,9 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
} else {
myProjectIcon.setVisible(false);
}
if (Registry.is("ide.new.settings.dialog")) {
result.setBackground(selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getSidePanelColor());
}
return result;
}
@@ -727,7 +733,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
super.processMouseEvent(e);
}
private class MyTreeUi extends BasicTreeUI {
private class MyTreeUi extends WideSelectionTreeUI {
@Override
public void toggleExpandState(final TreePath path) {
@@ -82,6 +82,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
myFilter = filter;
myRoot = new MyRoot(groups);
myTree = new MyTree();
myTree.putClientProperty(WideSelectionTreeUI.TREE_TABLE_TREE_KEY, Boolean.TRUE);
myTree.setBackground(UIUtil.getSidePanelColor());
myTree.getInputMap().clear();
TreeUtil.installActions(myTree);
@@ -15,7 +15,6 @@
*/
package com.intellij.testFramework;
import com.intellij.openapi.util.text.StringUtil;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
@@ -45,10 +44,15 @@ public class LoggedErrorProcessor {
public void processError(String message, Throwable t, String[] details, @NotNull Logger logger) {
logger.info(message, t);
System.err.println("ERROR: " + message);
if (t != null) t.printStackTrace(System.err);
if (details != null && details.length > 0) {
message += "\n Details:" + StringUtil.join(details, "\n ");
System.out.println("details: ");
for (String detail : details) {
System.out.println(detail);
}
}
throw new RuntimeException(message, t);
throw new AssertionError(message);
}
}
@@ -45,7 +45,7 @@ public class Conditions {
public static <T> Condition<T> is(final T option) {
return new Condition<T>() {
public boolean value(T t) {
return t == option;
return Comparing.equal(t, option);
}
};
}
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable;
public class StudyNewProject extends ProjectSpecificAction {
public StudyNewProject(@NotNull final String name, @Nullable final Runnable runnable) {
super(new GenerateProjectCallback(runnable), new StudyDirectoryProjectGenerator(), name);
super(new GenerateProjectCallback(runnable), new StudyDirectoryProjectGenerator(), name, true);
}
public StudyNewProject() {
+48
View File
@@ -1,4 +1,5 @@
import sys
import re
from docutils.core import publish_string
from docutils import nodes
from docutils.nodes import Text
@@ -54,6 +55,53 @@ class RestHTMLTranslator(_EpydocHTMLTranslator):
self.body.append("</a>")
HTMLTranslator.depart_field_body(self, node)
def visit_reference(self, node):
atts = {}
if 'refuri' in node:
atts['href'] = node['refuri']
if self.settings.cloak_email_addresses and atts['href'].startswith('mailto:'):
atts['href'] = self.cloak_mailto(atts['href'])
self.in_mailto = True
# atts['class'] += ' external'
else:
assert 'refid' in node, 'References must have "refuri" or "refid" attribute.'
atts['href'] = '#' + node['refid']
atts['class'] += ' internal'
if not isinstance(node.parent, nodes.TextElement):
assert len(node) == 1 and isinstance(node[0], nodes.image)
atts['class'] += ' image-reference'
self.body.append(self.starttag(node, 'a', '', **atts))
def starttag(self, node, tagname, suffix='\n', **attributes):
attr_dicts = [attributes]
if isinstance(node, nodes.Node):
attr_dicts.append(node.attributes)
if isinstance(node, dict):
attr_dicts.append(node)
# Munge each attribute dictionary. Unfortunately, we need to
# iterate through attributes one at a time because some
# versions of docutils don't case-normalize attributes.
for attr_dict in attr_dicts:
for (key, val) in attr_dict.items():
# Prefix all CSS classes with "rst-"; and prefix all
# names with "rst-" to avoid conflicts.
if key.lower() in ('class', 'id', 'name'):
attr_dict[key] = 'rst-%s' % val
elif key.lower() in ('classes', 'ids', 'names'):
attr_dict[key] = ['rst-%s' % cls for cls in val]
elif key.lower() == 'href':
if attr_dict[key][:1]=='#':
attr_dict[key] = '#rst-%s' % attr_dict[key][1:]
else:
pass
# For headings, use class="heading"
if re.match(r'^h\d+$', tagname):
attributes['class'] = ' '.join([attributes.get('class',''),
'heading']).strip()
return HTMLTranslator.starttag(self, node, tagname, suffix,
**attributes)
def visit_field_list(self, node):
fields = {}
@@ -1,60 +1,29 @@
package com.jetbrains.python.configuration;
import com.intellij.facet.impl.DefaultFacetsProvider;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.impl.ModuleConfigurationStateImpl;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ContentFolder;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.impl.ContentEntryImpl;
import com.intellij.openapi.roots.impl.ContentFolderBaseImpl;
import com.intellij.openapi.roots.ui.configuration.*;
import com.intellij.openapi.roots.ui.configuration.actions.ContentEntryEditingAction;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider;
import com.intellij.openapi.roots.ui.configuration.FacetsProvider;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.ui.JBColor;
import com.intellij.util.EventDispatcher;
import com.intellij.util.containers.MultiMap;
import com.jetbrains.python.templateLanguages.TemplatesService;
import icons.PythonIcons;
import com.jetbrains.python.module.PyContentEntriesEditor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
public class PyContentEntriesModuleConfigurable extends SearchableConfigurable.Parent.Abstract {
private static final Color TEMPLATES_COLOR = JBColor.MAGENTA;
private final Module myModule;
private final JPanel myTopPanel = new JPanel(new BorderLayout());
protected ModifiableRootModel myModifiableModel;
protected MyCommonContentEntriesEditor myEditor;
protected PyContentEntriesEditor myEditor;
public PyContentEntriesModuleConfigurable(final Module module) {
myModule = module;
@@ -108,8 +77,8 @@ public class PyContentEntriesModuleConfigurable extends SearchableConfigurable.P
myTopPanel.add(component, BorderLayout.CENTER);
}
protected MyCommonContentEntriesEditor createEditor(@NotNull Module module, @NotNull ModuleConfigurationStateImpl state) {
return new MyCommonContentEntriesEditor(module, state, JavaSourceRootType.SOURCE);
protected PyContentEntriesEditor createEditor(@NotNull Module module, @NotNull ModuleConfigurationStateImpl state) {
return new PyContentEntriesEditor(module, state, JavaSourceRootType.SOURCE);
}
@Override
@@ -171,314 +140,4 @@ public class PyContentEntriesModuleConfigurable extends SearchableConfigurable.P
return "python.project.structure";
}
private static class MyContentEntryTreeEditor extends ContentEntryTreeEditor {
private final ChangeListener myListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
update();
}
};
public MyContentEntryTreeEditor(Project project, List<ModuleSourceRootEditHandler<?>> handlers) {
super(project, handlers);
}
@Override
public void setContentEntryEditor(ContentEntryEditor newEditor) {
MyCommonContentEntriesEditor.MyContentEntryEditor existingEditor = getContentEntryEditor();
if (Comparing.equal(existingEditor, newEditor)) {
return;
}
if (existingEditor != null) {
existingEditor.removeListener(myListener);
}
if (newEditor != null) {
((MyCommonContentEntriesEditor.MyContentEntryEditor)newEditor).addListener(myListener);
}
super.setContentEntryEditor(newEditor);
}
@Override
public MyCommonContentEntriesEditor.MyContentEntryEditor getContentEntryEditor() {
return (MyCommonContentEntriesEditor.MyContentEntryEditor)super.getContentEntryEditor();
}
@Override
protected void createEditingActions() {
super.createEditingActions();
ContentEntryEditingAction a = new ContentEntryEditingAction(myTree) {
{
final Presentation templatePresentation = getTemplatePresentation();
templatePresentation.setText("Templates");
templatePresentation.setDescription("Template Folders");
templatePresentation.setIcon(PythonIcons.Python.TemplateRoot);
}
@Override
public boolean isSelected(AnActionEvent e) {
final VirtualFile[] selectedFiles = getSelectedFiles();
return selectedFiles.length != 0 && getContentEntryEditor().hasTemplateRoot(selectedFiles[0]);
}
@Override
public void setSelected(AnActionEvent e, boolean isSelected) {
final VirtualFile[] selectedFiles = getSelectedFiles();
assert selectedFiles.length != 0;
for (VirtualFile selectedFile : selectedFiles) {
boolean wasSelected = getContentEntryEditor().hasTemplateRoot(selectedFile);
if (isSelected) {
if (!wasSelected) {
getContentEntryEditor().addTemplateRoot(selectedFile);
}
}
else {
if (wasSelected) {
getContentEntryEditor().removeTemplateRoot(selectedFile);
}
}
}
}
};
myEditingActionsGroup.add(a);
a.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK)), myTree);
}
@Override
protected TreeCellRenderer getContentEntryCellRenderer() {
return new ContentEntryTreeCellRenderer(this, getEditHandlers()) {
@Override
protected Icon updateIcon(final ContentEntry entry, final VirtualFile file, final Icon originalIcon) {
if (getContentEntryEditor().hasTemplateRoot(file)) {
return PythonIcons.Python.TemplateRoot;
}
return super.updateIcon(entry, file, originalIcon);
}
};
}
}
protected static class MyCommonContentEntriesEditor extends CommonContentEntriesEditor {
private final MultiMap<ContentEntry, VirtualFilePointer> myTemplateRoots = new MultiMap<ContentEntry, VirtualFilePointer>();
private final Module myModule;
private Disposable myFilePointersDisposable;
private final VirtualFilePointerListener DUMMY_LISTENER = new VirtualFilePointerListener() {
@Override
public void beforeValidityChanged(@NotNull VirtualFilePointer[] pointers) {
}
@Override
public void validityChanged(@NotNull VirtualFilePointer[] pointers) {
}
};
public MyCommonContentEntriesEditor(Module module,
ModuleConfigurationStateImpl moduleConfigurationState,
JpsModuleSourceRootType<?>... rootTypes) {
super(module.getName(), moduleConfigurationState, rootTypes);
myModule = module;
reset();
}
@Override
protected ContentEntryTreeEditor createContentEntryTreeEditor(Project project) {
return new MyContentEntryTreeEditor(project, getEditHandlers());
}
@Override
protected List<ContentEntry> addContentEntries(VirtualFile[] files) {
List<ContentEntry> entries = super.addContentEntries(files);
addContentEntryPanels(entries.toArray(new ContentEntry[entries.size()]));
return entries;
}
@Override
public void reset() {
if (myFilePointersDisposable != null) {
Disposer.dispose(myFilePointersDisposable);
}
myTemplateRoots.clear();
myFilePointersDisposable = Disposer.newDisposable();
final TemplatesService instance = TemplatesService.getInstance(myModule);
if (instance != null) {
final List<VirtualFile> folders = instance.getTemplateFolders();
for (VirtualFile folder : folders) {
ContentEntry contentEntry = findContentEntryForFile(folder);
if (contentEntry != null) {
myTemplateRoots.putValue(contentEntry, VirtualFilePointerManager.getInstance().create(folder, myFilePointersDisposable,
DUMMY_LISTENER));
}
}
}
if (myRootTreeEditor != null) {
ContentEntryEditor editor = myRootTreeEditor.getContentEntryEditor();
if(editor!=null) editor.update();
myRootTreeEditor.update();
}
}
@Nullable
private ContentEntry findContentEntryForFile(VirtualFile virtualFile) {
for (ContentEntry contentEntry : getModel().getContentEntries()) {
final VirtualFile file = contentEntry.getFile();
if (file != null && VfsUtilCore.isAncestor(file, virtualFile, false)) {
return contentEntry;
}
}
return null;
}
@Override
public void disposeUIResources() {
super.disposeUIResources();
if (myFilePointersDisposable != null) {
Disposer.dispose(myFilePointersDisposable);
}
}
@Override
public void apply() throws ConfigurationException {
super.apply();
List<VirtualFile> templateRoots = getCurrentState();
TemplatesService.getInstance(myModule).setTemplateFolders(templateRoots.toArray(new VirtualFile[templateRoots.size()]));
}
private List<VirtualFile> getCurrentState() {
List<VirtualFile> result = new ArrayList<VirtualFile>();
for (ContentEntry entry : myTemplateRoots.keySet()) {
for (VirtualFilePointer filePointer : myTemplateRoots.get(entry)) {
result.add(filePointer.getFile());
}
}
return result;
}
@Override
public boolean isModified() {
if (super.isModified()) return true;
final TemplatesService templatesService = TemplatesService.getInstance(myModule);
if (templatesService != null) {
List<VirtualFile> original = templatesService.getTemplateFolders();
List<VirtualFile> current = getCurrentState();
if (!Comparing.haveEqualElements(original, current)) return true;
}
return false;
}
@Override
protected MyContentEntryEditor createContentEntryEditor(String contentEntryUrl) {
return new MyContentEntryEditor(contentEntryUrl, getEditHandlers());
}
protected class MyContentEntryEditor extends ContentEntryEditor {
private final EventDispatcher<ChangeListener> myEventDispatcher = EventDispatcher.create(ChangeListener.class);
public MyContentEntryEditor(String contentEntryUrl, List<ModuleSourceRootEditHandler<?>> handlers) {
super(contentEntryUrl, handlers);
}
@Override
protected ModifiableRootModel getModel() {
return MyCommonContentEntriesEditor.this.getModel();
}
public void addListener(ChangeListener changeListener) {
myEventDispatcher.addListener(changeListener);
}
public void removeListener(ChangeListener changeListener) {
myEventDispatcher.removeListener(changeListener);
}
@Override
protected ContentRootPanel createContentRootPane() {
return new MyContentRootPanel();
}
@Override
public void deleteContentFolder(ContentEntry contentEntry, ContentFolder folder) {
if (folder instanceof TemplateRootFolder) {
final VirtualFile file = folder.getFile();
if (file != null) {
removeTemplateRoot(file);
}
}
else {
super.deleteContentFolder(contentEntry, folder);
}
}
public void addTemplateRoot(@NotNull final VirtualFile file) {
final VirtualFilePointer root = VirtualFilePointerManager.getInstance().create(file, myFilePointersDisposable, DUMMY_LISTENER);
myTemplateRoots.putValue(getContentEntry(), root);
myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this));
update();
}
public void removeTemplateRoot(@NotNull final VirtualFile file) {
final VirtualFilePointer root = getTemplateRoot(file);
if (root != null) {
myTemplateRoots.remove(getContentEntry(), root);
myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this));
update();
}
}
public boolean hasTemplateRoot(@NotNull final VirtualFile file) {
return getTemplateRoot(file) != null;
}
@Nullable
public VirtualFilePointer getTemplateRoot(@NotNull final VirtualFile file) {
for (VirtualFilePointer filePointer : myTemplateRoots.get(getContentEntry())) {
if (Comparing.equal(filePointer.getFile(), file)) {
return filePointer;
}
}
return null;
}
protected class MyContentRootPanel extends ContentRootPanel {
public MyContentRootPanel() {
super(MyContentEntryEditor.this, getEditHandlers());
}
@Override
@NotNull
protected ContentEntryImpl getContentEntry() {
//noinspection ConstantConditions
return (ContentEntryImpl)MyContentEntryEditor.this.getContentEntry();
}
@Override
protected void addFolderGroupComponents() {
super.addFolderGroupComponents();
if (!myTemplateRoots.get(getContentEntry()).isEmpty()) {
final List<TemplateRootFolder> folders = new ArrayList<TemplateRootFolder>(myTemplateRoots.size());
for (VirtualFilePointer root : myTemplateRoots.get(getContentEntry())) {
folders.add(new TemplateRootFolder(root, getContentEntry()));
}
final JComponent sourcesComponent = createFolderGroupComponent("Template Folders",
folders.toArray(new ContentFolder[folders.size()]),
TEMPLATES_COLOR, null);
this.add(sourcesComponent, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0));
}
}
}
}
}
private static class TemplateRootFolder extends ContentFolderBaseImpl {
protected TemplateRootFolder(@NotNull VirtualFilePointer filePointer, @NotNull ContentEntryImpl contentEntry) {
super(filePointer, contentEntry);
}
}
}
@@ -61,6 +61,7 @@ import java.util.List;
abstract public class AbstractProjectSettingsStep extends AbstractActionWithPanel implements DumbAware {
protected final DirectoryProjectGenerator myProjectGenerator;
private final NullableConsumer<AbstractProjectSettingsStep> myCallback;
private final boolean myIsWelcomeScreen;
private PythonSdkChooserCombo mySdkCombo;
private boolean myInstallFramework;
private TextFieldWithBrowseButton myLocationField;
@@ -70,10 +71,13 @@ abstract public class AbstractProjectSettingsStep extends AbstractActionWithPane
private AnAction myCreateAction;
private Sdk mySdk;
public AbstractProjectSettingsStep(DirectoryProjectGenerator projectGenerator, NullableConsumer<AbstractProjectSettingsStep> callback) {
public AbstractProjectSettingsStep(DirectoryProjectGenerator projectGenerator,
NullableConsumer<AbstractProjectSettingsStep> callback,
boolean isWelcomeScreen) {
super();
myProjectGenerator = projectGenerator;
myCallback = callback;
myIsWelcomeScreen = isWelcomeScreen;
myProjectDirectory = FileUtil.findSequentNonexistentFile(new File(ProjectUtil.getBaseDir()), "untitled", "");
if (myProjectGenerator instanceof WebProjectTemplate) {
((WebProjectTemplate)myProjectGenerator).getPeer().addSettingsStateListener(new WebProjectGenerator.SettingsStateListener() {
@@ -109,17 +113,12 @@ abstract public class AbstractProjectSettingsStep extends AbstractActionWithPane
@Override
public JPanel createPanel() {
final JPanel basePanel = createBasePanel();
final JPanel mainPanel = new JPanel(new BorderLayout()) {
@Override
protected void paintComponent(Graphics g) {
myLocationField.requestFocus();
}
};
final JPanel mainPanel = new JPanel(new BorderLayout());
final JPanel scrollPanel = new JPanel(new BorderLayout());
final DirectoryProjectGenerator[] generators = Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME);
final int height = generators.length == 0 ? 150 : 400;
final int height = generators.length == 0 && !myIsWelcomeScreen ? 150 : 400;
mainPanel.setPreferredSize(new Dimension(mainPanel.getPreferredSize().width, height));
myErrorLabel = new JLabel("");
myErrorLabel.setForeground(JBColor.RED);
@@ -27,11 +27,11 @@ import java.util.List;
public class PluginSpecificProjectsStep extends DefaultActionGroup implements DumbAware {
public PluginSpecificProjectsStep(@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback,
@NotNull final List<DirectoryProjectGenerator> projectGenerators) {
@NotNull final List<DirectoryProjectGenerator> projectGenerators, boolean isWelcomeScreen) {
super("Plugin-specific", true);
getTemplatePresentation().setIcon(AllIcons.Nodes.PluginLogo);
for (DirectoryProjectGenerator generator : projectGenerators) {
add(new ProjectSpecificAction(callback, generator));
add(new ProjectSpecificAction(callback, generator, isWelcomeScreen));
}
}
}
@@ -28,16 +28,16 @@ public class ProjectSpecificAction extends DefaultActionGroup implements DumbAwa
private final ProjectSpecificSettingsStep mySettings;
public ProjectSpecificAction(@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback,
@NotNull final DirectoryProjectGenerator projectGenerator) {
this(callback, projectGenerator, projectGenerator.getName());
@NotNull final DirectoryProjectGenerator projectGenerator, boolean isWelcomeScreen) {
this(callback, projectGenerator, projectGenerator.getName(), isWelcomeScreen);
}
public ProjectSpecificAction(@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback,
@NotNull final DirectoryProjectGenerator projectGenerator,
@NotNull final String name) {
@NotNull final String name, boolean isWelcomeScreen) {
super(name, true);
getTemplatePresentation().setIcon(projectGenerator.getLogo());
mySettings = new ProjectSpecificSettingsStep(projectGenerator, callback);
mySettings = new ProjectSpecificSettingsStep(projectGenerator, callback, isWelcomeScreen);
add(mySettings);
}
@@ -31,8 +31,8 @@ import javax.swing.*;
public class ProjectSpecificSettingsStep extends AbstractProjectSettingsStep implements DumbAware {
public ProjectSpecificSettingsStep(@NotNull final DirectoryProjectGenerator projectGenerator,
@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback) {
super(projectGenerator, callback);
@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback, boolean isWelcomeScreen) {
super(projectGenerator, callback, isWelcomeScreen);
}
@Override
@@ -34,11 +34,15 @@ import java.util.List;
public class PyCharmNewProjectStep extends DefaultActionGroup implements DumbAware {
public PyCharmNewProjectStep(@NotNull final String name, @Nullable final Runnable runnable) {
this(name, runnable, false);
}
public PyCharmNewProjectStep(@NotNull final String name, @Nullable final Runnable runnable, boolean isWelcomeScreen) {
super(name, true);
final NullableConsumer<AbstractProjectSettingsStep> callback = new GenerateProjectCallback(runnable);
final ProjectSpecificAction action = new ProjectSpecificAction(callback, new PythonBaseProjectGenerator());
final ProjectSpecificAction action = new ProjectSpecificAction(callback, new PythonBaseProjectGenerator(), isWelcomeScreen);
add(action);
final DirectoryProjectGenerator[] generators = Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME);
@@ -57,19 +61,17 @@ public class PyCharmNewProjectStep extends DefaultActionGroup implements DumbAwa
List<DirectoryProjectGenerator> pluginSpecificGenerators = Lists.newArrayList();
for (DirectoryProjectGenerator generator : generators) {
if (generator instanceof PythonProjectGenerator)
add(new ProjectSpecificAction(callback, generator));
add(new ProjectSpecificAction(callback, generator, isWelcomeScreen));
else
pluginSpecificGenerators.add(generator);
}
if (!pluginSpecificGenerators.isEmpty()) {
add(new PluginSpecificProjectsStep(callback, pluginSpecificGenerators));
add(new PluginSpecificProjectsStep(callback, pluginSpecificGenerators, isWelcomeScreen));
}
}
public PyCharmNewProjectStep() {
this("Select Project Type", null);
this("Select Project Type", null, true);
}
}
@@ -15,15 +15,16 @@
*/
package com.jetbrains.python.module;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleConfigurationEditor;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.roots.ui.configuration.DefaultModuleConfigurationEditorFactory;
import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationEditorProvider;
import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationState;
import com.intellij.openapi.roots.ui.configuration.DefaultModuleConfigurationEditorFactory;
import com.intellij.openapi.module.ModuleConfigurationEditor;
import com.intellij.openapi.module.Module;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import java.util.List;
import java.util.ArrayList;
import java.util.List;
/**
* @author yole
@@ -34,7 +35,7 @@ public class PythonModuleConfigurationEditorProvider implements ModuleConfigurat
if (!(ModuleType.get(module) instanceof PythonModuleType)) return ModuleConfigurationEditor.EMPTY;
final DefaultModuleConfigurationEditorFactory editorFactory = DefaultModuleConfigurationEditorFactory.getInstance();
final List<ModuleConfigurationEditor> editors = new ArrayList<ModuleConfigurationEditor>();
editors.add(editorFactory.createModuleContentRootsEditor(state));
editors.add(new PyContentEntriesEditor(module, state, JavaSourceRootType.SOURCE));
editors.add(editorFactory.createClasspathEditor(state));
return editors.toArray(new ModuleConfigurationEditor[editors.size()]);
}
@@ -1,4 +1,4 @@
/* The following code was generated by JFlex 1.4.3 on 4/26/14 12:40 PM */
/* The following code was generated by JFlex 1.4.3 on 8/25/14 1:56 PM */
package com.jetbrains.rest.lexer;
@@ -11,8 +11,8 @@ import com.jetbrains.rest.RestTokenTypes;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 4/26/14 12:40 PM from the specification file
* <tt>/Users/ignatov/src/ultimate/tools/lexer/../../community/python/rest/src/com/jetbrains/rest/lexer/rest.flex</tt>
* on 8/25/14 1:56 PM from the specification file
* <tt>/home/ktisha/IDEA/tools/lexer/../../community/python/rest/src/com/jetbrains/rest/lexer/rest.flex</tt>
*/
public class _RestFlexLexer implements FlexLexer, RestTokenTypes {
/** initial size of the lookahead buffer */
@@ -1293,7 +1293,7 @@ public class _RestFlexLexer implements FlexLexer, RestTokenTypes {
"\1\232\21\42\1\0\1\33\1\0\1\42\1\33\1\42"+
"\7\0\1\164\1\0\1\165\1\33\4\0\1\33\6\0"+
"\4\42\1\233\22\42\1\0\1\33\1\0\1\42\1\33"+
"\1\42\12\0\1\33\4\0\1\33\6\0\27\56\1\0"+
"\1\42\12\0\1\33\4\0\1\56\6\0\27\56\1\0"+
"\1\234\1\0\1\56\1\33\1\56\12\0\1\33\4\0"+
"\1\33\1\235\1\0\1\236\3\0\27\237\1\0\1\33"+
"\1\0\1\237\1\33\1\240\1\241\2\0\1\242\1\243"+
@@ -170,7 +170,7 @@ ANY= .|\n
{USUAL_TYPES}"::" { yybegin(IN_VALUE); return DIRECTIVE;}
{HIGHLIGHT_TYPES}"::" { yybegin(IN_HIGHLIGHT); return CUSTOM_DIRECTIVE;}
[0-9A-Za-z\-:]*"::" { yybegin(IN_VALUE); return CUSTOM_DIRECTIVE;}
"|"[0-9A-Za-z]*"|" { return SUBSTITUTION;}
"|"[0-9A-Za-z_]*"|" { return SUBSTITUTION;}
[0-9A-Za-z_\[|.]* { yybegin(IN_COMMENT); return COMMENT;}
{CRLF}{2} { yybegin(INIT); return COMMENT;}
{SPACE}*{CRLF}+ { return WHITESPACE; }
@@ -95,7 +95,7 @@ public class RestParser implements PsiParser {
listMarker.drop();
}
private void parseMarkup(PsiBuilder builder) {
private static void parseMarkup(PsiBuilder builder) {
PsiBuilder.Marker marker = builder.mark();
IElementType type = builder.getTokenType();
if (type == RestTokenTypes.SUBSTITUTION) {
@@ -131,19 +131,19 @@ public class RestParser implements PsiParser {
}
}
private void gotoNextWhiteSpaces(PsiBuilder builder) {
private static void gotoNextWhiteSpaces(PsiBuilder builder) {
while(!"\n".equals(builder.getTokenText()) && !(builder.getTokenType() == RestTokenTypes.TITLE) && !builder.eof() && (builder.getTokenType() != null)) {
builder.advanceLexer();
}
}
private void skipBlankLines(PsiBuilder builder) {
private static void skipBlankLines(PsiBuilder builder) {
while("\n".equals(builder.getTokenText()) && !builder.eof() && (builder.getTokenType() != null)) {
builder.advanceLexer();
}
}
private void parseDirective(PsiBuilder builder, String white, PsiBuilder.Marker marker) {
private static void parseDirective(PsiBuilder builder, String white, PsiBuilder.Marker marker) {
gotoNextWhiteSpaces(builder);
if (builder.getTokenType() != RestTokenTypes.WHITESPACE) {
builder.advanceLexer();
@@ -157,7 +157,6 @@ public class RestParser implements PsiParser {
}
else {
marker.done(RestElementTypes.DIRECTIVE_BLOCK);
return;
}
}
}
@@ -34,6 +34,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.Function;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
@@ -44,13 +45,16 @@ import com.jetbrains.python.debugger.PySignatureCacheManager;
import com.jetbrains.python.debugger.PySignatureUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyTypeParser;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.toolbox.ChainIterable;
import com.jetbrains.python.toolbox.FP;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -414,8 +418,10 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
return true;
}
HttpClient client = new HttpClient();
client.setTimeout(5 * 1000);
client.setConnectionTimeout(5 * 1000);
HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
params.setSoTimeout(5 * 1000);
params.setConnectionTimeout(5 * 1000);
try {
HeadMethod method = new HeadMethod(url);
int rc = client.executeMethod(method);
@@ -618,9 +624,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
if (checkReturn) {
RaiseVisitor visitor = new RaiseVisitor();
PyStatementList statementList = element.getStatementList();
if (statementList != null) {
statementList.accept(visitor);
}
statementList.accept(visitor);
if (visitor.myHasReturn) {
builder.append(prefix).append("return:").append(offset);
if (PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB) {
@@ -72,9 +72,6 @@ public class PyStatementEffectInspection extends PyInspection {
final PyTryPart tryPart = PsiTreeUtil.getParentOfType(node, PyTryPart.class);
if (tryPart != null) {
final PyStatementList statementList = tryPart.getStatementList();
if (statementList == null) {
return;
}
if (statementList.getStatements().length == 1 && statementList.getStatements()[0] == node) {
return;
}
@@ -18,14 +18,12 @@ package com.jetbrains.python.inspections.quickfix;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyReferenceExpression;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
/**
@@ -77,14 +75,23 @@ public class StatementEffectFunctionCallQuickFix implements LocalQuickFix {
RemoveUnnecessaryBackslashQuickFix.removeBackSlash(next);
if (whiteSpace != null) whiteSpace.delete();
String commentText = null;
if (next != null) {
final String text = next.getText();
final PsiElement lastChild = next.getLastChild();
if (lastChild instanceof PsiComment) {
commentText = lastChild.getText();
}
final String text = next instanceof PyExpressionStatement ? ((PyExpressionStatement)next).getExpression().getText() : next.getText();
stringBuilder.append(text);
if (text.endsWith(",") && PyNames.PRINT.equals(expressionText))
stringBuilder.append(" end=' '");
next.delete();
}
stringBuilder.append(")");
if (commentText != null) {
stringBuilder.append(commentText);
}
expression.replace(elementGenerator.createFromText(LanguageLevel.forElement(expression), PyExpression.class,
stringBuilder.toString()));
}
@@ -0,0 +1,367 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.module;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ContentFolder;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.impl.ContentEntryImpl;
import com.intellij.openapi.roots.impl.ContentFolderBaseImpl;
import com.intellij.openapi.roots.ui.configuration.*;
import com.intellij.openapi.roots.ui.configuration.actions.ContentEntryEditingAction;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.ui.JBColor;
import com.intellij.util.EventDispatcher;
import com.intellij.util.containers.MultiMap;
import com.jetbrains.python.templateLanguages.TemplatesService;
import icons.PythonIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
public class PyContentEntriesEditor extends CommonContentEntriesEditor {
private static final Color TEMPLATES_COLOR = JBColor.MAGENTA;
private final MultiMap<ContentEntry, VirtualFilePointer> myTemplateRoots = new MultiMap<ContentEntry, VirtualFilePointer>();
private final Module myModule;
private Disposable myFilePointersDisposable;
private final VirtualFilePointerListener DUMMY_LISTENER = new VirtualFilePointerListener() {
@Override
public void beforeValidityChanged(@NotNull VirtualFilePointer[] pointers) {
}
@Override
public void validityChanged(@NotNull VirtualFilePointer[] pointers) {
}
};
public PyContentEntriesEditor(Module module, ModuleConfigurationState moduleConfigurationState,
JpsModuleSourceRootType<?>... rootTypes) {
super(module.getName(), moduleConfigurationState, rootTypes);
myModule = module;
reset();
}
@Override
protected ContentEntryTreeEditor createContentEntryTreeEditor(Project project) {
return new MyContentEntryTreeEditor(project, getEditHandlers());
}
@Override
protected List<ContentEntry> addContentEntries(VirtualFile[] files) {
List<ContentEntry> entries = super.addContentEntries(files);
addContentEntryPanels(entries.toArray(new ContentEntry[entries.size()]));
return entries;
}
@Override
public void reset() {
if (myFilePointersDisposable != null) {
Disposer.dispose(myFilePointersDisposable);
}
myTemplateRoots.clear();
myFilePointersDisposable = Disposer.newDisposable();
final TemplatesService instance = TemplatesService.getInstance(myModule);
if (instance != null) {
final List<VirtualFile> folders = instance.getTemplateFolders();
for (VirtualFile folder : folders) {
ContentEntry contentEntry = findContentEntryForFile(folder);
if (contentEntry != null) {
myTemplateRoots.putValue(contentEntry, VirtualFilePointerManager.getInstance().create(folder, myFilePointersDisposable,
DUMMY_LISTENER));
}
}
}
if (myRootTreeEditor != null) {
ContentEntryEditor editor = myRootTreeEditor.getContentEntryEditor();
if(editor!=null) editor.update();
myRootTreeEditor.update();
}
}
@Nullable
private ContentEntry findContentEntryForFile(VirtualFile virtualFile) {
for (ContentEntry contentEntry : getModel().getContentEntries()) {
final VirtualFile file = contentEntry.getFile();
if (file != null && VfsUtilCore.isAncestor(file, virtualFile, false)) {
return contentEntry;
}
}
return null;
}
@Override
public void disposeUIResources() {
super.disposeUIResources();
if (myFilePointersDisposable != null) {
Disposer.dispose(myFilePointersDisposable);
}
}
@Override
public void apply() throws ConfigurationException {
super.apply();
List<VirtualFile> templateRoots = getCurrentState();
TemplatesService.getInstance(myModule).setTemplateFolders(templateRoots.toArray(new VirtualFile[templateRoots.size()]));
}
private List<VirtualFile> getCurrentState() {
List<VirtualFile> result = new ArrayList<VirtualFile>();
for (ContentEntry entry : myTemplateRoots.keySet()) {
for (VirtualFilePointer filePointer : myTemplateRoots.get(entry)) {
result.add(filePointer.getFile());
}
}
return result;
}
@Override
public boolean isModified() {
if (super.isModified()) return true;
final TemplatesService templatesService = TemplatesService.getInstance(myModule);
if (templatesService != null) {
List<VirtualFile> original = templatesService.getTemplateFolders();
List<VirtualFile> current = getCurrentState();
if (!Comparing.haveEqualElements(original, current)) return true;
}
return false;
}
@Override
protected MyContentEntryEditor createContentEntryEditor(String contentEntryUrl) {
return new MyContentEntryEditor(contentEntryUrl, getEditHandlers());
}
protected class MyContentEntryEditor extends ContentEntryEditor {
private final EventDispatcher<ChangeListener> myEventDispatcher = EventDispatcher.create(ChangeListener.class);
public MyContentEntryEditor(String contentEntryUrl, List<ModuleSourceRootEditHandler<?>> handlers) {
super(contentEntryUrl, handlers);
}
@Override
protected ModifiableRootModel getModel() {
return PyContentEntriesEditor.this.getModel();
}
public void addListener(ChangeListener changeListener) {
myEventDispatcher.addListener(changeListener);
}
public void removeListener(ChangeListener changeListener) {
myEventDispatcher.removeListener(changeListener);
}
@Override
protected ContentRootPanel createContentRootPane() {
return new MyContentRootPanel();
}
@Override
public void deleteContentFolder(ContentEntry contentEntry, ContentFolder folder) {
if (folder instanceof TemplateRootFolder) {
final VirtualFile file = folder.getFile();
if (file != null) {
removeTemplateRoot(file);
}
}
else {
super.deleteContentFolder(contentEntry, folder);
}
}
public void addTemplateRoot(@NotNull final VirtualFile file) {
final VirtualFilePointer root = VirtualFilePointerManager.getInstance().create(file, myFilePointersDisposable, DUMMY_LISTENER);
myTemplateRoots.putValue(getContentEntry(), root);
myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this));
update();
}
public void removeTemplateRoot(@NotNull final VirtualFile file) {
final VirtualFilePointer root = getTemplateRoot(file);
if (root != null) {
myTemplateRoots.remove(getContentEntry(), root);
myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this));
update();
}
}
public boolean hasTemplateRoot(@NotNull final VirtualFile file) {
return getTemplateRoot(file) != null;
}
@Nullable
public VirtualFilePointer getTemplateRoot(@NotNull final VirtualFile file) {
for (VirtualFilePointer filePointer : myTemplateRoots.get(getContentEntry())) {
if (Comparing.equal(filePointer.getFile(), file)) {
return filePointer;
}
}
return null;
}
protected class MyContentRootPanel extends ContentRootPanel {
public MyContentRootPanel() {
super(MyContentEntryEditor.this, getEditHandlers());
}
@Override
@NotNull
protected ContentEntryImpl getContentEntry() {
//noinspection ConstantConditions
return (ContentEntryImpl)MyContentEntryEditor.this.getContentEntry();
}
@Override
protected void addFolderGroupComponents() {
super.addFolderGroupComponents();
if (!myTemplateRoots.get(getContentEntry()).isEmpty()) {
final List<TemplateRootFolder> folders = new ArrayList<TemplateRootFolder>(myTemplateRoots.size());
for (VirtualFilePointer root : myTemplateRoots.get(getContentEntry())) {
folders.add(new TemplateRootFolder(root, getContentEntry()));
}
final JComponent sourcesComponent = createFolderGroupComponent("Template Folders",
folders.toArray(new ContentFolder[folders.size()]),
TEMPLATES_COLOR, null);
this.add(sourcesComponent, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0));
}
}
}
}
private static class MyContentEntryTreeEditor extends ContentEntryTreeEditor {
private final ChangeListener myListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
update();
}
};
public MyContentEntryTreeEditor(Project project, List<ModuleSourceRootEditHandler<?>> handlers) {
super(project, handlers);
}
@Override
public void setContentEntryEditor(ContentEntryEditor newEditor) {
PyContentEntriesEditor.MyContentEntryEditor existingEditor = getContentEntryEditor();
if (Comparing.equal(existingEditor, newEditor)) {
return;
}
if (existingEditor != null) {
existingEditor.removeListener(myListener);
}
if (newEditor != null) {
((PyContentEntriesEditor.MyContentEntryEditor)newEditor).addListener(myListener);
}
super.setContentEntryEditor(newEditor);
}
@Override
public PyContentEntriesEditor.MyContentEntryEditor getContentEntryEditor() {
return (PyContentEntriesEditor.MyContentEntryEditor)super.getContentEntryEditor();
}
@Override
protected void createEditingActions() {
super.createEditingActions();
ContentEntryEditingAction a = new ContentEntryEditingAction(myTree) {
{
final Presentation templatePresentation = getTemplatePresentation();
templatePresentation.setText("Templates");
templatePresentation.setDescription("Template Folders");
templatePresentation.setIcon(PythonIcons.Python.TemplateRoot);
}
@Override
public boolean isSelected(AnActionEvent e) {
final VirtualFile[] selectedFiles = getSelectedFiles();
return selectedFiles.length != 0 && getContentEntryEditor().hasTemplateRoot(selectedFiles[0]);
}
@Override
public void setSelected(AnActionEvent e, boolean isSelected) {
final VirtualFile[] selectedFiles = getSelectedFiles();
assert selectedFiles.length != 0;
for (VirtualFile selectedFile : selectedFiles) {
boolean wasSelected = getContentEntryEditor().hasTemplateRoot(selectedFile);
if (isSelected) {
if (!wasSelected) {
getContentEntryEditor().addTemplateRoot(selectedFile);
}
}
else {
if (wasSelected) {
getContentEntryEditor().removeTemplateRoot(selectedFile);
}
}
}
}
};
myEditingActionsGroup.add(a);
a.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK)), myTree);
}
@Override
protected TreeCellRenderer getContentEntryCellRenderer() {
return new ContentEntryTreeCellRenderer(this, getEditHandlers()) {
@Override
protected Icon updateIcon(final ContentEntry entry, final VirtualFile file, final Icon originalIcon) {
if (getContentEntryEditor().hasTemplateRoot(file)) {
return PythonIcons.Python.TemplateRoot;
}
return super.updateIcon(entry, file, originalIcon);
}
};
}
}
private static class TemplateRootFolder extends ContentFolderBaseImpl {
protected TemplateRootFolder(@NotNull VirtualFilePointer filePointer, @NotNull ContentEntryImpl contentEntry) {
super(filePointer, contentEntry);
}
}
}
@@ -34,6 +34,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor {
public static WinPythonSdkFlavor INSTANCE = new WinPythonSdkFlavor();
private static Map<String, String> ourRegistryMap =
ImmutableMap.of("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore", "python.exe",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Python\\PythonCore", "python.exe",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython", "ipy.exe");
private WinPythonSdkFlavor() {
@@ -295,7 +295,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
}
}
commonRegisterProblem(message, " not support this syntax. Raise with no arguments can only be used in an except block",
len, node, null);
len, node, null, false);
// raise 1, 2, 3
len = 0;
message = new StringBuilder(myCommonMessage);
@@ -18,7 +18,7 @@ try:
<error descr="Python version 3.0 does not have module __builtin__">import __builtin__</error>
<error descr="Python version 3.0 does not support this syntax. Raise with no arguments can only be used in an except block">raise</error>
<warning descr="Python version 3.0 does not support this syntax. Raise with no arguments can only be used in an except block">raise</warning>
try:
pass
@@ -0,0 +1 @@
<warning descr="Statement seems to have no effect and can be replaced with function call to have effect">print</warning><error descr="End of statement expected"> </error><warning descr="Statement seems to have no effect">'%s %s %s %s' % bar</warning> # <- doesn't work either
@@ -0,0 +1 @@
print('%s %s %s %s' % bar) # <- doesn't work either
@@ -0,0 +1 @@
<warning descr="Statement seems to have no effect and can be replaced with function call to have effect">print</warning><error descr="End of statement expected"> </error><warning descr="Statement seems to have no effect">var,</warning>
@@ -0,0 +1 @@
print(var, end=' ')
@@ -251,6 +251,23 @@ public class PyQuickFixTest extends PyTestCase {
PyBundle.message("QFIX.statement.effect.introduce.variable"), true, true);
}
public void testReplacePrintEnd() {
runWithLanguageLevel(LanguageLevel.PYTHON34, new Runnable() {
@Override
public void run() {
doInspectionTest("ReplacePrintEnd.py", PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, true);
}});
}
public void testReplacePrintComment() {
runWithLanguageLevel(LanguageLevel.PYTHON34, new Runnable() {
@Override
public void run() {
doInspectionTest("ReplacePrintComment.py", PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true,
true);
}});
}
public void testUnresolvedWith() { // PY-2083
setLanguageLevel(LanguageLevel.PYTHON25);
doInspectionTest("UnresolvedWith.py", PyUnresolvedReferencesInspection.class,
@@ -12,8 +12,7 @@ import org.jetbrains.annotations.Nullable;
public interface JavaScriptDebuggerStarter<RC extends RunConfiguration, U> {
boolean isApplicable(@NotNull RunConfiguration runConfiguration);
// todo we must pass browser family, otherwise result could be unexpected (by default Chrome will be used, but user can prefer Firefox)
void start(@NotNull String url, @NotNull RC runConfiguration, @NotNull U userData);
void start(@NotNull String url, @NotNull RC runConfiguration, @NotNull U userData, @Nullable WebBrowser browser);
final class Util {
static final ExtensionPointName<JavaScriptDebuggerStarter> EP_NAME = ExtensionPointName.create("org.jetbrains.javaScriptDebuggerStarter");
@@ -31,11 +30,15 @@ public interface JavaScriptDebuggerStarter<RC extends RunConfiguration, U> {
}
public static <RC extends RunConfiguration> boolean start(@NotNull RC runConfiguration, @NotNull String url) {
return start(runConfiguration, url, null);
}
public static <RC extends RunConfiguration> boolean start(@NotNull RC runConfiguration, @NotNull String url, @Nullable WebBrowser browser) {
JavaScriptDebuggerStarter<RC, Object> starter = get(runConfiguration);
if (starter == null) {
return false;
}
starter.start(url, runConfiguration, NULL_OBJECT);
starter.start(url, runConfiguration, NULL_OBJECT, browser);
return true;
}
@@ -49,9 +52,13 @@ public interface JavaScriptDebuggerStarter<RC extends RunConfiguration, U> {
@NotNull String url,
@Nullable WebBrowser browser,
boolean startDebugger) {
if (!startDebugger || !start(runConfiguration, url)) {
if (!startDebugger || !start(runConfiguration, url, browser)) {
BrowserLauncher.getInstance().browse(url, browser, runConfiguration.getProject());
}
}
public static boolean hasStarters() {
return EP_NAME.getExtensions().length > 0;
}
}
}
@@ -40,15 +40,15 @@ public final class OpenUrlHyperlinkInfo implements HyperlinkWithPopupMenuInfo {
this(url, Conditions.<WebBrowser>alwaysTrue(), null);
}
public OpenUrlHyperlinkInfo(@NotNull String url, @Nullable WebBrowser browser) {
this(url, null, browser);
public OpenUrlHyperlinkInfo(@NotNull String url, @Nullable final WebBrowser browser) {
this(url, browser == null ? Conditions.<WebBrowser>alwaysTrue() : Conditions.is(browser));
}
public OpenUrlHyperlinkInfo(@NotNull String url, @NotNull Condition<WebBrowser> browserCondition) {
this(url, browserCondition, null);
}
private OpenUrlHyperlinkInfo(@NotNull String url, @Nullable Condition<WebBrowser> browserCondition, @Nullable WebBrowser browser) {
private OpenUrlHyperlinkInfo(@NotNull String url, @NotNull Condition<WebBrowser> browserCondition, @Nullable WebBrowser browser) {
this.url = url;
this.browserCondition = browserCondition;
this.browser = browser;
@@ -58,7 +58,7 @@ public final class OpenUrlHyperlinkInfo implements HyperlinkWithPopupMenuInfo {
public ActionGroup getPopupMenuGroup(@NotNull MouseEvent event) {
DefaultActionGroup group = new DefaultActionGroup();
for (final WebBrowser browser : WebBrowserManager.getInstance().getActiveBrowsers()) {
if (browserCondition == null ? (this.browser == null || browser.equals(this.browser)) : browserCondition.value(browser)) {
if (browserCondition.value(browser)) {
group.add(new AnAction("Open in " + browser.getName(), "Open URL in " + browser.getName(), browser.getIcon()) {
@Override
public void actionPerformed(AnActionEvent e) {
@@ -59,7 +59,7 @@ public class StartBrowserPanel {
private JPanel myRoot;
public StartBrowserPanel() {
myStartJavaScriptDebuggerCheckBox.setVisible(JavaScriptDebuggerStarter.Util.EP_NAME.getExtensions().length > 0);
myStartJavaScriptDebuggerCheckBox.setVisible(JavaScriptDebuggerStarter.Util.hasStarters());
myRoot.addAncestorListener(new AncestorListenerAdapter() {
@Override
public void ancestorAdded(AncestorEvent event) {