Skip to content

一些自用代码示例

获取插件当前路径

java
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;

public class PathUtil {

    public static String pluginPath() throws URISyntaxException {
        // 获取当前类的 ClassLoader
        URL location = PathUtil.class.getProtectionDomain().getCodeSource().getLocation();
        // 将 URL 转换为文件路径
        File jarFile = new File(location.toURI());
        return jarFile.getParentFile().getAbsolutePath();
    }
}

自用——带有进度条的 Worker

展开查看
java
import com.nomagic.magicdraw.core.Application;
import org.apache.log4j.Logger;

import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import java.util.List;

public abstract class BaseWorker<T> extends SwingWorker<T, String> {

    protected static final Logger log = Logger.getLogger(BaseWorker.class);

    /**
     * 进度条窗口
     */
    private final ProgressBarFrame frame;
    /**
     * 主过程中的错误
     */
    protected Exception e;

    public BaseWorker() {
        // 创建进度条
        this.frame = new ProgressBarFrame();
        frame.setVisible(true);
    }

    public BaseWorker(String defaultLoading) {
        this.frame = new ProgressBarFrame(defaultLoading);
        frame.setVisible(true);
    }

    /**
     * worker 的主要工作
     *
     * @return 工作后的返回
     */
    protected abstract T mainProcess() throws Exception;

    /**
     * 成功回调
     *
     * @param t 消费 worker 的返回
     */
    protected abstract void onSuccess(T t) throws Exception;

    protected void onError(Exception e) {
        String message = e.getMessage();
        if (message == null) {
            message = e.getStackTrace()[0].toString();
        }
        log.error("onError", e);
        Application.getInstance().getGUILog().showError(message);
    }

    @Override
    protected T doInBackground() {
        try {
            return mainProcess();
        } catch (Exception e) {
            this.e = e;
        }
        return null;
    }

    @Override
    protected void process(List<String> chunks) {
        for (String value : chunks) {
            frame.updateProgress(value);
        }
    }

    @Override
    protected void done() {
        // 显示错误信息
        frame.dispose();
        if (e != null) {
            onError(e);
        } else {
            try {
                onSuccess(get());
            } catch (Exception ex) {
                onError(ex);
            }
        }
    }
}

class ProgressBarFrame extends JFrame {

    private final JProgressBar progressBar;

    public ProgressBarFrame() {
        this("loading...");
    }

    public ProgressBarFrame(String defaultLoading) {
        this.progressBar = new JProgressBar(JProgressBar.HORIZONTAL);
        this.progressBar.setIndeterminate(true);
        this.progressBar.setStringPainted(true);
        this.progressBar.setBorderPainted(false);
        this.progressBar.setString(defaultLoading);
        this.add(progressBar);
        this.setResizable(false);
        this.setUndecorated(true);
        this.setSize(300, 35);
        this.setAlwaysOnTop(true);
        this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        this.setLocationRelativeTo(null);
    }

    public void updateProgress(String value) {
        progressBar.setString(value);
    }
}
可取消的 Worker(需要在 mainProcess 中监控isCanceled()值)
java
public abstract class CancelableWorker<T> extends SwingWorker<T, String> {

    protected static final Logger log = Logger.getLogger(CancelableWorker.class);

    /**
     * 进度条窗口
     */
    private final ProgressBarFrame frame;

    public CancelableWorker() {
        // 创建进度条
        this.frame = new ProgressBarFrame(this::cancelAction);
        frame.setVisible(true);
    }

    public CancelableWorker(String defaultLoading) {
        this.frame = new ProgressBarFrame(defaultLoading, this::cancelAction);
        frame.setVisible(true);
    }

    /**
     * worker 的主要工作
     *
     * @return 工作后的返回
     */
    protected abstract T mainProcess() throws Exception;

    /**
     * 成功回调
     *
     * @param t 消费 worker 的返回
     */
    protected abstract void onSuccess(T t) throws Exception;

