IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
한국 developerWorks   >   Open developerWorks  > developerworks

로터스 노츠에서의 Gantt Chart 구현



김현우
정우철 woocheol.jeong@gmail.com

소프트웨어 한글화 업무를 하다가 우연하게 노츠에 빠져 들어, 현재는 맥킨지(McKinsey) 서울사무소의 IT 팀에서 관련 업무를 하고 있다. 최근에는 시맨틱 웹을 노츠에서 응용할 수 없을까 하는 공상을 가끔 한다.


난이도 : 초급
2007년 1월 2일


[오픈 디벨로퍼웍스]는 여러분이 직접 필자로 참가하는 코너입니다. 이번에는 정우철님이 작성한 로터스 노츠에서 효과적으로 Gantt Chart를 구현하는 방법을 소개합니다.

로터스 도미노/노츠(Lotus Domino/Notes)를 클라이언트-서버 환경에서 사용하는 고객이 프로젝트 일정을 갠트 차트(Gantt chart)로 표현할 수 있는 노츠 데이터베이스를 의뢰하는 경우, 노츠 애플리케이션 개발자는 잠시나마 고민에 빠질 것이다. 노츠의 캘린더 뷰를 사용하면 달력을 쉽게 구현할 수 있는 것처럼, 갠트 차트를 쉽게 구현할 수 있는 요소가 디자이너에서 제공되면 좋겠으나 아쉽게도 IBM은 개발자에게 그 몫을 남겨놓았다.
일반적으로 갠트 차트는 특정 항목의 제목 또는 설명이 왼쪽 부분에, 일련의 타임 프레임(time frame)이 오른쪽에 위치하며, 타임 프레임 부분에 각 항목의 일정 정보에 맞추어 특정 색으로 강조된 막대가 표시되는 형식이다. 즉, 전체적으로 일정한 테이블 구조라는 사실과 타임 프레임에 해당되는 각 테이블 셀의 배경색을 조정하면 간략하게 표현할 수 있음을 알 수 있다. 이 기사에서는 제3의 다른 구성요소를 사용하지 않고서 노츠가 제공하는 기능만을 활용하여 갠트 차트를 구현하는 방법에 대해 설명한다.
참고로, 이 기사는 디자인과 사용자 인터페이스 등의 요소를 최소화하고 구현 방법 그 자체에 초점을 두고 있다. 미려한 디자인과 편리한 사용자 인터페이스 구성 등은 독자에게 맡긴다.

적합한 구현 방법

갠트 차트를 표현할 테이블은 데이터 항목의 개수에 따라 테이블의 행(row)이 유동적이어야 하며 타임 프레임 또한 시간 흐름 등에 따라 동적으로 표시되어야 하기 때문에, 노츠 폼에서 고정된 행과 열을 갖는 테이블을 활용하거나 노츠 뷰에서 컬럼을 이용하는 방법은 적합하지 않을 수 있다. NotesRichTextItem 클래스를 사용하여 리치 텍스트(rich text) 필드에서 테이블을 동적으로 생성하는 방법도 고려할 수 있으나, 테이블을 자세하게 제어할 수 있는 프로퍼티와 메소드가 충분하게 제공되지 않는다. HTML은 마크업 언어의 특성상 프로그램 실행 중에 동적으로 컨텐츠를 작성하는 것이 가능하므로 이와 같은 요구를 충족시키는 데 적합하다.
노츠 R6에서는 NotesMimeEntity 클래스를 사용해 특정한 MIME(Multipurpose Internet Mail Extensions) 엔티티를 액세스하거나 새로운 엔티티를 생성할 수 있으며, NotesStream 클래스를 통해 엔티티의 컨텐츠를 읽거나 직접 작성하는 등의 조작을 할 수 있다. 그리고 MIME 엔티티가 포함된 문서를 노츠에서 열면 노츠에 포함된 브라우저가 해당 엔티티들을 인식하여 적절하게 화면에 표시해준다.
즉, 개발자는 프로그램 내에서 새로운 MIME 엔티티를 생성하여 동적으로 작성한 HTML을 엔티티에 저장할 수 있고, 사용자는 이 엔티티를 노츠 브라우저를 통해 특별한 노력 없이 볼 수 있다는 의미다. 이들 클래스에 대한 자세한 내용은 디자이너 도움말(Designer Help)을 참조하기 바란다.




