Month: September 2014

Swift:フォルダの一斉開閉機能を見直し

フォルダを全部開く機能に対して全部閉じる機能がなかったので追加しました。

全部のフォルダを1クリックで開いたり閉じたりできるようにしました。

そもそも全部のフォルダを開く機能は、Drag and Dropとの配列競合によっておきたバグを調べるために追加したのですが、使ってみると意外に便利なので、ついでに、全部のフォルダを閉じる機能を追加しました。

また、フォルダ開閉機能のコードが重複していている部分があったり、単純でない箇所があったので、整理しました。だいぶすっきりしました。

Swift:MesaClipper 2.0 Swiftソースコード

ようやくbug fixができましたので、ソースコードをリリースします。

まだデバッグ中ですが、いい線までできてきましたのでソースコードをリリースアップしました。

主要機能と機能追加項目は次の通りです。ドキュメントは準備中です。

主要機能:

  • webベージの読み込み・表示
  • 読み込んだwebページのテキストや図形等の切貼、文字の追加、色付、文字サイズやフォントの変更
  • 加工編集したwebページを.webarchiveファイルとして保存・再表示
  • 参照したオリジナルwebページのURLの保存・再表示
  • Java ON/OFF

v1.0からの機能追加項目:

  • Drag and Drop (Rename)
  • Drag and delete
  • Sort
  • フォルダ開閉
  • 閉じたフォルダをすべて開ける機能

留意事項:

  • Drag and Dropは基本的にはmoveになります。dropする先にすでに同じファイルがあるとき、置き換えない仕様としました。また、フォルダをまたがって複数ファイルのDrag and Dropが可能です。
  • Drag and Dropはフォルダを閉じている場合でもできるようにしました。
  • フォルダの開閉状態は、アプリ再開後も前の状態を引き継ぎます。

Swift:フォルダ開閉のバグ発見

ロジックをシンプルにしながら、Drag and Dropのあとにおかしくなるバグを調査中。

信じられないことに、フォルダ開閉で使っているsave/restoreの配列をDrag and Dropでも効率化のために使い回していました。これは実にまずいです。

また、Drag and Dropでフォルダから別のフォルダにファイルを移す場合、ファイル名が同じになる可能性があり、そのチェックが漏れていました。やれやれ。

これではフォルダ開閉をいくら調べても原因がわからないはずです。このバグを直したらソースコードをアップできると思います。多分。

  • Drag and Dropで使っているsave/restoreの配列名を変更したらOKになりました。
  • Drag and Dropする前にファイルチェックして、同一ファイルを回避すればもうひとつの問題も解決できます。しかし、Drag and Dropは、書いているときは理解できても、あとになるとやはり複雑です。

Swift:NSImageViewに写真を表示する

広告の代わりに写真を表示するようにしました。

これまでWebViewにURLを表示するようにしていたのですが、写真を枠内に収めるには、元々の画像を縮小しておくか、プログラムで縮小しないといけないことがわかりました。

それでNSImageViewを使うことにしたのですが、表示の仕方がわかりませんでした。調べていったら、ファイルから表示する方法とURLから表示する方法があることがわかりました。

基本的には3行ですみます。この場合、写真のURLが入っている配列mcAdArrayからURLを取り出し、NSURLに変換します。それからcontentsOfURL:でURLを読み込みます。

@IBOutlet var xbImage:NSImageView

var wurl    = mcAdArray[mcAdInx]
var imageURL: NSURL = NSURL.URLWithString(wurl)
xbImage.image = NSImage(contentsOfURL:imageURL)

ファイルパスの場合、xbImage.image = NSImage(contentsOfFile: filepath)のようにNSURLの代わりにファイルパスを指定して読み込みます。

NSImageViewは該当するエリアに自動的に写真をfitしてくれます。Document Builderのatributes inspectorで表示位置(揃え)を指定しておけば、何もしなくてすみます。右上の写真(サムネール)がそうです。

追記:写真の読み込みはブログからしているのですが、意外に時間がかかるので、いったん溜め込んだものをImage Viewに入れるように変更しました。

スクリーンショット 2014-09-27 20.39.08

Swift:NSTableViewのDrag and Drop

結論から言うと、ずっと前にObjective-CでDrag and Dropを実装しようとして諦めたときに訪れたwebサイトがとても参考になりました。

それは、Drag rows inside a NSTableViewです。Appleのサンプルプログラムやほかのものも参照したのですが、このサイトの通りに実装したら自分の思っている通りのことが実現できました。

この際、NSTableViewのDrag and Dropを整理しておきます。

使ったメソッド(呼び出される順番に列挙):

  1. func tableView(aTableView: NSTableView!, writeRowsWithIndexes  rowIndexes: NSIndexSet!, toPasteboard pboard: NSPasteboard!) -> Bool
  2. func tableView(tableView: NSTableView,  draggingSession session:NSDraggingSession!,  willBeginAtPoint screenPoint:NSPoint, forRowIndexes rowIndexes:NSIndexSet!)
  3. func tableView(aTableView:NSTableView,  validateDrop info:NSDraggingInfo, proposedRow row:Int, proposedDropOperation operation:NSTableViewDropOperation) -> NSDragOperation
  4. func tableView(tableView: NSTableView!, updateDraggingItemsForDrag draggingInfo: NSDraggingInfo!)
  5. func tableView(aTableView:NSTableView,acceptDrop info:NSDraggingInfo!,
    row: Int,dropOperation operation:NSTableViewDropOperation) -> Bool
  6. func tableView(tableView: NSTableView, draggingSession session: NSDraggingSession, endedAtPoint screenPoint: NSPoint, operation: NSDragOperation)

