GXT RIA App 만들기2011. 1. 20. 23:09

오늘 시간에는 중간 프로그램 영역을 코딩하도록 하자. 중간 프로그램 영역은 좌측 메뉴에서 하나의 Row를 클릭했을 때 이곳에 해당 프로그램이 보여지도록 해야한다.
1. Controller와 View를 하나씩 생성하자. ContentController.java와 ContentView.java를 mvc패키지내에 생성하고 아래와 같이 코딩하자.

☞ ContentController.java
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.gxt.riaapp.client.AppEvents;

public class ContentController extends Controller {
	private ContentView view;

	public ContentController() {
		registerEventTypes(AppEvents.Init, AppEvents.ShowPage);
	}

	public void initialize() {
		view = new ContentView(this);
	}

	public void handleEvent(AppEvent event) {
		forwardToView(view, event);
	}

}
☞ ContentView.java
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.View;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.gxt.riaapp.client.AppEvents;
import com.gxt.riaapp.client.mvc.model.Entry;

public class ContentView extends View {
	private TabPanel tabPanel;
	
	public ContentView(Controller controller) {
		super(controller);
	}
	
	@Override
	protected void initialize() {
		tabPanel = new TabPanel();
		tabPanel.setCloseContextMenu(true);
		tabPanel.setBorderStyle(false);
		tabPanel.setBodyBorder(false);
		tabPanel.setTabScroll(true);
		tabPanel.setAnimScroll(true);
		ContentPanel center = (ContentPanel) Registry.get(AppView.CENTER_PANEL);
	    center.add(tabPanel);
	    center.layout();
	}
	
	public void onShowPage(Entry entry) {
		System.out.println("ContentView.onShowPage() called.." + entry.getName());
	}
	
	@Override
	protected void handleEvent(AppEvent event) {
		EventType type = event.getType();
		if(type == AppEvents.ShowPage){	// Init일 경우에는 작동하지 않음.
			Entry entry = event.getData(); // 이벤트에 전달된 객체를 가져온다.
			onShowPage(entry);
		}
	}
}

☞ RiaApp.java를 수정하자.
	public void onModuleLoad() {
		model = new RiaAppModel();
	    Registry.register(MODEL, model);  // 최초 실행시 Registry에 RiaAppModel을 등록한다.
	    
		dispatcher = Dispatcher.get();
	    dispatcher.addController(new AppController());
	    dispatcher.addController(new NavigationController());  // 좌측
	    dispatcher.addController(new ContentController());
	    dispatcher.dispatch(AppEvents.Init);
	    
	    if(model.getEntries().size()>0) // 등록된 첫번째 프로그램을 보여준다.
			showPage(model.getEntries().get(0));
	}

	/**
	 * ShowPage이벤트를 가지고 있는 Controller를 통해 ContentView를 보여준다. 여기서 중요한 것은 이벤트와 함께
	 * Entry 객체를 전달했다는 것이다. 이 객체는 화면에 보여줘야할 우리가 클릭한 객체로 이 객체를 전달하면 ContentView에서
	 * 이 객체를 이벤트를 통해 전달 받고 화면에 보여주게 된다.
	 * 
	 * @param entry
	 */
	public static void showPage(Entry entry) {
		AppEvent appEvent = new AppEvent(AppEvents.ShowPage, entry); // 이벤트에 객체전달
		appEvent.setHistoryEvent(true);
		appEvent.setToken(entry.getId());
		Dispatcher.forwardEvent(appEvent);  // ShopPage이벤트가 등록되어 있는 ContentController가 ContentView를 보여주게된다.
	}

☞ 이제 실행해 보자 이번에 수정한 부분은 ContentController를 RiaApp에 등록했고 이 컨트롤러를 통해 ContentView가 실행되게 된다. 이때 ContentView가 보여지게 되는 과정에 주목하자.
 RiaApp에 ContentController를 등록하면서 우리는 RiaAppModel의 첫번째 객체를 RiaApp.showPage()메소드에 전달했다.