위로


예제 데이터베이스

HTML과 MIME 엔티티를 사용하여 갠트 차트를 표시하는 예제 데이터베이스를 실제로 설계해 보자. 최종적으로 표현하고자 하는 갠트 차트에는 프로젝트 제목, 담당자 및 12개월의 타임 프레임을 표시하는 것으로 하고, 프로젝트 일정을 세분화해 표시하기 위해 각 달은 각각 10일씩 상순, 중순, 하순으로 나누어 표시한다. 완성된 예제 데이터베이스에서의 결과 화면은 그림 1과 같다.

그림 1. 최종 결과로 나온 갠트 차트 화면

최종 결과로 나온 갠트 차트 화면

이 데이터베이스에는 표 1에 설명되어 있는 것과 같이 두 개의 폼, 그리고 각각 하나씩의 뷰와 에이전트 요소들을 작성한다. 이후 데이터로서 프로젝트의 간략한 정보가 포함된 문서가 몇 개 작성되어야 한다. 이 요소들 중에서 HTML과 MIME을 사용하여 갠트 차트를 표현하는 핵심 기능은 에이전트가 수행하게 된다.


표 1. 데이터베이스의 요소 및 설명
개발 요소설명
Project form 프로젝트의 간략한 정보를 포함한다. 이 폼으로 작성된 각 문서들의 정보가 갠트 차트에서 하나의 행으로 표시된다.
Gantt form 에이전트가 생성한 MIME 엔티티가 포함되고, 갠트 차트가 실제로 화면에 표시되는 폼이다. 읽기 전용으로 사용되기 때문에 문서로서 저장되지는 않는다.
Project view 프로젝트 폼의 모든 문서들이 이 뷰에 표시된다. 에이전트가 이 뷰에 표시된 모든 문서들을 액세스한다.
Gantt agent 프로젝트 뷰에 있는 문서들을 액세스하고 그 정보에 따라 갠트 차트를 표현하는 HTML을 동적으로 생성한 후, 갠트 폼의 문서에 MIME 엔티티로 저장해 화면에 표시한다.

이제 구현하고자 하는 방법과 최종 결과, 작성해야 할 요소가 대략적으로나마 정의되었다. 이제 각각의 요소들을 작성해 보자.




위로


프로젝트 폼에는 프로젝트 제목, 담당자, 시작일과 종료일 등 간략한 정보가 포함되는 필드 네 개를 작성한다. Title과 Manager 필드는 Text 타입이고, BeginDate와 EndDate 필드는 Date 타입이며 날짜만 표시하는 것으로 Field properties에서 설정한다. 그림 2는 이와 같이 작성한 프로젝트 폼의 결과 화면이다.

그림 2. 완성된 프로젝트 폼

완성된 프로젝트 폼

갠트 폼에서는 MIME 엔티티가 포함될 리치 텍스트 타입의 Body 필드를 작성한 후, 그림 3에서와 같이 Field properties에서 ‘Store contents as HTML and MIME’ 옵션을 선택한다.

그림 3. Body 필드의 Field properties

Body 필드의 Field properties

사용자가 이 폼을 사용해 직접 문서를 저장할 것은 아니므로, Form properties에서 ‘Create in Menu’ 옵션을 선택하지 않는다. 또한 문서를 닫을 때 나타날 수 있는 Save 화면을 나타나지 않게 하기 위해 SaveOptions 필드를 작성하고 기본 값으로 “0”을 설정한 후, properties에서 노츠 화면에 표시되지 않도록 설정한다. 이와 같이 완성한 갠트 폼의 화면은 그림 4와 같다.

그림 4. 완성된 갠트 폼

완성된 갠트 폼


위로


프로젝트 뷰에서는 프로젝트 폼의 모든 필드 값을 표시하기 위해 컬럼을 모두 네 개 작성한다. 각 컬럼의 값으로서 Title, Manager, StartDate 및 EndDate 필드를 지정한다. 그림 5는 이와 같이 작성한 결과 화면이다.

