initial commit
This commit is contained in:
+403
@@ -0,0 +1,403 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
import DocView 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
width: 1100; height: 800; minimumWidth: 480; minimumHeight: 360
|
||||
visible: true
|
||||
title: reader.title + (reader.title === "DocView" ? "" : " — DocView")
|
||||
property bool dark: reader.settings.ui.theme === "system"
|
||||
? Qt.styleHints.colorScheme !== Qt.ColorScheme.Light : reader.settings.ui.theme !== "light"
|
||||
property color backgroundColor: dark ? "#181c20" : "#f1f3f4"
|
||||
property color surfaceColor: dark ? "#22282e" : "#ffffff"
|
||||
property color textColor: dark ? "#d8e0e8" : "#24303b"
|
||||
property color mutedColor: dark ? "#97a4b1" : "#586775"
|
||||
property color accentColor: dark ? "#abc8de" : "#215f8e"
|
||||
property bool tocVisible: reader.settings.ui.toc_visible
|
||||
property bool pagesVisible: reader.settings.ui.pages_visible
|
||||
property bool statusVisible: reader.settings.ui.status_bar
|
||||
property var collapsed: ({})
|
||||
property var tocRows: []
|
||||
readonly property int visibleCurrentOutline: {
|
||||
var current = reader.currentOutline, visible = -1
|
||||
for (var i = 0; i < tocRows.length; ++i) {
|
||||
if (tocRows[i].originalIndex === current) return i
|
||||
// A collapsed ancestor represents the current section below it.
|
||||
if (tocRows[i].originalIndex < current && collapsed[tocRows[i].originalIndex]) {
|
||||
var depth = tocRows[i].depth || 0, within = true
|
||||
for (var j = tocRows[i].originalIndex + 1; j <= current; ++j)
|
||||
if ((reader.outline[j].depth || 0) <= depth) { within = false; break }
|
||||
if (within) visible = i
|
||||
}
|
||||
}
|
||||
return visible
|
||||
}
|
||||
property bool searchInput: false
|
||||
property string previousContext: ""
|
||||
property var commandNames: ({
|
||||
"file.open": qsTr("文書を開く"), "app.quit": qsTr("終了"),
|
||||
"operation.cancel": qsTr("処理を取り消す"), "document.root.choose": qsTr("文書フォルダーを指定"),
|
||||
"document.info": qsTr("文書情報"), "history.clear": qsTr("履歴を消去"),
|
||||
"scroll.down": qsTr("下へスクロール"), "scroll.up": qsTr("上へスクロール"),
|
||||
"scroll.left": qsTr("左へスクロール"), "scroll.right": qsTr("右へスクロール"),
|
||||
"scroll.half_down": qsTr("半画面進む"), "scroll.half_up": qsTr("半画面戻る"),
|
||||
"scroll.page_down": qsTr("一画面進む"), "scroll.page_up": qsTr("一画面戻る"),
|
||||
"nav.document_start": qsTr("文書の先頭"), "nav.document_end": qsTr("文書の末尾"),
|
||||
"nav.page": qsTr("指定ページへ移動"), "nav.page_next": qsTr("次のPDFページ"),
|
||||
"nav.page_previous": qsTr("前のPDFページ"), "nav.heading_next": qsTr("次の見出し"),
|
||||
"nav.heading_previous": qsTr("前の見出し"), "nav.chapter_next": qsTr("次の章"),
|
||||
"nav.chapter_previous": qsTr("前の章"), "panel.toc.toggle": qsTr("目次の表示切替"),
|
||||
"panel.pages.toggle": qsTr("ページ一覧の表示切替"), "panel.status.toggle": qsTr("ステータスの表示切替"),
|
||||
"focus.next": qsTr("操作する領域を切替"), "focus.content": qsTr("本文に戻る"),
|
||||
"zoom.in": qsTr("拡大"), "zoom.out": qsTr("縮小"), "zoom.fit_width": qsTr("幅に合わせる"),
|
||||
"view.rotate": qsTr("PDFを回転"), "command.open": qsTr("コマンドを入力"),
|
||||
"config.reload": qsTr("設定を再読込"), "help.toggle": qsTr("操作一覧"),
|
||||
"nav.back": qsTr("移動履歴を戻る"), "nav.forward": qsTr("移動履歴を進む"),
|
||||
"search.open": qsTr("本文を検索"), "search.next": qsTr("次の検索結果"),
|
||||
"search.previous": qsTr("前の検索結果"), "panel.next": qsTr("次の項目を選択"),
|
||||
"panel.previous": qsTr("前の項目を選択"), "panel.collapse": qsTr("階層を折りたたむ"),
|
||||
"panel.expand": qsTr("階層を展開"), "panel.first": qsTr("先頭項目を選択"),
|
||||
"panel.last": qsTr("末尾項目を選択"), "panel.half_down": qsTr("項目を半画面進む"),
|
||||
"panel.half_up": qsTr("項目を半画面戻る"), "panel.activate": qsTr("選択項目へ移動"),
|
||||
"link.next": qsTr("次のリンク・PDF注釈を選択"), "link.previous": qsTr("前のリンク・PDF注釈を選択"),
|
||||
"link.activate": qsTr("選択リンク・PDF注釈を開く"), "unbound": qsTr("割り当てなし")
|
||||
})
|
||||
function contextName(value) {
|
||||
return value === "content" ? qsTr("本文") : value === "toc" ? qsTr("目次")
|
||||
: value === "pages" ? qsTr("ページ一覧") : qsTr("共通")
|
||||
}
|
||||
color: backgroundColor
|
||||
font.family: "monospace"
|
||||
font.pixelSize: reader.settings.ui.font_size
|
||||
|
||||
function focusContent() {
|
||||
previousContext = "" // Explicit navigation takes precedence over temporary UI restoration.
|
||||
reader.context = "content"
|
||||
if (reader.format === "pdf") pdf.forceActiveFocus()
|
||||
else if (reader.format !== "") web.focusContent()
|
||||
else if (recentList.count > 0) recentList.forceActiveFocus()
|
||||
else content.forceActiveFocus()
|
||||
}
|
||||
function beginTemporary() {
|
||||
if (!previousContext) previousContext = reader.context
|
||||
}
|
||||
function endTemporary() {
|
||||
reader.mode = "normal"
|
||||
var target = previousContext
|
||||
previousContext = ""
|
||||
if (!target) return // A successful action already selected its own focus.
|
||||
if (target === "toc" && tocVisible && tocList.count > 0) {
|
||||
reader.context = "toc"; tocList.forceActiveFocus()
|
||||
} else if (target === "pages" && pagesVisible && pageList.count > 0) {
|
||||
reader.context = "pages"; pageList.forceActiveFocus()
|
||||
} else focusContent()
|
||||
}
|
||||
function setInputMode(mode) { reader.mode = mode }
|
||||
function updateToc(resetSelection) {
|
||||
var previous = resetSelection ? null : tocRows[tocList.currentIndex]
|
||||
let list = [], skipDepth = -1
|
||||
for (let i = 0; i < reader.outline.length; ++i) {
|
||||
let row = reader.outline[i], depth = row.depth || 0
|
||||
if (skipDepth >= 0 && depth > skipDepth) continue
|
||||
skipDepth = -1
|
||||
let copy = Object.assign({}, row)
|
||||
copy.originalIndex = i
|
||||
copy.hasChildren = i + 1 < reader.outline.length && (reader.outline[i+1].depth || 0) > depth
|
||||
list.push(copy)
|
||||
if (collapsed[i]) skipDepth = depth
|
||||
}
|
||||
tocRows = list
|
||||
var selected = 0
|
||||
if (previous) {
|
||||
for (var row = 0; row < list.length; ++row)
|
||||
if (list[row].originalIndex === previous.originalIndex && list[row].title === previous.title &&
|
||||
list[row].href === previous.href && list[row].page === previous.page) { selected = row; break }
|
||||
}
|
||||
tocList.currentIndex = list.length ? selected : -1
|
||||
}
|
||||
function panelCommand(id) {
|
||||
let list = reader.context === "toc" ? tocList : pageList
|
||||
if (list.count === 0) return
|
||||
let next = list.currentIndex
|
||||
if (id === "panel.next") next++
|
||||
if (id === "panel.previous") next--
|
||||
if (id === "panel.first") next = 0
|
||||
if (id === "panel.last") next = list.count - 1
|
||||
if (id === "panel.half_down") next += Math.max(1, Math.floor(list.height / 56))
|
||||
if (id === "panel.half_up") next -= Math.max(1, Math.floor(list.height / 56))
|
||||
if (id === "panel.activate") { reader.activateItem(list.model[list.currentIndex]); return }
|
||||
if (reader.context === "toc" && (id === "panel.collapse" || id === "panel.expand")) {
|
||||
let row = tocRows[list.currentIndex]
|
||||
let c = Object.assign({}, collapsed)
|
||||
if (id === "panel.collapse") {
|
||||
if (row.hasChildren && !c[row.originalIndex]) c[row.originalIndex] = true
|
||||
else for(let i = list.currentIndex-1; i >= 0; --i) if ((tocRows[i].depth || 0) < (row.depth || 0)) { next = i; break }
|
||||
} else {
|
||||
if (c[row.originalIndex]) delete c[row.originalIndex]
|
||||
else if (row.hasChildren) next++
|
||||
}
|
||||
collapsed = c; updateToc()
|
||||
}
|
||||
list.currentIndex = Math.max(0, Math.min(list.count-1,next))
|
||||
list.positionViewAtIndex(list.currentIndex,ListView.Contain)
|
||||
}
|
||||
function beginInput(search) {
|
||||
beginTemporary(); searchInput = search
|
||||
reader.mode = search ? "search" : "command"
|
||||
commandField.text = ""; commandField.forceActiveFocus()
|
||||
}
|
||||
function recentCommand(id) {
|
||||
if (!recentList.count || reader.state !== "Empty") return
|
||||
if (id === "link.next" || id === "link.previous") {
|
||||
if (clearRecent.activeFocus) recentList.forceActiveFocus()
|
||||
else clearRecent.forceActiveFocus()
|
||||
return
|
||||
}
|
||||
if (id === "link.activate") {
|
||||
if (clearRecent.activeFocus) reader.execute("history.clear")
|
||||
else if (recentList.currentIndex >= 0) reader.openRecent(recentList.model[recentList.currentIndex].documentId)
|
||||
return
|
||||
}
|
||||
let next = recentList.currentIndex
|
||||
if (id === "scroll.down") next++
|
||||
if (id === "scroll.up") next--
|
||||
if (id === "nav.document_start") next = 0
|
||||
if (id === "nav.document_end") next = recentList.count - 1
|
||||
if (id === "scroll.half_down" || id === "scroll.page_down") next += Math.max(1, Math.floor(recentList.height / 52))
|
||||
if (id === "scroll.half_up" || id === "scroll.page_up") next -= Math.max(1, Math.floor(recentList.height / 52))
|
||||
recentList.currentIndex = Math.max(0, Math.min(recentList.count - 1, next))
|
||||
recentList.positionViewAtIndex(recentList.currentIndex, ListView.Contain)
|
||||
recentList.forceActiveFocus()
|
||||
}
|
||||
function endInput() { endTemporary() }
|
||||
Connections {
|
||||
target: reader
|
||||
function onNavigationChanged() { window.updateToc() }
|
||||
function onDocumentChanged() { window.collapsed = ({}); window.updateToc(true) }
|
||||
function onRecentDocumentsChanged() {
|
||||
Qt.callLater(function() { if (reader.format === "" && reader.mode === "normal") window.focusContent() })
|
||||
}
|
||||
function onUiCommand(id,args) {
|
||||
if(id === "file.open") { beginTemporary(); reader.mode = "dialog"; fileDialog.open() }
|
||||
else if(id === "panel.toc.toggle") { tocVisible = !tocVisible; if(!tocVisible && reader.context === "toc") focusContent() }
|
||||
else if(id === "panel.pages.toggle") { pagesVisible = !pagesVisible; if(!pagesVisible && reader.context === "pages") focusContent() }
|
||||
else if(id === "panel.status.toggle") statusVisible = !statusVisible
|
||||
else if(id.startsWith("panel.")) panelCommand(id)
|
||||
else if(id === "focus.next") {
|
||||
previousContext = ""; let areas=["content"]; if(tocVisible && reader.outline.length)areas.push("toc");if(pagesVisible && reader.pages.length)areas.push("pages")
|
||||
reader.context=areas[(areas.indexOf(reader.context)+1)%areas.length]
|
||||
if(reader.context === "toc")tocList.forceActiveFocus();else if(reader.context === "pages")pageList.forceActiveFocus();else focusContent()
|
||||
}
|
||||
else if(id === "focus.content") focusContent()
|
||||
else if(id === "command.open") beginInput(false)
|
||||
else if(id === "search.open") beginInput(true)
|
||||
else if(id === "help.toggle") { beginTemporary(); reader.mode="dialog"; helpDialog.open() }
|
||||
else if(id === "document.info") { beginTemporary(); infoText.text=args.text; infoDialog.title=args.title || qsTr("文書情報"); reader.mode="dialog"; infoDialog.open() }
|
||||
else if(id === "document.root.choose") { beginTemporary(); reader.mode="dialog"; folderDialog.open() }
|
||||
else if(id === "history.clear") { beginTemporary(); reader.mode="dialog"; historyDialog.open() }
|
||||
else if(id === "recent.navigate") recentCommand(args.command)
|
||||
}
|
||||
function onPasswordNeeded(name) { beginTemporary(); reader.mode="dialog"; passwordDialog.title=name; passwordField.text="";passwordDialog.open();passwordField.forceActiveFocus() }
|
||||
function onEntryNeeded(candidates) { beginTemporary(); candidateList.model=candidates; reader.mode="dialog"; entryDialog.open();candidateList.forceActiveFocus() }
|
||||
function onExternalLinkRequested(url) { beginTemporary(); externalDialog.destination=url;reader.mode="dialog";externalDialog.open() }
|
||||
function onSettingsChanged() {
|
||||
tocVisible=reader.settings.ui.toc_visible;pagesVisible=reader.settings.ui.pages_visible;statusVisible=reader.settings.ui.status_bar
|
||||
if ((!tocVisible && reader.context === "toc") || (!pagesVisible && reader.context === "pages")) focusContent()
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.fill: parent; spacing: 0
|
||||
RowLayout {
|
||||
Layout.fillWidth: true; Layout.fillHeight: true; spacing: 1
|
||||
ColumnLayout {
|
||||
objectName: "navigationSidebar"
|
||||
visible: (tocVisible && (reader.outline.length > 0 || reader.outlineLoading)) || (pagesVisible && reader.pages.length > 0)
|
||||
readonly property real panelWidth: Math.min(reader.settings.ui.panel_width,window.width*0.4)
|
||||
Layout.preferredWidth: panelWidth
|
||||
Layout.minimumWidth: panelWidth
|
||||
Layout.maximumWidth: panelWidth
|
||||
Layout.fillWidth: false
|
||||
Layout.fillHeight: true; spacing: 1
|
||||
Rectangle {
|
||||
visible: tocVisible && (reader.outline.length > 0 || reader.outlineLoading)
|
||||
Layout.fillWidth:true;Layout.fillHeight:true;color:surfaceColor
|
||||
border.color:reader.context === "toc" ? accentColor : surfaceColor
|
||||
ColumnLayout {
|
||||
anchors.fill:parent;anchors.margins:8;spacing:6
|
||||
Label { objectName:"outlineTitle";text:reader.outlineTitle;color:mutedColor;font.pixelSize:12 }
|
||||
Label { objectName:"outlineLoading";visible:reader.outlineLoading;text:qsTr("目次を読み込んでいます…");color:mutedColor;wrapMode:Text.Wrap;Layout.fillWidth:true;textFormat:Text.PlainText }
|
||||
ListView {
|
||||
id:tocList;objectName:"tocList";Layout.fillWidth:true;Layout.fillHeight:true;clip:true;model:window.tocRows;currentIndex:0
|
||||
delegate: Rectangle {
|
||||
required property var modelData;required property int index
|
||||
objectName:"tocRow";property bool readingCurrent:window.visibleCurrentOutline === index
|
||||
property bool keyboardSelected:tocList.currentIndex === index
|
||||
width:ListView.view.width;height:32;color:tocList.currentIndex === index ? (dark ? "#35414b" : "#dce6ee") : "transparent"
|
||||
border.width:keyboardSelected ? 1 : 0;border.color:mutedColor
|
||||
Label { anchors.fill:parent;anchors.leftMargin:4+(modelData.depth||0)*14;verticalAlignment:Text.AlignVCenter;color:textColor;elide:Text.ElideRight;text:(readingCurrent ? "> " : " ")+(modelData.hasChildren ? (window.collapsed[modelData.originalIndex] ? "+ " : "− ") : " ")+(modelData.title||qsTr("見出し"));textFormat:Text.PlainText }
|
||||
MouseArea { anchors.fill:parent;onClicked:{tocList.currentIndex=index;reader.context="toc";reader.activateItem(modelData)} }
|
||||
}
|
||||
ScrollBar.vertical:ScrollBar{}
|
||||
Accessible.name:qsTr("目次一覧")
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
visible:pagesVisible && reader.pages.length > 0
|
||||
Layout.fillWidth:true;Layout.fillHeight:true;color:surfaceColor
|
||||
border.color:reader.context === "pages" ? accentColor : surfaceColor
|
||||
ColumnLayout {
|
||||
anchors.fill:parent;anchors.margins:8;spacing:6
|
||||
Label{text:reader.listTitle;color:mutedColor;font.pixelSize:12}
|
||||
ListView {
|
||||
id:pageList;Layout.fillWidth:true;Layout.fillHeight:true;clip:true;model:reader.pages;currentIndex:0
|
||||
delegate:Rectangle {
|
||||
required property var modelData;required property int index
|
||||
width:ListView.view.width;height:32;color:pageList.currentIndex === index ? (dark ? "#35414b" : "#dce6ee") : "transparent"
|
||||
Label{anchors.fill:parent;anchors.leftMargin:4;verticalAlignment:Text.AlignVCenter;color:textColor;elide:Text.ElideRight;text:(reader.format === "pdf" && pdf.currentPage === index ? "> " : " ")+(modelData.title||modelData.href||String(index+1));textFormat:Text.PlainText}
|
||||
MouseArea{anchors.fill:parent;onClicked:{pageList.currentIndex=index;reader.context="pages";reader.activateItem(modelData)}}
|
||||
}
|
||||
ScrollBar.vertical:ScrollBar{}
|
||||
Accessible.name:reader.listTitle
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id:content;objectName:"documentContent";Layout.fillWidth:true;Layout.fillHeight:true;focus:true
|
||||
PdfCanvas { id:pdf;anchors.fill:parent;visible:reader.format === "pdf";backgroundColor:window.backgroundColor;Component.onCompleted:reader.attachCanvas(pdf);Accessible.name:qsTr("PDF本文") }
|
||||
WebPane { id:web;anchors.fill:parent;visible:reader.format !== "pdf" && reader.format !== "" }
|
||||
ColumnLayout {
|
||||
id:initialScreen;objectName:"initialScreen"
|
||||
readonly property real availableHeight:content.height-(noticeBanner.visible ? noticeBanner.height : 0)
|
||||
anchors.centerIn:parent;width:Math.min(580,parent.width-48);spacing:8;visible:reader.format === ""
|
||||
anchors.verticalCenterOffset:noticeBanner.visible ? -noticeBanner.height/2 : 0
|
||||
Label { text:qsTr("Ctrl+O: 文書を開く");color:textColor;Layout.fillWidth:true }
|
||||
Label { text:qsTr("?: 操作一覧");color:mutedColor;Layout.fillWidth:true }
|
||||
Label { visible:recentList.count>0;text:qsTr("最近使った文書");color:textColor;Layout.topMargin:12;Layout.fillWidth:true }
|
||||
ListView {
|
||||
id:recentList;objectName:"recentDocumentsList"
|
||||
readonly property real rowHeight: Math.max(52, window.font.pixelSize+34)
|
||||
Layout.fillWidth:true;Layout.preferredHeight:Math.min(260,Math.max(rowHeight,initialScreen.availableHeight-4*window.font.pixelSize-154),count*rowHeight)
|
||||
visible:count>0;enabled:reader.state === "Empty";clip:true
|
||||
model:reader.recentDocuments;currentIndex:0;keyNavigationEnabled:true
|
||||
onCountChanged:currentIndex=count>0 ? Math.max(0,Math.min(currentIndex,count-1)) : -1
|
||||
Keys.onPressed:event=>{
|
||||
if (event.key === Qt.Key_Home) currentIndex=0
|
||||
else if (event.key === Qt.Key_End) currentIndex=count-1
|
||||
else return
|
||||
positionViewAtIndex(currentIndex,ListView.Contain);event.accepted=true
|
||||
}
|
||||
delegate:ItemDelegate {
|
||||
required property var modelData;required property int index
|
||||
width:ListView.view.width;height:recentList.rowHeight;padding:6;focusPolicy:Qt.NoFocus
|
||||
highlighted:recentList.currentIndex===index
|
||||
background:Rectangle {
|
||||
color:recentList.currentIndex===index ? (dark ? "#35414b" : "#dce6ee") : surfaceColor
|
||||
border.color:recentList.activeFocus && recentList.currentIndex===index ? accentColor : "transparent"
|
||||
}
|
||||
contentItem:Column {
|
||||
Label { width:parent.width;text:modelData.title;textFormat:Text.PlainText;color:textColor;elide:Text.ElideRight }
|
||||
Label { width:parent.width;text:modelData.path;textFormat:Text.PlainText;color:mutedColor;font.pixelSize:12;elide:Text.ElideMiddle }
|
||||
}
|
||||
Accessible.name:modelData.title+" — "+modelData.path
|
||||
onClicked: { recentList.currentIndex=index;recentList.forceActiveFocus();reader.openRecent(modelData.documentId) }
|
||||
}
|
||||
ScrollBar.vertical:ScrollBar{}
|
||||
Accessible.name:qsTr("最近使った文書。上下キーで選択し、Enterで開きます")
|
||||
}
|
||||
RowLayout {
|
||||
visible:recentList.count>0;Layout.fillWidth:true
|
||||
Label { text:qsTr("↑↓: 選択 Enter: 開く");color:mutedColor;font.pixelSize:12;Layout.fillWidth:true }
|
||||
Button { id:clearRecent;objectName:"clearRecentDocuments";text:qsTr("履歴を消去…");enabled:reader.state === "Empty";onClicked:reader.execute("history.clear") }
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id:noticeBanner;objectName:"noticeBanner"
|
||||
anchors.left:parent.left;anchors.right:parent.right;anchors.bottom:parent.bottom
|
||||
visible:reader.notice.length > 0;height:noticeLabel.implicitHeight+20;color:surfaceColor
|
||||
Label { id:noticeLabel;anchors.left:parent.left;anchors.right:parent.right;anchors.margins:12;anchors.verticalCenter:parent.verticalCenter;text:reader.notice;textFormat:Text.PlainText;wrapMode:Text.Wrap;color:textColor;Accessible.role:Accessible.AlertMessage }
|
||||
}
|
||||
DropArea { anchors.fill:parent;onDropped:drop=>{if(drop.hasUrls){reader.open(drop.urls[0]);drop.acceptProposedAction()}} }
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
visible:statusVisible;Layout.fillWidth:true;Layout.preferredHeight:28;color:surfaceColor
|
||||
RowLayout {
|
||||
anchors.fill:parent;anchors.leftMargin:10;anchors.rightMargin:10
|
||||
Label { Layout.fillWidth:true;text:reader.title;elide:Text.ElideMiddle;color:mutedColor;textFormat:Text.PlainText }
|
||||
Label { text:reader.state === "Opening" ? qsTr("読込中") : reader.position;color:textColor }
|
||||
Label { text:reader.pending;color:accentColor }
|
||||
Label { text:reader.context === "content" ? qsTr("内容") : reader.context === "toc" ? qsTr("目次") : reader.listTitle;color:mutedColor;leftPadding:18 }
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
visible:reader.mode === "command" || reader.mode === "search"
|
||||
Layout.fillWidth:true;spacing:0
|
||||
Label { text:window.searchInput ? "/" : ":";color:textColor;leftPadding:10 }
|
||||
TextField {
|
||||
id:commandField;Layout.fillWidth:true;selectByMouse:true;color:textColor;background:Rectangle{color:surfaceColor}Accessible.name:window.searchInput ? qsTr("本文検索") : qsTr("コマンド")
|
||||
placeholderText:window.searchInput ? (reader.format === "epub" ? qsTr("表示中の章を検索") : reader.format === "pdf" ? qsTr("本文を検索") : qsTr("表示中のHTMLを検索")) : ""
|
||||
onAccepted:{if(inputMethodComposing)return;if(window.searchInput){reader.search(text);endInput()}else if(reader.command(text)){if(reader.mode === "command")endInput();else text=""}}
|
||||
Keys.onEscapePressed:event=>{if(!inputMethodComposing){endInput();event.accepted=true}}
|
||||
}
|
||||
}
|
||||
}
|
||||
FileDialog { id:fileDialog;title:qsTr("文書を開く");nameFilters:[qsTr("文書 (*.pdf *.html *.htm *.xhtml *.zip *.epub)"),qsTr("すべて (*)")];onAccepted:{reader.mode="normal";reader.open(selectedFile);endTemporary()}onRejected:endTemporary() }
|
||||
FolderDialog { id:folderDialog;title:qsTr("文書フォルダーを指定");onAccepted:{reader.mode="normal";reader.setHtmlRoot(selectedFolder);endTemporary()}onRejected:endTemporary() }
|
||||
Dialog {
|
||||
id:passwordDialog;anchors.centerIn:parent;modal:true;standardButtons:Dialog.Ok|Dialog.Cancel
|
||||
TextField{id:passwordField;width:300;echoMode:TextInput.Password;Accessible.name:qsTr("PDFパスワード");onAccepted:if(!inputMethodComposing)passwordDialog.accept()}
|
||||
onAccepted:{reader.mode="normal";let value=passwordField.text;passwordField.text="";reader.password(value);endTemporary()}
|
||||
onRejected:{passwordField.text="";reader.mode="normal";reader.cancel();endTemporary()}
|
||||
}
|
||||
Dialog {
|
||||
id:entryDialog;objectName:"entryDialog";anchors.centerIn:parent;modal:true;title:qsTr("入口HTMLを選択");width:Math.min(600,window.width-48);height:Math.min(440,window.height-60);standardButtons:Dialog.Ok|Dialog.Cancel
|
||||
ListView{id:candidateList;objectName:"entryCandidates";anchors.fill:parent;clip:true;currentIndex:0;delegate:ItemDelegate{required property string modelData;required property int index;width:ListView.view.width;text:modelData;highlighted:candidateList.currentIndex===index;onClicked:{candidateList.currentIndex=index;entryDialog.accept()}}Keys.onReturnPressed:entryDialog.accept()}
|
||||
onAccepted:{reader.mode="normal";if(candidateList.currentIndex>=0)reader.chooseEntry(candidateList.model[candidateList.currentIndex]);endTemporary()}
|
||||
onRejected:{reader.cancel();endTemporary()}
|
||||
}
|
||||
Dialog {
|
||||
id:externalDialog;property url destination;anchors.centerIn:parent;modal:true;title:qsTr("外部ブラウザーで開く");width:Math.min(640,window.width-48);standardButtons:Dialog.Open|Dialog.Cancel
|
||||
Label{width:parent.width;text:externalDialog.destination.toString();textFormat:Text.PlainText;wrapMode:Text.WrapAnywhere}
|
||||
onAccepted:{reader.openExternal(destination);endTemporary()}
|
||||
onRejected:endTemporary()
|
||||
}
|
||||
Dialog {
|
||||
id:infoDialog;objectName:"infoDialog";anchors.centerIn:parent;modal:true;title:qsTr("文書情報")
|
||||
width:Math.min(640,window.width-48);height:Math.min(implicitHeight,window.height-60)
|
||||
standardButtons:Dialog.Close
|
||||
contentItem:ScrollView {
|
||||
id:infoScroll;objectName:"infoScroll";clip:true
|
||||
contentWidth:availableWidth;implicitHeight:infoText.implicitHeight
|
||||
Label{id:infoText;objectName:"infoText";width:infoScroll.availableWidth;wrapMode:Text.WrapAnywhere;textFormat:Text.PlainText}
|
||||
}
|
||||
onClosed:endTemporary()
|
||||
}
|
||||
Dialog {
|
||||
id:historyDialog;objectName:"historyDialog";anchors.centerIn:parent;modal:true
|
||||
title:qsTr("履歴と保存位置を消去");width:Math.min(580,window.width-48);standardButtons:Dialog.Ok|Dialog.Cancel
|
||||
Label { id:historyConfirmation;objectName:"historyConfirmation";width:parent.width;wrapMode:Text.Wrap }
|
||||
onAboutToShow:historyConfirmation.text=qsTr("%1 件の履歴と読書位置を消去します。原本は変更されません。").arg(reader.historyCount())
|
||||
onAccepted:{reader.clearHistory();endTemporary()}
|
||||
onRejected:endTemporary()
|
||||
}
|
||||
Dialog {
|
||||
id:helpDialog;anchors.centerIn:parent;modal:true;title:qsTr("操作一覧");width:Math.min(760,window.width-48);height:Math.min(620,window.height-60);standardButtons:Dialog.Close
|
||||
ColumnLayout {
|
||||
anchors.fill:parent
|
||||
Label{text:qsTr("Vim風の閲覧操作です。q単押しでは終了しません。:q で終了します。");wrapMode:Text.Wrap;Layout.fillWidth:true}
|
||||
ListView {
|
||||
Layout.fillWidth:true;Layout.fillHeight:true;clip:true;model:reader.settings.keybindings
|
||||
delegate:Label{required property var modelData;width:ListView.view.width;text:modelData.keys.join(" ")+" "+(window.commandNames[modelData.command] || modelData.command)+" ["+window.contextName(modelData.context)+"]";textFormat:Text.PlainText;font.family:"monospace";height:26;elide:Text.ElideRight}
|
||||
ScrollBar.vertical:ScrollBar{}
|
||||
}
|
||||
}
|
||||
onClosed:endTemporary()
|
||||
}
|
||||
Shortcut { sequence:"?";enabled:helpDialog.visible;onActivated:helpDialog.close() }
|
||||
Component.onCompleted:{updateToc();focusContent()}
|
||||
}
|
||||
Reference in New Issue
Block a user