Doxygenの設定メモ

今までpdf出力は文字化けがするので諦めていた。 以下のサイトを参考に色々と試したら、文字化けが治ったしフォントも綺麗になった。

残念ながら、今はもう紙の関数仕様書を要求する仕事は無いし、おそらくこれからも無いので単純に趣味の世界です。

で、作業メモ。

環境

環境は、macPortsで構築した。

  • macosx 10.12.4
  • xcode 8.3.1
  • MacPorts 2.4.1
  • TeX Live 2016/MacPorts 2016_4
  • doxygen 1.8.13

構築したと言っても以下の1行を入力しただけ。

$ sudo port install texlive +full

Doxyfileファイルの設定

最低限、以下の3項目を変更すれば良い。

OUTPUT_LANGUAGE = English
LATEX_CMD_NAME  = latex
USE_PDFLATEX    = YES

これらの項目を以下のように変える。

OUTPUT_LANGUAGE = Japanese
LATEX_CMD_NAME  = uplatex
USE_PDFLATEX    = NO

それぞれの意味は、参考にしたサイトに載っているので特にここでは書かない。

ソースコードの位置や出力ファイルの位置も各自に合わせること。

最初の出力

一度、doxygenコマンドを実行して、latexディレクトリを生成する。

生成されたmakeファイルを実行すると文字化けのするpsファイルやpdfファイルしか作成できない。

その壊れたlatexディレクトリ中のmakeファイルを修正する。

修正箇所は3箇所。

1. pdfの生成にはdvipdfmxを使う

PostScriptファイルから生成している箇所をdvipdfmxから生成するように変更するだけです。

以下の箇所を変更します。

refman.pdf: refman.ps
       ps2pdf refman.ps refman.pdf

変更後は以下のようになります。

refman.pdf: refman.dvi
       dvipdfmx refman.dvi

2. pdfの複数のページを1ページにまとめるにはpdfnupを使う

ps2pdfはうまく日本語が通らないようなので、pdfnupを使います。

以下の箇所を変更します。

refman_2on1.pdf: refman_2on1.ps
       ps2pdf refman_2on1.ps refman_2on1.pdf

変更後は以下のようになります。

refman_2on1.pdf: refman.pdf
       pdfnup refman.pdf
       mv refman-nup.pdf refman_2on1.pdf

3. 複数のpdfをまとめたファイルの後片付けをする

おそらく、doxygenの記載漏れ。clean時にrefman_2on1.pdfも含めるだけ。

以下の箇所を変更します。

clean:
       rm -f *.ps *.dvi *.aux *.toc *.idx *.ind *.ilg *.log *.out *.brf *.blg *.bbl refman.pdf

変更後は以下のようになります。

clean:
       rm -f *.ps *.dvi *.aux *.toc *.idx *.ind *.ilg *.log *.out *.brf *.blg *.bbl refman.pdf refman_2on1.pdf

pdfに目次を作る

ここまでの変更を行うとpdfの文字化けは治ります。ここから先は、大抵の人には関係ありません。

印刷時の目次はあります。ここで作る目次は、pdfのbookmarkと呼ばれる機能です。

リンクの色は黒。bookmarkはdvipdfmxに対応させる。

% Hyperlinks (required, but should be loaded last)
\usepackage{ifpdf}
\ifpdf
  \usepackage[pdftex,pagebackref=true]{hyperref}
\else
  \usepackage[ps2pdf,pagebackref=true]{hyperref}
\fi
\hypersetup{%
  colorlinks=true,%
  linkcolor=blue,%
  citecolor=blue,%
  unicode%
}

上記のコードを以下に置き換え。

% Hyperlinks (required, but should be loaded last)
% hyperrefをdvipdffmx用に決め打ち
\usepackage[dvipdfmx,
            pagebackref=true,
            colorlinks=true,
            linkcolor=darkgray,
            urlcolor=darkgray,
            bookmarks
           ]{hyperref}
\usepackage{pxjahyper} % 日本語で'しおり'したい

これで、目次も出来て、リンクも作成された。

見た目を整える

完全に趣味です。

本文を明朝体にして、章立てやラベルはゴシック体に変更する。

% Custom commandsの末尾にでも以下のコードを追加する。

\usepackage[uplatex,deluxe, expert]{otf}

% sectionの書体を"ゴシック体、サンセリフ体、太字"
\allsectionsfont{
\gtfamily\sffamily
\color{darkgray}
}

% labelの書体を"ゴシック体、サンセリフ体、太字"
\renewcommand{\DoxyLabelFont}{
\gtfamily\sffamily
\color{darkgray}
}

\renewcommand{\kanjifamilydefault}{\mcdefault} % 日本語書体を明朝体
\renewcommand{\familydefault}{\rmdefault} % 欧文書体をローマン体

また、細すぎるので表紙のタイトルはゴシック体のボールドにする。begin{titlepage}の次の行に追加。

\begin{titlepage}
\gtfamily\sffamily\bfseries % <-- これを追加

ヒラギノフォントを使っているかも

macPorts の場合以下のコマンドでヒラギノを有効にした記憶があるが定かでは無い。