이 메소드는 AppEvent를 생성하는데 AppEvent는 인자로 이벤트타입과 객체를 받게 된다. 이 애기는 특정이벤트를 콜하면서 객체를 전달할 수 있다는 애기다. showPage메소드의 맨아래 코딩을 보면 Dispatcher클래스의 forwardEvent()메소드를 통해 해당 이벤트가 등록되어 있는 Controller에게 제어권을 넘기고 해당 Controller는 handleEvent메소드에 정의 된 View를 보여지게 된다.
 여기서는 ContentController를 통해 ContentView가 보여지게 되는 것이다. 그러나 이번에도 실행한 결과 별반 달라진게 없을 것이다. 단지 아래 그림처럼 ContentView클래스의 onShowPage()가 호출되는 것을 콘솔을 통해 확인할 수 있다.

2. 이제 프로그램 영역이 마저 보일 수 있도록 수정해 보자

☞ SmplProgram.java를 com.gxt.riaapp.client.mvc 아래에 추가하고 아래와 같이 코딩하자. 이 클래스를 우측 프로그램 영역에 보이도록 할 것이다.
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.VerticalPanel;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
import com.google.gwt.user.client.Element;

public class SmplProgram  extends LayoutContainer {
	@Override
	protected void onRender(Element parent, int index) {
		// TODO Auto-generated method stub
		super.onRender(parent, index);
		VerticalPanel vp = new VerticalPanel();
		vp.setSpacing(10);
		Button btn =new Button("테스트");
		setLayout(new FlowLayout(10));
		vp.add(btn);
		add(vp);
	}
}
☞ RiaAppModel.java의 생성자를 아래와 같이 수정하자.
	public RiaAppModel() {
		Category pgm = new Category("시스템관리","SYS00002");
		pgm.add("시스템사용자관리", "0001", new SmplProgram());
		addCategory(pgm);
		loadEntries(this);
	}
☞ Entry 클래스의 생성자를 약간 수정하자.
	
    public Entry(String name, String id, LayoutContainer example) {
		this.name = name;
		set("name", name);
		set("id", id);
		this.id = id;
		set("program", example); // example를 program으로 변경하자.
	}
	public LayoutContainer getProgram() {  // 추가하자
		return (LayoutContainer) get("program");
	}
☞ model패키지내에 Page클래스를 추가하자. 이 클래스는 Entry클래스를 받아 TabPanel에 TabItem을 추가할 수 있도록 구현되어 있다.
package com.gxt.riaapp.client.mvc.model;

import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
/**
 * 이 클래스는 Entry를 받아 TabPanel에 추가할 수 있는 TabItem으로 변환하여 TabPanel에 추가하는 역할을 한다.
 * @author KYS
 *
 */
public class Page extends TabPanel {
	protected Entry entry;
	public Page(final Entry entry) {
		this.entry = entry;
		setTabPosition(TabPosition.BOTTOM);
		setBorderStyle(false);
		setBodyBorder(false);
		
		TabItem demo = new TabItem();
		demo.setScrollMode(Scroll.AUTO);
		demo.setHideMode(entry.getHideMode());
		demo.add(entry.getProgram());  // RiaAppModel에서 add한 프로그램
		add(demo);
	}
}

☞ ContentView 클래스의 onShowPage() 메소드를 아래와 같이 추가 코딩하도록 하자.
	public void onShowPage(Entry entry) {
		System.out.println("ContentView.onShowPage() called.." + entry.get("page"));
		Page page = entry.get("page");
	    if (page == null) {	// entry에 page가 세팅되어 있지 않다면 이 Entry는 우측 프로그램 영역에 없는 Entry이다.
	      page = new Page(entry);	// Page객체를 생성하고
	      entry.set("page", page); // entry에 page를 추가한다.
	    }
	    /**
	     * page id로 검색해서 없다면 추가하는 로직
	     */
		TabItem item = tabPanel.findItem("page__" + page.getId(), false);
		if (item == null) {
			item = new TabItem();
			item.setData("entry", entry);
			item.setClosable(entry.isClosable());
			item.setId("page__" + page.getId()); // 나중에 찾을 수 있도록 아이디 세팅
			item.setText(entry.getName());
			item.setLayout(new FitLayout());
			item.add(page); // TabItem
			tabPanel.add(item);
		}
	}