    protected void onError(Throwable e) {
        String message = e.getMessage();
        if (message == null) {
            message = e.getStackTrace()[0].toString();
        }
        log.error("onError", e);
        Application.getInstance().getGUILog().showError(message);
    }

    protected void cancelAction(ActionEvent e) {
        this.cancel(true);
        log.info("已发起取消请求...");
    }

    @Override
    protected T doInBackground() throws Exception {
        return mainProcess();
    }

    @Override
    protected void process(List<String> chunks) {
        for (String value : chunks) {
            frame.updateProgress(value);
        }
    }

    @Override
    protected void done() {
        // 显示错误信息
        frame.dispose();
        if (isCancelled()) {
            log.info("成功取消...");
            return;
        }
        try {
            onSuccess(get());
        } catch (ExecutionException ex) {
            onError(ex.getCause());
        } catch (Exception ex) {
            onError(ex);
        }
    }
}

class ProgressBarFrame extends JFrame {

    private final JProgressBar progressBar;

    public ProgressBarFrame(ActionListener cancelAction) {
        this("loading...", cancelAction);
    }

    public ProgressBarFrame(String defaultLoading, ActionListener cancelAction) {
        this.progressBar = new JProgressBar(JProgressBar.HORIZONTAL);
        this.progressBar.setIndeterminate(true);
        this.progressBar.setStringPainted(true);
        this.progressBar.setBorderPainted(false);
        this.progressBar.setString(defaultLoading);
        this.setLayout(new BorderLayout());
        this.add(progressBar, BorderLayout.CENTER);
        JButton cancelBtn = new JButton("取消");
        cancelBtn.addActionListener(cancelAction);
        this.add(cancelBtn, BorderLayout.EAST);
        this.setResizable(false);
        this.setUndecorated(true);
        this.setSize(320, 30);
        this.setAlwaysOnTop(true);
        this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        this.setLocationRelativeTo(null);
    }

    public void updateProgress(String value) {
        progressBar.setString(value);
    }
}

创建 Notification

java
private static void showNotification(String title) {
    Notification notification = new Notification("com.atoz.qidsfhvf.notification.ARL", title);
    NotificationManager notificationManager = NotificationManager.getInstance();
    NotificationViewConfig infoConfig = notificationManager.getInfoConfig();
    infoConfig.setExpirationTime(2);
    notificationManager.showNotification(notification, infoConfig);
}

嵌套菜单示例-带【更多】

java
ActionsCategory category = new ActionsCategory(null, "测试");
category.setNested(true);
List<MDMenuAction> topLevels = IntStream.rangeClosed(1, 20).mapToObj(i -> {
    MDMenuAction topLevel = new MDMenuAction(null, "顶层节点" + i, null, null) {
        @Override
        public void menuSelected(MenuEvent menuEvent) {
            List<MDAction> actions = IntStream.rangeClosed(i * 100, i * 100 + 15).mapToObj(j -> new MDAction(null, "次级节点" + j, null, null) {
                @Override
                public void actionPerformed(@CheckForNull ActionEvent actionEvent) {
                    Application.getInstance().getGUILog().showMessage("您点击了 " + i + ", " + j);
                }
            }).collect(Collectors.toList());
            breakActions(this, actions, 10, "More", true);
        }
    };
    topLevel.setNested(true);
    return topLevel;
}).collect(Collectors.toList());
ActionsCategory.breakActions(category, topLevels, 10, "...", true);
ActionsConfiguratorsManager manager = ActionsConfiguratorsManager.getInstance();
AMConfigurator configurator = new AMConfigurator() {
    @Override
    public void configure(ActionsManager actionsManager) {
        actionsManager.addCategory(category);
    }

    @Override
    public int getPriority() {
        return MEDIUM_PRIORITY;
    }
};
manager.addMainMenuConfigurator(configurator);
效果如下图

官方常用工具类 API

CoreHelper

  • getSupplierElement
  • getClientElement
  • setSupplierElement
  • setClientElement

