2011年4月30日土曜日

Smart Cover発送される

本日、Smart Coverを発送した、というメールが届く。到着予定が5月4日とな。

順当なら月曜日あたりで届くはずだけど、震災の影響を加味している、ということかな。
iPad2本体はいつになることやら。Smart Coverだけで何をして遊ぼうかなあ(^^;)。

Cocoa Tabbed Interface Notification

overflowボタンを押した、という通知はNotificationでやってみる。これにはメニュー表示を伴うため、NSEventが必要になる。KVOでもNSDictionaryをつけることができるからNotificationにしなければいけない必然性はない。ま、なんでもやってみるということで。

-(void)mouseDown:(NSEvent *)theEvent{
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
    if(buttonState!=OV_DISABLE){
        if (NSPointInRect(point, buttonImageRect)){
            if(buttonState==OV_HOVER){
                buttonState=OV_PUSHED;
                isPress=YES;
            }
            [self setNeedsDisplay:YES];
        }
    }
}
-(void)mouseUp:(NSEvent *)theEvent{
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
    if(buttonState!=OV_DISABLE){
        if (NSPointInRect(point, buttonImageRect)){
            if(buttonState==OV_PUSHED){
                
                buttonState=OV_HOVER;
                isPress=NO;
                NSDictionary* userInfo=[NSDictionary dictionaryWithObject:theEvent forKey:@"buttonEvent" ];
              
                [[NSNotificationCenter defaultCenter]postNotificationName:@"OverflowButtonIsPressed" object:self userInfo:userInfo];
                //[self tabScroll:OV_LEFT :theEvent];                
            }
        }
        else buttonState=OV_NORMAL;
        [self setNeedsDisplay:YES];
    }
}

isPressってのがKVO用に用意していたメンバなわけだが、結局使ってないな。こんな感じでNSEventをNSDictionaryに収めてNotificationを飛ばし、これをTabBarControllerで受ける、と。

だいたいこれでTab関係の書き直しが終了したので、本日は新しいプロジェクトを作ってtab関連のファイルをコピーして使えるか試してもみた。

実はこれですごい苦労をした。.xibファイルのコピーって鬼門なのかな。TabBarControllerの- (id)initWithNibName:でKVOのaddObserverが有効にならないし、nib上のViewのメンバを書き換えられなくなった。うーん、と腕を組んだけど- (id)initWithNibName:以外ならIBOutletでつながれたViewにちゃんとアクセスできたのでそれでよしとする。要調査。

2011年4月29日金曜日

iPad2発注

本日からiPad2がオンラインストアでも注文できるということなので、Apple Storeを覗いてみたら発送は1〜2週かかるとある。

ふむ、いちおうSoftBankの店頭の状況を確認しようと、近所の大型家電店のSoftBankコーナーで聞いてみたら、「白の16G、3Gモデルなら若干の在庫あり。Wifiモデルはすでに売り切れ、再入荷は早くて3週間後」というお答え。

それならもうApple Storeで買ってしまえということで「黒・16G・Wifiモデル+Smart Coverポリウレタン青」を注文した。

発送予定はきっちり2週間後。しかしSmart Coverだけは1週間後に届く予定。ちょっと悲しいな。

今回はお母ちゃんもけっこう乗り気なので、届くのが楽しみだ。

Cocoa Tabbed Interface NSViewControllerで作り直し(2) キー値監視

TabbedInterfaceを実現するために、現在作っているのは
・Tab・・tabそのものの描画とイベント処理をするクラス
・TabBar・・tabをsubViewとして管理するクラス、tabのoverflowなどの処理をする
・OverflowButton・・tabがoverflowした時に表示される>>みたいなボタン
・TabbarController・・以上のクラスのインスタンスを管理するクラス

以上4つ。このうちOverflowButtonを新しく作ったので、けっこう苦労している。TabとTabBarだけの時は実質ひとつのView(TabBar)でユーザー入力を処理していたので、コードがごちゃごちゃになった点を除けば[self 〜]でほとんどの処理ができたが、現在は複数のViewを同期させる必要ある。・・・といっても実質2つか(^^;)。

TabBar上でtabが描画しきれなくなったのでOverflowButtonを表示させたい、という場合、どうやってインスタンス同士が連携するのか本日勉強。

ま、一番わかりやすいのはNotificationですわな。その他、キー値監視という仕組みを使えばいいらしいことは知っていた。というわけでKVOを初めて使ってみた。苦労しましたわ、理解するまで。

TabBar上のstartIndexという数値が変化したら、その値を調べてOverflowButtonの動作を変更したい、というのがやりたい処理。どちらのクラスについても「知っている」必要があるので、結局TabbarController上で(Controllerなのでnib上のIBOutletでTabBar、OverflowButton両方をメンバとして持っているわけですな)
 [tabBar addObserver:self forKeyPath:@"startIndex" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)  context:NULL];