実装したが呼び出されなかったメソッド:

  • func ExecWriteItems(wkArraySave:[NSArray], toPasteboard pasteboard: NSPasteboard)-> Bool
  • func writableTypesForPasteboard(pasteboard: NSPasteboard!) -> [AnyObject]!
  • func writingOptionsForType(type: String!, pasteboard : NSPasteboard!) -> NSPasteboardWritingOptions
  • func tableView(aTableView: NSTableView, namesOfPromisedFilesDroppedAtDestination dropDestination: NSURL!,   forDraggedRowsWithIndexes indexSet: NSIndexSet!) -> [AnyObject]!

注意が必要な事柄:

  • awakeFromNib()等で複数行を選択可能にし、Drag and Dropの初期化が必要。DraggedTypesはなぜこのvalueでないといけないのか、そこまで深く追求していません。
    xbTableView.allowsMultipleSelection = true
    xbTableView.registerForDraggedTypes([NSStringPboardType, NSPasteboardTypeString])
    xbTableView.registerForDraggedTypes([NSPasteboardTypeString])
    xbTableView.setDraggingSourceOperationMask(NSDragOperation.Copy, forLocal: true)
  • MesaClipperでは、.webarchiveファイルをNSTableView (内部的にはNSDictionary)で管理しているため、NSTableViewのDrag and Dropを実装するとき、.webarchiveファイルを動かす処理をしなければなりませんでした。これが少し面倒でした。よくあるサンプルプログラムのファイル一覧を作るDrag and Dropは、あまり参考になりませんでした(というか、それでは実装に漕ぎ着けませんでした)。
  • そういう訳で、Drag and Dropのメソッドで利用している部分は、Drag範囲、Drop位置、タイミングの3点で、そのほかは自分で力づくで実装しなければなりませんでした。
  • selectRowでどの行が選択されているかわかるようにした方がデバッグが早いかもしれません。
  • sortによってDragした行がバラけます。Drop先頭行位置はそれで変わらないか、次にどの行を表示するか等、気をつけた方がいいと思います。
  • 先程、webViewのoverrideに制御が渡って来ないことに気がつきました。NSObjectからNSTableViewに変更したことが原因かもしれません。それで、!を取ってら制御が渡ってくるようになりました。
    理由はよくわかりません。

override func webView(sender: WebView, didFinishLoadForFrame frame: WebFrame)

  • バグ修正:既に.webffileが存在するとき、表の行情報(NSTableView or NSDictinary)を今まで更新していなかったのですが、URLをURL2にセットして、これをNSDictinaryに反映させる仕様に変えたので、webffileが存在するときでも表の行情報を更新しなければならないことがわかりました。
  • マニュアル修正:今週末はマニュアルを修正して、ソースコードをアップする予定です。ただし、マンション組合の提案資料作りもしないといけないので、全部終わるかどうか?

Swift:ファイルのリネームの仕方

これには成程と感心しました。

Drag and DropでNSTableView中のフォルダの中のファイルを移したとき、実際のファイルも移す必要があります。感覚的には、古いファイルを読んで削除する。新しいファイルをDrop先のフォルダの中に入れるために新しいファイルパスで書き込めばいいはず。

しかし、そんなことをしなくても、ちゃんとリネームメソッドがありました。おかげで、.webarchiveファイルを読み込んで書き込んだ場合、編集不可能なWebViewをsaveすることになる問題、言い換えるとリンクが無効になってしまう問題を回避できました。

 var wfilepath:String    = wkArray[inx][“fFilepath”]  as String
var fileManager:NSFileManager   = NSFileManager.defaultManager()
wError  = nil
rBool   = fileManager.moveItemAtPath(wfilepath, toPath: ffFilepath, error: &wError)

このあと、Dragによる削除を実装します。それから、検索機能を追加すれば、boookmark検索がしやすくなるので調べたいと考えています。

Swift:Drag and Dropが少し・・・

Drag and Dropが少し動き始めました。

原因はいろいろあるのですが、pasteboardへの書き込みとTypeの設定の仕方の2点に問題がありました。

これを修正したら、複数行を選択して1行だけcopy and pasteができるようになりました。

  • 全部の行をpasteできるようにする。
    ➡️実装済み
  • フォルダはpasteしない。
    ➡️実装済み
  • フォルダが選択されていたときの仕様を決める(直前の行までとするか、フォルダだけ無視するか?)
    ➡️実装済み フォルダだけ無視する。
  • Drop後にソートする。
    ➡️実装済み
  • Drop後にどの行を表示するようにするか仕様を決める。
    ➡️実装済み
  • 削除の実装。
    ➡️実装済み
  • copyにするか、moveにするか。
    ➡️実装済み moveにする
    ➡️ファイルのrename。フォルダに関する処理も必要。

Swift:Drag and Dropの機能追加ステータス

Dragはなんとなく通りはじめたのですが、Dropが全く反応せずです。

現在の状況は次の通りです。

  • Drag開始・終了でDrag範囲のインデックスを拾えます。
  • このあと、NSCellの削除ボタンをクリックしたとき該当するrowを削除すれば、削除についてはOKになります。これは比較的簡単にできそうです。
  • 問題はcopy and pasteで、Dropしたインデックスを拾えないと先に行きません。
  • もうひとつの問題は、Dragでpasteboardにcopyする処理をしなければならないのですが、NSDictionaryの抽出行をうまくpasteboardに入れられません。警告メッセージに従ってあれこれやっているところです。
  • あと、Drag adn Dropなのですが、ダブルクリックしないとDragが効かないようですが、これは少し気になります。NSTableViewの仕様なのでしょうか?
  • 簡単そうでなかなかパパッと行かないものですね。