/* * Copyright 2000-2009 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.intellij.xdebugger.impl.breakpoints; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.editor.markup.GutterDraggableObject; import com.intellij.openapi.editor.markup.MarkupEditorFilterFactory; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.DocumentUtil; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerUtil; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.intellij.xdebugger.breakpoints.XLineBreakpointType; import com.intellij.xdebugger.ui.DebuggerColors; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.dnd.DragSource; import java.io.File; import java.util.List; /** * @author nik */ public class XLineBreakpointImpl

extends XBreakpointBase, P, LineBreakpointState

> implements XLineBreakpoint

{ @Nullable private RangeHighlighterEx myHighlighter; private final XLineBreakpointType

myType; private XSourcePosition mySourcePosition; private boolean myDisposed; public XLineBreakpointImpl(final XLineBreakpointType

type, XBreakpointManagerImpl breakpointManager, @Nullable final P properties, LineBreakpointState

state) { super(type, breakpointManager, properties, state); myType = type; } XLineBreakpointImpl(final XLineBreakpointType

type, XBreakpointManagerImpl breakpointManager, final LineBreakpointState

breakpointState) { super(type, breakpointManager, breakpointState); myType = type; } public void updateUI() { if (myDisposed || ApplicationManager.getApplication().isUnitTestMode()) { return; } Document document = getDocument(); if (document == null) { return; } EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); TextAttributes attributes = scheme.getAttributes(DebuggerColors.BREAKPOINT_ATTRIBUTES); RangeHighlighterEx highlighter = myHighlighter; if (highlighter != null && (!highlighter.isValid() || !DocumentUtil.isValidOffset(highlighter.getStartOffset(), document) || !Comparing.equal(highlighter.getTextAttributes(), attributes) // it seems that this check is not needed - we always update line number from the highlighter // and highlighter is removed on line and file change anyway /*|| document.getLineNumber(highlighter.getStartOffset()) != getLine()*/)) { removeHighlighter(); highlighter = null; } MarkupModelEx markupModel; if (highlighter == null) { markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), true); highlighter = markupModel.addPersistentLineHighlighter(getLine(), DebuggerColors.BREAKPOINT_HIGHLIGHTER_LAYER, attributes); if (highlighter == null) { return; } highlighter.setGutterIconRenderer(createGutterIconRenderer()); highlighter.putUserData(DebuggerColors.BREAKPOINT_HIGHLIGHTER_KEY, Boolean.TRUE); highlighter.setEditorFilter(MarkupEditorFilterFactory.createIsNotDiffFilter()); myHighlighter = highlighter; } else { markupModel = null; } updateIcon(); if (markupModel == null) { markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, getProject(), false); if (markupModel != null) { // renderersChanged false — we don't change gutter size markupModel.fireAttributesChanged(highlighter, false); } } } @Nullable public Document getDocument() { VirtualFile file = getFile(); if (file == null) return null; return FileDocumentManager.getInstance().getDocument(file); } @Nullable private VirtualFile getFile() { return VirtualFileManager.getInstance().findFileByUrl(getFileUrl()); } @Override @NotNull public XLineBreakpointType

getType() { return myType; } @Override public int getLine() { return myState.getLine(); } @Override public String getFileUrl() { return myState.getFileUrl(); } @Override public String getPresentableFilePath() { String url = getFileUrl(); if (url != null && LocalFileSystem.PROTOCOL.equals(VirtualFileManager.extractProtocol(url))) { return FileUtil.toSystemDependentName(VfsUtilCore.urlToPath(url)); } return url != null ? url : ""; } @Override public String getShortFilePath() { final String path = getPresentableFilePath(); if (path.isEmpty()) return ""; return new File(path).getName(); } @Nullable public RangeHighlighter getHighlighter() { return myHighlighter; } @Override public XSourcePosition getSourcePosition() { if (mySourcePosition == null) { new ReadAction() { @Override protected void run(@NotNull Result result) { mySourcePosition = XDebuggerUtil.getInstance().createPosition(getFile(), getLine()); } }.execute(); } return mySourcePosition; } @Override public boolean isValid() { return myHighlighter != null && myHighlighter.isValid(); } @Override public void dispose() { removeHighlighter(); myDisposed = true; } private void removeHighlighter() { if (myHighlighter != null) { myHighlighter.dispose(); myHighlighter = null; } } @Override protected GutterDraggableObject createBreakpointDraggableObject() { return new GutterDraggableObject() { @Override public boolean copy(int line, VirtualFile file) { if (canMoveTo(line, file)) { setFileUrl(file.getUrl()); setLine(line, true); return true; } return false; } @Override public Cursor getCursor(int line) { return canMoveTo(line, getFile()) ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop; } }; } private boolean canMoveTo(int line, VirtualFile file) { return file != null && myType.canPutAt(file, line, getProject()) && getBreakpointManager().findBreakpointAtLine(myType, file, line) == null; } public void updatePosition() { if (myHighlighter != null && myHighlighter.isValid()) { setLine(myHighlighter.getDocument().getLineNumber(myHighlighter.getStartOffset()), false); } } public void setFileUrl(final String newUrl) { if (!Comparing.equal(getFileUrl(), newUrl)) { myState.setFileUrl(newUrl); mySourcePosition = null; removeHighlighter(); fireBreakpointChanged(); } } private void setLine(final int line, boolean removeHighlighter) { if (getLine() != line) { myState.setLine(line); mySourcePosition = null; if (removeHighlighter) { removeHighlighter(); } fireBreakpointChanged(); } } @Override public boolean isTemporary() { return myState.isTemporary(); } @Override public void setTemporary(boolean temporary) { if (isTemporary() != temporary) { myState.setTemporary(temporary); fireBreakpointChanged(); } } @Override protected List getAdditionalPopupMenuActions(final XDebugSession session) { return getType().getAdditionalPopupMenuActions(this, session); } @Override protected void updateIcon() { final Icon icon = calculateSpecialIcon(); if (icon != null) { setIcon(icon); return; } setIcon(isTemporary() ? myType.getTemporaryIcon() : myType.getEnabledIcon()); } @Override public String toString() { return "XLineBreakpointImpl(" + myType.getId() + " at " + getShortFilePath() + ":" + getLine() + ")"; } }