그림 5. 완성된 프로젝트 뷰

완성된 프로젝트 뷰


에이전트

갠트 에이전트는 프로젝트 뷰에 있는 모든 문서를 순차적으로 액세스하면서 적절한 HTML 코드를 생성해 새로운 MIME 엔티티에 저장하는 가장 중요한 역할을 수행한다. 사용자가 Actions 메뉴에서 이 에이전트를 선택하여 실행하도록 하기 위해 Agent properties의 runtime 옵션에서 ‘on event’와 ‘actions menu selection’을 선택하고, target 옵션에 None을 선택한다.
이 에이전트를 통해 만들고자 하는 갠트 차트에는 첫 번째와 두 번째 컬럼에 프로젝트 제목과 담당자를 표시하고, 이후 현재 달부터 12개월 동안의 타임 프레임을 표시하고자 한다. 각 달은 10일씩 나누어 초순, 중순, 하순으로 구분하고 해당 타임 프레임의 테이블 셀이 프로젝트의 시작일과 종료일 사이에 해당된다면 셀의 배경 색을 다른 색으로 표시하여 프로젝트가 진행되는 기간임을 나타낸다.
이 에이전트의 초기화(Initialize) 이벤트에 포함되어야 하는 전체 LotusScript 코드는 리스트 1과 같다.

리스트 1. 갠트 에이전트의 초기화 이벤트 코드

  

Sub Initialize
‘ ===== Part 1 =====
	Dim uiws As NotesUIWorkspace
	Dim ss As NotesSession
	Dim db As NotesDatabase
	Dim vw As NotesView
	Dim vwec As NotesViewEntryCollection
	Dim vwe As NotesViewEntry
	Dim projDoc As NotesDocument
	Dim ganttDoc As NotesDocument
	Dim mime As NotesMimeEntity
	Dim stream As NotesStream
	Dim i As Integer
	
	Set ss = New NotesSession
	Set db = ss.CurrentDatabase
	Set vw = db.GetView("Project")
	Set vwec = vw.AllEntries
	ss.ConvertMime = False
	Set ganttDoc = New NotesDocument(db)
	Call ganttDoc.AppendItemValue("Form", "Gantt")
	Set mime = ganttDoc.CreateMIMEEntity("Body")
	Set stream = ss.CreateStream()
	
‘ ===== Part 2 =====
	Call stream.WriteText(|<html>|, 0)
	Call stream.WriteText(|<head>|, 0)
	Call stream.WriteText(|<meta HTTP-EQUIV="content-type" CONTENT="text/html; charset=EUC-KR">|, 0)
	Call stream.WriteText(|<title>Project Gantt Chart</title>|, 0)
	Call stream.WriteText(|<style type="text/css">|, 0)
	Call stream.WriteText(|BODY {|, 0)
	Call stream.WriteText(|font-family: Tahoma;|, 0)
	Call stream.WriteText(|font-size: 8pt;|, 0)
	Call stream.WriteText(|}|, 0)
	Call stream.WriteText(|TD, TH {|, 0)
	Call stream.WriteText(|font-size: 8pt;|, 0)
	Call stream.WriteText(|}|, 0)
	Call stream.WriteText(|</style>|, 0)
	Call stream.WriteText(|</head>|, 0)
	Call stream.WriteText(|<body>|, 0)
	Call stream.WriteText(|<b>Project Gantt Chart</b>|, 0)
	Call stream.WriteText(|<table cellpadding=1 cellspacing=0 style="border:solid black 1px;"> |, 0)
	Call stream.WriteText(|<tr>|, 0)
	' table header
	Call stream.WriteText(|<th align="center">제목</th>|, 0)
	Call stream.WriteText(|<th align="center">담당자</th>|, 0)
	For i = 0 To 11
		Call stream.WriteText(|<th colspan=3 align="center">| + 
		Format$(Datenumber(Year(Today), Month(Today) + i, 1), "mmm") + |</th>|, 0)
	Next	Call stream.WriteText(|</tr>|, 0)
	
