2015-02-24 80 views
1

我正在使用一个项目,在那里我有许多其他模型'B','C'等参考的EMF模型'A'等。我想要的是我想要为这些资源提供重命名功能。所以当用户重命名'A'时,其引用必须更新。EMF资源的重命名功能

请提供一些想法,如果有任何框架工作,或者我必须获取所有的引用,然后以编程方式迭代和更新引用。

+0

您是否尝试玩过EMF观察员/通知?您可以注册观察员并对特定事件作出反应(例如,资源上的一组名称特征)。 – 2015-02-24 09:38:12

+0

当我更改任何属性的名称时,我是否可以知道要在“B”,“C”等中执行哪种更新?如果该属性值在引用中被认为是FQN,那么它会自动启动更新。 – 2015-04-05 03:08:25

回答

0

我以另一种方式解决了同样的问题。

最根本的问题是引用的资源文件可能会被重命名,这会中断引用。

而不是自动更新所有引用的重构,我创建了一个修复文件引用命令,用户可以在编辑的模型上调用该命令。

的命令执行下列步骤操作:

  1. 提示用户选择一个缺少资源来修复
  2. 提示用户在具有代理模型来选择替换文件
  3. 更新所有对象与缺失资源相匹配的URI。用新资源中已解析的对象替换代理。

如果你仍然想做一个重构,我认为你可以使用我的代码作为一个起点。

/** 
* Locates and fixes unresolved references in a model. 
*/ 
public class ReferenceRepairer { 
    public static final String COMMAND_ID = Activator.PLUGIN_ID + ".commands.repairReferences"; 

    /** 
    * 1) Prompts the user to select a missing resource to repair 
    * 2) Prompts the user to select a replacement file 
    * 3) Updates all objects in the model with a proxy URI that matches the missing resource. Replaces proxies 
    * with resolved objects in the new resource. 
    */ 
    public static void repairResourceReference(Shell shell, EditingDomain editingDomain) { 
     Resource res = promptMissingResource(shell, editingDomain); 

     if (res == null) return; 

     IFile newFile = promptReplacementFile(shell); 

     if (newFile == null) return; 

     repairReferences(editingDomain, res, URI.createPlatformResourceURI(newFile.getFullPath().toString(), true)); 
    } 

    private static void repairReferences(final EditingDomain editingDomain, Resource missingRes, final URI newUri) { 
     URI missingUri = missingRes.getURI(); 

     // Create new resource for the replacement file 
     Resource newRes = editingDomain.getResourceSet().getResource(newUri, true); 

     Map<EObject, Collection<Setting>> proxies = UnresolvedProxyCrossReferencer.find(editingDomain.getResourceSet()); 

     CompoundCommand repairRefsCommand = new CompoundCommand("Repair references") { 
      /** 
      * Disallow undo. The model changes could be undone, but it seems impossible to 
      * recreate a non-existent resource in the resource set. 
      */ 
      @Override 
      public boolean canUndo() { 
       return false; 
      } 
     }; 

     // Resolve all proxies from this resource and repair reference to those objects 

     for (Entry<EObject, Collection<Setting>> entry : proxies.entrySet()) { 

      EObject proxy = entry.getKey(); 
      URI proxyUri = EcoreUtil.getURI(proxy); 
      if (!proxyUri.trimFragment().equals(missingUri)) continue; 

      EObject resolved = newRes.getEObject(proxyUri.fragment()); 

      if (resolved.eIsProxy()) continue; 

      // Update all objects that have references to the resolved proxy 

      for (Setting sett : entry.getValue()) { 
       if (sett.getEStructuralFeature().isMany()) { 
        @SuppressWarnings("unchecked") 
        EList<Object> valueList = (EList<Object>) sett.get(true); 
        int proxyIx = valueList.indexOf(proxy); 

        repairRefsCommand.append(SetCommand.create(editingDomain, 
         sett.getEObject(), sett.getEStructuralFeature(), resolved, proxyIx)); 
       } else { 
        repairRefsCommand.append(SetCommand.create(editingDomain, 
         sett.getEObject(), sett.getEStructuralFeature(), resolved)); 
       } 
      } 
     } 

     if (!repairRefsCommand.isEmpty()) { 
      editingDomain.getCommandStack().execute(repairRefsCommand); 
     } 

     // Remove the 
     editingDomain.getResourceSet().getResources().remove(missingRes); 
    } 

    private static IFile promptReplacementFile(Shell shell) { 
     ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(shell, 
      new WorkbenchLabelProvider(), new WorkbenchContentProvider()); 

     dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); 
     dialog.setTitle("Select Replacement Resource"); 
     dialog.setMessage("Select a file which will replace the missing file."); 

     dialog.setValidator(new ISelectionStatusValidator() { 
      @Override 
      public IStatus validate(Object[] selection) { 
       if (selection.length == 0 || !(selection[0] instanceof IFile)) { 
        return ValidationStatus.error("The selected object is not a file."); 
       } 

       return new Status(IStatus.OK, Activator.PLUGIN_ID, ""); 
      } 
     }); 


     if (dialog.open() != Window.OK) return null; 

     return (IFile) dialog.getFirstResult(); 
    } 

    private static Resource promptMissingResource(Shell shell, EditingDomain editingDomain) { 
     ElementListSelectionDialog dialog = new ElementListSelectionDialog(shell, 
       new LabelProvider() { 
        @Override 
        public String getText(Object elem) { 
         return ((Resource) elem).getURI().toString(); 
        } 
      }) 
     { 
      /** Make dialog OK button enabled when there are errors, instead of vise-versa. */ 
      @Override 
      protected void updateButtonsEnableState(IStatus status) { 
       Button okButton = getOkButton(); 
       if (okButton != null && !okButton.isDisposed()) { 
        okButton.setEnabled(!status.isOK()); 
       } 
      } 

      /** Disable filter text field */ 
      @Override 
      protected Text createFilterText(Composite parent) { 
       Text text = super.createFilterText(parent); 
       text.setSize(0, 0); 
       text.setLayoutData(GridDataFactory.swtDefaults().exclude(true).create()); 
       text.setVisible(false); 
       return text; 
      } 
     }; 

     dialog.setTitle("Select Missing Resource"); 
     dialog.setMessage(
      "Select a URI of a missing resource file that should be replaced by an URI to an existing file."); 
     dialog.setElements(getMissingResources(editingDomain.getResourceSet().getResources()).toArray()); 

     if (dialog.open() != Window.OK) return null; 

     return (Resource) dialog.getFirstResult(); 
    } 

    private static List<Resource> getMissingResources(List<Resource> resources) { 
     List<Resource> missingResources = new ArrayList<>(); 
     for (Resource res : resources) { 
      try { 
       if (res.getURI().isPlatformPlugin()) continue; 
       URL url = FileLocator.toFileURL(new URL(res.getURI().toString())); 
       java.net.URI uri = new java.net.URI(url.getProtocol(), "", "/" + url.getPath(), null); 
       if (!Files.exists(Paths.get(uri))) { 
        missingResources.add(res); 
       } 
      } catch (InvalidPathException | IOException | URISyntaxException exc) { 
       // Ignore. There mighe be weird Sirius resource in the resources set which we can't recognice 
      } 

     } 
     return missingResources; 
    } 
}