とした上で、
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    
    if([keyPath isEqualToString:@"startIndex"]){
     
        if (tabBar.startIndex>0) {
            leftOverFlowButton.buttonState=OV_NORMAL;
            
        }

とかなんとかやればいい、ということがわかった。しかしobserveValueForKeyPath:の引数を全然つかっていないので、Notification使ったほうがスマートな感じがするなあ。

[監視されるクラス addObserver:監視するクラス forKeyPath:監視されるクラスのメンバ]という関係がわかるまでけっこう時間がかかってしまった。さらに forKeyPathで指定されたメンバの変更は、[self set〜]形式で変更されたものでないと通知されない、と。やっぱNotificationのほうが便利なような気がする・・・(^^;)

自分のクラスのプロパティが、外部のクラスで変更された時に使うのが便利なのか。

というわけで、「OverflowButtonが押された時の処理」はNotificationでやってみることにする。これは明日。

2011年4月28日木曜日

Cocoa Tabbed Interface NSViewControllerで作ってみる

これまでつくってきたTab、TabBarに、OverflowButtonを新しく作りなおして、この3つのViewを管理するTabBarControllerを作ってみる。

一応NSViewContrllerのサブクラスにしてみたが(controller1つで1つのnibファイルを管理する形にできるので・・)果たしてそれで正解なのかどうかはまだわからない。NSViewContrllerの働きをわかっていないので練習のつもり。

とりあえず今日はここまで。


見た目はほとんど変わらないが、TabBarの両端にあるOverflowButtonは新しくNSViewをサブクラス化したもの。TabBarから独立させた分、表示の管理は楽になると思われる。

ただ、ControllerがTabのデータ(model?)を所持するとして、複数のViewの連携がうまくできるのかはかなり心もとない。大丈夫なのかいな、と思いつつ以降は明日。

2011年4月27日水曜日

Cocoa Tabbed Interface SplitViewをのせてみる

ある程度tabが出来上がってきたの、試しにsplitViewをのせ、さらにoutLineView、TableViewをのせて表示してみた。


なんとなくそれらしい見た目にはなった。そこで、前に作りかけたOutLineViewのプロジェクトをのぞいてみたところ、わお、課題がたくさん。全部のクラスを、ひとつずつ書きなおして(というか1から作り上げて)いかないければならないことがわかった。相当時間がかかるなあ。

当面はまずTabBarControllerから手をつけていこう。
とか書きながら、さっきまでtabの見た目をちょいちょいいじっていた。とりあえず角を丸める。

bezierPathWithRoundedRect:xRadius:yRadius:とcurveToPoint:controlPoint1:controlPoint2:の組み合わせでせこせこ描いてみた。こんなんでいいのか、という汚いソースになっている・・・。おそらくこれに「白い線」を書き加えていくともう少し立体感が出ると思われる。あるいは影か。

2011年4月26日火曜日

Cocoa Tabbed Interface tabのoverflow処理


Caccoで作図してみた。たしかに手軽でわかりやすいサイトだ。ま、絵心がないからどんなToolも猫に小判なんだけど。

それはともかく、TabbedInterfaceの続き。ウィンドウのサイズが変更されて、tabが表示しきれなくなった時の処理を書いている。

表示しきれなくなったら、tabの両端に「まだこっちにtabがあるよ」ボタンを表示する。

今現在はTabBarというNSViewのサブクラスで、単にボタンの画像を出力しているだけ。そのため、マウスカーソルがホバーした時やmouseDownが来た時の処理はいちいちTabBarクラスが担当している。例えばmouseDownは現在こうなっている。
-(void)mouseDown:(NSEvent *)theEvent{
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
    if(leftOverflowButtonState!=OV_DISABLE){
        if (NSPointInRect(point, leftOverflowRect)){
            if(leftOverflowButtonState==OV_HOVER) leftOverflowButtonState=OV_PUSHED;
            [self setNeedsDisplay:YES];
        }
    }
    if(rightOverflowButtonState!=OV_DISABLE){
        if (NSPointInRect(point, rightOverflowRect)){
            if(rightOverflowButtonState==OV_HOVER) rightOverflowButtonState=OV_PUSHED;
            [self setNeedsDisplay:YES];
        }
    }
    
}

2つの画像についていちいち同じ処理をしている。馬鹿みたい。(^^;)これは書きなおさなければ、と思いつつ、とりあえずキリのいいところ書いてしまおうという素人技が炸裂中。

書き直しの方針として、Controllerを作ってTabBarとOverflowButtonを管理するようにしようと考えている。それが上のCaccoの図になっているわけですな。OverflowButtonもNSViewかNSButtonのサブクラスにしてしまえばきっと楽だろう。画面上に2つしか表示しないので、Viewにする贅沢をしてもいいはず。

さて、tabがoverflowしたら、表示しきれないtabを再表示するときはoverflowボタンを押すと望む方向にスクロールしていくのがいいだろう。

しかし、自分の好みとしては「アクティブなtabを隠さない」のがいいと思うので、こんな感じにしてみた。

tabは10個あって、現在表示しているのは先頭の5個。

右側のoverflowボタンを押すと右にスクロールしていく、わけだが、アクティブなtabが「1」なので、スクロールすると「1」が隠れてしまう。そのため、こういう場合はメニューで隠れているtabを表示するようにした。
この部分のソースはこうなっている。

-(void)tabScroll:(NSInteger)direction :(NSEvent*)theEvent{
    if (direction==OV_LEFT) {
        
        if (endIndex==activeTabIndex) {
            NSMenu* theMenu=[[[NSMenu alloc]initWithTitle:@"overflow_menu"]autorelease];
            NSMenuItem* item;
            for (NSInteger i=0; i0) {
            startIndex--;
            endIndex--;
            [self  setNeedsDisplay:YES];
        }
    }
    else{
        if (startIndex==activeTabIndex) {
            NSMenu* theMenu=[[[NSMenu alloc]initWithTitle:@"overflow_menu"]autorelease];
            NSMenuItem* item;
            for (NSInteger i=endIndex+1; i<[[self subviews]count]; i++) {
                Tab* tab=[[self subviews] objectAtIndex:i];
                item=[[NSMenuItem alloc]initWithTitle:[tab title] action:@selector(moveIndexByMenu:) keyEquivalent:@""];
                [item setTag:[tab index]];
                [theMenu addItem:item];
                [item release];
                
            }
            [NSMenu popUpContextMenu:theMenu withEvent:theEvent forView:self];
            
        }
        
        else if(endIndex<[[self subviews]count]){
            endIndex++;
            startIndex++;
            [self  setNeedsDisplay:YES];
        }
    }
}

で、メニューから「「10」を選ぶと、

「10」を一番右端にして表示しなおす、と。

左ボタンと右ボタンで同じコードを2回ずつ書いている、という状態の他は、ほぼ考えていた通りを動きをするようになってきた。

そろそろ、OutlineView、TableViewをあわせて、まともにフォルダの中身を表示できるのか確かめたくなってきた。

Tab関連のクラスの書き直しは今度の3連休に挑戦しよう。

2011年4月25日月曜日

Cocoa Tabbed Interface tabの最小サイズ

tabが増えてくるとだんだんtabのタイトルに表示できる文字数が減ってくる。
そのためたいていのtabbedInterfaceでは、tabの最小サイズを設定して、それ以下になりそうになると多すぎるtabの一部を隠すようにしている。

驚いたのがChromeで、いくらtabを開いてもtabはひとつも隠れない。そんなのをCMでやっていた気もする。

firefoxやsafari、ついでにXcode4でもtabの挙動をいろいろ調べた。appleのとった方法は今イチよく理解出来ない。


tabが増えすぎると、「一番新しいtab」が一番右端に表示されて、「それまで表示されていたtab」が温存され、新しいtabは大方隠される。tabの移動は画像のようにmenuからアクセスするしかないようだ。この辺、深く追求したわけでもないのでいい方法があるのかもしれないが。

firefoxの挙動が一番しっくりくる。tabが増えた分どんどん新しいtabを表示して、元から表示されていたtabは横スクロールで隠れていく。tabの両端にスクロールボタンが出る。ただ、アクティブなtabまで隠れてしまうのが今イチ使いにくい、とふだんから感じている。この辺は個人の好みだけど。

ただ、作っているのがファイルマネージャーのようなものである。「バックグラウンドで新しいtabを開く」ことは考えていない。tabのサイズ変更はウィンドウのサイズ変更のタイミング一番多いと思われる。

「現在開いているtab」(アクティブなtab)が隠れないようにtabのサイズ変更ができるようにしたい。
そこでいろいろやってみた結果、まあまあ納得のいく挙動をさせることができた。

まず普通の状態。

10個のtabを全て表示している。これをウィンドウのサイズを小さくしていくと、

設定しておいたtabの最小幅まで各tabが縮んだあと、一番右端のtabが隠れて「隠れたtabがありますよ」インジケーターが出る。

では、アクティブなtabがこういう状態ならどうなるか。

ウィンドウを小さくしていくと、アクティブなtabの右側のtabが消えていく。

しかしアクティブなtabまでくると、今度は左側から消えていく。


ここまで作るのに大変な苦労をした。「アクティブなtabが右端に来た以降の挙動」をどうやってプログラミングするか、かなり悩んでしまって時間がかかった。素人の悲しさだなー。以降は明日。

2011年4月24日日曜日

Cocoa Tabbed Interface 閉じるボタン

本日はTabクラスに「閉じるボタン」をつけてみた。

OSXのお作法(?)にしたがって、普段はまったく表示せず、tabにマウスがのったら表示する。


さらに「閉じるボタン」の上にマウスがのると


ま、このくらいでいいかな、と。もちろん「閉じるボタン」が押されるとこれまた微妙に違う画像に差し替えている。
tab全体をtrackingAreaにして、mouseMoveでボタンを表示している。
-(void)mouseMoved:(NSEvent *)theEvent{
    isHover=YES;
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
    if (NSPointInRect(point, closeButtonRect)){
        isCloseButtonHover=YES; 
    }else{
        isCloseButtonHover=NO;
        isCloseButtonPushed=NO;
    }
    [self setNeedsDisplay:YES];
}

BOOL値で状態遷移を表しているが、enumの方がいいかしらん。素人のコードなんで、かっこ良さより自分のわかりやすさ優先。閉じるボタンをNSViewのサブクラスで作るほうが簡単と思われるが、Viewばっかりになるのもどうかな、ということでTabクラスの中に押し込めた。Cellで同じことをやるよりは大分楽だ。

この他、本日は時間があったのでtabの見た目をグラデーションさせてみたりしたが、

それほど劇的な効果はないので却下。(^^;)

2011年4月23日土曜日

Cocoa Tabbed Interface NSView(2)

Tab本体もNSViewにしてTabbedInterfaceの作り直し。

本日はここまで。

エディタ「kod」にはChromeライクなtabが実装されていて、Chromeのコードも使われている。で、kodのプロジェクトをダウンロードしてあったので、そこからtab関連のソースを眺めてみた。

Chromeのタブは台形なわけだが、これはどうやらNSAffineTransformというクラスを使って変形しているようだ。とかなんとか調べているうちにあっという間に時間がたって、今日は複数のtabをアクティブ、非アクティブに切り替えて表示するところまで。tabのタイトルをtruncateさせるのはすでにCellの時にやっていたのでコピペですんだ。

マウスをトラッキングしてクローズボタンを表示するのは、せっかくtab本体がNSViewなので自前でやるつもり。つまりクローズボタンをさらにNSButtonなりNSViewで実装しない、と。

それができたらクローズ処理、タブが多すぎるときのOverflowMenu、という感じかな。ドラッグアンドドロップでtabの表示入れ替え、もやってみたいなあ。

tabがクリックされてアクティブなtabが切り替わる処理は、tabを管理しているTabBar側でやっている。しかし現在は[self superView]でTabBarを呼び出し、そこからchangeActiveTabIndexとかなんとか直接呼び出しているのがダサい、と自分でも思う。これはやはり、近い将来のためにもNotificationでいくべきだろうなあ。

とかなんとか、Cocoaプログラミングのことばっかり考えている毎日。楽しいなあ。

2011年4月22日金曜日

Cocoa Tabbed Interface NSViewでもう1回初めから

NSCellのサブクラス化で実験していたtabbed interface、どう考えてもこの先苦労が待っているようなので、ここは一度NSViewで作ってみて、それからまた考えることにする。tabのドラッグアンドドロップとかするとなると、Cellだととんでもないことになる気がするので。

本日はここまで。


Cellの場合、-(void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlViewの中で

NSBezierPath* path=[NSBezierPath bezierPathWithRoundedRect:cellFrame xRadius:3 yRadius:3];

としてから[path stroke]、[path fill]とすればそれらしい見た目になった(・・すごくいい加減な方法なんだけど、pathの外周の線がfillすると底辺だけ上書きされるというcocoaのCell描画の挙動に身を任せただけ)わけだが、Viewだとそうはいかない。

底辺以外をlineToPointでせっせと描いている。いつかはこういう作業もするだろうな、と思っていたのでいい勉強になる。こののっぺりした見た目をどうやったらもう少しかっこよくできるのだろうか・・。

今のところ、Tab本体を描画するクラスと、それをsubViewで管理するTabBarという2つのクラスで作っていこうとしてみている。

2011年4月21日木曜日

Cocoa なんちゃってtabbed interface NSCellで行くか、NSViewにするか


Developer toolの中にQuartz Debug.appというtoolがあって、グラフィックス系の処理のdebugやらパフォーマンス測定やらをビジュアルに確かめることができる。


このtoolで「Show tracking rectangles」を有効にすると、各アプリのウィンドウのtrackingAreaを視覚的に確かめることができる。NSTrackingAreaはNSViewしか持てない(・・・と理解しているがそれでいいのだろうか。)、しかもViewひとつにつきTrakingAreaもひとつ、のようなので、TrakingAreaイコールView、ということになる。

いろいろなタブインターフェイス付きのアプリで試してみたところ、とりあえずapple謹製アプリでタブインターフェイスを持つものは、タブをNSViewで作っているようだ。

GoogleのChromeもタブは全部TrakingAreaを持っていた。firefoxはタブに全くTrakingAreaがない。独自に実装しているのということか。

Cellでタブを作っていくと、TrakingAreaを独自に持てないため、「閉じるボタン」の状態遷移とか、マウスイベント処理がけっこう面倒なことになる。

その点Viewにしてしまえば、マウスイベントが処理できるため何かと楽。タブを表現するViewクラスで一度実装してしまえば面倒なことがない。

というわけで、このままCellでいくか、Viewに変更するかちょっと悩み中。
こういう時はViewでタブを実装してしまうサンプルを作ってみるのが話が早い。この週末の楽しみ、ということにしよう。

Cocoa なんちゃってtabbed interface(5)NSTrackingArea

たくさんタブが表示された時の処理、の前に懸案だったNSTrackingAreaで「タブを閉じるボタン」を表示する処理を実装してみる。

タブを管理しているView全体をTrakingAreaにして、mouseMovedでカーソルのあるタブを検出、「タブを閉じるボタン」を表示していなければ表示する、という流れになる。

CellにshowedCloseButtonというBOOL値を持たせて、YESなら描画処理の中で「閉じるボタン」を描画する。
    if (showedCloseButton) {
        [[self image] drawAtPoint:NSMakePoint(cellFrame.origin.x+CELL_LEFT_SPACING, (cellFrame.size.height-stringSize.height) /2) fromRect:NSZeroRect
                    operation:NSCompositeSourceOver fraction:0.8];
    }
管理View側のmouseMoved、mouseExitedはこんな感じ。(汚いソースで恥ずかしいなあ、自分用備忘録なので勘弁して下さい)
-(void)mouseMoved:(NSEvent *)theEvent{
    
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
    NSInteger index = [self cellAtPoint:point];
   
    if (index>-1) {
        if (index==showedCloseButtonCellIndex) return;
        else{
            MyCell *cell;
            if(showedCloseButtonCellIndex!=NO_SHOWED){
                cell=[tabs objectAtIndex:showedCloseButtonCellIndex];
                cell.showedCloseButton=NO;
            }
            cell=[tabs objectAtIndex:index];
            if (!cell.showedCloseButton) {
                cell.showedCloseButton=YES;
                showedCloseButtonCellIndex=index;
                [self setNeedsDisplay:YES];
            }
        }
    }else{
        if (showedCloseButtonCellIndex!=NO_SHOWED) {
            MyCell* cell=[tabs objectAtIndex:showedCloseButtonCellIndex];
            cell.showedCloseButton=NO;
            [self setNeedsDisplay:YES];
            showedCloseButtonCellIndex=NO_SHOWED;
        }
    }
    
}
-(void)mouseExited:(NSEvent *)theEvent{
    if(showedCloseButtonCellIndex!=NO_SHOWED){
        MyCell* cell=[tabs objectAtIndex:showedCloseButtonCellIndex];
        cell.showedCloseButton=NO;
        [self setNeedsDisplay:YES];
        showedCloseButtonCellIndex=NO_SHOWED;
    }
}

これで無事「閉じるボタン」が描画されるようになる。

マウスがViewを抜けるとボタンも消える。

うーん、この後は「閉じるボタン」の上にカーソルが来た時の処理、マウスクリックされた時、mouseUpが来た時、と続くわけだが・・・。

2011年4月20日水曜日

Cocoa なんちゃってtabbed interface(4)NSStringでTruncate処理

なまじstringAttrbutesとかで描画用の属性をつけてしまっているので、Truncate処理が悲惨なことになった。

フツーにNSStringでdrawAtPointにしといたほうがよかったか・・。

とりあえずTruncate処理を付け加えることはできた。

ウィンドウをのサイズを変えるとこんなふうになる。


日本語でも処理そのものには全く支障がなかった。賢いぞCocoa。
考え方としては

1,描画したい領域のWidthよりも文字列のsize.widthが大きかったら
2,文字列をMutableStringにコピーして
3,forループで最終文字から1文字ずつ削りとり
4,描画したい領域より文字列のwidthが小さくなったら
5,forループから抜け出て
6,さらにうしろから2文字分削りとり
7、「..」を付け加る

という感じになる。ただしAttributedがはいるのでソースはこんなに汚くなる。(^^;)
NSAttributedString* sourceAttributedTitle=[[[NSAttributedString alloc] initWithString:title attributes:stringAttrbutes]autorelease];
    NSMutableAttributedString *titleForDraw=[[[NSMutableAttributedString alloc] initWithAttributedString:sourceAttributedTitle]autorelease];
    if([sourceAttributedTitle size].width> cellFrame.size.width){
        for (NSInteger i=[sourceAttributedTitle length]-1;i>0; i--) {
            [titleForDraw deleteCharactersInRange:NSMakeRange(i, 1)];
            if ([titleForDraw size].width< cellFrame.size.width){
                break;
            }
        }
        [titleForDraw deleteCharactersInRange:NSMakeRange([titleForDraw length]-2,2)];
        [titleForDraw appendAttributedString:[[NSAttributedString alloc] initWithString:@".." attributes:stringAttrbutes]]; 
    
    }
bloggerに文句を言われるため不等号は全角にしてある。
一応これで動くのでよしとするが、今後tabを増やす処理を付け加えていけば当然「1文字も描画できないせまさのtab」ができてしまうこともあるので、tabの最小幅を設定して、「見えなくなったtab」にどうにかしてアクセスする方法を考えていかなければ・・・。

その前に、現在はプレースホルダでしかない「新しいtabを増やす」、「tabを閉じる」ボタンを実装するほうが先か。

2011年4月19日火曜日

Cocoa なんちゃってtabbed interface(3)

なんちゃってtabbedインターフェイス、本日はここまで作った。


まだ見た目を整えている段階。今日は「tabがたくさん増えたらtabの幅を調整する」部分を実装した。ウィンドウの大きさを変えたら


tabの幅も自動的に広がる、と。
あとはtab中の文字描画のtruncateだなあ。全角文字もありえるから果たして自分にできるかしらん。

いちおう現在のところのクラス構成はこうなっている。


MyCellクラスがtabの描画そのもの。だからtruncateもこのクラスの仕事になる。
TabViewはMyCellをMutableArrayで保持しており、tabの大きさと位置をきめている。現在アクティブなtabを記録するのもこのクラス。
PanelViewは単に「アクティブなtabと同じ色にぬられた」というだけのView。あとあとこのViewにファイルマネージャーもどきの実際のViewを置いていくことになる計画。
MyCellの描画コード。

-(void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView{
    [NSGraphicsContext saveGraphicsState];
    [controlView lockFocus];
    NSBezierPath* path=[NSBezierPath bezierPathWithRoundedRect:cellFrame xRadius:3 yRadius:3];
   
    [[NSColor blackColor] set];
    [path stroke];
    if(active){
       
        [[NSColor colorWithDeviceWhite:0.84 alpha:1.0]set]; 

    }
    else{
         [[NSColor windowFrameColor] set];
    }
        
    [path fill];
     
    NSSize size=[title sizeWithAttributes:stringAttrbutes];
    NSPoint point=NSMakePoint(((cellFrame.size.width-size.width)/2)+cellFrame.origin.x, (cellFrame.size.height-size.height) /2);
    [title drawAtPoint:point withAttributes:stringAttrbutes];
    drawedFrame=cellFrame;
    [controlView unlockFocus];
    [NSGraphicsContext restoreGraphicsState];
}
- (id)initWithTitle:(NSString *)aTitle{
    self=[super init];
    if(self){
        title=aTitle;
        active=NO;
        
        stringAttrbutes=[[NSMutableDictionary dictionary]retain];
        [stringAttrbutes setObject:[NSColor blackColor]
                              forKey:NSForegroundColorAttributeName];
  [stringAttrbutes setObject:[NSFont systemFontOfSize:13.0]
                              forKey: NSFontAttributeName];     
    }
    return self;
}

文字描画のアトリビュートが大半でありますな。

TabViewの描画部分。
-(CGFloat)calcTabWidth{
    CGFloat width=MAX_TAB_WIDTH;
    CGFloat frameWidth=[self bounds].size.width;
    if(FIRST_TAB_MARGIN+(width*[tabs count])+LAST_TAB_MARGIN>frameWidth){
        width=(frameWidth- FIRST_TAB_MARGIN-LAST_TAB_MARGIN)/[tabs count];
    }
    return width;
}
- (void)drawRect:(NSRect)dirtyRect
{
    // Drawing code here.
   
    NSBezierPath* path = [NSBezierPath bezierPathWithRect:[self bounds]];
 CGFloat closeButtonX;
  [[NSColor colorWithDeviceWhite:0.7 alpha:1.0]set]; 
 [path fill];
       
    if([tabs count]>0){
        CGFloat tabWidth=[self calcTabWidth];
        for(NSInteger i=0;i<[tabs count];i++){
            MyCell* cell=[tabs objectAtIndex:i];
            if(i==activeTabIndex) cell.active=YES;
            
            [cell drawWithFrame:NSMakeRect(FIRST_TAB_MARGIN+(i*tabWidth), 0, tabWidth, TAB_HEIGHT) inView:self];
            closeButtonX=FIRST_TAB_MARGIN+((i+1)*tabWidth);
        }
        
    }
    
  
    [closeButtonImage drawAtPoint:NSMakePoint(closeButtonX+10, 3) fromRect:NSZeroRect operation: NSCompositeSourceOver fraction:0.6];
    
}
-(NSInteger)cellAtPoint:(NSPoint)point{
    //NSLog(@"%lu",[tabs count]);
    MyCell* cell;
    for(NSUInteger i=0;i<[tabs count];i++){
        cell=[tabs objectAtIndex:i];
        NSRect rect=[cell drawedFrame];
        if(NSPointInRect(point, rect)){
            return i;
        }
    }
    return -1;
}
-(void)mouseDown:(NSEvent *)theEvent{
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
 NSInteger index = [self cellAtPoint:point];
    if(index!=-1 && index!=activeTabIndex){
        MyCell* cell=[tabs objectAtIndex:activeTabIndex];
        cell.active=NO;
        cell=[tabs objectAtIndex:index];
        cell.active=YES;
        activeTabIndex=index;
        [self setNeedsDisplay:YES];
    }
}

新しいtabを開くためのボタンはまだdrawAtPointしているだけなので、これの処理が今後の課題。CellにViewなんか載せたくないしなあ。TabView側で「tabをくわえる」ボタンや「tabを閉じるボタン」のTrakingAreaとかも全部処理するしかないかな、というところ。

2011年4月18日月曜日

Cocoa なんちゃってtabbed interface(2) NSCell

単に図形としてTabを描くだけではその後の処理がいろいろたいへんになりそうなので、NSCellのカスタムクラスでTabを表現してみることにした。

NSMatrixで横一列にして表示できるのでは?と思ってNSMatrixについて調べ始めたが、これが全然わかんない。(^^;)xcatsan師匠の解説の通りにやってみようとしたのだけれど、Cellが描画されずに悶絶する。

どーもNSMatrixは鬼門だ。MacRubyの時も挫折したし。

試しにNSViewのカスタムクラスの中で、
MyCell *cell=[[MyCell alloc]initWithTitle:@"first"];
    [cell drawWithFrame:NSMakeRect(10, 0, 100, 20) inView:self];

とやってみたら簡単にNSCellが描画された。なーんだ、NSMatrix使わなくてもいいじゃない。
で、少しコードを書いた結果がこれ。


相変わらずのインチキコードなんだけど、それらしくなることはなるな。
ところがNSCell、軽量なクラスだけあってイベント処理ができない(らしい)。mouseDownもNSCellを保持しているView側で全部処理する必要がある。

そこでやっぱりxcatsan師匠のサンプルコードを読みながらイベント処理を付け加えようとしたら、なんだかよくわからないエラーが発生して難儀しているのが現在。

うーん、NSCellではなくViewでやっちゃおうか。(^^;)

(追記)
恥ずかしながらエラーの原因が判明。
tabs=[[NSMutableArray alloc]initWithCapacity:1];
としなければいけないところを、
tabs=[NSMutableArray initWithCapacity:1];
としていた。orz。その後は順調。

2011年4月17日日曜日

Cocoa なんちゃってtabbed interface

休日をのんびり過ごしながらtabbedインターフェイスについて引き続き調べる。

調べ方が悪いのと、xcode4ということもあってなかなか手軽に使わせてもらえそうなフレームワークが見つからない。

考えてみると、今つくっている「ファイルマネージャーのようなもの」はDocumentBaseではないので、「タブでDocumentを切り替える」ということまでは必要ない。タブをドラッグしたら別ウィンドウになる、なんていう高度な技も必要ではない。表示するディレクトリをぱっぱと切り替えることができたらそれでいいわけで、表示したいディレクトリ名をタブにして画面に置いておければいい。

それなら自分で作ってみるか、と始めたのがこの画面。


はっはっは、それっぽくは表示できた。やっていることはこれだけだけど。

    NSRect rect=NSMakeRect(10, 0, 100, 20);
    NSBezierPath *path=[NSBezierPath bezierPathWithRect:rect];
    [[NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:1.0] set];
    [NSBezierPath setDefaultLineWidth:0.1];
    [path stroke];
    [[NSColor colorWithDeviceRed:0.8 green:0.8 blue:0.8 alpha:1.0] set];
    [path fill];
[[NSColor colorWithDeviceRed:0.8 green:0.8 blue:0.8 alpha:1.0] set];で下のViewと色を合わせているだけでなんとなくそれっぽくなる、と。
さらに続けて

NSRect rect2=NSMakeRect(112, 0, 100, 20);
    NSBezierPath *path2=[NSBezierPath bezierPathWithRect:rect2];
    [[NSColor colorWithDeviceRed:0.7 green:0.7 blue:0.7 alpha:1.0] set];
    [path2 fill];
    [[NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:1.0] set];
    [path2 setLineWidth:0.3];
    [path2 stroke];
としてみたらこうなる。

色の具合はこっちのほうがいいかなあ。

マウスイベントを処理することを考えると、単なるNSBezirPathではなくてViewにするかCellにするかしたほうがいい感じ。これは明日以降。

2011年4月16日土曜日

Cocoa tabbed interfaceについて調べる

要はXcodeやsafariのようなtabで切り替わるインターフェイス。この辺のところはハッカーな人たちが便利なクラスやコントロールを用意してくれているのではないか、と期待したが・・・。

有名所でPSMTabBarControl。これはiTermとかでも使われているのだけれど、OSX10.6には対応していないみたい。その辺を修正したものがちゃんとあって、ソースがここにあった

しかしInterfaceBuilder3用のpluginだからXocde4だと「InterfaceBuilder3で編集しなさい」と怒られる。ソースコードだけで使えるかどうかはこれから調査。

新しいところでは
rsms/chromium-tabs - GitHub
という、OSX用のエディタKodで使われているtabbedインターフェイスがあるけれど、自分のプロジェクトにこれを組み込むと

#import

でビルドエラーになってしまう。うーむ、知識不足だな。サンプルプログラムはちゃんとビルドできるんだから、何かの設定が足りないようだ。

タブインターフェイスはぜひほしいのだけれど、自分で作るのはちょっと無理そう(^^;)なので他力本願だったのだが、とりあえず今日のところは頓挫した。がっくり。

2011年4月15日金曜日

Cocoa NSFileManager

NSFileManagerについて軽く調べる。

attributesOfItemAtPath:error:で得られるファイルの属性をNSLogであれこれ表示。このメソッドが返すNSDictionaryをそのままデータ保存用のクラスに格納すべきか、それとも必要な属性だけ個別に格納するか考える。

同時にFinderで言うところの「ファイルの種類」をどうやって取得するのか研究中。

実験結果を反映させていく仮アプリ名は「Nise」か「Ese」にしようと思う。偽、似非、でありますな。どーせ自分が作るのは「偽◯◯」か「似非◯◯」としか言いようのないアプリだろうから。(^^;)

2011年4月14日木曜日

Cocoa NSTableView Cocoaバインディングでiconを表示する(2)

xcatsan師匠のこちらのアーティクルで疑問解決。

NSTableView にカスタムビューを表示する (5)カスタムセルへ bindings経由でモデルオブジェクトを渡す

ArrayControllerとひもづけるデータ保持クラスに、

- (id)copyWithZone:(NSZone *)zone

を作ればOKだった。なるほど、昨日の失敗も[DirItem copyWithZone]unrecognized selector sent to instance...とずっと表示され続けていた。


いろいろ書き散らかしているので、OutlineView用のファイル関連データ保持クラス、TableView用データ保持クラス、と同じようなクラスをだらだら書いてしまった。

そろそろ、ファイル関連のデータを取得して保持するクラスをちゃんと書いて、MainControllerで操作する、みたいなプロジェクトを作ってみよう。まだまだ実験中。

2011年4月13日水曜日

Cocoa NSTableView Cocoaバインディングでiconを表示する(1)

表題どおり、NSTableViewでカスタムセルを使ってicon表示してみる。

しかし、テキストは表示できてもimageがでない。なぜだろう・・・。xcatsan師匠の解説通りにやっているつもりなんだけど。

明日以降もう1度やってみよう。今日は残念ながら収穫なし。

2011年4月12日火曜日

筋萎縮性側索硬化症の開発者、亡くなる3日前にモールス信号で修正したGNOMEのパッチを提出 - スラッシュドット・ジャパン

筋萎縮性側索硬化症の開発者、亡くなる3日前にモールス信号で修正したGNOMEのパッチを提出 - スラッシュドット・ジャパン: "

本当にこのハッカーはクールだ。泣けた。

FileManagerを作り始める理由

実はOSX初心者(^^;)なので、ファイルの扱いが今イチうまくいかない。

自分でFileManagerを作ってみようか、と思い始めて、初めてFinderをあれこれいじってみている。泥縄もいいところ。

いじってみて知ったのは「Finderは便利だ」ということ。(あははは)
ファイルのコピーや移動が今イチ便利じゃなかったのは、Finderをいわゆる「アイコンビュー」で使っていたからかも。
最近、これとか

これとかで

使ってみたら、ファイル操作は基本的にFinderで十分だな、と思ってしまった。ではなぜそれでもFileManagerを作ろうとしているかというと、こういうことがやりたいから。

.appディレクトリの中のリソースに、簡単にアクセスできるようにしたい、と。Finderでもできるんだけど、次から次へ、といかないので。(右クリック→コンテンツを表示、で別ウィンドウ表示になる、と)

ま、その他にいくつか「こんなことができたら」と考えていることはあるんだけれど、果たして完成まで行き着くか非常に怪しいのでこれくらいにしておこうっと。

Cocoa NSCollectionView(2)Cocoaバインディング

xcatsan師匠こちらの記事を読みながら、Cocoaバインディングをもう1回やってみる。ちなみにリンク先の記事は、あれこれ読んだ中で一番分かりやすく、一番実践的なCocoaバインディングの解説と思われる。

解説通りにやればもちろんうまくいく。それでは自分のコードではなぜうまくいかないか・・・。xcatsan師匠の解説では、ViewControllerのinit中でNSMutableArrayにデータを入れている。しかし自分のコードでは、NSOutlineViewで選択行が変更された時にデータを入れ替えている。

どうやら、ArrayControllerに、データソースであるNSMutableArrayのデータが変更されたよ、と教えるメソッドが必要らしい、とわかった。

ADCのサンプル、SourceViewのソースを追うと、なるほど、データが変更されたときはちゃんとupdateというメソッドを読んでいた。つまり、ArrayControllerに結び付けられたNSMutableArrayがlistと言う名前で、それが

@property (readwrite,assign)NSMutableArray* list;
とプロパティ宣言されているとしたら、
-(void)updateList:(id)obj{
    [self setList:obj];
}
というメソッドを記述しておかないとlistに対する変更がArrayControllerに伝わらない、と。

逆を言えば、updateを記述しておくだけであとはArrayControllerが面倒を見てくれるわけで、たしかに便利なしくみではある。わかるまでに時間がかかったけど。

で、こうなりましたよ。

うむー、NSCollectionView、アニメーションがなんかヤだなあ。(^^;)ひとつのアイコンにViewが2つも3つも使われているからけっこう処理が重そうだし。
NSCellを使った独自描画のViewを考えるべきかなあ。

その前にNSTableViewでバインディングとカスタム描画をやってみよう。これは明日以降。

2011年4月11日月曜日

Cocoa NSCollectionView

というわけでNSCollectionViewに、ファイル一覧を表示できるか挑戦中。

xcatsan師匠解説やADCサンプルの「SourceView」のコードを読んで、そのとおりにやっているつもりだけどCocoaバインディングがうまく動かない。

どこがまずいのかさっぱり見当がつかないのでいらついているおやぢ。

ここは無理して自力でカスタムビューを作るか。

2011年4月10日日曜日

Cocoa NSOutlineView(3)NSCellカスタマイズ

NSOutlineViewの各行を、アイコン付きで表示してみる。

これはもうFAQと言っていいネタらしく、ググってみたらすぐに答えが出た。NSCellをカスタマイズすればいいらしい。

たどり着いたのは木下誠氏のこのページ。

NSCell

ここにあったソースをコピペしてプロジェクトに追加。そしてdatasourceの
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
    return (item == nil) ? @"/" : [item relativePath];
}
 
このメソッドをiconも表示するように以下のように変更した。
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
    
    NSString* path;
    NSImage* iconImage;
    
    if(item == nil) {
        path = @"/";
        iconImage = [[NSWorkspace sharedWorkspace] iconForFile:path];
    }
    else {
        path = [item relativePath];
        iconImage = [[NSWorkspace sharedWorkspace] iconForFile:[item fullPath]];
    }
    
    // Set image
    [[tableColumn dataCell] setImage:iconImage];
    
    return path;
    
}

えらそうに書いているけど変更点も木下誠氏のサンプルからコピペ。

これだけでできてしまった。


うーん、いい感じだなー。しかしコピペばっかりだからいざ自分でなにかしようとしたら、全然わかんない、という状態が悲しい。

明日以降はいよいよCocoaバインディングに挑戦することになりそう。さっぱりわかんないんだよなあ、バインディング。(^^;)

2011年4月9日土曜日

読書中:百万遍

百万遍―流転旋転〈上巻〉
花村 萬月
新潮社
売り上げランキング: 147623

花村萬月を読んでいる。

過剰なくらい性的な描写が続くのだが、それが「やがて悲しき」につながる。

主人公惟朔はやたらかっこいい若者で、自伝的な作品というなら美化しすぎてね?と感じるわけだが、人間にとっての「性」が主要テーマなので美化もそれほど鼻につかない。

あまり立て続けにこの人の作品ばかり読み続けるといささか飽きがくるけれど、たまに読むと文章の力にぐいぐい引き込まれる。

appCodeを試す

歓迎会でいい気になってビールをがぶ飲みしている間に、以前一度触れた、Xcode代替ObjC用IDE、appCider改めappCodeのベータ版がリリースされていた。

酔眼を凝らして昨夜インストールだけはしていたので、本日少しいじってみた。

こんなICON。

試しに新しいプロジェクトを作ってみた。


設定の項目はXcodeとほぼ同じ。で、プロジェクトを開いたところ。


エディタのカラーテーマはまだデフォルトしか用意されていない。設定項目が多くてカスタマイズはかなり大変みたい。少しやってみたけど、背景を黒くすると見やすくなるまでけっこうあれこれいじる必要がある。おそらくこれからテーマが増えていくのでしょう。

さて、肝心の使い心地だが、xibファイルはInterfaceBuilderでいじることになる。Xcode3までならInterfaceBuilderが単独で起動していたので問題ないが、Xcode4だと結局Xcode4本体が起動されるので、代替IDEを使うテンションがかなり下がる。Xcode4が起動するならXcode4使えばいいじゃん、という。

ただコード補完はかなり優秀。エディタとして使う、という使い方はあるな、と感じた。
最大の難点はJavaで作られているためか起動が遅いこと。アプリ本体が起動してから、Cocoaフレームワークのヘッダを読み込むまでえらく時間がかかる。

今後のブラッシュアップに期待したい、というのが結論かな。

Cocoa NSOutlineView(2)

NSOutlineViewの研究その2。

デベロッパドキュメントの

Writing an Outline View Data Source

からソースをまんまコピーして実行してみる。


ふぉっふぉっふぉっ、簡単にできるのお。コピペなので全然中身を理解していないため、これをいじくっていくうちに理解を深める・・・予定。(^^;)

次に作りたいな、と思っていたのが「自分用ファイルマネージャ」だったので、このサンプルコードは渡りに船、だった。ラッキー。
一応コードを載せておく。
#import "FileSystemItem.h"


@implementation FileSystemItem
static FileSystemItem *rootItem = nil;

static NSMutableArray *leafNode = nil;

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }
    
    return self;
}