‘ ===== Part 3 =====
	Set vwe = vwec.GetFirstEntry()
	Do While Not vwe Is Nothing
		Set projDoc = vwe.Document
		Call stream.WriteText(|<tr>|, 0)
		Call stream.WriteText(|<td>| + projDoc.GetItemValue("Title")(0) + |</td>|, 0)
		Call stream.WriteText(|<td>| + projDoc.GetItemValue("Manager")(0) + |</td>|, 0)
		For i = 0 To (12 * 3 - 1)
			Dim beginDate As Variant, endDate As Variant
			If projDoc.GetItemValue("BeginDate")(0) < Datenumber(Year(Today), Month(Today), 1) Then
				beginDate = Datenumber(Year(Today), Month(Today), 1)
			Else
				beginDate = projDoc.GetItemValue("BeginDate")(0)
			End If
			If projDoc.GetItemValue("EndDate")(0) > Datenumber(Year(Today), Month(Today) + 13, -1)
			Then
				endDate = Datenumber(Year(Today), Month(Today) + 13, -1)
			Else
				endDate = projDoc.GetItemValue("EndDate")(0)
			End If
			If Datenumber(Year(Today), Month(Today) + Int(i / 3), 
			(i Mod 3 + 1) * 10 + 1) > beginDate And  Datenumber(Year(Today), 
			Month(Today) + Int(i / 3), (i Mod 3) * 10 + 1) <= endDate Then
				Call stream.WriteText(|<td bgcolor="#A0A000" width=8>&nbsp;</td>|, 0)
			Else
				Call stream.WriteText(|<td width=8>&nbsp;</td>|, 0)
			End If
		Next
		Call stream.WriteText(|</tr>|, 0)
		
		Set vwe = vwec.GetNextEntry(vwe)
	Loop
	Call stream.WriteText(|</table>|, 0)
	Call stream.WriteText(|</body>|, 0)
	Call stream.WriteText(|</html>|, 0)

‘ ===== Part 4 =====
	Call mime.SetContentFromText(stream, "text/html;charset=EUC-KR", 1725)
	Call ganttDoc.CloseMIMEEntities(True, "Body")
	Set uiws = New NotesUIWorkspace
	Call uiws.EditDocument(False, ganttDoc)
	ss.ConvertMime = True
End Sub


이 코드를 수행하는 역할에 따라 크게 네 개 부분으로 나누어서 설명하면, 1번 부분은 필요한 변수의 선언 및 초기화에 해당되는 것으로 필요한 변수를 설정하고 프로젝트 뷰의 모든 엔트리에 액세스하기 위해 NotesViewEntryCollection 오브젝트를 준비한다. 노츠가 MIME 엔티티를 자동으로 노츠 형식으로 변환하는 것을 방지하기 위해 NotesSession의 ConverMime 프로퍼티를 False로 지정하는 것이 필요하다. 이 값은 추후 에이전트의 실행이 종료되기 전에 다시 True로 설정될 것이다. 이후 갠트 폼을 갖는 새로운 백엔드 문서(back-end document) 오브젝트와 새로운 MIME 엔티티 오브젝트, HTML 컨텐츠를 기록할 NotesStream 오브젝트를 생성한다.
2번 부분부터 갠트 차트를 표현하는 HTML 코드 작성을 시작해 NotesStream.WriteText 메소드를 사용하여 NotesStream 오브젝트에 저장한다. HTML 형식에 따라 적합한 HTML 헤더를 기록한 후, 테이블의 첫 번째 행에 컬럼 이름으로 ‘제목’, ‘담당자’ 및 타임 프레임에 해당되는 ‘월 이름’을 기록한다. 각 달은 3개의 컬럼으로 세분화되므로 ‘월 이름’ 컬럼에는 colspan=3 속성이 지정되어야 한다.
3번 부분의 코드는 프로젝트 뷰에 표시되는 모든 문서를 While 구문 내에서 순차적으로 액세스하면서, 필요한 정보를 가져와 갠트 테이블의 컨텐츠를 작성한다. 타임 프레임에 해당되는 테이블 셀은 한 행에 총 12x3개이므로 For 루프를 이 횟수만큼 수행하면서 각 셀에 해당되는 날짜와 프로젝트의 시작일 및 종료일을 비교하여, 해당되는 경우 셀의 배경 색을 지정하는 TD 구문을 기록한다. 하나의 뷰 엔트리를 이와 같이 처리한 후, < /tr>로 테이블 행을 닫고 다음 뷰 엔트리를 처리한다. 모든 문서를 처리한 후에는 HTML 코드를 완료함으로써 필요한 HTML 코드 생성이 종료된다. 마지막 부분에서는 HTML 코드가 포함된 NotesStream 오브젝트를 NotesMimeEntity의 SetContentFromText 메소드를 사용하여 Body 필드에 저장한다. 이때 컨텐츠 타입은 반드시 text/html이 되어야 하며, 캐릭터셋(charset)과 인코딩 값으로는 표시될 데이터의 언어에 따라 적절한 값을 지정한다. 이후 CloseMIMEEntities 메소드로 MIME 엔티티 처리를 종료하고 NotesUIWorkspace.EditDocument를 통해 작성된 백엔드 문서를 화면에 표시한다. 그리고 에이전트가 종료되기 전에 NotesSession.ConvertMime 프로퍼티를 다시 True로 설정한다.

