Category Archives: 소프트웨어

Qt 4.2: 스타일시트

말도 많고 탈도 많았던 Qt 4.2가 드디어 나왔다. 가장 큰 차이점은 http://doc.trolltech.com/4.2/qt4-2-intro.html 페이지에 그대로 나와 있다. Qt 4.2 덕분에 QOM에서 해결하지 못했던 난제 중 하나인 사용자 정의 온라인 사전 찾기 기능(기본적으로 뇌입어, 위키낱말사전 제공 예정), 시스템 트레이 상주(쓸 사람 있으려나) 등의 구현이 쉬워졌지만, 트롤텍이 말씀하시길 이 모든 기능을 저 골로 보낼 수 있는

“위젯 스타일시트”

가 등장하였다. CSS를 모르는 사람은 없을 것이다. 그런데 그런 CSS가 웹에만 쓰이는 것이 아니라 데스크탑 테마를 꾸미는 데 사용된다고?! 그것도 우리가 늘상 보아 오는 그런 것들에?! 나도 처음에는 이 개념이 잘 이해가 가지 않았지만, 위젯 스타일 시트 문서를 보니까 조금씩 이해가 가기 시작했다. 우선 간단한 예제를 보자.
이 예제는 Qt 4.2에 포함되어 있는 스타일시트 예제이다. 일단 이것을 기본값으로 실행시키면 평범한 윈도 프로그램인 척 하고 있다.

Coffee 스타일시트를 적용시키면 이렇게 변신한다.

Pagefold 스타일시트는 이렇게 변하는데, 우리가 주목해야 할 것은 엄마친구아들이 아닌, QWidget에 걸려 있는 백그라운드이다. 즉, 다른 클래스에도 스타일시트를 적용하면 간지나는 버튼을 만들기 위해서 고민해야 할 필요가 없다는 것이다.

KDE4가 아마도 Qt 4.2 기반으로 탄생할 것이라고 하는데, 이렇게 되면 테마 만들기가 더욱 수월해 질 것이라고 하며, 위젯들의 OpenGL 기반 렌더링까지 지원하기 때문에 별의별 일이 가능해질 것이라고 한다. 일단 QOM에도 스타일시트 기반 스킨 기능을 추가시키는 것이 좋을 것 같은데… 아직 QOM 2가 끝나지 않은 상태에서 섣부른 기댄가.

Qt에서 프로그램 설정 저장하기

언제 나올지 모르는 QOM 2.0을 작업하고 있는 이 시점에서 최근 이뤄진 기능은 환경 설정과 저장이다. 대부분의 프로그램이 따르듯이 시작 시 로드/종료 시 저장 모델을 따르기 위해서 시작 시 레지스트리나 C:\Documents and Settings\%USERNAME%\Application Data\QOM 같은 폴더에 파일을 쓴 다음 불러오는 모델을 취하려고 했다. 그래서 QOM의 입력/테스트 플러그인 모두가 개별 설정을 가질 수 있도록 하였고, API에 LoadConf와 InitTest2 함수가 추가되었다. 이들은 각각 설정과 관련되어 있는 함수이다.
그런데 내가 plain text 파일로만 할 것인가? 그래서 레지스트리에 저장도 고민해 보았지만 이것은 크로스 플랫폼적인 방법이 아니다. QOM의 장점 중 하나인 리눅스 및 맥 OS X 소스 호환성을 내가 앞장서서 깰 이유는 없기 때문이다. 그래서 찾다찾다 고민하다 나온 것이 QSettings 클래스이다. 이 녀석은 다양한 곳에 단순하게 쓸 수 있는 것이 을 연상시킨다.
쓰는 방법이 실제로 간단하다. 우선 ui가 시작되는 곳에
QSettings settings("회사명", "프로그램명");
을 집어넣는다. 그리고 설정을 읽어오려면
global.showwords = ksets.value("module/showwords", false).toBool();
global.random = ksets.value("module/random", false).toBool();
global.inverse = ksets.value("module/inverse", false).toBool();
global.whole = ksets.value("module/whole", true).toBool();
global.list_inverse = ksets.value("module/list_inverse", false).toBool();
global.words_count = ksets.value("module/words_count", -1).toInt();