InstanceSpecificationHelper

  • setSlotValue
  • getValueBySlot
  • setValueSpecificationValue
  • getValueSpecificationValue

Interactions/InteractionHelper

  • getSendElement
  • getReceiveElement
  • setDurationInterval
  • setTimeInterval
  • setEventForTimeExpression

ModelHelper

  • getFirstEnd
  • getSecondEnd
  • pureAttributes
  • setConstraintText

StateMachineHelper

  • getSignalForTransition

StereotypesHelper

  • getProfile
  • getStereotype

TagsHelper

  • setStereotypePropertyValue
  • getTaggedValue

ValueSpecificationHelper

  • setValueSpecificationValue
  • getValueSpecificationValue

Connectors/ConnectorsCollector

  • collectConnectors

UsageInDiagramUtils/UsageInHelper

  • UsageInDiagramUtils.getDiagramsElementUsedIn
  • UsageInHelper.getUsageInInstancesElements
  • UsageInHelper.getUsageInElementsWithAdditional

DSL

  • getPropertyGroups

元素操作

元素类型判断

java
public static boolean isTypeOf(Element el, String typeName) {
    List<Stereotype> list = el.getAppliedStereotype();
    for (Stereotype stereotype : list) {
        if (typeName.equals(stereotype.getName())) {
            return true;
        }
        List<Classifier> baseClassifiers = getBaseClassifiers(stereotype);
        for (Classifier classifier : baseClassifiers) {
            if (typeName.equals(classifier.getName())) {
                return true;
            }
        }
    }
    java.lang.Class<?> clazz = ClassTypes.getClassType(typeName);
    if (clazz == null) {
        return false;
    }
    return clazz.isAssignableFrom(el.getClass());
}

public static List<Classifier> getBaseClassifiers(Classifier classifier) {
    List<Classifier> ret = new ArrayList<>();
    if (classifier != null) {
        recursiveBaseClassifiers(classifier, ret);
    }
    return ret;
}

private static void recursiveBaseClassifiers(Classifier classifier, List<Classifier> ret) {
    if (classifier == null) {
        return;
    }
    Collection<Classifier> generals = classifier.getGeneral();
    if (generals == null) {
        return;
    }
    for (Classifier general : generals) {
        ret.add(general);
        recursiveBaseClassifiers(general, ret);
    }
}

/**
 * 是否是 Block
 *
 * @param objInput Tree 上面挂载的元素
 * @return 是否
 */
public static boolean isBlock(Object objInput) {
    if (!(objInput instanceof Class)) {
        return false;
    }
    Class obj = (Class) objInput;
    if ("Block".equals(obj.getHumanType())) {
        return true;
    }
    return isTypeOf(obj, "Block");
}

/**
 * 是否是 ValueProperty
 *
 * @param obj 属性元素
 * @return 是否
 */
public static boolean isValueProperty(Property obj) {
    if ("Value Property".equals(obj.getHumanType())) {
        return true;
    }
    return isTypeOf(obj, "ValueProperty");
}

getDefaultValue

java
public static String getDefaultValueString(Property property) {
    return String.valueOf(ValueSpecifications.getValueSpecificationValue(property.getDefaultValue()));
}

setDefaultValue

java
public static void setDefaultValueString(Property property, String value) {
    ValueSpecificationHelper.setValueSpecificationValue(property.getDefaultValue(), value);
}

setDocumentation

java
private static void setDocumentation(Element owner, String mark, ElementsFactory factory) {
    Collection<Comment> comments = owner.getOwnedComment();
    if (!comments.isEmpty()) {
        for (Comment comment : comments) {
            if (comment.getAnnotatedElement().contains(owner)) {
                comment.setBody(mark);
                return;
            }
        }
    }
    Comment commentInstance = factory.createCommentInstance();
    commentInstance.setBody(mark);
    commentInstance.setOwner(owner);
    commentInstance.getAnnotatedElement().add(owner);
    comments.add(commentInstance);
}

