2017年10月29日日曜日

テキストエディタをJavaで作成する計画5

日曜プログラマーごっこやるのもいいですが、晴れの日は外で遊びたいです。。。
今日は雨なので、久しぶりにブログ更新です!!

今回は「上書き保存」機能を実装してみます。
今作っているテキストエディタは複数ウィンドウ出て来て、それぞれファイルを開くことができることもあって、ファイルロックは実装しておきたいところです。
それと新規作成でファイルを開いていない状態からの「上書き保存」は「名前を付けて保存」ってことなので、「名前を付けて保存」が実装されたら処理変更しないといけないです。
ということで、割と重い作業なので、ファイルロックだけ実装します。

①ファイルを開くときにファイルをロックする。
②ファイルを閉じるときにロックを解除する。

ファイルロックできないときは考えてないので、とりあえず例外だけ投げて放置です。

【FXMLDocumentController】

    private ProcessManager pm;

    private void openAction(ActionEvent event) {

        bottomLabel.setText("開く");
        pm.setSelectedFile(pm.openFileChooser(scene));

        // ファイルが選択されたとき
        if (pm.getSelectedFile() != null) {
            pm.setCurrentFilePath(Paths.get(pm.getSelectedFile().getAbsolutePath()));

            try {
//            ファイルチャンネルを設定する
                pm.setFileChannel(FileChannel.open(pm.getSelectedFile().toPath(),
                        StandardOpenOption.CREATE,
                        StandardOpenOption.WRITE));
                if (pm.getFileChannel().tryLock() != null) {
                    // ファイルロックができれば表示する
                    textArea.setText(new String(Files.readAllBytes(pm.getCurrentFilePath()), pm.getCharset()));
                }
            } catch (OverlappingFileLockException ex) {
                // 別のプロセスがロック中
            } catch (IOException ex) {
                Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
            }
            bottomLabel.setText(pm.getSelectedFile().getName());
        }
    }


    /**
     * MenuItem[閉じる] イベントが発生したウィンドウを非表示にします。
     *
     * @param event
     */
    @FXML
    void closeAction(ActionEvent event) {
        bottomLabel.setText("閉じる");
        try {
            // ファイルロック解除
            if(pm.getFileChannel() != null) {
                pm.getFileChannel().close();
            }
        } catch (IOException ex) {
            Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
        }
        pm.terminateTextEditer(getScene());
    }

    /**
     * メニューの「上書き保存」を押下しすると、saveTextメソッドを呼び出します。
     *
     * @param event
     */
    @FXML
    private void saveAction(ActionEvent event) {
        bottomLabel.setText("上書き保存");
        pm.saveText(textArea.getText());
    }

【ProcessManager】

    /**
     * 編集中のファイルパス
     */
    private Path currentFilePath;
    /**
     * 作業中のファイルチャンネル
     */
    private FileChannel fileChannel;

    /**
     * 開いているファイルにテキストデータを上書き保存します。
     *
     * @param text 保存するテキストデータ
     */
    public void saveText(String text) {
        try {
            Files.write(currentFilePath, text.getBytes(charset),
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING
            );
        } catch (IOException ex) {
            Logger.getLogger(ProcessManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

ソースが長くなってきて、かなり省略してますけど、いるところ抜けてないかな?
アクションにロジック書いちゃったのはミスでした。
ファイルロックできないときは参照モードとかもいるのかな?
テキストエディタって思ったより大変ですね。

2017年10月1日日曜日

テキストエディタをJavaで作成する計画4

今回はファイルを「開く」機能を追加します。

流れとしては、

①メニューの「開く」ボタンを押下する。
②FileChooserを用いてファイルを選択する。
③選択したファイルのデータがTextAreaに表示される。

です。下記の内容で実装してみました。

【FXMLDocumentControllerクラス】FileChooserを呼び出し、戻り値のFileをUTF-8で読み込み、値をTextAreaにセットします。ついでに、ウィンドウの下の方にファイル名が表示されるようにしました。
public class FXMLDocumentController implements Initializable {

    private ProcessManager pm;
    private Scene scene;

    private void openAction(ActionEvent event) {
        bottomLabel.setText("開く");
        File selectedFile = pm.openFileChooser(scene);
        if(selectedFile != null) {
            try {
                textArea.setText(new String(Files.readAllBytes(Paths.get(selectedFile.getAbsolutePath())), StandardCharsets.UTF_8.name()));
            } catch(IOException e) {
                e.printStackTrace();
            }
            bottomLabel.setText(selectedFile.getName());
        }
    }
}


【ProcessManagerクラス】拡張子のフィルター機能がありますが、今回は一旦、「すべてのファイル」としておきました。
public class ProcessManager extends Application {

    public File openFileChooser(Scene scene) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().addAll(
                new ExtensionFilter("すべてのファイル", "*.*")
        );
        File selectedFile = fileChooser.showOpenDialog(scene.getWindow());
        return selectedFile;
    }
}






という事で、UTF-8ならちゃんとファイルを開くことができるプログラムができました。