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