$ cd /opt/local/share/texmf-texlive/scripts/cjk-gs-integrate
$ sudo perl cjk-gs-integrate.pl --link-texmf --force
$ sudo mktexlsr
$ sudo kanji-config-updmap-sys hiragino-elcapitan-pron

以下のコマンドではヒラギノが埋め込まれているように見える。

$ pdffonts refman.pdf

参考URL

次は、上記のサイトのように、スクリプトで自動化したい。

Cocoaからのライブ変換(LiveConversion)の変更と監視

今の所、専用のAPIは見つかっていない。設定ファイルやDistributedNotificationの監視で見つかった事を書く。

  • 変更の監視
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   [[NSDistributedNotificationCenter defaultCenter]
           addObserver:self
              selector:@selector(jimPreferencesDidChangeNotification:)
                  name:@"com.apple.inputmethod.JIM.PreferencesDidChangeNotification"
               object:nil
    suspensionBehavior:0];
}

- (void) jimPreferencesDidChangeNotification:(NSNotification*)note
{
    NSLog(@"jimPreferencesDidChangeNotification => %@",
          [note.userInfo valueForKey:@"JIMPrefLiveConversionKey"]);
}
  • 現在の設定の確認
NSUserDefaults* theUD = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.inputmethod.Kotoeri"];

NSLog(@"[theUD valueForKey:JIMPrefLiveConversionKey] => %@",
        [theUD valueForKey:@"JIMPrefLiveConversionKey"]);

Warning

ImputMethodのprefarenceを参照しているだけなので、sandbox環境では正常に動作しない。

  • ライブ変換を有効/無効にする

有効

[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.inputmethod.JIM.PreferencesDidChangeNotification"
                                                                  object:@"com.apple.JIMSession"
                                                                userInfo:/*@{@"JIMPrefLiveConversionKey" : @(1)}*/ // <--コメントアウトを外して使用すること
                                                                 options:0];
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.inputmethod.JIM.PreferencesDidChangeNotification"
                                                                  object:@"com.apple.JIMPreferences"
                                                                userInfo:/*@{@"JIMPrefLiveConversionKey" : @(1)}*/ // <--コメントアウトを外して使用すること
                                                                 options:0];

無効

[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.inputmethod.JIM.PreferencesDidChangeNotification"
                                                               object:@"com.apple.JIMSession"
                                                             userInfo:/*@{@"JIMPrefLiveConversionKey" : @(0)}*/ // <--コメントアウトを外して使用すること
                                                              options:0];
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.inputmethod.JIM.PreferencesDidChangeNotification"
                                                               object:@"com.apple.JIMPreferences"
                                                             userInfo:/*@{@"JIMPrefLiveConversionKey" : @(0)}*/ // <--コメントアウトを外して使用すること
                                                              options:0];

Warning

sandbox環境では、NSDistributedNotificationはuserInfoにデータを渡すことはできない。sandbox環境では動作しない。

以上のコードでライブ変換の監視/変更が出来るが、sandbox環境では正常動作しない。 sandbox環境で動作するのは変更したタイミングの取得だけ。

“HIToolbox/TextInputSources.h”にあるInputSourceの変更が正規のAPIの可能性があると思い、TISCreateInputSourceListで取得できるリストを見たがそれらしきものはなかった。

最小限アウトラインプロセッサの作り方

Cocoa勉強会松戸用の資料。

NSOutlineViewとNSTreeControllerを使って、”Copy&Paste”,”書類の保存と読み込み”,”Drag&Drop”の実装までの最小限アウトラインプロセッサの作り方の資料です。

なお、ソースコードとPDFはここです。

( TreeOutliner_01.zip ) ( 最小限アウトラインプロセッサの作り方.zip )

解説は当日に行います。

pragma markによるメソッドの分類

この記事は、pragma markを最初にコピペする事でクラス実装の抜けや漏れを防ぐ方法の紹介です。

コメントと同じく機械側には無くても良いが、プログラマ側に実装すべきメソッドを思い出しやすくします。

最初にpragma mark のリストをコピペする

クラスを作成すると、.hと.mに以下のコードをコピペします。

#pragma mark - class methods

#pragma mark - init methods

#pragma mark - dealloc

#pragma mark - NSCopying, hash, isEqual:

#pragma mark - NSCoding methods

#pragma mark - restorableState methods

#pragma mark - life cycle methods

#pragma mark - action methods

#pragma mark - event handling methods

#pragma mark - drawing methods

#pragma mark - delegate/datasource methods

#pragma mark - accessor methods (in pairs)

#pragma mark - Utility methods

あとは、メソッドを書いてゆくだけです。

メリットは、以下の2点です。

  1. 次に書くべきメソッドを思い出しやすい。
人間は穴埋め問題の様に場所が決まっていると、何をすれば良いかが思い出しやすい。
  1. コードのブラウズ時に検索や移動がやりやすい。
メソッドの分類毎に、”mark -“の文字列があるので、”⌘F mark -“と”⌘G”で分類の間を移動できる。

Note