☞ 이제 다시 실행해 보도 록 하자 실행된 브라우저에서 F5키를 누르면 RiaAppModel에 추가한 SmplProgram이 프로그램 영역에 보이는 것을 확인 할 수 있다.
 
3. 여기까지 해서 프로그램영역에 신규로 작성한 프로그램이 출력되도록 코딩하였다. 그러나 위의 그림처림 "시스템사용자관리"가 화면에 출력되는 것은 좌측 메뉴를 클릭해서 출력되는 것이 아니라 RiaApp.java에 RiaAppModel클래스에 등록된 프로그램중 0번째 즉 첫번째 프로그램이 출력되도록 코딩되어 있어 보여지는 것이다.
 등록된 프로그램이 복수개이면 좌측 메뉴를 클릭해서 우측 프로그램 영역에 보여지도록 해야한다. 보통은 Model에 등록된 0번째 프로그램은 게시판이나 전체상황을 볼수 있는 상황판이 떠야하므로 0번째 프로그램에는 게시판이나 상황판을 배치하고 이 후부터 업무용 프로그램을 배치하도록 하는것이 맞을 듯 하다.

이제부터는 여러개의 프로그램을 등록하고 좌측 메뉴의 프로그램을 클릭해서 우측 프로그램 영역에 출력되도록 만들어보자.

☞ SmplProgram.java를 아래와 같이 수정하자.
public class SmplProgram  extends LayoutContainer {
	String txt = "";
	public SmplProgram(String txt) {
		this.txt = txt;
	}
	@Override
	protected void onRender(Element parent, int index) {
		// TODO Auto-generated method stub
		super.onRender(parent, index);
		VerticalPanel vp = new VerticalPanel();
		vp.setSpacing(10);
		Button btn =new Button(txt);
		setLayout(new FlowLayout(10));
		vp.add(btn);
		add(vp);
	}
}


☞ RiaAppModel을 아래와 같이 수정하여 여러개의 프로그램을 좌측메뉴에 추가해보자.
	public RiaAppModel() {
		Category pgm = new Category("시스템관리","SYS00002");
		pgm.add("시스템사용자관리1", "0001", new SmplProgram("시스템사용자관리1"));
		pgm.add("시스템사용자관리2", "0002", new SmplProgram("시스템사용자관리2"));
		pgm.add("시스템사용자관리3", "0003", new SmplProgram("시스템사용자관리3"));
		pgm.add("시스템사용자관리4", "0004", new SmplProgram("시스템사용자관리4"));
		addCategory(pgm);
		loadEntries(this);
	}