+ (void)initialize {
    
    if (self == [FileSystemItem class]) {
        
        leafNode = [[NSMutableArray alloc] init];
        
    }
    
}

- (id)initWithPath:(NSString *)path parent:(FileSystemItem *)parentItem {
    
    self = [super init];
    
    if (self) {
        
        relativePath = [[path lastPathComponent] copy];
        
        parent = parentItem;
        
    }
    
    return self;
    
}

+ (FileSystemItem *)rootItem {
    
    if (rootItem == nil) {
        
        rootItem = [[FileSystemItem alloc] initWithPath:@"/" parent:nil];
        
    }
    
    return rootItem;
    
}

// Creates, caches, and returns the array of children

// Loads children incrementally

- (NSArray *)children {
    
    
    
    if (children == nil) {
        
        NSFileManager *fileManager = [NSFileManager defaultManager];        
        NSString *fullPath = [self fullPath];        
        BOOL isDir, valid;
        valid = [fileManager fileExistsAtPath:fullPath isDirectory:&isDir];
        
        if (valid && isDir) {
            NSArray *array = [fileManager contentsOfDirectoryAtPath:fullPath error:NULL];
            //NSArray *array=[fileManager subpathsAtPath:fullPath];
            NSUInteger numChildren, i;
            numChildren = [array count];
            
            children = [[NSMutableArray alloc] initWithCapacity:numChildren];
            for (i = 0; i < numChildren; i++)
            {
                BOOL dir,val;
                NSString* path=[fullPath stringByAppendingPathComponent:[array objectAtIndex:i]];
                
                val=[fileManager fileExistsAtPath:path isDirectory:&dir];
                if(val && dir){
                    FileSystemItem *newChild = [[FileSystemItem alloc]
                    initWithPath:[array objectAtIndex:i] parent:self];
                    [children addObject:newChild];
                    [newChild release];
                }
                
            }
        }
        else {
            children = leafNode;
        }
    }
    return children;
    
}