今まで私は”ハイフン”行と”分類名”行で2行に分けて記述していました。 しかし、先ほど試した結果1行でも問題なくXCodeが動作しました。 ですので、今後は1行で記述するつもりです。

次は、それぞれの分類に何を書いているかの説明です。

pragma mark - class methods

クラスメソッドを書く場所。

[NSDocument autosavesInPlace]などのクラス特有の性質を示すメソッドやインスタントイニシャライザを書く。

例:

+ (BOOL) autosavesInPlace;
+ (NSURL*) fileURLWithPath:(NSString*) path;

pragma mark - init methods

イニシャライザを書く場所。

引数が少ないメソッドを上の方に、引数の多いメソッドをしたの方に書く様に気をつける事。

書くときはすこし手間が増えるが、コードを読むときに流れが上から下になるので分かりやすくなる。

Objective-Cのイニシャライザでは最も引数の多いメソッドが、指定イニシャライザ になるので、必然的に上記の様になる。

例:

- (instancetype) init;
- (instancetype) initFileURLWithPath:(NSString *)path;

pragma mark - dealloc

deallocを書く場所。

各種プロパティをnilに戻す事や、KVOの停止、Notificationの受信の停止など。

例:

- (void) dealloc;

pragma mark - NSCopying, hash, isEqual:

オブジェクトのコピーや同一性に関わるメソッドの実装を書く場所。

MVCで言うところのViewクラスやControllerクラスでは必要ありませんが、逆にmodelクラスに相当するクラスの場合は実装はほぼ必須です。

例:

- (id) copyWithZone:(NSZone *)zone;
- (id) mutableCopyWithZone:(NSZone *)zone;
- (BOOL) isEqual:(id)object;
- (NSUInteger) hash;

pragma mark - NSCoding methods

シリアライズ化メソッドを書く場所。

Cut&PasteやDrag&Drop、ファイル保存の実装にはNSCodingのメソッドを使うと簡単になる。

例:

- (void)encodeWithCoder:(NSCoder *)aCoder;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;

pragma mark - restorableState methods

状態保存関係のコードを書く場所。

クラスメソッドであるが[NSResponder (NSRestorableState) restorableStateKeyPaths]もここに書く。

例:

+ (NSArray *)restorableStateKeyPaths;
- (void) encodeRestorableStateWithCoder:(NSCoder *)coder;
- (void) restoreStateWithCoder:(NSCoder *)coder;

pragma mark - life cycle methods

オブジェクトのライフサイクルのコードを書く場所。

ViewControllerやWindowControllerのライフサイクルに関するメソッドを書きます。 場合によっては、delegateやnotificationに分類される様なメソッドも書きます。

例:

- (void)awakeFromNib;

// windowControllerの場合
- (void)windowWillLoad;
- (void)windowDidLoad;

// ViewControllerの場合
- (void)viewDidLoad;

- (void)viewWillAppear;
- (void)viewDidAppear;
- (void)viewWillDisappear;
- (void)viewDidDisappear;

// NSApplicationDelegateの場合
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
- (void)applicationWillTerminate:(NSNotification *)aNotification;

pragma mark - action methods

IBActionのメソッドを書く場所。

ユーザーが実行できるコマンドの単位になる、IBAction系のメソッドを書く。

また、enable/disableを制御するためのcanAction系のメソッドも一緒に書いておくと楽。 ライブラリcontrolEnablerを使用すると良い。 validateuserinterfaceitem(7)

例:

- (IBAction) anAction:(id)sender;        // action
- (BOOL)     canAnAction:(id)sender;     // actionを呼出すボタンの有効無効を制御

pragma mark - event handling methods

イベント処理のメソッドをこの場所に書く。

NSResponderのサブクラスでない場合でも、KVOの監視メソッドや、Notificationの受信メソッドをイベント処理と考えて、この場所に書いておくと楽。

例:

// KVOの監視メソッド
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context;

// なんらかのnotificationのレシーバー
- (void) nanikanoNotificationNoReciver:(NSNotification *)aNotification;

// キーダウンイベントを処理したり
- (void)keyDown:(NSEvent *)event;

pragma mark - drawing methods

描画系のメソッドを書く場所。

NSViewのサブクラスしか関係ないが、当然まとめておくと楽。

例:

- (void)drawRect:(NSRect)dirtyRect;

pragma mark - delegate/datasource methods

他の分類には分けられない、delegateメソッドやdatsourceメソッドを書く場所。

例:

// NSSpliterViewのdelegate
- (void)splitViewWillResizeSubviews:(NSNotification *)notification;
- (void)splitViewDidResizeSubviews:(NSNotification *)notification;

pragma mark - accessor methods (in pairs)

アクセッサとKVCに関連するものを書く。

依存関係の記述の”keyPathsForValuesAffectingプロパティ名”クラスメソッドもここに書く。 インデックス付きアクセッサパターンのメソッドもここにまとめます。

例:

+ (NSSet *)keyPathsForValuesAffectingObject
- (id) object
- (void) setObject:(id)inObject

pragma mark - Utility methods

その他のユーティリティメソッドを書く。例は特になし。

参考文献

元ネタは、ヒレガス本かその前後のはずだがググっても出てこない。