같이 value 함수를 이용해서 원하는 경로에 있는 값을 읽어올 수 있다. 그리고 설정을 쓰는 것은 프로그램이 종료될 때 똑같은 선언을 해 준 다음
ksets.setValue("module/showwords", global.showwords);
ksets.setValue("module/random", global.random);
ksets.setValue("module/inverse", global.inverse);
ksets.setValue("module/whole", global.whole);
ksets.setValue("module/list_inverse", global.list_inverse);
ksets.setValue("module/words_count", global.words_count);
ksets.setValue("module/encoding_name", global.encoding_name);

와 같이 setValue를 사용해 주면 된다. 기본적으로 모든 플랫폼에서 가장 적합한 방법을 고르기 때문에 문제가 생길 가능성은 없다. 윈도의 경우 레지스트리 키가 이렇게 생긴다.
리눅스의 경우 conf 파일이 비슷하게 생긴다고 알고 있으며, 결론은 귀찮게 레지 값이나 텍스트 파일 찌르는 것보다 이런 게 더 낫다는 것이다.

태터용 Monobook 스킨

그게 바로 지금 쓰고 있는 스킨이다. 전의 스킨에 비해서 상당히 허접해진 것 같은데, 이건 어쩔 수 없다. 내 HTML 실력이 영 안 좋아서 말이다. 이것을 하기 위해서 미디어위키의 페이지를 하나 얻어 온 다음 그것을 무작정 태터의 기본 스킨에 합쳐 버렸다. 그리고 위키와 블로그가 서로 다른 개념을 가지고 접근하기 때문에 이것을 해결해야만 했다.
위키는 한 페이지에 하나의 글이 있다는 것을 전제로 하고, 아무나 수정할 수 있기 때문에 수정이 쉬워야 하며 하나의 글을 기준으로 작성해도 된다. 그러나 블로그는 한 페이지에 여러 개의 글이 올 수 있으며 주인장 말고는 편집할 수 있는 사람이 없다. 이를 극복하기 위하여 미디어위키의 스타일을 대부분 뜯어고쳤다.
한편 미디어위키의 모노북 CSS 파일에도 블로그로 쓰기는 부적합한 부분이 몇 군데 있는데 그 중 하나가 왼쪽 사이드바이다. 사이드바의 넓이를 더 넓혀야 했으며 display 속성이 block으로 되어 있는 부분을 inline으로 되돌려야 했다. 그래서 br 태그가 없는데도 불구하고 링크들이 각 줄에 하나씩만 표현되는 이상한 현상이 계속 나타났다.
당분간 이 스킨은 블로그 메인으로 쓰일 예정이다. 그와 함께 더더욱 업그레이드 될 것이다.

데이터베이스와 함께한 오전

뷁키백과는 데이터베이스 엔진으로 미디어위키를 쓴다. 그런데, 뷁키백과 데이터베이스를 흔드는 과정에서 미디어위키 데이터베이스에 너무 많은 글이 들어가서 글 개수 통계가 섞이는 등 만행이 일어났기 때문에 이런 특단의 조치로 전체 리비전을 지웠다.

  1. 우선 리비전을 지울 글을 클릭해서 “편집”을 누른다.
  2. 그 다음, 명령줄에서 "php -cli nukePages.php [페이지_제목]"을 입력한다.
  3. 다 되면 저장을 누른다.

그런데 이 과정에서 ㅅㄱㅎ 문서가 제대로 복구되지 않아서 옛 버전으로 남아있었다는 것을 망각했던 채

php -cli nukePages.php ㅅㄱㅎ