在模型树中选中元素

java
private static void selectElementInTree(Element el) {
    SelectInBrowserTreeUtils.selectInContainmentTree(el); // 2022
    // SelectInContainmentTreeAction.selectInBrowser(el); // 2021
}

FlowProperty 获取方向

java
/**
 * 获取 FlowProperty 的方向
 *
 * @param flowProperty        flowProperty
 * @param isConjugated        是否共轭
 * @param directionDefinition 方向的 tagDefinition
 * @return 处理共轭后的方向
 */
public static String getFlowPropertyDirection(Property flowProperty, boolean isConjugated, Property directionDefinition) {
    TaggedValue taggedValue = TagsHelper.getTaggedValue(flowProperty, directionDefinition);
    if (taggedValue == null) {
        return "--";
    }
    List<?> values = taggedValue.getValue();
    if (values.size() != 1) {
        return "--";
    }
    NamedElement value = (NamedElement) values.get(0);
    log.info(value.getName() + " " + isConjugated);
    if (isConjugated) {
        switch (value.getName()) {
            case "in":
                return "去往";
            case "out":
                return "接入";
            case "inout":
            default:
                return "去往/接入";
        }
    } else {
        switch (value.getName()) {
            case "in":
                return "接入";
            case "out":
                return "去往";
            case "inout":
            default:
                return "去往/接入";
        }
    }
}

getUnitName

java
/**
 * 获取 ValueProperty 的单位
 *
 * @param property     valueProperty
 * @param unitProperty 单位的 tagDefinition
 * @return 单位值
 */
public static String getUnitName(Property property, Property unitProperty) {
    Type type = property.getType();
    if (type != null) {
        TaggedValue taggedValue = TagsHelper.getTaggedValue(type, unitProperty);
        if (taggedValue != null) {
            List<?> value = taggedValue.getValue();
            Object o = value.get(0);
            if (o instanceof InstanceSpecification) {
                InstanceSpecification instanceSpecification = (InstanceSpecification) o;
                return instanceSpecification.getName();
            }
        }
    }
    return "";
}

时序图

组合片段创建和绘制

java
/**
 * 创建组合片段
 *
 * @param factory       元素工厂
 * @param interaction   交互
 * @param specification 名称
 * @param fromLifeLine  client 生命线
 * @param toLifeLine    supplier 生命线
 * @return 组合片段元素
 */
private static CombinedFragment createCombinedFragment(ElementsFactory factory, Interaction interaction,
                                                        String specification, Lifeline fromLifeLine, Lifeline toLifeLine) {
    CombinedFragment fragment = factory.createCombinedFragmentInstance();
    Collection<Lifeline> covered = fragment.getCovered();
    covered.add(fromLifeLine);
    covered.add(toLifeLine);
    fragment.setInteractionOperator(InteractionOperatorKindEnum.OPT);
    fragment.setOwner(interaction);
    fragment.setName(specification);

    InteractionOperand operand = factory.createInteractionOperandInstance();
    operand.setOwner(fragment);

    InteractionConstraint interactionConstraint = factory.createInteractionConstraintInstance();
    interactionConstraint.setOwner(operand);

    LiteralString literalString = factory.createLiteralStringInstance();
    literalString.setOwner(interactionConstraint);
    literalString.setValue(specification + "进入条件");

    interactionConstraint.setSpecification(literalString);
    operand.setGuard(interactionConstraint);
    return fragment;
}

/**
 * 绘制组合片段
 *
 * @param pem                 绘制工厂
 * @param dpe                 时序图画板
 * @param messagePathElements 所含消息的图形元素集合
 * @param fragment            组合片段元素
 */
