[farman] ".." を一番上に表示

前回の続き。

前回を踏まえて、QDirModel の派生クラスである FolderModel を、QSortFilterProxyModel を派生させ、QFileSystemModel を SourceModel として使用するものに置き換えた。

QFileSytemModel::setRootPath()

QFileSystemModel と QDirModel の違いだが、ソート機能がない以外はそれほど大きな違いはないようだ。

ただ、現在のフォルダから移動する際、従来の QDirModel + QTableView では QDirModel::index(フォルダパス) で返された index を QTableView::setRootIndex() に渡せばよかったが、QFileSystemModel では QFileSystemModel::setRootPath(フォルダパス) でまず Model 側のルートパスを切り替え、さらに setRootPath() から返された index を QTableView::setRootIndex() に渡す必要がある。

従来は、この後 QTableView 上のファイル一覧が移動先の内容に切り替わり、移動先が子フォルダであればリストの先頭、親フォルダ("..")であれば移動前のフォルダにカーソルを移動(必要であればスクロール位置も)させて終了となるが、何故かうまく動作しない。
それで調べたところ、QFileSystemModel::setRootPath() を呼び出すとルートパスを切り替える処理自体は非同期で行われるようで、まず同メソッド内から QFileSystemModel::rootPathChanged の signal が送られる。
また、一覧表示するためにフォルダ内の情報を収集するのだが、これもその後ルートパス内の強制ソート処理が非同期で行われているようで、rootPathChanged の後に QFileSystemModel::directoryLoaded の signal が送られてくるので、これを待ってからフォルダ内の情報を取得するようにしないと正確な QModelIndex が取得できないっぽかった。
ここに行き着くまでにかなり時間がかかってしまった。

フィルタ

QFileSystemModel にソートの機能は無いが、フィルタは QFileSystemModel・QSortFilterProxyModel 両方に存在する。
ファイルシステムに依存するフィルタ(隠しファイルの表示/非表示、ディレクトリの表示・非表示など)はもちろん QFileSystemModel のフィルタを使うしか無いが、正規表現を使ったフィルタは QSortFilterProxyModel でないとできないっぽいし、ワイルドカードは QFileSytemModel・QSortFilterProxyModel どちらでもできるようだ。
どうするか悩んだが、正規表現を使ったファイルの絞り込み機能はあまり使わない気がしたので、フィルタについては QFileSytemModel の機能をそのまま使うことにした。
現在の farman にはワイルドカードを使った絞り込み機能は存在しないが、前回作ったテストアプリで実験して問題なく動作することは確認済みなので、いずれ実装しようと思う。

ということで

現在のアプリはこんな感じになった。
スクリーンショット 2018-05-17 7.12.21.png
↑のスクショを見てもらえれば分かる通り、ソート設定ではフォルダは最後に表示となっているが、".." のみ先頭に表示している。
また、今回 FolderModel を再実装するにあたり、やはり Type(≒ 拡張子)はファイル名とは別に表示した方がいいかなと思い直し、4カラムにした。

前回にも書いた通り、QSortFilterProxyModel::lessThan() をオーバーライドしているので、どういったソート条件であっても理論上は実装可能だ。
なので、だいなファイラーのように、複数のソート条件を優先度を付けて設定したりすることもできそうである。
パーミッション別とか、そういったことも可能だろう(需要があるかは兎も角)。

体調のこともあり、思った以上に時間がかかってしまったが、今後ソート機能を拡張できる余地ができたのはよかった。
(2018/5/19)
QFileSystemModel::setRootPath() の挙動についてちょっと嘘書いちゃってたので修正。
やっぱちゃんとソース読まなきゃダメだな。

この記事へのコメント