<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    BaNg@taobao

    Just Do It!

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      20 Posts :: -1 Stories :: 202 Comments :: 0 Trackbacks
    Eclipse提供了非常多的view,從表現(xiàn)形式來(lái)說(shuō)可分為table view和tree view;從結(jié)構(gòu)上來(lái)說(shuō)可分成三類(lèi):Common navigator view, Pagebook view, Task-oriented view。一般情況下,CNV與Resource有關(guān),pagebook跟selection有關(guān),而task-oriented 為自定義的視圖?;舅械?* explorer都是CNV型的view,基本所有主要插件都有CNV的影子比如IDE,Navigator, Team,JDT, CDT, DTP等。為什么要使用CNV? Paper Napkin的文章說(shuō)的很清楚了,我的看法是,對(duì)于怎樣面對(duì)大批量+復(fù)雜應(yīng)用的二次抽象(view超多,view內(nèi)容聯(lián)系超復(fù)雜緊密),CNV提供了一個(gè)很好的完整實(shí)例。

    ==>> 代碼下載,下載后import到Eclipse 3.4.1+JDK 1.6,run/debug即可。

    CNV的視圖特征:

    10分鐘,一個(gè)CNV Resource View
    1. 新建一個(gè)plugin項(xiàng)目,名字 com.lifesting.hush,將圖標(biāo)解壓縮到項(xiàng)目下,刷新,打開(kāi)MANIFEST.MF,在build項(xiàng)里面將icon目錄鉤上。
    2. 定位Dependencies項(xiàng),依次加入 org.eclipse.ui.navigator,org.eclipse.ui.navigator.resources,org.eclipse.ui.ide,org.eclipse.jface.text,org.eclipse.ui.editors, org.eclipse.core.resources,org.eclipse.ui.views插件。
    3. 配置一個(gè)view extension, 如下圖:


      需要注意的是,這個(gè)view的implementation是navigator插件里面的CommonNavigator,目前我們不需要手寫(xiě)任何代碼。
    4. 使用Extension Point org.eclipse.ui.navigator.viewer, new一個(gè)viewer,viewId設(shè)置為 com.lifesting.hush.view.cnf,popMenuId暫時(shí)置空;new一個(gè)viewerContentBinding,viewId不變,添加一個(gè)includes子節(jié)點(diǎn),然后在其上添加一個(gè)contentExtension,屬性pattern為org.eclipse.ui.navigator.resourceContent,isRoot為true.
    5. 啟動(dòng),點(diǎn)擊菜單Window->Show View->General->Html Explorer,就可以看到效果了,如果view是空白,也不是bug,在左邊的Pakcage Explorer或Resource Explorer新建一個(gè)項(xiàng)目,然后關(guān)閉Html Explorer再打開(kāi),就會(huì)看到Html Explorer顯示的和Resource Explorer一模一樣的項(xiàng)目結(jié)構(gòu)。

    雖然這個(gè)Html Explorer出來(lái)了,但設(shè)置的org.eclipse.ui.navigator.resourceContent哪來(lái)的?怎么定義的?怎么添加右鍵菜單?Link為啥無(wú)效?怎樣定制這個(gè)顯示?CNF好像也沒(méi)有顯著的特點(diǎn)阿?不著急,逐一搞定,從頭開(kāi)始,最終的效果會(huì)是這樣的:


    CNV的核心是navigatorContent,所有操作都是圍繞它展開(kāi)的(可以選擇org.eclipse.ui.navigator.navigatorContent,選擇find references,看看SDK都提供了哪些content),我們這個(gè)Html Explorer為了把過(guò)程將的更清楚,將使用兩個(gè)自定義的navigatorContent。下面是步驟:

    1. 通過(guò)extension point org.eclipse.ui.navigator.navigatorContent 新建一個(gè)id為com.lifesting.cnf.directorycontent的navigatorContent,activatorByDefault=true,LabelProvider=
      org.eclipse.ui.model.WorkbenchLabelProvider,而contentProvider需要新建一個(gè)類(lèi),非常簡(jiǎn)單,就是遍歷IProject或IFolder的子資源(Folder或File)。它的getElement方法實(shí)現(xiàn):
          @Override
          
      public Object[] getElements(Object inputElement) {
              
      if (inputElement instanceof IProject)
              {
                  
      try {
                      
      return ((IProject)inputElement).members();
                  } 
      catch (CoreException e) {
                      e.printStackTrace();
                  }
              }
              
      else if (inputElement instanceof IFolder){
                  
      try {
                      
      return ((IFolder)inputElement).members();
                  } 
      catch (CoreException e) {
                      e.printStackTrace();
                  }
              }
              
      return EMPTY;
          }
      1. 每個(gè)navigatorContent都有triggerPoints,很顯然剛才定義的content通過(guò)IProject和IFolder來(lái)觸發(fā)view tree生成。在這個(gè)content下面new 一個(gè)triggerPoints,再new兩個(gè)instanceof分別指向IProject和IFile。
      2. 在定義actionProvider的時(shí)候,需要知道selection大致的類(lèi)型,在這個(gè)content下面new一個(gè)possibleChildren,再new一個(gè)instanceof 先后IResource(IFile或者IFolder)。

    2. 通過(guò)extension point org.eclipse.ui.viewActions給ui view添加一個(gè)action用來(lái)設(shè)置content的Root,它的class如下:
      //bind to mycnfview
      public class OpenDirectoryAction implements IViewActionDelegate {
          
      private MyCnfView view;
          
      public OpenDirectoryAction() {
          }

          @Override
          
      public void init(IViewPart view) {
              
      this.view = (MyCnfView) view;
          }
          @Override
          
      public void run(IAction action) {
              DirectoryDialog dir_dialog 
      = new DirectoryDialog(view.getSite()
                      .getShell());
              String dir_location 
      = retriveSavedDirLocation();
              initDialog(dir_dialog, dir_location);
              String dir 
      = dir_dialog.open();
              
      if (null != dir && !dir.equals(dir_location)) {
                  saveDirLocation(dir);
                  createPhantomProject(dir);
                  fireDirChanged(dir);
              }
          }

          
      private void createPhantomProject(String dir_location) {
              IProject project 
      = ResourcesPlugin.getWorkspace().getRoot().getProject(MyCnfView.PHANTOM_PROJECT_NAME);
              
      // 1 delete previous defined project
              if (project.exists()) {
                  
      try {
                      project.delete(
      falsetruenull);
                  } 
      catch (CoreException e) {
                      e.printStackTrace();
                  }
              }
              
      // 2 create new project with the same name
              final IProjectDescription desc = ResourcesPlugin.getWorkspace().newProjectDescription(MyCnfView.PHANTOM_PROJECT_NAME);
              desc.setLocationURI(
      new File(dir_location).toURI());
              IRunnableWithProgress op 
      = new IRunnableWithProgress() {
                  
      public void run(IProgressMonitor monitor)
                          
      throws InvocationTargetException {
                      CreateProjectOperation op 
      = new CreateProjectOperation(desc,
                              
      "Build Algorithm Library");
                      
      try {
                          PlatformUI.getWorkbench().getOperationSupport()
                                  .getOperationHistory().execute(
                                          op,
                                          monitor,
                                          WorkspaceUndoUtil
                                                  .getUIInfoAdapter(view.getSite().getShell()));
                      } 
      catch (ExecutionException e) {
                          
      throw new InvocationTargetException(e);
                      }
                  }
              };
              
      try {
                  view.getSite().getWorkbenchWindow().run(
      falsefalse, op);
              } 
      catch (InvocationTargetException e) {
                  e.printStackTrace();
              } 
      catch (InterruptedException e) {
                  e.printStackTrace();
              }
              
      // 3 add the new created project to default workingset
              if (project.exists()) {
                  view.getSite().getWorkbenchWindow().getWorkbench().getWorkingSetManager().addToWorkingSets(project,
                          
      new IWorkingSet[] {});
                  
      //4 waiting the project is ready(file structure is built)
                  try {
                      project.refreshLocal(IResource.DEPTH_INFINITE, 
      null);
                  } 
      catch (CoreException e) {
                      e.printStackTrace();
                  }
              }  
          }

         
      //...略..輔助方法
      }
      代碼要表達(dá)的就是建立一個(gè)隱含的project,將action取得的directory下所有的文件都倒入到項(xiàng)目中來(lái)。

    3. 將ui view的class從CommonNavigator變?yōu)橐粋€(gè)它的子類(lèi)MyCnfView:
      public class MyCnfView extends CommonNavigator {

          
      public static final String KEY_DIR_LOCATION="com.lifesting.cnf.myview_location";
          
      public static final String PHANTOM_PROJECT_NAME=".htmlproject";
          
      public MyCnfView() {
          }
          
      public IAdaptable getProjectInput(){
              IWorkspaceRoot ws_root 
      = ResourcesPlugin.getWorkspace().getRoot();
              IProject proj 
      = ws_root.getProject(PHANTOM_PROJECT_NAME);
              
      if (!proj.exists()) return getSite().getPage().getInput();
              
      return proj;
          }
          
      public void reset()
          {
              getCommonViewer().setInput(getProjectInput());
              getCommonViewer().refresh();
          }
          @Override
          
      protected IAdaptable getInitialInput() {
              
      return getProjectInput();
          }

      }

    4. 將viewerContentBinding/includes的contentExtension的pattern替換為剛才定義的com.lifesting.cnf.directorycontent。

    5. 因?yàn)槭荋tml Explorer,需要過(guò)濾掉非html文件,需要設(shè)置一個(gè)過(guò)濾器。通過(guò)extension point org.eclipse.ui.navigator.navigatorContent 新建一個(gè)id為com.lifesting.cnf.filter.nothtml的filter,它的class非常簡(jiǎn)單:
      public class NotHtmlFilter extends ViewerFilter {

          
      public NotHtmlFilter() {
          }

          @Override
          
      public boolean select(Viewer viewer, Object parentElement, Object element) {
              
      if (element instanceof IFile)
              {
                  
      return Util.isHtmlFile((IFile)element);
              }
              
      return true;
          }
      }
    6. 再將此filter配置到cnv的viewerContentBinding/includes中去,跟contentExtension配置過(guò)程一樣。
    7. 啟動(dòng)后,cnv已經(jīng)可以工作,為了演示navigatorContent的可重復(fù)利用性,再定義一個(gè)只包含html文檔標(biāo)題的html title content(為方便只掃描標(biāo)題),掛在前面定義的directory content上。directory content的model是IProject/IFile/IFolder,html title content需要定義一個(gè)model,一個(gè)html文檔掃描器,還有contentPrvoider和lableProvider。
      • model
        public class HeadTitle {
            
        private String title;
            
        private IFile file;
            
        private int from = 0;
            
        public int getFrom() {
                
        return from;
            }
                
        //略set/get
        }
      • scaner
            public static HeadTitle parse(InputStream in) throws IOException {
                BufferedReader br 
        = new BufferedReader(new InputStreamReader(in));
                
        int c = -1;
                StringBuffer sb 
        = new StringBuffer();
                
        boolean tag = false;
                
        boolean found_title = false;
                String to_match 
        = "title";
                HeadTitle title 
        = new HeadTitle();
                
        int counter = 0;
                
        int start = 0;
                outer: 
        while ((c = br.read()) != -1) {
                    
        if (c == '<') {
                        br.mark(
        3);
                        
        if (br.read() == '!' && br.read() == '-' && br.read() == '-') {
                            
        // loop over html comment until -->
                            counter += 3;
                            
        int t1, t2, t3;
                            t1 
        = t2 = t3 = 0;
                            
        while ((c = br.read()) != -1) {
                                t3 
        = t2;
                                t2 
        = t1;
                                t1 
        = c;
                                counter
        ++;
                                
        if (t3 == '-' && t2 == '-' && t1 == '>') {
                                    counter
        ++// '<' also need be countered
                                    continue outer;
                                }
                            }
                            
        break outer; //reach the end
                        } else {
                            br.reset();
                        }
                        tag 
        = true;
                        
        if (found_title) {
                            title.setTitle(sb.toString());
                            title.setFrom(start);
                            title.setTo(counter);
                            
        return title;
                        }
                    } 
        else if (c == '>') {
                        start 
        = counter + 1;
                        
        if (tag) {
                            String s 
        = sb.toString().trim();
                            found_title 
        = to_match.equalsIgnoreCase(s);
                            sb.setLength(
        0);
                            tag 
        = false;
                        }
                    } 
        else {
                        sb.append((
        char) c);
                    }
                    counter
        ++;
                }
                title.setTitle(
        "No title");
                
        return title;
            }
      • contentProvider只有一個(gè)getChildren比較重要
            private static final Object[] EMPTY = new Object[0];
            @Override
            
        public Object[] getChildren(Object parentElement) {
                
        if (parentElement instanceof IFile)
                {
                    IFile f 
        = (IFile) parentElement;
                    
        if(Util.isHtmlFile(f))
                    {
                        
        try {
                            HeadTitle head 
        = SimpleHtmlParser.parse(f.getContents());
                            head.setFile(f);
                            
        return new HeadTitle[]{head};
                        } 
        catch (IOException e) {
                            e.printStackTrace();
                        } 
        catch (CoreException e) {
                            e.printStackTrace();
                        }
                    }
                }
                
        return EMPTY;
            }
      • labelProivder
        public class HtmlTitleLabelProvider extends LabelProvider {
            
        public static final String KEY_TITLE_IMAGE="icon/title.GIF";
            @Override
            
        public String getText(Object element) {
                
        if (element instanceof HeadTitle)
                    
        return ((HeadTitle)element).getTitle();
                
        else if (element instanceof IFile)
                    
        return ((IFile)element).getName();
                
        return super.getText(element);
            }
            @Override
            
        public Image getImage(Object element) {
                
        if (element instanceof HeadTitle)
                {
                    
                    Image img 
        = Activator.getDefault().getImageRegistry().get(KEY_TITLE_IMAGE);
                    
        if (img == null)
                    {
                        Activator.getDefault().getImageRegistry().put(KEY_TITLE_IMAGE, (img 
        = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, KEY_TITLE_IMAGE).createImage()));
                    }
                    
        return img;            
                }
                
        return super.getImage(element);
            }
        }

    8. html title content利用directory content找到文件,提取標(biāo)題,但二者有個(gè)東西來(lái)觸發(fā)這個(gè)過(guò)程。在html title content下定義個(gè)一個(gè)triggerPoints,使用instanceof=IFile來(lái)觸發(fā)。
    9. 所有的功能基本完成,剩下popmenu和link,popmenu可以有兩種方式, contribute或cnv下的popmenu子節(jié)點(diǎn).contribute會(huì)在popmenu下建一堆比如group.*的menu placeholder。content下可以配置actionProvider來(lái)完成popmenu的功能,為簡(jiǎn)單只在popmenu上放置一個(gè)open的動(dòng)作,即open html file,如果是html file,直接打開(kāi);如果是html file title,還須將html title高亮顯示,以示不通,actionProivder:
      public class MyCommonActionProvider extends CommonActionProvider {

          
      private IAction action;
          
      public MyCommonActionProvider() {
              
          }
          @Override
          
      public void init(ICommonActionExtensionSite site) {
              
      super.init(site);
              ICommonViewerSite check_site 
      = site.getViewSite();
              
      if (check_site instanceof ICommonViewerWorkbenchSite)
              {
                  ICommonViewerWorkbenchSite commonViewerWorkbenchSite 
      = (ICommonViewerWorkbenchSite)check_site;
                  action 
      = new OpenFileAction(commonViewerWorkbenchSite.getPage(),commonViewerWorkbenchSite.getSelectionProvider());
              }
          }
          @Override
          
      public void fillActionBars(IActionBars actionBars) {
              
      super.fillActionBars(actionBars);
              actionBars.setGlobalActionHandler(ICommonActionConstants.OPEN, action);
          }
          @Override
          
      public void fillContextMenu(IMenuManager menu) {
              
      super.fillContextMenu(menu);
              
      if (action.isEnabled())
                  menu.appendToGroup(
      "group.edit", action);
          }
      }
      open file action:
      public class OpenFileAction extends Action {

          
      private IWorkbenchPage page;
          
      private ISelectionProvider provider;
          
      private Object selected = null;
          
          
      public OpenFileAction(IWorkbenchPage page,
                  ISelectionProvider selectionProvider) {
              
      this.page = page;
              
      this.provider = selectionProvider;
              setText(
      "Open");
              setDescription(
      "Doo");
              setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, 
      "icon/lookin.GIF"));
          }
          @Override
          
      public boolean isEnabled() {
              ISelection selection 
      = provider.getSelection();
              
      if(!selection.isEmpty())
              {
                  IStructuredSelection structuredSelection 
      = (IStructuredSelection)selection;
                  Object element 
      = structuredSelection.getFirstElement();
                  selected 
      = element;
                  
      return element instanceof IFile || element instanceof HeadTitle;
              }
              selected 
      = null;
              
      return false;
          }
          @Override
          
      public void run() {
              
      if (null == selected) return ;
              IFile file 
      = ((selected instanceof HeadTitle) ? ((HeadTitle)selected).getFile() : (IFile)selected);
              FileEditorInput fileEditInput 
      = new FileEditorInput(file);
              
      try {
                  TextEditor editor 
      = (TextEditor) page.openEditor(fileEditInput, "org.eclipse.ui.DefaultTextEditor");
                  
      if (selected instanceof HeadTitle)
                  {
                      
      int from = ((HeadTitle)selected).getFrom();
                      
      int to = ((HeadTitle)selected).getTo();
                      editor.selectAndReveal(from, to
      -from);
                  }
              } 
      catch (PartInitException e) {
                  e.printStackTrace();
              }
          }
          
      }
    10. Link功能非常簡(jiǎn)單,使用extension point org.eclipse.ui.navigator.linkHelper,它有兩個(gè)子節(jié)點(diǎn)selectionEnablement和editorinputEnablement,分別對(duì)應(yīng)在view中的selection和打開(kāi)editor中的editorInput,class為:
      public class SimpleHtmlLinkHelper implements ILinkHelper {

          @Override
          
      public void activateEditor(IWorkbenchPage page,
                  IStructuredSelection selection) {
              Object obj 
      = selection.getFirstElement();
              
      if (obj instanceof IFile)
              {
                  FileEditorInput input 
      = new FileEditorInput((IFile) obj);
                  IEditorPart editor 
      = page.findEditor(input);
                  
      if(editor != null)
                  {
                      page.bringToTop(editor);
                  }
              }
          }

          @Override
          
      public IStructuredSelection findSelection(IEditorInput anInput) {
              
      if (anInput instanceof IFileEditorInput)
              {
                  IFile file 
      = ((IFileEditorInput)anInput).getFile();
                  StructuredSelection selection 
      = new StructuredSelection(file);
                  
      return selection;
              }
              
      return null;
          }

      }
    插件太復(fù)雜,不適合一篇blog講清楚,如果有人對(duì)cnv有些比明白,歡迎來(lái)郵件討論。

    posted on 2008-11-30 01:28 Always BaNg. 閱讀(4343) 評(píng)論(2)  編輯  收藏 所屬分類(lèi): JavaEclipse 、源代碼分析

    Feedback

    # re: 插件開(kāi)發(fā)之:Common Navigator View (CNV) 通用導(dǎo)航試圖[未登錄](méi) 2008-12-01 09:03 寒武紀(jì)
    不錯(cuò),支持一下  回復(fù)  更多評(píng)論
      

    # re: 插件開(kāi)發(fā)之:Common Navigator View (CNV) 通用導(dǎo)航試圖 2012-03-09 15:50 songlei
    不知博主的這篇文章還更新不,我在想個(gè)問(wèn)題:selectAndReveal的效果是定位+高亮。但是否可以模仿selectAndReveal的效果,不同的是高亮的顏色由代碼控制,不知博主是否考慮過(guò)?  回復(fù)  更多評(píng)論
      

    主站蜘蛛池模板: 好看的电影网站亚洲一区| 亚洲成人影院在线观看| 亚洲福利在线观看| 免费无码又爽又刺激网站| 亚洲va久久久噜噜噜久久| 大地资源中文在线观看免费版| 亚洲中文字幕无码久久2017| 无码日韩人妻AV一区免费l | 久久久久久久久亚洲| 3344在线看片免费| 亚洲一区中文字幕久久| 8888四色奇米在线观看免费看| 在线免费观看亚洲| 91免费国产在线观看| 亚洲乱理伦片在线观看中字| 国产三级免费电影| www免费黄色网| 久久久久亚洲av无码专区蜜芽| 91精品国产免费久久国语麻豆| 亚洲国产日韩在线成人蜜芽| 成人免费福利电影| 免费国产va视频永久在线观看| 亚洲日韩小电影在线观看| 无码A级毛片免费视频内谢| 亚洲国产午夜电影在线入口| 国产美女精品久久久久久久免费| 天堂亚洲免费视频| 亚洲国产高清人在线| 成人免费午间影院在线观看| 日韩毛片在线免费观看| 亚洲色成人WWW永久网站| 亚欧免费无码aⅴ在线观看| 亚洲精品天堂在线观看| 免费一区二区三区四区五区 | 一级女性全黄生活片免费看| 午夜亚洲www湿好大| 人禽杂交18禁网站免费| 亚洲日韩在线观看免费视频| 亚洲最大黄色网址| 亚洲日本韩国在线| 日韩中文字幕精品免费一区|