- (NSString *)relativePath {
    
    return relativePath;
    
}
- (NSString *)fullPath {
    
    // If no parent, return our own relative path
    
    if (parent == nil) {
        return relativePath;
    }
    // recurse up the hierarchy, prepending each parent’s path
    
    return [[parent fullPath] stringByAppendingPathComponent:relativePath];
    
}

- (FileSystemItem *)childAtIndex:(NSUInteger)n {
    
    return [[self children] objectAtIndex:n];
    
}

- (NSInteger)numberOfChildren {
    
    NSArray *tmp = [self children];
    
    return (tmp == leafNode) ? (-1) : [tmp count];
    
}

- (void)dealloc {
    
    if (children != leafNode) {
        [children release];
    }
    
    [relativePath release];
    
    [super dealloc];
    
}
@end
なお上記のコードは原本に若干手を加えていて、ファイルを全て、ではなくディレクトリだったら表示するようにしている。該当箇所は
BOOL dir,val;
NSString* path=[fullPath stringByAppendingPathComponent:[array objectAtIndex:i]];
                
val=[fileManager fileExistsAtPath:path isDirectory:&dir];
if(val && dir){
このあたり。

2011年4月7日木曜日

Cocoa NSOutlineView

PDFkitを使うと、NSOutlineViewのDataSourceにPDFOutlineを渡せばそれでほぼことが済む。では自分でDataSourceを用意する場合はどうするのか。この辺りの勉強から始める。

デベロッパドキュメントを読んだり、ADCサンプルの「SourceView」を調べているうちに自由時間終了。

明日は職場の歓迎会。Cocoaの勉強に使える時間はないなあ。

新学期が始まって肉体疲労が激しい。帰宅後、30分くらい仮眠をとらないとiMacの前に座るのさえつらい状態。年をとるというのはそういうことなんだな。

2011年4月6日水曜日

PDFkit 一旦終了

PDFAnnotationについて調べている。調べながら、あまりいっしょうけんめいになれない感じがして、はたと考える。

Skimという最高のPDFビューワがあるから、PDFビューワを本気で作ろうとはしていない。辞書引きに便利なビューワがほしい、最低これくらいの機能をつけて・・・と作業していたが、それほど興味のある分野でないことは確か。

Spinの場合もそれほどたいした機能ではないけれど、どこにもないから自分で作ろうとして大変おもしろかった。PDFkitが便利なことはわかったので、そろそろ一度やめて、Spinの次に作ろうかな、と考えていたプロジェクトの準備にかかることにしよう。

SubViewの切り替えとか、TableViewとかOutlineViewとか、ポピュラーなUIの作り方はかなり勉強になった。

2011年4月5日火曜日

PDFkit Annotation

さて、ブックマーク。重要な箇所に付箋をつける、というイメージである。ただの「しおり」だとなぜ自分がそこにしおりをはさんだのかわからないから、簡単なテキストを入力できるようにしておく、と。

・・・なーんだ、いわゆるAnnotationのAnnotationTextとAnnotationPopupの組み合わせで、ちゃんと用意されているみたい。素人の考えることなんぞはこんなものだ。


AnnotationPopup付きのドキュメントを自作PDFビューワで読み込むと、なにもしていないけれどちゃんとAnnotationが表示された。ということは、PDFDocumentあたりで実装されているのかな、と思ったらPDFPageらしい。

もう少しデベロッパドキュメントを読んで研究しよう。

2011年4月4日月曜日

Excel 共有違反

できあがったワークシートをさっそく学年打ち合わせで使ってみた。bookを「共有する」にしておけば、ネット上のドキュメントを複数人で編集しながらあれこれ打ち合わせる、はずだったのに、なぜか「共有違反で保存できません」というエラーが頻発する。

しかも一度閉じたファイルが「ロックされています」とか言われて開けなくなってしまう。なんじゃいなExcel。

がっくりきましたよ、土曜日半日かけたので。しかたなく共有しない状態で(ひとりだけ編集できて、後の人は読み込み専用状態で閲覧)打ち合わせをすることになってしまった。がっくり。

帰宅してからググってみたらけっこう有名なエラーらしい。ウィルスバスターが悪い、という説がたくさんあちこちで書かれているが、MSご本尊はこんなふうにも書いている。

Windows Vista または Windows 7 上の Excel 2007 または Excel 2010 でファイルの上書き保存に失敗する場合がある

修正プログラムがあるらしいんだけど・・・パソコン使うのに慣れていない人たちがパッチを当ててくれるかが疑問だなあ。

PDFkit PDFSelection

PDFドキュメントが必ずアウトラインをもっているわけでなく、そういう場合はアウトラインがないよ、と表示する専用のViewを用意した。


具体的に書かれていたわけではないけれど、デベロッパドキュメントではそれらしい書き方がされていた、と。

アウトラインはそれでいいわけだが、こういうドキュメントで検索をするとこうなってしまう。

検索結果の2番目の列には、検索文字列が含まれているアウトラインの見出しを入れる仕様だから(ま、これもデベロッパドキュメントどおりなんだけど)仕方がない。

あまりにも味気ないので、Skimのように検索文字列の前後を表示するにはどうするのか調べてみた。

PDFSelectionにそれらしいメソッドがないか探してみたら、あったあった。便利なメソッドがちゃんと用意されているもんだなあ。
extendSelectionAtEnd:
こいつが検索文字列を後方に伸ばしてくれるメソッド。前方に伸ばすのはextendSelectionAtStart:。

実際に試してみたところ、前方にも後方にも伸ばしてみると


こうなった。うーむ、ちょっと見づらいなあ。で、後方に伸ばすだけにしてみたらいい具合。


コードはこうなる。

PDFSelection *copy=[[searchResults objectAtIndex:row] copy] ;
//[copy extendSelectionAtStart:5];
[copy extendSelectionAtEnd:15];
NSString *label=[copy string];
return label;
[copy release];
コメントアウトしているのが前方に伸ばしている部分。もう少し「伸ばした部分」の文字列によって処理を変えてやれば見た目の美しい結果になるような気もする。でも、できたからまあいいか、と。
もちろんど素人なので、Skimのソースを参照した結果である。でもなんとなくうれしい。

サイドパネル関連はこんなところかなー。次はブックマーク関連の調査に入るつもり。