private static void drawCombinedFragment(PresentationElementsManager pem, DiagramPresentationElement dpe,
                                            LinkedList<SeqBaseMessageView> messagePathElements, CombinedFragment fragment) throws ReadOnlyElementException {
    SeqBaseMessageView first = messagePathElements.getFirst();
    SeqBaseMessageView last = messagePathElements.getLast();
    Point clientPoint1 = last.getClientPoint();
    Point supplierPoint1 = last.getSupplierPoint();
    int x = Math.min(clientPoint1.x, supplierPoint1.x) - 75;
    int y = first.getMinY() - 50;
    int width = Math.abs(clientPoint1.x - supplierPoint1.x) + 210;
    int height = last.getMaxY() - first.getMinY() + 110;
    ShapeElement shapeElement = pem.createShapeElement(fragment, dpe);
    shapeElement.setBounds(new Rectangle(x, y, width, height));
}

时间间隔创建

java
/**
 * 创建时间间隔
 *
 * @param factory 元素工厂
 * @param interaction 交互
 * @param message1 消息 1
 * @param message2 消息 2
 * @param text 最小值
 * @return 时间间隔
 */
private static DurationConstraint createDurationConstraint(ElementsFactory factory, Interaction interaction, Message message1, Message message2, String text) {
    DurationConstraint durationConstraint = factory.createDurationConstraintInstance();
    durationConstraint.setOwner(interaction);
    durationConstraint.getConstrainedElement().add(message1);
    durationConstraint.getConstrainedElement().add(message2);
    InteractionHelper.setDurationInterval(durationConstraint,
            text, // 最小值
            null); // 最大值
    return durationConstraint;
}

时间约束和约束创建

java
/**
 * 创建时间约束
 *
 * @param message 消息
 * @param owner   父级(交互)
 * @param text    约束内容
 * @param factory 元素工厂
 * @return 创建的时间约束
 */
private TimeConstraint addTimeConstraint(Message message, Element owner, String text, ElementsFactory factory) {
    TimeConstraint timeConstraint = factory.createTimeConstraintInstance();
    timeConstraint.setOwner(owner);

    //noinspection ConstantConditions
    InteractionHelper.setTimeInterval(timeConstraint, text, null);
    //noinspection ConstantConditions
    InteractionHelper.setEventForTimeExpression(timeConstraint.getSpecification().getMin(), message);

    timeConstraint.getConstrainedElement().add(message);
    return timeConstraint;
}

/**
 * 创建约束
 *
 * @param message 消息
 * @param owner   父级(交互)
 * @param text    约束内容
 * @param factory 元素工厂
 */
private void addConstraint(Message message, Element owner, String text, ElementsFactory factory) {
    Constraint constraint = factory.createConstraintInstance();
    constraint.setOwner(owner);

    ModelHelper.setConstraintText(constraint, text, false, true);

    constraint.getConstrainedElement().add(message);
}

模块定义图

java
/**
 * 创建并绘制 Link
 *
 * @param owner 父元素
 * @param dpe BDD 图表
 * @param pe1 Link 的其中一端的图形元素
 * @param pe2 Link 的另一端的图形元素
 * @return Link 的图形元素
 */
public static LinkView createAndDrawLink(Element owner, DiagramPresentationElement dpe, PresentationElement pe1, PresentationElement pe2) {
    Project prj = Project.getProject(owner);
    SessionManager.getInstance().checkSessionExistence(prj);
    ElementsFactory f = prj.getElementsFactory();
    InstanceSpecification linkIS = f.createInstanceSpecificationInstance();
    linkIS.setOwner(owner);
    UmlPresentationElementCreator creator = new UmlPresentationElementCreator(dpe);
    creator.getConfig().setSelectCreated(false);
    DiagramWindow window = prj.getProjectDiagramWindowsManager().getWindow(dpe);
    if (window != null) {
        window.getPanel().repaint();
    }
    return (LinkView) creator.createPathElement(linkIS, pe1, pe2, prj.getCommandForAppending());
}

在 Magicdraw 右侧创建 Panel 面板示例

java
public class MyTestPlugin extends Plugin {