☞ 여기까지 실행해서 좌측 트리메뉴를 확인하면 위에서 추가한 4개의 트리가 보일 것 이다. 그러나 트리를 클릭해도 아무런 반응이 없을 것이다. 이제 트리를 클릭했을 경우 우측 프로그램 영역에 프로그램이 보여지도록 하자. 좌측 영역이므로 NavigationView클래스에서 해당 트리가 SelectionChanged 될 경우 클릭한 프로그램이 보이도록 수정하자. 아래와 같이 NavigationView.java의 initialize()메소드에 추가 코딩을 하자.
	@Override
	protected void initialize() {
		super.initialize();
		model = (RiaAppModel) Registry.get(RiaApp.MODEL);
		/**
		 * 트리내에서 다른 트리를 클릭했을 경우.
		 */
		SelectionService.get().addListener(
				new SelectionChangedListener() {
					public void selectionChanged(SelectionChangedEvent event) {
						List sel = event.getSelection();
						if (sel.size() > 0) {
							TreeModel m = (TreeModel) event.getSelection().get(0);
							if (m != null && m instanceof Entry) {
								RiaApp.showPage((Entry) m);
							}
						}
					}
				}
		);
		// 필터 생성
		....
☞ 이제 실행해서 작동이 되는지 확인해보자. 실행하여 좌측 트리메뉴를 펼쳐 클릭해보면 아래와 같이 클릭한 프로그램에 우측 TabPanel에 TabItem으로 추가되는 것을 볼수 있다.

☞ 마지막으로 프로그램 영역의 맨 아래 부분에 대한 처리를 추가하도록 하자. 우리는 프로그램 영역의 아래쪽에 도움말 탭을 추가하려고 한다. 즉 현재 위의 그림과 같이 보여지고 있는 프로그램 영역과 함께 도움말 탭을 추가하여 해당 프로그램에 대한 도움말을 추가할 영역을 만들어 주자. 도움말 영역은 html파일이 추가 될 수 있도록 url을 지정가능하게 하자.

// Entry.java
	public String getSourceUrl() {
		Object o = (Object) get("program");
		String name = o.getClass().getName();

		name = name.substring(name.lastIndexOf("program.") + 9);
		name = "code/" + name + ".html";
		name = name.replaceFirst("\\.", "/");

		return name;
	}
// Page.java
		....
		TabItem demo = new TabItem();
		demo.setScrollMode(Scroll.AUTO);
		demo.setHideMode(entry.getHideMode());
		demo.setText("프로그램");
		demo.add(entry.getProgram());
		add(demo);
		if (entry.isClosable()) {
			TabItem source = new TabItem();
			source.setText("도움말");
			source.setUrl(entry.getSourceUrl());
			add(source);
		}
Posted by 베니94
일상2011. 1. 18. 12:46
mind42.com이라는 사이트에 가면 MindMap이라는 프로그램을 볼 수 있다.
아래 그림은 MindMap로 둘리의 가족 구성원과 성격을 정리해 보았다. 이름 그대로 생각나는 것을 입력하고
파생되는 생각을 이어 붙이게 된다. 이렇게 해서 큰 생각의 지도를 완성한다.


☞ 재밌는 것은 아래와 같이 구글 검색을 통해 각종 이미지를 지도에 추가할 수 있는것이다.
즉 지도를 그리는데 검색엔진을 이용해 영역을 무한대로 넓혀 놓았다는 것..



'일상' 카테고리의 다른 글

iWatch 아이폰과 손목시계가 하나로 ^^  (0) 2011.01.06
Posted by 베니94
GXT RIA App 만들기2011. 1. 18. 12:28

이전 강좌에서 우리는 AppView.java에 프로그램의 뼈대를 구성하였다. 이어 이번에는 좌측화면과, 프로그램영역을 제어할 Controller를 생성하고 이Controller에 의해 제어될 View를 구성해 보자.
1. 좌측 메뉴을 제어할 Controller와 AppView내의 viewport의 좌측에 해당되는 부분을 재정의할 View클래스를 생성한다.

☞ NavigationController.java
package com.gxt.riaapp.client.mvc;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.gxt.riaapp.client.AppEvents;
/** * 좌측트리메뉴를 제어할 컬트롤 클래스 
* @author KYS
* 
*/
public class NavigationController extends Controller{	
	private NavigationView view;	// AppView.java에서 정의한 viewport의 WestPanel을 구성함.	
	public NavigationController() {		
		registerEventTypes(AppEvents.Init);	// 사용할 이벤트 등록	
	}	
	public void initialize() {	    
		view = new NavigationView(this);	 
 	}	
	@Override	public void handleEvent(AppEvent event) {		
		forwardToView(view, event);	// 이벤트가 발생할 경우 view로 이동.	
	}
}
☞ NavigationView.java
package com.gxt.riaapp.client.mvc;
import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.View;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.extjs.gxt.ui.client.widget.TabPanel.TabPosition;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
/** * AppView클래스의 WEST_PANEL을 구성한다. 
*  
* @author KYS 
*  
*/
public class NavigationView extends View {	
	private ContentPanel westPanel;	
	private TabPanel tabPanel;	
	private TabItem listItem, treeItem;	

	@Override	protected void initialize() {		
		// TODO Auto-generated method stub		
		super.initialize();		
		// AppView의 좌측 패널로 정의된 ContentPanel을 얻어온다. 이렇게 얻어오기 위해선		
		// AppView에 Registry.register(WEST_PANEL, westPanel); 와 같이 기술되어 있어야한다.		
		westPanel = (ContentPanel) Registry.get(AppView.WEST_PANEL);		
		westPanel.setHeading("Navigation");		
		westPanel.setLayout(new FitLayout());		
		westPanel.add(createTabPanel());		
		westPanel.syncSize();	
	}	
	public NavigationView(Controller controller) {		
		super(controller);	
	}	
	@Override	protected void handleEvent(AppEvent event) {	
	}	
	private TabPanel createTabPanel() {		
		tabPanel = new TabPanel();		
		tabPanel.setMinTabWidth(70);		
		tabPanel.setBorderStyle(false);		
		tabPanel.setBodyBorder(false);		
		tabPanel.setTabPosition(TabPosition.BOTTOM);	
	
		treeItem = new TabItem();		
		treeItem.setText("Tree");		
		tabPanel.add(treeItem);	
	
		listItem = new TabItem();		
		listItem.setText("List");		
		tabPanel.add(listItem);		
		return tabPanel;	
	}
}
☞ 위에서 주목해야 할 부분은 "westPanel = (ContentPanel) Registry.get(AppView.WEST_PANEL);"으로 AppView.java에 아래와 같이 추가해야한다. AppView에서 각 영역을 생성했고 이 생성된 영역을 Registry에 등록시키므로 해서 어디서든 Registry.get()으로 이용할 수 있다. 세션처럼 말이다.
/** 
* 좌측 메뉴영역 
*/
private void createWest() {    
	...	
	viewport.add(westPanel, data);	
	Registry.register(WEST_PANEL, westPanel);  // Rigistry에 등록
}
/** 
* 중간 프로그램 영역 
*/
private void createCenter() {    
	....		
	viewport.add(centerPanel, data);	
	Registry.register(CENTER_PANEL, centerPanel); // Rigistry에 등록
}
/** * 상단 영역 구성하기 */
private void createNorth() {    
	....	
	viewport.add(northPanel, data);	
	Registry.register(NORTH_PANEL, northPanel);  // Registry에 등록
}
☞ NavigationController를 RiaApp내의 Dispatcher에 추가하자.
	
public void onModuleLoad() {		
	dispatcher = Dispatcher.get();	    
	dispatcher.addController(new AppController());	    
	dispatcher.addController(new NavigationController());  // 좌측	    
	dispatcher.dispatch(AppEvents.Init);	
}

 

☞ 여기까지 코딩이 끝났다면 실행시켜 결과를 확인을 해보자. 좌측 메뉴 패널이 변경된 것을 확인 할 수 있다.


☞ 이제 남은 것은 툴바를 생성하고 툴바내에 필터를 추가할 것이고, 2개의 TabItem, Tree, List TabItem을 구현해야한다. 그러기 전에 2개의 TabItem에 들어갈 객체를 정의해야 한다. 이 객체는 BaseTreeModel을 상속 받고 getter와 setter메소드들로 채워져 있다. 아래는 Entry.java의 전문이다. com.gxt.riaapp.client.mvc 아래 model 패키지를 생성하고 Entry.java 추가하자.
package com.gxt.riaapp.client.mvc.model;
import com.extjs.gxt.ui.client.Style.HideMode;
import com.extjs.gxt.ui.client.data.BaseTreeModel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
/** 
* 좌측 메뉴의 TreeItem과 ListItem에 채워질 entity class 
*  
* @author winkos1 
*  
*/
public class Entry extends BaseTreeModel {	
	private String name;	
	private String id;	
	private boolean fill;	
	private boolean closable = true;	
	private HideMode hideMode = HideMode.DISPLAY;	
	protected Entry() {	
	}		
	/**	 
	* Constructor	 
	* 	 
	* @param name	 
	* @param example	 
	* @param image	 
	*/	
	public Entry(String name, LayoutContainer example, String image) {		
		this.name = name;		
		set("name", name);		
		set("image", image);		
		set("example", example);	
	}	

	public Entry(String name, LayoutContainer example) {		
		this.name = name;		
		set("name", name);		
		set("example", example);	
	}	

	public Entry(String name, String id, LayoutContainer example) {		
		this.name = name;		
		set("name", name);		
		set("id", id);		
		this.id = id;		
		set("example", example);	
	}	

	public Entry(String name, LayoutContainer example, String image,	
				boolean fill) {		
		this(name, example, image);		
		this.fill = fill;	
	}	

	public Entry(String name, LayoutContainer example, String image,	
			boolean fill, boolean closable) {		
		this(name, example, image, fill);		
		this.closable = closable;	
	}	

	public Entry(String name, LayoutContainer example, String image,			
		boolean fill, boolean closable, HideMode hideMode) {		
		this(name, example, image, fill, closable);		
		this.setHideMode(hideMode);	
	}	

	public String getId() {		
		return id;	
	}		

	public HideMode getHideMode() {		
		return hideMode;	
	}	

	public String getName() {		
		return (String) get("name");	
	}	

	public boolean isClosable() {		
		return closable;	
	}	

	public boolean isFill() {		
		return fill;	
	}	

	public void setFill(boolean fill) {		
		this.fill = fill;	
	}	

	public void setHideMode(HideMode hideMode) {		
		this.hideMode = hideMode;	
	}	

	public String toString() {		
		return getName();	
	}
}

☞ 이번에는 Entry클래스의 상위클래스를 생성하자. 이클래스는 Category클래스로 트리에서 parent역할을 담당할 클래스다. model 패키지에 Category.jav를 추가하고 아래와 같이 코딩하자.
package com.gxt.riaapp.client.mvc.model;
import java.io.Serializable;
import com.extjs.gxt.ui.client.Style.HideMode;
import com.extjs.gxt.ui.client.data.BaseTreeModel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
public class Category extends BaseTreeModel implements Serializable {	
	protected Category() {	
	}	

	public Category(String name) {		
		set("name", name);	
	}	

	public Category(String name, String id) {		
		set("name", name);		
		set("id", id);	
	}	

	public String getId(){		
		return  (String)get("id");	
	}	

	public String getName() {		
		return (String) get("name");	
	}	

	public String toString() {		
		return getName();	
	}	

	public void add(String title, LayoutContainer page, String image) {		
		add(new Entry(title, page, image));	
	}	

	public void add(String title, LayoutContainer page, String image,			
		boolean fill) {		
		add(new Entry(title, page, image, fill));	
	}	

	public void add(String title, LayoutContainer page) {		
		add(new Entry(title, page ));	
	}	
	
	public void add(String title, String id, LayoutContainer page) {			
		add(new Entry(title, id,  page ));	
	}	

	public void add(String title, LayoutContainer page, String image,			
		boolean fill, boolean closable, HideMode hideMode) {		
		add(new Entry(title, page, image, fill, closable, hideMode));	
	}
}

☞ NavigationView.java를 수정하자. 수정할 내용은 툴바를 추가하고 툴바내 필터를 삽입한다. 그리고 TreeItem과 ListItem을 구현하도록 하자.
	
private ToolBar toolBar;	
private StoreFilterField filter;
private TreePanel tree;	
private TreeStore treeStore;		
@Override	protected void initialize() {		
	// TODO Auto-generated method stub		
	super.initialize();		
	// 필터 생성		
	filter = new StoreFilterField() {			
		@Override			
		protected boolean doSelect(Store store,					
			ModelData parent, ModelData child, String property,					
			String filter) {								
			String name = child.get("name");				
			name = name.toLowerCase();				
			if (name.indexOf(filter.toLowerCase()) != -1) return true;				
			return false;			
		}		
	};		
	// AppView의 좌측 패널로 정의된 ContentPanel을 얻어온다. 이렇게 얻어오기 위해선		
	// AppView에 Registry.register(WEST_PANEL, westPanel); 와 같이 기술되어 있어야한다.		
	westPanel = (ContentPanel) Registry.get(AppView.WEST_PANEL);		
	westPanel.setHeading("Navigation");		
	westPanel.setLayout(new FitLayout());		
	westPanel.add(createTabPanel());
				
	toolBar = (ToolBar) westPanel.getTopComponent();	    
	IconButton filterBtn = new IconButton("icon-filter");	  
  	    
	filterBtn.setWidth(20);	    
	toolBar.add(filterBtn);	    
	toolBar.add(filter);	    	    

	createListContent();  // ListItem구현	    
	createTreeContent();	// TreeIem구현	
    		
	westPanel.syncSize();	
}	
private void createTreeContent() {	    
	TreeLoader loader = new BaseTreeLoader(new TreeModelReader>()) {	      
		@Override	      
		public boolean hasChildren(ModelData parent) {	        
			return parent instanceof Category;	      
		}	    
	};	    
	treeStore = new TreeStore(loader);	    
	tree = new TreePanel(treeStore);	    
	tree.expandAll();	    
	tree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);	    
	tree.getStyle().setLeafIcon(IconHelper.createStyle("icon-list"));	    
	tree.setDisplayProperty("name");	
    
	SelectionService.get().addListener(new SourceSelectionChangedListener(tree.getSelectionModel()));	    
	SelectionService.get().register(tree.getSelectionModel());	
    
	filter.bind(treeStore);	    

	treeItem.setBorders(false);	    
	treeItem.setLayout(new FitLayout());	    
	treeItem.add(tree);	  
}		
@SuppressWarnings("unchecked")	
private void createListContent() {		
	listItem.setLayout(new FitLayout());	    
	listItem.setBorders(false);	    

	ListView list = new ListView();	    
	list.setDisplayProperty("name");	    
	list.setBorders(false);	    
	list.getSelectionModel().addSelectionChangedListener(new SelectionChangedListener() {	      
		@Override	      
		public void selectionChanged(SelectionChangedEvent se) {	    	  
			Entry e = se.getSelection().get(0);	        
			if (e != null && e instanceof Entry) {	        	
			// 나중에 구현	        		        
			}	      
		}	    
	});	    

	ListStore store = new ListStore();	    
	store.setStoreSorter(new StoreSorter(new Comparator() {	      
		public int compare(Entry e1, Entry e2) {	        
			return e1.getName().compareTo(e2.getName());	      
		}	    
	}));	    

	list.setStore(store);	    
	filter.bind((Store) store);	    
	listItem.add(list);	
}

