diff --git a/README.md b/README.md index dfff248..f3bf245 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ ![interface](image/screenshot.png) ## 使用方式 + 1. 拖动PDF文件到窗口 2. 写入目录文本,格式在下面 3. 设定 页面偏移量=PDF中的页码–原书的页码 @@ -55,6 +56,7 @@ ![screenvideo_1](image/screenvideo_1.gif) +[1.0版本使用说明移步这里](https://zhuanlan.zhihu.com/p/390719305) ### Tips diff --git a/src/main/java/com/ririv/quickoutline/pdfProcess/OutlineProcessor.java b/src/main/java/com/ririv/quickoutline/pdfProcess/OutlineProcessor.java index 876f5b6..4377425 100644 --- a/src/main/java/com/ririv/quickoutline/pdfProcess/OutlineProcessor.java +++ b/src/main/java/com/ririv/quickoutline/pdfProcess/OutlineProcessor.java @@ -16,7 +16,7 @@ public interface OutlineProcessor { 当再次使用上次被打开的pdfDoc时,会报错head not found 因此这里调用函数时打开doc,并在函数中即时关闭它 */ - void setContents(Bookmark rootBookmark, String srcFilePath, String destFilePath, PdfViewScaleType scaleType) throws IOException; + void setContents(Bookmark rootBookmark, String srcFilePath, String destFilePath, ViewScaleType scaleType) throws IOException; String getContents(String srcFilePath, int offset) throws IOException; diff --git a/src/main/java/com/ririv/quickoutline/pdfProcess/PageLabel.java b/src/main/java/com/ririv/quickoutline/pdfProcess/PageLabel.java new file mode 100644 index 0000000..0cb52ef --- /dev/null +++ b/src/main/java/com/ririv/quickoutline/pdfProcess/PageLabel.java @@ -0,0 +1,31 @@ +package com.ririv.quickoutline.pdfProcess; + + +//https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf#page=383 +//根据PDF标准 +//与iText的PageLabel对应 +public record PageLabel(int pageNum, PageLabelNumberingStyle numberingStyle, String labelPrefix, Integer firstPage){ + + public enum PageLabelNumberingStyle{ + /** + * 1, 2, 3, 4... + */ + DECIMAL_ARABIC_NUMERALS, + /** + * I, II, III, IV... + */ + UPPERCASE_ROMAN_NUMERALS, + /** + * i, ii, iii, iv... + */ + LOWERCASE_ROMAN_NUMERALS, + /** + * A, B, C, D... + */ + UPPERCASE_LETTERS, + /** + * a, b, c, d... + */ + LOWERCASE_LETTERS + } +} \ No newline at end of file diff --git a/src/main/java/com/ririv/quickoutline/pdfProcess/PageLabelSetter.java b/src/main/java/com/ririv/quickoutline/pdfProcess/PageLabelSetter.java new file mode 100644 index 0000000..a97d338 --- /dev/null +++ b/src/main/java/com/ririv/quickoutline/pdfProcess/PageLabelSetter.java @@ -0,0 +1,11 @@ +package com.ririv.quickoutline.pdfProcess; + +import java.io.IOException; +import java.util.List; + +public interface PageLabelSetter { + + void setPageLabels(String srcFilePath, String destFilePath, List labelList) throws IOException; + + T mapPageLabelNumberingStyle(PageLabel.PageLabelNumberingStyle numberingStyle); +} diff --git a/src/main/java/com/ririv/quickoutline/pdfProcess/PdfViewScaleType.java b/src/main/java/com/ririv/quickoutline/pdfProcess/ViewScaleType.java similarity index 82% rename from src/main/java/com/ririv/quickoutline/pdfProcess/PdfViewScaleType.java rename to src/main/java/com/ririv/quickoutline/pdfProcess/ViewScaleType.java index f08bf12..cfa1bc1 100644 --- a/src/main/java/com/ririv/quickoutline/pdfProcess/PdfViewScaleType.java +++ b/src/main/java/com/ririv/quickoutline/pdfProcess/ViewScaleType.java @@ -1,6 +1,6 @@ package com.ririv.quickoutline.pdfProcess; -public enum PdfViewScaleType { +public enum ViewScaleType { FIT_TO_WIDTH, FIT_TO_HEIGHT, FIT_TO_PAGE, diff --git a/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextOutlineProcessor.java b/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextOutlineProcessor.java index 31a1392..22bdfb7 100644 --- a/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextOutlineProcessor.java +++ b/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextOutlineProcessor.java @@ -9,7 +9,7 @@ import com.ririv.quickoutline.exception.NoOutlineException; import com.ririv.quickoutline.model.Bookmark; import com.ririv.quickoutline.pdfProcess.OutlineProcessor; -import com.ririv.quickoutline.pdfProcess.PdfViewScaleType; +import com.ririv.quickoutline.pdfProcess.ViewScaleType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +25,7 @@ public class ItextOutlineProcessor implements OutlineProcessor { // 如果rootBookmark没有Children,即之前的text为空(当然这种情况已在Controller中被排除) // list.clear()没有起作用(不知道原因),最终目录没有影响,怀疑原因是没有写入操作。 @Override - public void setContents(Bookmark rootBookmark, String srcFilePath, String destFilePath, PdfViewScaleType scaleType) throws IOException { + public void setContents(Bookmark rootBookmark, String srcFilePath, String destFilePath, ViewScaleType scaleType) throws IOException { if (checkEncrypted(srcFilePath)) throw new EncryptedPdfException(); PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcFilePath), new PdfWriter(destFilePath)); @@ -41,7 +41,7 @@ public void setContents(Bookmark rootBookmark, String srcFilePath, String destFi //合并了上面两个函数 - private void bookmarkToOutlines(Bookmark parentBookmark, PdfOutline rootOutline, PdfDocument srcDoc, PdfViewScaleType scaleType) { + private void bookmarkToOutlines(Bookmark parentBookmark, PdfOutline rootOutline, PdfDocument srcDoc, ViewScaleType scaleType) { //不为根结点时,进行添加操作 if (!parentBookmark.isRoot()) { diff --git a/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextPageLabelSetter.java b/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextPageLabelSetter.java index f5c2b1e..9302e45 100644 --- a/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextPageLabelSetter.java +++ b/src/main/java/com/ririv/quickoutline/pdfProcess/itextImpl/ItextPageLabelSetter.java @@ -1,106 +1,74 @@ package com.ririv.quickoutline.pdfProcess.itextImpl; -import com.itextpdf.io.font.constants.StandardFonts; -import com.itextpdf.kernel.font.PdfFont; -import com.itextpdf.kernel.font.PdfFontFactory; -import com.itextpdf.kernel.geom.PageSize; -import com.itextpdf.kernel.geom.Rectangle; -import com.itextpdf.kernel.pdf.*; -import com.itextpdf.kernel.pdf.action.PdfAction; -import com.itextpdf.kernel.pdf.annot.PdfAnnotation; -import com.itextpdf.kernel.pdf.annot.PdfTextAnnotation; -import com.itextpdf.kernel.pdf.canvas.PdfCanvas; -import com.itextpdf.kernel.pdf.xobject.PdfFormXObject; -import com.itextpdf.layout.Document; -import com.itextpdf.layout.element.AreaBreak; -import com.itextpdf.layout.element.Link; -import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.kernel.pdf.PageLabelNumberingStyle; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.ririv.quickoutline.pdfProcess.PageLabel; +import com.ririv.quickoutline.pdfProcess.PageLabelSetter; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; -public class ItextPageLabelSetter { - - public static final String DEST = "./target/sandbox/objects/page_labels.pdf"; +// https://kb.itextpdf.com/itext/page-labels +public class ItextPageLabelSetter implements PageLabelSetter { public static void main(String[] args) throws IOException { + final String SRC = ""; + final String DEST = "./target/sandbox/objects/page_labels.pdf"; + + List labelList = new ArrayList<>(); + labelList.add(new PageLabel(1, PageLabel.PageLabelNumberingStyle.UPPERCASE_LETTERS,null,null)); File file = new File(DEST); file.getParentFile().mkdirs(); - new ItextPageLabelSetter().setPdfLabels(DEST); + new ItextPageLabelSetter().setPageLabels(SRC, DEST, labelList); } - protected void setPdfLabels(String dest) throws IOException { - PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest)); - Document doc = new Document(pdfDoc); - - PdfViewerPreferences viewerPreferences = new PdfViewerPreferences(); - viewerPreferences.setPrintScaling(PdfViewerPreferences.PdfViewerPreferencesConstants.NONE); - pdfDoc.getCatalog().setPageMode(PdfName.UseThumbs); - pdfDoc.getCatalog().setPageLayout(PdfName.TwoPageLeft); - pdfDoc.getCatalog().setViewerPreferences(viewerPreferences); - - doc.add(new Paragraph("Hello World")); - doc.add(new Paragraph("Hello People")); - - doc.add(new AreaBreak()); - PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA); + public void setPageLabels(String srcFilePath, String destFilePath, List labelList) throws IOException { + PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcFilePath), new PdfWriter(destFilePath)); - // Add the text to the direct content, but not in the right order - PdfCanvas canvas = new PdfCanvas(pdfDoc.getPage(2)); - canvas.beginText(); - canvas.setFontAndSize(font, 12); - canvas.moveText(88.66f, 788); - canvas.showText("ld"); - canvas.moveText(-22f, 0); - canvas.showText("Wor"); - canvas.moveText(-15.33f, 0); - canvas.showText("llo"); - canvas.moveText(-15.33f, 0); - canvas.showText("He"); - canvas.endText(); - PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(250, 25)); - new PdfCanvas(formXObject, pdfDoc).beginText() - .setFontAndSize(font, 12) - .moveText(0, 7) - .showText("Hello People") - .endText(); - canvas.addXObjectAt(formXObject, 36, 763); + for(PageLabel label: labelList){ + int pageNum = label.pageNum(); + PageLabelNumberingStyle numberingStyle = mapPageLabelNumberingStyle(label.numberingStyle()); - pdfDoc.setDefaultPageSize(new PageSize(PageSize.A4).rotate()); - doc.add(new AreaBreak()); - doc.add(new Paragraph("Hello World")); + String labelPrefix = label.labelPrefix(); + Integer firstPage = label.firstPage(); - pdfDoc.setDefaultPageSize(new PageSize(842, 595)); - doc.add(new AreaBreak()); - doc.add(new Paragraph("Hello World")); + if (label.firstPage() ==null){ + pdfDoc.getPage(pageNum).setPageLabel(numberingStyle, labelPrefix); + } else { + pdfDoc.getPage(pageNum).setPageLabel(numberingStyle, labelPrefix, firstPage); + } + } - pdfDoc.setDefaultPageSize(PageSize.A4); - doc.add(new AreaBreak()); - pdfDoc.getLastPage().setCropBox(new Rectangle(10, 70, 525, 755)); - doc.add(new Paragraph("Hello World")); - - doc.add(new AreaBreak()); - pdfDoc.getLastPage().getPdfObject().put(PdfName.UserUnit, new PdfNumber(5)); - doc.add(new Paragraph("Hello World")); - - doc.add(new AreaBreak()); - pdfDoc.getLastPage().setArtBox(new Rectangle(36, 36, 523, 770)); - Paragraph p = new Paragraph("Hello ") - .add(new Link("World", PdfAction.createURI("http://maps.google.com"))); - doc.add(p); - PdfAnnotation a = new PdfTextAnnotation( - new Rectangle(36, 755, 30, 30)) - .setTitle(new PdfString("Example")) - .setContents("This is a post-it annotation"); - pdfDoc.getLastPage().addAnnotation(a); - - - pdfDoc.getPage(1).setPageLabel(PageLabelNumberingStyle.UPPERCASE_LETTERS, null); - pdfDoc.getPage(3).setPageLabel(PageLabelNumberingStyle.DECIMAL_ARABIC_NUMERALS, null); - pdfDoc.getPage(4).setPageLabel(PageLabelNumberingStyle.DECIMAL_ARABIC_NUMERALS, "Custom-", 2); + } - doc.close(); + @Override + public PageLabelNumberingStyle mapPageLabelNumberingStyle(PageLabel.PageLabelNumberingStyle numberingStyle) { + + switch (numberingStyle) { + case PageLabel.PageLabelNumberingStyle.DECIMAL_ARABIC_NUMERALS -> { + return PageLabelNumberingStyle.DECIMAL_ARABIC_NUMERALS; + } + case PageLabel.PageLabelNumberingStyle.LOWERCASE_ROMAN_NUMERALS -> { + return PageLabelNumberingStyle.LOWERCASE_ROMAN_NUMERALS; + } + case PageLabel.PageLabelNumberingStyle.UPPERCASE_ROMAN_NUMERALS-> { + return PageLabelNumberingStyle.UPPERCASE_ROMAN_NUMERALS; + } + case PageLabel.PageLabelNumberingStyle.LOWERCASE_LETTERS-> { + return PageLabelNumberingStyle.LOWERCASE_LETTERS; + } + case PageLabel.PageLabelNumberingStyle.UPPERCASE_LETTERS-> { + return PageLabelNumberingStyle.UPPERCASE_LETTERS; + } + case null -> { + return null; + } + } } } diff --git a/src/main/java/com/ririv/quickoutline/service/PdfLabelService.java b/src/main/java/com/ririv/quickoutline/service/PdfLabelService.java new file mode 100644 index 0000000..24563ff --- /dev/null +++ b/src/main/java/com/ririv/quickoutline/service/PdfLabelService.java @@ -0,0 +1,18 @@ +package com.ririv.quickoutline.service; + +import com.itextpdf.kernel.pdf.PageLabelNumberingStyle; +import com.ririv.quickoutline.pdfProcess.PageLabel; +import com.ririv.quickoutline.pdfProcess.PageLabelSetter; +import com.ririv.quickoutline.pdfProcess.itextImpl.ItextPageLabelSetter; + +import java.io.IOException; +import java.util.List; + +public class PdfLabelService { + private final PageLabelSetter pageLabelSetter = new ItextPageLabelSetter(); + + public void setPageLabels(String srcFilePath, String destFilePath, List labelList) throws IOException{ + pageLabelSetter.setPageLabels(srcFilePath, destFilePath, labelList); + } + +} diff --git a/src/main/java/com/ririv/quickoutline/service/PdfService.java b/src/main/java/com/ririv/quickoutline/service/PdfOutlineService.java similarity index 93% rename from src/main/java/com/ririv/quickoutline/service/PdfService.java rename to src/main/java/com/ririv/quickoutline/service/PdfOutlineService.java index c452ccf..9ff01e3 100644 --- a/src/main/java/com/ririv/quickoutline/service/PdfService.java +++ b/src/main/java/com/ririv/quickoutline/service/PdfOutlineService.java @@ -5,7 +5,7 @@ import com.ririv.quickoutline.exception.NoOutlineException; import com.ririv.quickoutline.model.Bookmark; import com.ririv.quickoutline.pdfProcess.OutlineProcessor; -import com.ririv.quickoutline.pdfProcess.PdfViewScaleType; +import com.ririv.quickoutline.pdfProcess.ViewScaleType; import com.ririv.quickoutline.pdfProcess.itextImpl.ItextOutlineProcessor; import com.ririv.quickoutline.textProcess.TextProcessor; import com.ririv.quickoutline.textProcess.methods.Method; @@ -13,11 +13,11 @@ import java.io.IOException; -public class PdfService { +public class PdfOutlineService { private final OutlineProcessor outlineProcessor = new ItextOutlineProcessor(); - public void setContents(String text, String srcFilePath, String destFilePath, int offset, Method method, PdfViewScaleType scaleType) throws IOException { + public void setContents(String text, String srcFilePath, String destFilePath, int offset, Method method, ViewScaleType scaleType) throws IOException { if (srcFilePath.isEmpty()) throw new RuntimeException("PDF路径为空"); Bookmark rootBookmark = convertTextToBookmarkTreeByMethod(text, offset, method); diff --git a/src/main/java/com/ririv/quickoutline/service/TocService.java b/src/main/java/com/ririv/quickoutline/service/PdfTocService.java similarity index 96% rename from src/main/java/com/ririv/quickoutline/service/TocService.java rename to src/main/java/com/ririv/quickoutline/service/PdfTocService.java index bdb905e..898c8c8 100644 --- a/src/main/java/com/ririv/quickoutline/service/TocService.java +++ b/src/main/java/com/ririv/quickoutline/service/PdfTocService.java @@ -5,7 +5,7 @@ import java.io.IOException; -public class TocService { +public class PdfTocService { public String extract(String pdfPath){ try { diff --git a/src/main/java/com/ririv/quickoutline/view/App.java b/src/main/java/com/ririv/quickoutline/view/App.java index e3e36c2..16540d3 100644 --- a/src/main/java/com/ririv/quickoutline/view/App.java +++ b/src/main/java/com/ririv/quickoutline/view/App.java @@ -1,4 +1,4 @@ -package com.ririv.quickoutline.view;//package com.ririv.contents.view; +package com.ririv.quickoutline.view; import javafx.application.Application; import javafx.fxml.FXMLLoader; @@ -14,7 +14,7 @@ public class App extends Application { -// 注意javafx程序架子顺序:main启动程序,加载fxml,fxml加载指定的controller +// 注意javafx程序架子顺序:main启动程序,加载fxml,fxml加载指定的controller @Override public void start(Stage stage) throws IOException { FXMLLoader fxmlLoader = new FXMLLoader(); @@ -27,7 +27,7 @@ public void start(Stage stage) throws IOException { // stage.setResizable(false); //不可调整大小 - stage.setTitle("QuickOutline - 编辑与添加PDF目录"); + stage.setTitle("QuickOutline - 编辑与添加PDF书签/目录"); stage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("icon/icon.png")))); stage.setScene(scene); stage.show(); diff --git a/src/main/java/com/ririv/quickoutline/view/GetContentsPopupController.java b/src/main/java/com/ririv/quickoutline/view/GetContentsPopupController.java index 2c2dfda..4a04903 100644 --- a/src/main/java/com/ririv/quickoutline/view/GetContentsPopupController.java +++ b/src/main/java/com/ririv/quickoutline/view/GetContentsPopupController.java @@ -1,6 +1,6 @@ package com.ririv.quickoutline.view; -import com.ririv.quickoutline.service.TocService; +import com.ririv.quickoutline.service.PdfTocService; import com.ririv.quickoutline.view.controls.Message; import com.ririv.quickoutline.view.controls.Switch; import javafx.beans.property.BooleanProperty; @@ -57,7 +57,7 @@ public GetContentsPopupController(MainController mainController) { } public void initialize() { - TocService tocService = new TocService(); + PdfTocService pdfTocService = new PdfTocService(); autoRecognize.bind(autoRecognizeSwitch.valueProperty()); @@ -104,12 +104,12 @@ public void initialize() { String contents; if (autoRecognize.get()) { - contents = tocService.extract(filepath.get()); + contents = pdfTocService.extract(filepath.get()); } else { if (startTF.getText().isEmpty() || endTF.getText().isEmpty()) { mainController.messageManager.showMessage("请输入起始页码和结束页码", Message.MessageType.WARNING); } - contents = tocService.extract(filepath.get(), Integer.parseInt(startTF.getText()), Integer.parseInt(endTF.getText())); + contents = pdfTocService.extract(filepath.get(), Integer.parseInt(startTF.getText()), Integer.parseInt(endTF.getText())); } this.mainController.textTabViewController.contentsTextArea.setText(contents); }); diff --git a/src/main/java/com/ririv/quickoutline/view/LeftPaneController.java b/src/main/java/com/ririv/quickoutline/view/LeftPaneController.java new file mode 100644 index 0000000..5d023d8 --- /dev/null +++ b/src/main/java/com/ririv/quickoutline/view/LeftPaneController.java @@ -0,0 +1,103 @@ +package com.ririv.quickoutline.view; + +import com.ririv.quickoutline.view.MainController.FnTab; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.image.Image; +import javafx.stage.Stage; +import org.slf4j.Logger; + +import java.io.IOException; +import java.util.Objects; + +public class LeftPaneController { + + private static final Logger logger = org.slf4j.LoggerFactory.getLogger(LeftPaneController.class); + + + public Node root; + private Stage helpStage; + + + public ToggleButton textTabBtn; + public ToggleButton treeTabBtn; + public ToggleGroup tabToggleGroup; + public Button helpBtn; + + public ToggleButton tocTabBtn; + public ToggleButton labelTabBtn; + + + public MainController mainController; + + FnTab currenTab; + + + void setMainController(MainController mainController){ + this.mainController = mainController; + this.root = mainController.root; + this.currenTab = mainController.currenTab; + } + + + public void initialize() { + textTabBtn.setSelected(true); + + tabToggleGroup.selectedToggleProperty().addListener((event,oldValue,newValue) -> { + // 保持选中状态,防止取消选中 + if (newValue == null){ + tabToggleGroup.selectToggle(oldValue); + logger.info("select {}", oldValue); + } + + if (textTabBtn.isSelected()) { + mainController.switchTab(FnTab.text); + } else if (treeTabBtn.isSelected()) { + mainController.switchTab(FnTab.tree); + } else if (tocTabBtn.isSelected()) { + mainController.switchTab(FnTab.toc); + } else if (labelTabBtn.isSelected()) { + mainController.switchTab(FnTab.label); + } + }); + } + + + @FXML + public void createHelpWindowAction(ActionEvent actionEvent) throws IOException { + if (helpStage == null) { + helpStage = new Stage(); + + FXMLLoader loader = new FXMLLoader(getClass().getResource("HelpWindow.fxml")); + Parent helpWinRoot = loader.load(); + + helpStage.setTitle("帮助"); + helpStage.setScene(new Scene(helpWinRoot, 400, 300)); + + helpStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("icon/help_black.png")))); + helpStage.setResizable(false); //不可调整大小,且使最大化不可用 + helpStage.initOwner(root.getScene().getWindow());//可以使最小化不可用,配合上一条语句,可以使最小化最大化隐藏,只留下"×" + helpStage.show(); +// helpStage.focusedProperty().addListener((observable, oldValue, newValue) -> { +// if (!observable.getValue()) { +// helpStage.hide(); +// ((Stage) root.getScene().getWindow()).toFront(); +// } +// }); + } + else { + // 如果窗口已经创建但被隐藏,重新显示 + // 如果窗口已存在,将其聚焦到前台 + helpStage.show(); +// helpStage.toFront(); + helpStage.requestFocus(); + } + } +} diff --git a/src/main/java/com/ririv/quickoutline/view/MainController.java b/src/main/java/com/ririv/quickoutline/view/MainController.java index 97f1cc4..c6e71e8 100644 --- a/src/main/java/com/ririv/quickoutline/view/MainController.java +++ b/src/main/java/com/ririv/quickoutline/view/MainController.java @@ -4,8 +4,8 @@ import com.ririv.quickoutline.exception.EncryptedPdfException; import com.ririv.quickoutline.exception.NoOutlineException; import com.ririv.quickoutline.model.Bookmark; -import com.ririv.quickoutline.pdfProcess.PdfViewScaleType; -import com.ririv.quickoutline.service.PdfService; +import com.ririv.quickoutline.pdfProcess.ViewScaleType; +import com.ririv.quickoutline.service.PdfOutlineService; import com.ririv.quickoutline.textProcess.methods.Method; import com.ririv.quickoutline.utils.InfoUtil; import com.ririv.quickoutline.view.controls.Message; @@ -14,25 +14,23 @@ import com.ririv.quickoutline.view.controls.Remind; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.scene.control.*; -import javafx.scene.image.Image; import javafx.scene.input.Dragboard; import javafx.scene.input.MouseEvent; import javafx.scene.input.TransferMode; +import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import javafx.stage.FileChooser; -import javafx.stage.Stage; import org.slf4j.Logger; import java.awt.*; import java.io.*; -import java.util.Objects; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import static com.ririv.quickoutline.view.MyAlert.showAlert; @@ -55,30 +53,24 @@ public class MainController { public StackPane root; - public PdfViewScaleType viewScaleType = PdfViewScaleType.None; + public ViewScaleType viewScaleType = ViewScaleType.None; //必须映射到textModeController,否则会无法报错 //与下面的textMode区分,其映射的是绑定的控件 public TextTabController textTabViewController; public TreeTabController treeTabViewController; + public LeftPaneController leftPaneController; // public TreeWebVIewController treeModeController; - - - public ToggleButton textTabBtn; - public ToggleButton treeTabBtn; - public ToggleGroup tabToggleGroup; - public Button helpBtn; - - public ToggleButton tocTabBtn; - public MessageContainer messageManager; public Remind indentRBtnRemind; public Remind seqRBtnRemind; + public BorderPane leftPane; + public Button setPageLabelBtn; - PdfService pdfService = new PdfService(); + PdfOutlineService pdfOutlineService = new PdfOutlineService(); @FXML private Node textTabView; // 实际上对应的HBox类型 @@ -86,49 +78,32 @@ public class MainController { private Node treeTabView; @FXML private Node tocGeneratorTabView; - + @FXML + private Node pageLabelTabView; public enum FnTab{ - text, tree, toc, setting - } - - private FnTab currenTab; - - private Stage helpStage; - - - public void switchTab(FnTab targetTab) { - if (targetTab == FnTab.text) { - textTabView.setVisible(true); - treeTabView.setVisible(false); - tocGeneratorTabView.setVisible(false); - - } else if (targetTab == FnTab.tree) { - treeTabView.setVisible(true); - textTabView.setVisible(false); - tocGeneratorTabView.setVisible(false); - reconstructTree(); - } else if (targetTab == FnTab.toc) { - tocGeneratorTabView.setVisible(true); - treeTabView.setVisible(false); - textTabView.setVisible(false); - } - currenTab = targetTab; + text, tree, toc, setting, label } + public List viewList; + // 定义一个枚举类型的属性 + FnTab currenTab; public void initialize() { textTabViewController.setMainController(this); treeTabViewController.setMainController(this); + leftPaneController.setMainController(this); + + currenTab = FnTab.text; seqRBtn.setUserData(Method.SEQ); indentRBtn.setUserData(Method.INDENT); seqRBtn.setSelected(true); - textTabBtn.setSelected(true); - currenTab = FnTab.text; + viewList = new ArrayList<>(Arrays.asList(textTabView,treeTabView, + tocGeneratorTabView,pageLabelTabView)); offsetTF.textProperty().addListener((observable, oldValue, newValue) -> { @@ -171,22 +146,7 @@ public void initialize() { openFile(file); }); - tabToggleGroup.selectedToggleProperty().addListener((event,oldValue,newValue) -> { - // 保持选中状态,防止取消选中 - if (newValue == null){ - switch (currenTab){ - case text -> tabToggleGroup.selectToggle(textTabBtn); - case tree -> tabToggleGroup.selectToggle(treeTabBtn); - } - } - if (textTabBtn.isSelected()) { - switchTab(FnTab.text); - } else if (treeTabBtn.isSelected()) { - switchTab(FnTab.tree); - } else if (tocTabBtn.isSelected()) { - switchTab(FnTab.toc); - } - }); + methodToggleGroup.selectedToggleProperty().addListener(event -> { if (currenTab == FnTab.tree) reconstructTree(); @@ -206,6 +166,20 @@ public void initialize() { setContentsBtn.addEventHandler(MouseEvent.MOUSE_ENTERED, popup2::showEventHandler); } + public void switchTab(FnTab targetTab) { + if (targetTab == FnTab.text) { + viewList.forEach(view-> view.setVisible(view == textTabView)); + } else if (targetTab == FnTab.tree) { + viewList.forEach(view-> view.setVisible(view == treeTabView)); + reconstructTree(); + } else if (targetTab == FnTab.toc) { + viewList.forEach(view-> view.setVisible(view == tocGeneratorTabView)); + } else if (targetTab == FnTab.label){ + viewList.forEach(view-> view.setVisible(view == pageLabelTabView)); + } + currenTab = targetTab; + } + @FXML private void getContentsBtnAction(ActionEvent event) { if (!textTabViewController.contentsTextArea.getText().isEmpty()) { @@ -235,8 +209,6 @@ private String destFilePath(){ return srcFilePath.substring(0, srcFilePath.lastIndexOf(srcFileName)) + srcFileName.substring(0, srcFileName.lastIndexOf(".")) + "_含目录" + ext; } - - private void openFile(File file){ if (file == null) return; @@ -245,7 +217,7 @@ private void openFile(File file){ if (newFilePath.equals(oldFilePath)) return; try { - pdfService.checkOpenFile(newFilePath); + pdfOutlineService.checkOpenFile(newFilePath); } catch (IOException e) { messageManager.showMessage("无法打开文档\n"+e.getMessage(), Message.MessageType.ERROR); return; @@ -298,7 +270,7 @@ private void setContentsBtnAction(ActionEvent event) { String srcFilePath = filepathTF.getText(); String destFilePath = destFilePath(); try { - pdfService.setContents(text, srcFilePath, destFilePath, offset(), + pdfOutlineService.setContents(text, srcFilePath, destFilePath, offset(), (Method) methodToggleGroup.getSelectedToggle().getUserData(), viewScaleType); } catch (BookmarkFormatException e) { @@ -379,7 +351,7 @@ private void getContents() { // 这里原本传入offset是用来相减,原本该功能未获取目录,而不是重置目录 // 因为比较迷惑,现在不再支持,设为0 try { - String contents = pdfService.getContents(filepathTF.getText(), 0); + String contents = pdfOutlineService.getContents(filepathTF.getText(), 0); textTabViewController.contentsTextArea.setText(contents); } catch (NoOutlineException e) { e.printStackTrace(); @@ -399,7 +371,7 @@ public int offset() { } public void reconstructTree() { - Bookmark rootBookmark = pdfService.convertTextToBookmarkTreeByMethod( + Bookmark rootBookmark = pdfOutlineService.convertTextToBookmarkTreeByMethod( textTabViewController.contentsTextArea.getText(), 0, (Method) methodToggleGroup.getSelectedToggle().getUserData() ); @@ -411,39 +383,7 @@ public void deleteBtnAction(ActionEvent event) { messageManager.showMessage("请选择PDF文件", Message.MessageType.WARNING); return; } - pdfService.deleteContents(filepathTF.getText(), destFilePath()); + pdfOutlineService.deleteContents(filepathTF.getText(), destFilePath()); showSuccessDialog(); } - - @FXML - public void createHelpWindowAction(ActionEvent actionEvent) throws IOException { - if (helpStage == null) { - helpStage = new Stage(); - - FXMLLoader loader = new FXMLLoader(getClass().getResource("HelpWindow.fxml")); - Parent helpWinRoot = loader.load(); - - helpStage.setTitle("帮助"); - helpStage.setScene(new Scene(helpWinRoot, 400, 300)); - - helpStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("icon/help_black.png")))); - helpStage.setResizable(false); //不可调整大小,且使最大化不可用 - helpStage.initOwner(root.getScene().getWindow());//可以使最小化不可用,配合上一条语句,可以使最小化最大化隐藏,只留下"×" - helpStage.show(); -// helpStage.focusedProperty().addListener((observable, oldValue, newValue) -> { -// if (!observable.getValue()) { -// helpStage.hide(); -// ((Stage) root.getScene().getWindow()).toFront(); -// } -// }); - } - else { - // 如果窗口已经创建但被隐藏,重新显示 - // 如果窗口已存在,将其聚焦到前台 - helpStage.show(); -// helpStage.toFront(); - helpStage.requestFocus(); - } - } - } diff --git a/src/main/java/com/ririv/quickoutline/view/PageLabelController.java b/src/main/java/com/ririv/quickoutline/view/PageLabelController.java new file mode 100644 index 0000000..e5e4cf1 --- /dev/null +++ b/src/main/java/com/ririv/quickoutline/view/PageLabelController.java @@ -0,0 +1,8 @@ +package com.ririv.quickoutline.view; + +import javafx.scene.control.ScrollPane; + +public class PageLabelController { + + public ScrollPane labelRuleListLayout; +} diff --git a/src/main/java/com/ririv/quickoutline/view/SetContentsPopupController.java b/src/main/java/com/ririv/quickoutline/view/SetContentsPopupController.java index cdae9e9..274cd11 100644 --- a/src/main/java/com/ririv/quickoutline/view/SetContentsPopupController.java +++ b/src/main/java/com/ririv/quickoutline/view/SetContentsPopupController.java @@ -1,6 +1,6 @@ package com.ririv.quickoutline.view; -import com.ririv.quickoutline.pdfProcess.PdfViewScaleType; +import com.ririv.quickoutline.pdfProcess.ViewScaleType; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.Label; @@ -48,16 +48,16 @@ public void initialize() { String labelText; if (newValue == fitToWidthBtn){ labelText = "适合宽度"; - this.mainController.viewScaleType = PdfViewScaleType.FIT_TO_WIDTH; + this.mainController.viewScaleType = ViewScaleType.FIT_TO_WIDTH; } else if (newValue == fitToHeightBtn){ labelText = "适合高度"; - this.mainController.viewScaleType = PdfViewScaleType.FIT_TO_HEIGHT; + this.mainController.viewScaleType = ViewScaleType.FIT_TO_HEIGHT; } else if (newValue == actualSizeBtn){ labelText = "实际大小"; - this.mainController.viewScaleType = PdfViewScaleType.ACTUAL_SIZE; + this.mainController.viewScaleType = ViewScaleType.ACTUAL_SIZE; } else { // null labelText = "无缩放"; - this.mainController.viewScaleType = PdfViewScaleType.None; + this.mainController.viewScaleType = ViewScaleType.None; } label.setText(labelText); }); diff --git a/src/main/java/com/ririv/quickoutline/view/TextTabController.java b/src/main/java/com/ririv/quickoutline/view/TextTabController.java index ffdd2d0..4fa9eb2 100644 --- a/src/main/java/com/ririv/quickoutline/view/TextTabController.java +++ b/src/main/java/com/ririv/quickoutline/view/TextTabController.java @@ -1,6 +1,6 @@ package com.ririv.quickoutline.view; -import com.ririv.quickoutline.service.PdfService; +import com.ririv.quickoutline.service.PdfOutlineService; import com.ririv.quickoutline.service.syncWithExternelEditor.SyncWithExternalEditorService; import com.ririv.quickoutline.utils.Pair; import javafx.application.Platform; @@ -43,12 +43,12 @@ public class TextTabController { private static final Pattern INDENT_PATTERN = Pattern.compile("^(\\t|\\s{1,4})"); - private PdfService pdfService; + private PdfOutlineService pdfOutlineService; private MainController mainController; public void setMainController(MainController mainController) { this.mainController = mainController; - this.pdfService = mainController.pdfService; + this.pdfOutlineService = mainController.pdfOutlineService; } public void initialize() { @@ -286,7 +286,7 @@ private void externalEditorBtnAction() { @FXML private void autoFormatBtnAction(ActionEvent event) { - contentsTextArea.setText(pdfService.autoFormat(contentsTextArea.getText())); + contentsTextArea.setText(pdfOutlineService.autoFormat(contentsTextArea.getText())); syncWithExternalEditorService.writeTemp(contentsTextArea.getText()); //自动格式化后,将方式切换为"indent",由于操作较为隐蔽,使用者不易发现变化,容易迷惑使用者,所以关闭 diff --git a/src/main/java/com/ririv/quickoutline/view/TreeTabController.java b/src/main/java/com/ririv/quickoutline/view/TreeTabController.java index 1226017..5485068 100644 --- a/src/main/java/com/ririv/quickoutline/view/TreeTabController.java +++ b/src/main/java/com/ririv/quickoutline/view/TreeTabController.java @@ -1,7 +1,7 @@ package com.ririv.quickoutline.view; import com.ririv.quickoutline.model.Bookmark; -import com.ririv.quickoutline.service.PdfService; +import com.ririv.quickoutline.service.PdfOutlineService; import com.ririv.quickoutline.textProcess.methods.Method; import javafx.beans.property.ReadOnlyStringWrapper; import javafx.beans.property.SimpleStringProperty; @@ -27,13 +27,13 @@ public class TreeTabController { - private PdfService pdfService; + private PdfOutlineService pdfOutlineService; private MainController mainController; public void setMainController(MainController mainController) { this.mainController = mainController; - this.pdfService = mainController.pdfService; + this.pdfOutlineService = mainController.pdfOutlineService; } @@ -72,7 +72,7 @@ public void grade(boolean isGrade) { sb.append(line).append("\n"); } System.out.println(sb); - rootBookmark = pdfService.convertTextToBookmarkTreeByMethod(sb.toString(), 0, Method.INDENT + rootBookmark = pdfOutlineService.convertTextToBookmarkTreeByMethod(sb.toString(), 0, Method.INDENT // ,true ); diff --git a/src/main/java/com/ririv/quickoutline/view/controls/PopupCard.java b/src/main/java/com/ririv/quickoutline/view/controls/PopupCard.java index d41ecd8..018d397 100644 --- a/src/main/java/com/ririv/quickoutline/view/controls/PopupCard.java +++ b/src/main/java/com/ririv/quickoutline/view/controls/PopupCard.java @@ -18,36 +18,52 @@ public class PopupCard extends Popup { PauseTransition delay = new javafx.animation.PauseTransition(Duration.seconds(1)); private boolean isHideAfterDelayWhenEscaped = true; + private Parent content; - public PopupCard(Parent parent) { - parent.getStylesheets().add(getClass().getResource("PopupCard.css").toExternalForm()); - parent.getStyleClass().add("card"); - this.getScene().setRoot(parent); + + public PopupCard(Parent content) { + this.content = content; + + content.getStylesheets().add(getClass().getResource("PopupCard.css").toExternalForm()); + content.getStyleClass().add("card"); + this.getScene().setRoot(content); // this.setAutoHide(true); // 设置此会因为this获得焦点而导致点击按钮第一次无效(失去焦点) // 如果不设置宽高,第一出现popup是他们的值为0,导致出现位置错误 // 已改为监听宽高,修复错误 // this.setWidth(popupNode.getPrefWidth()); // this.setHeight(popupNode.getPrefHeight()); - keepDelayWhenHover(parent); + keepDelayWhenHover(content); } // 窗口移动时,PopupCard没有跟着移动 public void showEventHandler(Event event) { Node ownerNode = (Node) event.getSource(); Bounds buttonBounds = ownerNode.localToScreen( ownerNode.getBoundsInLocal()); - this.widthProperty().addListener((observable, oldValue, newValue) -> { - double x = buttonBounds.getCenterX() - newValue.doubleValue()/2; + + this.setOnShown(e->{ + // Popup的width和height不一定是content的宽高 + double x = buttonBounds.getCenterX() - this.getWidth() / 2; + double y = buttonBounds.getMinY() - this.getHeight() - 5; this.setX(x); - logger.debug("x: {}", x); - }); - this.heightProperty().addListener((observable, oldValue, newValue) -> { - double y = buttonBounds.getMinY() - newValue.doubleValue() - 5; this.setY(y); - logger.debug("y: {}", y); + logger.info("x: {}", x); + logger.info("y: {}", y); }); +// +// this.widthProperty().addListener((observable, oldValue, newValue) -> { +// double x = buttonBounds.getCenterX() - newValue.doubleValue()/2; +// this.setX(x); +// logger.info("x: {}", x); +// }); +// this.heightProperty().addListener((observable, oldValue, newValue) -> { +// double y = buttonBounds.getMinY() - newValue.doubleValue() - 5; +// this.setY(y); +// logger.info("y: {}", y); +// }); + logger.debug("buttonBounds: {}", buttonBounds); logger.debug("popup: w:{} h:{}", this.getWidth(), this.getHeight()); this.show(ownerNode.getScene().getWindow()); diff --git a/src/main/resources/com/ririv/quickoutline/view/HelpWindow.fxml b/src/main/resources/com/ririv/quickoutline/view/HelpWindow.fxml index 8f1ba21..c8991fb 100644 --- a/src/main/resources/com/ririv/quickoutline/view/HelpWindow.fxml +++ b/src/main/resources/com/ririv/quickoutline/view/HelpWindow.fxml @@ -19,7 +19,7 @@ > 使用说明: diff --git a/src/main/resources/com/ririv/quickoutline/view/LeftPane.fxml b/src/main/resources/com/ririv/quickoutline/view/LeftPane.fxml new file mode 100644 index 0000000..433a73f --- /dev/null +++ b/src/main/resources/com/ririv/quickoutline/view/LeftPane.fxml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/com/ririv/quickoutline/view/MainView.css b/src/main/resources/com/ririv/quickoutline/view/MainView.css index 2a073cb..9d9cbcf 100644 --- a/src/main/resources/com/ririv/quickoutline/view/MainView.css +++ b/src/main/resources/com/ririv/quickoutline/view/MainView.css @@ -94,7 +94,7 @@ -fx-background-color: -my-color-divding-line; } -.tab-icon{ +.icon-tab{ -fx-pref-height: 20px; -fx-pref-width: 20px; } \ No newline at end of file diff --git a/src/main/resources/com/ririv/quickoutline/view/MainView.fxml b/src/main/resources/com/ririv/quickoutline/view/MainView.fxml index f213da9..11ef888 100644 --- a/src/main/resources/com/ririv/quickoutline/view/MainView.fxml +++ b/src/main/resources/com/ririv/quickoutline/view/MainView.fxml @@ -2,7 +2,7 @@ - + @@ -40,77 +40,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
@@ -122,6 +52,7 @@ + @@ -129,8 +60,8 @@ - - + + @@ -214,6 +145,25 @@ + + +