2015-02-24 75 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; 
    } 
}