결론 및 추후 과제

이상으로 MIME 엔티티를 자체적으로 표시할 수 있는 노츠의 기능과 MIME 엔티티를 프로그램에서 조작할 수 있는 LotusScript의 클래스를 사용하여, HTML로 표현할 수 있는 간단한 갠트 차트를 작성해 보았다. 이 방법은 필요에 따라 갠트 차트가 포함된 노츠 메일을 전송하는 것으로 응용할 수 있으며, 동적 테이블의 구현 등이 필요한 상황에 대해서도 적용할 수 있는 이점이 있다.
그러나 상당히 많은 문서가 있는 데이터베이스 또는 느린 네트워크 사용자가 많은 환경에 이 방법을 적용하는 경우, 모든 문서가 에이전트 내에서 순차적으로 액세스되는 구조 때문에 만족할 만한 응답 시간을 얻지 못할 수 있다. 또한 내용이 변경되지 않은 문서의 정보가 갠트 차트를 표시할 때마다 액세스되어야 하는 것 또한 성능에 있어 최적화되지 않은 면을 보인다. 이러한 제한점들은 자체적으로 캐시 알고리듬을 구현하거나 로컬 복제(local replica)를 사용하는 등의 방법을 통해 어느 정도 개선할 수 있을 것이다.
디자인 면에 있어 CSS(Cascade Style Sheet)를 적절히 사용하면 더 세련된 갠트 차트를 표시할 수 있으나, 노츠 R6에서는 모든 CSS 요소들의 사용을 완벽하게 지원하지 않는다. 기회가 되면 같은 주제에 대한 다른 접근 방식으로서 웹 브라우저 컨트롤과 CSS를 활용하는 방법에 대해 소개하겠다.




위로


참고 자료
Lotus Designer Help


dW의 관련 기술 자료

  1. How To Access HTML in a Rich Text Field Using LotusScript
  2. Domino 4.6: MIME support





이제 전문가의 글을 단순히 ‘보는 것’에서, 직접 여러분이 developerWorks의 필자가 될 수 있습니다. IBM developerWorks를 통해 공유하고 싶은 지식이 있으신 분들은 원고 기획안을 접수해주세요. 채택되신 분께는 소정의 원고료를 드립니다.
Open developerWorks 신청하기   MS워드 아이콘   아래아한글 아이콘



[지난 open dW 보기]

사이트 여행

dW 커뮤니티
포럼 | 블로그 | Spaces
dW Student Community

로컬 컨텐츠

행사 및 세미나

기획 기사

개발자 입문

튜토리얼 및 교육

TOP 10 인기자료

SW 다운로드

RSS 피드

뉴스레터
  
자바스크립트가 작동이 중지되었습니다. 이 기능을 수행하시려면 브라우저에서 자바스크립스트를 작동시켜 주시거나 이곳을 클릭해주세요.
Special offers
IBM SOA Sandbox 시험판
dW Student Community
로보코드
코드 트레이닝


    IBM 소개 개인정보 보호정책 문의