이 명령을… 때렸다! 처참한 결과만 남아서 울고 있었다. 위키백과의 특정 버전 삭제와는 다르게 이 명령은 데이터베이스 자체적으로 모든 것을 지우기 때문에, undo가 가능한 특정 버전 삭제와는 달리 동작은 한 방향이다. 이럴 때 쓸 수 있는 말이 OTL이지.
그러나 하늘이 무너져도 희망은 있는 법. 윈도우 서버 RWAPM이라는 것이 떠올라서 그 녀석을 통해서 전에 받아 두었던 DB 전체 백업을 다시 올렸다. 그리고 phpMyAdmin으로 들어가서 페이지를 찾아야 했다. 그렇지만 미디어위키의 너무 철저한 리비전 때문에 한 문서를 가르키는 테이블이 총 3종류 있다. 그 셋은 [prefix]_page, _text, _revision이다. 이제 이 세 테이블을 따라가 보자. [prefix] 값은 적절한 것을 찾으면 되고 여기서는 brw_이다.
우선, brw_page 테이블에서 page_title을 기준으로 ㅅㄱㅎ를 검색한다. 그러면 그에 대응하는 page_id와 page_latest 값을 찾을 수 있다. page_id 값과 page_latest 값을 기억한 다음, brw_revision에서 rev_id 기준으로 아까 찾은 값을 대입해서 검색한다. 그러면 rev_page 값과 page_id 값이 같으면 빙고라는 뜻을 이야기한다. 그 다음 brw_text로 간다.
그런데 이 녀석이 BLOB으로 기록되어 있다? 그래서 phpMyAdmin은 보여 주기를 거부하고 있다. 그것 때문에 MySQL을 직접 건드려도 봤으나 별 소득이 없었다. 그러다가 내 눈에 들어온 것이…

Export

였다! 즉, CSV 파일로 내보낸 다음에 검색하면 된다는 뜻이다. 이것을 몰라서 오늘 오전 내내 허공에다가 삽질하고 있었다. CSV 파일에서 검색은 page_latest 값을 기준으로 검색하면 내용이 나온다. 그러나, 다행히도 내용의 일부를 기억하고 있기 때문에 그것을 기준으로 검색을 해서 결국 문서를 살렸다.
오늘의 결론.

  • 백업과 복원을 생활화하자.
  • 무엇이든지 원리와 구조를 알고 논리적으로 접근하자.
  • 경희누나 미안.

결국 Drupal 포기

최근 KSA Ubuntu 서버를 Ubuntu 5.10->6.06.1로 업그레이드하면서 많은 것이 바뀌었다. 가장 크리티컬했던 것은 MySQL 5였다. 그런데 MySQL 4에서 물어 보지도 않고 그냥 5로 올려 버렸기 때문에 문자 인코딩 문제를 건너뛸 수 없었고, 결국에는 Drupal과 Mediawiki가 충돌하는 사태까지 벌어졌다.
게다가 Drupal 4.7의 로그인 버그는 이제 참고 쓰기에 심각한 수준이 되었으며, 옛날에 버렸던 태터툴즈가 GPL이라는 옷을 입고 다시 도착했기 때문에 TT로 복귀하는 데 대해서 미련이 없어졌다. 하지만 기존의 Drupal로 썼던 글들을 어떻게 처리하냐? 그 문제가 있었다. 단지 테이블의 헤더만 바꾸어 주면 된다. Drupal의 node_revisions 테이블에서 tt_Entries 테이블로 다음과 같이 처리해 주면 된다.
owner - 1
id - nid 값 사용
draft - 0
visibility - 2
category - 1
title - 그대로
slogan - title에서 공백을 하이픈으로 변경
content - body
location - /
password - 글을 테스트로 쓴 다음 거기서 추출
published - timestamp
created - timestamp
modified - timestamp

그 동안 정도 많이 들었던 Drupal이지만, 이렇게 떠나보낸다는 게 서운도 하다. 하지만 난 절대로 Drupal을 개인 블로그용으로 권장하고 싶지 않다. 호랑이를 토끼 우리 안에 집어넣고 키우는 꼴이라고 할까.