☞ 여기까지 끝났다면 실행해보도록 하자. 실행 결과를 보면 "Navigation"클자 아래에 필터와 필터버튼이 추가된 것을 제외하곤 달라진 것이 없을 것이다. 아직 Tree에 아무것도 추가하지 않았으므로 보여지는것이 없는 것이다. 이제 좌측메뉴에 트리가 출력되도록 수정해보자.
☞ com.gxt.riaapp.client.mvc하위에 RiaAppModel.java를 추가하자. 이 클래스는 Category와 Entry클래스를 이용해 좌측 TreeItem과 ListItem에 출력될 수 있도록 구성한다. Category는 상위 폴더를 Entry는 폴더아래의 최종 프로그램이라고 할 수 있다.

package com.gxt.riaapp.client.mvc;
import java.util.ArrayList;
import java.util.List;
import com.extjs.gxt.ui.client.data.BaseTreeModel;
import com.extjs.gxt.ui.client.data.ModelData;
import com.gxt.riaapp.client.mvc.model.Category;
import com.gxt.riaapp.client.mvc.model.Entry;
public class RiaAppModel  extends BaseTreeModel {	
	protected List entries = new ArrayList();	

	public RiaAppModel() {		
		Category pgm = new Category("시스템관리","SYS00002");
		//		pgm.add("시스템사용자관리", "0001", new SystemManagerMain());		
		pgm.add("시스템사용자관리", "0001");		
		addCategory(pgm);		
		loadEntries(this);	
	}	