    private final static WindowComponentInfo info = new WindowComponentInfo("COMPONENT_ID", "COMPONENT_NAME", null,
            ProjectWindowsManager.SIDE_EAST,
            ProjectWindowsManager.STATE_DOCKED,
            false);

    @Override
    public void init() {
        Browser.addBrowserInitializer(new Browser.BrowserInitializer() {
            @Override
            public void init(Browser browser, Project project) {
                browser.addPanel(new BrowserPanel());
            }

            @Override
            public WindowComponentInfoRegistration getInfo() {
                return new WindowComponentInfoRegistration(info, null);
            }
        });
    }

    @Override
    public boolean close() {
        return true;
    }

    @Override
    public boolean isSupported() {
        return true;
    }

    static class BrowserPanel extends ExtendedPanel implements WindowComponent {
        /**
         * Constructor.
         */
        public BrowserPanel() {
            JLabel label = new JLabel("BrowserPanel");
            label.setHorizontalAlignment(SwingConstants.CENTER);
            add(label, BorderLayout.CENTER);
        }

        @Override
        public WindowComponentInfo getInfo() {
            return info;
        }

        @Override
        public WindowComponentContent getContent() {
            return new WindowComponentContent() {

                @Override
                public Component getWindowComponent() {
                    return BrowserPanel.this;
                }

                @Override
                public Component getDefaultFocusComponent() {
                    return BrowserPanel.this;
                }
            };
        }
    }
}

创建带选中状态的菜单项

java
public class SimpleStateAction extends MDStateAction {
	private boolean iAmSelected;

	/**
	 * Constructor for SimpleStateAction.
	 *
	 * @param id   action id
	 * @param name action name
	 */
	public SimpleStateAction(String id, String name)
	{
		super(id, name, null, null);
	}

	/**
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		// changing state
		iAmSelected = !iAmSelected;
		// showing changes
		JOptionPane.showMessageDialog(MDDialogParentProvider.getProvider().getDialogOwner(), "This is:" + getName() + " checked:" + iAmSelected);
	}

	/**
	 * @see com.nomagic.actions.NMAction#updateState()
	 */
	@Override
	public void updateState() {
		setState(iAmSelected);
	}

}

创建单选组的菜单项

java
private static NMAction getGroupedStateAction()
{
    String[] choice = new String[1];

    SimpleChoiceAction a1 = new SimpleChoiceAction("R1", "R1", choice);
    SimpleChoiceAction a2 = new SimpleChoiceAction("R2", "R2", choice);
    choice[0] = a1.getName();
    a1.updateState();
    a2.updateState();
    // actions must be added to one category.
    ActionsCategory cat = new ActionsCategory();
    cat.addAction(a1);
    cat.addAction(a2);
    return cat;
}

public class SimpleChoiceAction extends MDStateAction
{
	/**
	 * Current choice value. Value is shared between several actions.
	 */
	private final String[] currentChoice;

	/**
	 * Constructor for SimpleChoiceAction.
	 *
	 * @param id            Action id
	 * @param name          action name
	 * @param currentChoice shared choice value
	 */
	public SimpleChoiceAction(String id, String name, String[] currentChoice)
	{
		super(id, name, null, null);
		setGrouped(true);
		this.currentChoice = currentChoice;
	}

	/**
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		// changing choice only when it is not already selected.
		if (!getState())
		{
			currentChoice[0] = getName();
			// showing information about changes
			JOptionPane.showMessageDialog(MDDialogParentProvider.getProvider().getDialogOwner(), "Selected:" + getName());
		}
		// updating other actions state, making only one action from group selected.
		// This can be done in several ways, one way is to call for every action updateState() method.
		// If action execution will create session, actions will be updated automatically.
		ActionsStateUpdater.updateActionsState();
	}

	/**
	 * @see com.nomagic.actions.NMAction#updateState()
	 */
	@Override
	public void updateState()
	{
		// setting this action state to true only when it is current choice.
		setState(getName().equals(currentChoice[0]));
	}

}