	public void addCategory(ModelData child) {		
		if(child != null)			
			add(child);	  
	}	

	public List getEntries() {		
		return entries;	
	}	

	private void loadEntries(TreeModel model) {		
		for (ModelData child : model.getChildren()) {			
			if (child instanceof Entry) {				
				entries.add((Entry) child);			
			} else if (child instanceof Category) {				
				loadEntries((Category) child);			
			}		
		}	
	}
}

☞ 위 클래스에서는 Category를 생성하고 생성된 Category클래스에 pgm.add()를 이용하여 Entry클래스를 하위로 추가한것을 볼 수 있다. Category클래스의 add()메소드를 보자. add메소드가 여러종류가 있지만 위에서 주석이 된 부분과 그 아래 부분의 add()메소드를 보면 주석달린 add(String title, String id, LayoutContainer page) 메소드는 인자로 LayoutContainer를 받고 있다.
☞ 이 클래스는 우리가 여러개의 프로그램을 작성해서 우측 프로그램 영역에 보여지게 할 것인데 이때 작성되는 프로그램은 모두 LayoutContainer를 상속받아야 한다. 두번째 add(String title, String id)메소드는 테스트를 추가한 메소드로 화면상에 보여주기만 하려고 제목과 아이디만 인자로 받고 있다. 이 메소드를 추가하도록 하자 Category.java와 Entry.java에 아래와 같이 메소드를 추가하도록 하자.
// Category.java
public void add(String title, String id) {		
	add(new Entry(title, id ));	
}

// Entry.java	
public Entry(String name, String id) {		
	this.name = name;		
	set("name", name);		
	set("id", id);		
	this.id = id;	
}
☞ 이제 위에서 작성한 RiaAppModel클래스를 TreeItem과 ListItem에 추가하여 좌측메뉴에 "시스템관리->시스템사용자관리"가 보여지도록 수정해보자. RiaApp.java를 아래와 같이 수정하자.
public static final String MODEL = "RiaAppModel";
private RiaAppModel model;	

public void onModuleLoad() {		
	model = new RiaAppModel();	    
	Registry.register(MODEL, model);  // 최초 실행시 Registry에 RiaAppModel을 등록한다.	    		
	dispatcher = Dispatcher.get();	    
	dispatcher.addController(new AppController());	    
	dispatcher.addController(new NavigationController());  // 좌측	    
	dispatcher.dispatch(AppEvents.Init);	
}
☞ NavigationView.java를 열고 아래와 같이 모델이 세팅될 수 있도록 수정한다.
private RiaAppModel model;
...	
	@Override	
	protected void initialize() {		
		super.initialize();		
		model = (RiaAppModel) Registry.get(RiaApp.MODEL);
		...
	}
	private void createTreeContent() {
		...	    
		filter.bind(treeStore);	    
		loader.load(model); // RiaAppModel set	    	    
		treeItem.setBorders(false);
		...
	}	
	@SuppressWarnings("unchecked")	
	private void createListContent() {
		...	    
		ListStore store = new ListStore();	    
		store.setStoreSorter(new StoreSorter(new Comparator() {	      
			public int compare(Entry e1, Entry e2) {	        
				return e1.getName().compareTo(e2.getName());	      
			}	    
		}));	    
		store.add(model.getEntries());	    	    
		list.setStore(store);
		...
	}

☞ 실행해서 결과를 확인해보자. 아래의 그림과 같이 좌측 트리에 "시스템관리->시스템사용자관리"가 출력되는 것을 볼 수 있다. 필터에 키인을 하고 잘 작동하는지도 확인한다.

Posted by 베니94