1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-01 19:18:28 -04:00

notepad: add inline tab renaming and bump tab size

This commit is contained in:
bbedward
2026-07-07 11:05:14 -04:00
parent 32e2d96e55
commit 71b1901ab0
6 changed files with 338 additions and 288 deletions
+17 -2
View File
@@ -120,12 +120,18 @@ Singleton {
function setMonitorScrollPosition(screenName, scrollX, scrollY) { function setMonitorScrollPosition(screenName, scrollX, scrollY) {
var newPositions = Object.assign({}, monitorScrollPositions); var newPositions = Object.assign({}, monitorScrollPositions);
newPositions[screenName] = { scrollX: scrollX, scrollY: scrollY }; newPositions[screenName] = {
scrollX: scrollX,
scrollY: scrollY
};
monitorScrollPositions = newPositions; monitorScrollPositions = newPositions;
} }
function getMonitorScrollPosition(screenName) { function getMonitorScrollPosition(screenName) {
return monitorScrollPositions[screenName] || { scrollX: 50, scrollY: 50 }; return monitorScrollPositions[screenName] || {
scrollX: 50,
scrollY: 50
};
} }
function clearMonitorScrollPosition(screenName) { function clearMonitorScrollPosition(screenName) {
@@ -209,6 +215,8 @@ Singleton {
property string locale: "" property string locale: ""
property string timeLocale: "" property string timeLocale: ""
property string notepadLastMode: ""
property string launcherLastMode: "all" property string launcherLastMode: "all"
property string launcherLastFileSearchType: "all" property string launcherLastFileSearchType: "all"
property string launcherLastQuery: "" property string launcherLastQuery: ""
@@ -1216,6 +1224,13 @@ Singleton {
I18n.useLocale(locale, locale.startsWith("en") ? "" : I18n.folder + "/" + locale + ".json"); I18n.useLocale(locale, locale.startsWith("en") ? "" : I18n.folder + "/" + locale + ".json");
} }
function setNotepadLastMode(mode) {
if (notepadLastMode === mode)
return;
notepadLastMode = mode;
saveSettings();
}
function setLauncherLastMode(mode) { function setLauncherLastMode(mode) {
launcherLastMode = mode; launcherLastMode = mode;
saveSettings(); saveSettings();
@@ -88,6 +88,8 @@ var SPEC = {
locale: { def: "", onChange: "updateLocale" }, locale: { def: "", onChange: "updateLocale" },
timeLocale: { def: "" }, timeLocale: { def: "" },
notepadLastMode: { def: "" },
launcherLastMode: { def: "all" }, launcherLastMode: { def: "all" },
launcherLastFileSearchType: { def: "all" }, launcherLastFileSearchType: { def: "all" },
launcherLastQuery: { def: "" }, launcherLastQuery: { def: "" },
+4 -4
View File
@@ -373,7 +373,7 @@ Item {
} }
function open(): string { function open(): string {
if (SettingsData.notepadDefaultMode === "popout") { if (PopoutService.notepadResolvedMode === "popout") {
PopoutService.openNotepadPopout(); PopoutService.openNotepadPopout();
return "NOTEPAD_OPEN_SUCCESS"; return "NOTEPAD_OPEN_SUCCESS";
} }
@@ -388,7 +388,7 @@ Item {
function openFile(path: string): string { function openFile(path: string): string {
if (!path) if (!path)
return open(); return open();
if (SettingsData.notepadDefaultMode === "popout") { if (PopoutService.notepadResolvedMode === "popout") {
PopoutService.openNotepadPopoutWithFile(path); PopoutService.openNotepadPopoutWithFile(path);
return "NOTEPAD_OPEN_FILE_SUCCESS"; return "NOTEPAD_OPEN_FILE_SUCCESS";
} }
@@ -402,7 +402,7 @@ Item {
} }
function close(): string { function close(): string {
if (SettingsData.notepadDefaultMode === "popout") { if (PopoutService.notepadResolvedMode === "popout") {
PopoutService.notepadPopout?.hide(); PopoutService.notepadPopout?.hide();
return "NOTEPAD_CLOSE_SUCCESS"; return "NOTEPAD_CLOSE_SUCCESS";
} }
@@ -415,7 +415,7 @@ Item {
} }
function toggle(): string { function toggle(): string {
if (SettingsData.notepadDefaultMode === "popout") { if (PopoutService.notepadResolvedMode === "popout") {
PopoutService.toggleNotepadPopout(); PopoutService.toggleNotepadPopout();
return "NOTEPAD_TOGGLE_SUCCESS"; return "NOTEPAD_TOGGLE_SUCCESS";
} }
+78 -3
View File
@@ -13,12 +13,19 @@ Column {
property int draggedIndex: -1 property int draggedIndex: -1
property int dropTargetIndex: -1 property int dropTargetIndex: -1
property bool suppressShiftAnimation: false property bool suppressShiftAnimation: false
readonly property real tabItemSize: 128 + Theme.spacingXS property int editingIndex: -1
readonly property real tabItemSize: tabRow.dynamicTabWidth + Theme.spacingXS
signal tabSwitched(int tabIndex) signal tabSwitched(int tabIndex)
signal tabClosed(int tabIndex) signal tabClosed(int tabIndex)
signal newTabRequested signal newTabRequested
function commitRename(index, newTitle) {
if (index >= 0)
NotepadStorageService.renameTab(index, newTitle);
editingIndex = -1;
}
function hasUnsavedChangesForTab(tab) { function hasUnsavedChangesForTab(tab) {
if (!tab) if (!tab)
return false; return false;
@@ -32,11 +39,19 @@ Column {
spacing: Theme.spacingXS spacing: Theme.spacingXS
Row { Row {
id: tabRow
width: parent.width width: parent.width
height: 36 height: 36
spacing: Theme.spacingXS spacing: Theme.spacingXS
readonly property real dynamicTabWidth: {
var count = Math.max(1, NotepadStorageService.tabs.length);
var raw = (tabScroll.width - (count - 1) * Theme.spacingXS) / count;
return Math.max(128, Math.min(300, raw));
}
ScrollView { ScrollView {
id: tabScroll
width: parent.width - newTabButton.width - Theme.spacingXS width: parent.width - newTabButton.width - Theme.spacingXS
height: parent.height height: parent.height
clip: true clip: true
@@ -57,7 +72,8 @@ Column {
readonly property bool isActive: NotepadStorageService.currentTabIndex === index readonly property bool isActive: NotepadStorageService.currentTabIndex === index
readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse
readonly property real tabWidth: 128 readonly property bool editing: root.editingIndex === index
readonly property real tabWidth: tabRow.dynamicTabWidth
property bool longPressing: false property bool longPressing: false
property bool dragging: false property bool dragging: false
property point dragStartPos: Qt.point(0, 0) property point dragStartPos: Qt.point(0, 0)
@@ -138,6 +154,7 @@ Column {
StyledText { StyledText {
id: tabText id: tabText
visible: !delegateItem.editing
width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0) width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0)
text: { text: {
var prefix = ""; var prefix = "";
@@ -155,13 +172,54 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
TextInput {
id: renameField
visible: delegateItem.editing
enabled: delegateItem.editing
width: parent.width
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.primary
selectionColor: Theme.primary
selectedTextColor: Theme.background
selectByMouse: true
clip: true
onEditingFinished: root.commitRename(index, text)
Keys.onEscapePressed: event => {
text = modelData.title || "Untitled";
root.editingIndex = -1;
event.accepted = true;
}
// A tab switch re-focuses the editor via Qt.callLater; the
// timer fires afterwards so the field keeps focus + selection.
Timer {
id: renameFocusTimer
interval: 20
repeat: false
onTriggered: {
renameField.forceActiveFocus();
renameField.selectAll();
}
}
onVisibleChanged: {
if (!visible)
return;
text = modelData.title || "Untitled";
renameFocusTimer.restart();
}
}
Rectangle { Rectangle {
id: tabCloseButton id: tabCloseButton
width: 20 width: 20
height: 20 height: 20
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0) color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
visible: NotepadStorageService.tabs.length > 1 visible: NotepadStorageService.tabs.length > 1 && !delegateItem.editing
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
DankIcon { DankIcon {
@@ -195,11 +253,24 @@ Column {
MouseArea { MouseArea {
id: tabMouseArea id: tabMouseArea
anchors.fill: parent anchors.fill: parent
enabled: !delegateItem.editing
hoverEnabled: true hoverEnabled: true
preventStealing: dragging || longPressing preventStealing: dragging || longPressing
cursorShape: dragging || longPressing ? Qt.ClosedHandCursor : Qt.PointingHandCursor cursorShape: dragging || longPressing ? Qt.ClosedHandCursor : Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onDoubleClicked: {
root.tabSwitched(index);
root.editingIndex = index;
}
onExited: tabTooltip.hide()
onContainsMouseChanged: {
if (containsMouse && tabText.truncated)
tabTooltip.show(modelData.title || "Untitled", delegateItem, 0, 0, "bottom");
}
onPressed: mouse => { onPressed: mouse => {
if (mouse.button === Qt.LeftButton && NotepadStorageService.tabs.length > 1) { if (mouse.button === Qt.LeftButton && NotepadStorageService.tabs.length > 1) {
delegateItem.dragStartPos = Qt.point(mouse.x, mouse.y); delegateItem.dragStartPos = Qt.point(mouse.x, mouse.y);
@@ -279,4 +350,8 @@ Column {
onClicked: root.newTabRequested() onClicked: root.newTabRequested()
} }
} }
DankTooltipV2 {
id: tabTooltip
}
} }
+227 -276
View File
@@ -29,45 +29,48 @@ Singleton {
function setSessionBuffer(tabId, content, baseline) { function setSessionBuffer(tabId, content, baseline) {
if (tabId === undefined || tabId === null || tabId < 0) if (tabId === undefined || tabId === null || tabId < 0)
return return;
var next = Object.assign({}, sessionBuffers) var next = Object.assign({}, sessionBuffers);
if (content !== baseline) { if (content !== baseline) {
next[tabId] = { content: content, baseline: baseline } next[tabId] = {
content: content,
baseline: baseline
};
} else { } else {
delete next[tabId] delete next[tabId];
} }
sessionBuffers = next sessionBuffers = next;
sessionBufferRevision++ sessionBufferRevision++;
} }
function getSessionBuffer(tabId) { function getSessionBuffer(tabId) {
return sessionBuffers[tabId] return sessionBuffers[tabId];
} }
function clearSessionBuffer(tabId) { function clearSessionBuffer(tabId) {
if (sessionBuffers[tabId] === undefined) if (sessionBuffers[tabId] === undefined)
return return;
var next = Object.assign({}, sessionBuffers) var next = Object.assign({}, sessionBuffers);
delete next[tabId] delete next[tabId];
sessionBuffers = next sessionBuffers = next;
sessionBufferRevision++ sessionBufferRevision++;
} }
property var conflictTabId: -1 property var conflictTabId: -1
property string conflictDiskContent: "" property string conflictDiskContent: ""
function flagConflict(tabId, diskContent) { function flagConflict(tabId, diskContent) {
conflictDiskContent = diskContent conflictDiskContent = diskContent;
conflictTabId = tabId conflictTabId = tabId;
} }
function clearConflict() { function clearConflict() {
conflictTabId = -1 conflictTabId = -1;
conflictDiskContent = "" conflictDiskContent = "";
} }
Component.onCompleted: { Component.onCompleted: {
ensureDirectories() ensureDirectories();
} }
FileView { FileView {
@@ -78,64 +81,66 @@ Singleton {
onLoaded: { onLoaded: {
try { try {
var data = JSON.parse(text()) var data = JSON.parse(text());
root.tabs = data.tabs || [] root.tabs = data.tabs || [];
root.currentTabIndex = data.currentTabIndex || 0 root.currentTabIndex = data.currentTabIndex || 0;
root.metadataLoaded = true root.metadataLoaded = true;
root.validateTabs() root.validateTabs();
} catch(e) { } catch (e) {
log.warn("Failed to parse notepad metadata:", e) log.warn("Failed to parse notepad metadata:", e);
root.createDefaultTab() root.createDefaultTab();
} }
} }
onLoadFailed: { onLoadFailed: {
root.createDefaultTab() root.createDefaultTab();
} }
} }
onRefCountChanged: { onRefCountChanged: {
if (refCount === 1 && !metadataLoaded) { if (refCount === 1 && !metadataLoaded) {
metadataFile.path = "" metadataFile.path = "";
metadataFile.path = root.metadataPath metadataFile.path = root.metadataPath;
} }
} }
function ensureDirectories() { function ensureDirectories() {
mkdirProcess.running = true Proc.runCommand("", ["mkdir", "-p", root.baseDir, root.filesDir], null);
} }
function loadMetadata() { function loadMetadata() {
metadataFile.path = "" metadataFile.path = "";
metadataFile.path = root.metadataPath metadataFile.path = root.metadataPath;
} }
function createDefaultTab() { function createDefaultTab() {
var id = Date.now() var id = Date.now();
var filePath = "notepad-files/untitled-" + id + ".txt" var filePath = "notepad-files/untitled-" + id + ".txt";
var fullPath = baseDir + "/" + filePath var fullPath = baseDir + "/" + filePath;
var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) var newTabsBeingCreated = Object.assign({}, tabsBeingCreated);
newTabsBeingCreated[id] = true newTabsBeingCreated[id] = true;
tabsBeingCreated = newTabsBeingCreated tabsBeingCreated = newTabsBeingCreated;
root.createEmptyFile(fullPath, function() { root.createEmptyFile(fullPath, function () {
root.tabs = [{ root.tabs = [
id: id, {
title: I18n.tr("Untitled"), id: id,
filePath: filePath, title: I18n.tr("Untitled"),
isTemporary: true, filePath: filePath,
lastModified: new Date().toISOString(), isTemporary: true,
cursorPosition: 0, lastModified: new Date().toISOString(),
scrollPosition: 0 cursorPosition: 0,
}] scrollPosition: 0
root.currentTabIndex = 0 }
];
root.currentTabIndex = 0;
var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated);
delete updatedTabsBeingCreated[id] delete updatedTabsBeingCreated[id];
tabsBeingCreated = updatedTabsBeingCreated tabsBeingCreated = updatedTabsBeingCreated;
root.saveMetadata() root.saveMetadata();
}) });
} }
function saveMetadata() { function saveMetadata() {
@@ -143,82 +148,73 @@ Singleton {
version: 1, version: 1,
currentTabIndex: currentTabIndex, currentTabIndex: currentTabIndex,
tabs: tabs tabs: tabs
} };
metadataFile.setText(JSON.stringify(metadata, null, 2)) metadataFile.setText(JSON.stringify(metadata, null, 2));
} }
function getTabById(tabId) { function getTabById(tabId) {
for (var i = 0; i < tabs.length; i++) { for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id === tabId) if (tabs[i].id === tabId)
return tabs[i] return tabs[i];
} }
return null return null;
} }
function loadTabContent(tabIndex, callback) { function loadTabContent(tabIndex, callback) {
if (tabIndex < 0 || tabIndex >= tabs.length) { if (tabIndex < 0 || tabIndex >= tabs.length) {
callback("") callback("");
return return;
} }
var tab = tabs[tabIndex] var tab = tabs[tabIndex];
var requestTabId = tab.id var requestTabId = tab.id;
var fullPath = tab.isTemporary var fullPath = tab.isTemporary ? baseDir + "/" + tab.filePath : tab.filePath;
? baseDir + "/" + tab.filePath
: tab.filePath
if (tabsBeingCreated[tab.id]) { if (tabsBeingCreated[tab.id]) {
Qt.callLater(() => { Qt.callLater(() => {
loadTabContent(tabIndex, callback) loadTabContent(tabIndex, callback);
}) });
return return;
} }
var fileChecker = fileExistsComponent.createObject(root, { Proc.runCommand("", ["test", "-f", fullPath], (output, exitCode) => {
path: fullPath, var currentTab = root.getTabById(requestTabId);
callback: (exists) => { var currentPath = currentTab ? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath) : "";
var currentTab = root.getTabById(requestTabId)
var currentPath = currentTab
? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath)
: ""
if (!currentTab || currentPath !== fullPath) { if (!currentTab || currentPath !== fullPath) {
callback("") callback("");
return return;
}
if (exists) {
var loader = tabFileLoaderComponent.createObject(root, {
path: fullPath,
callback: callback
})
} else {
log.warn("Tab file does not exist:", fullPath)
callback("")
}
} }
})
if (exitCode === 0) {
tabFileLoaderComponent.createObject(root, {
path: fullPath,
callback: callback
});
} else {
log.warn("Tab file does not exist:", fullPath);
callback("");
}
});
} }
function saveTabContent(tabIndex, content) { function saveTabContent(tabIndex, content) {
if (tabIndex < 0 || tabIndex >= tabs.length) return if (tabIndex < 0 || tabIndex >= tabs.length)
return;
var tab = tabs[tabIndex] var tab = tabs[tabIndex];
var fullPath = tab.isTemporary var fullPath = tab.isTemporary ? baseDir + "/" + tab.filePath : tab.filePath;
? baseDir + "/" + tab.filePath
: tab.filePath
var saver = tabFileSaverComponent.createObject(root, { var saver = tabFileSaverComponent.createObject(root, {
path: fullPath, path: fullPath,
content: content, content: content,
tabIndex: tabIndex tabIndex: tabIndex
}) });
} }
function createNewTab() { function createNewTab() {
var id = Date.now() var id = Date.now();
var filePath = "notepad-files/untitled-" + id + ".txt" var filePath = "notepad-files/untitled-" + id + ".txt";
var fullPath = baseDir + "/" + filePath var fullPath = baseDir + "/" + filePath;
var newTab = { var newTab = {
id: id, id: id,
@@ -228,29 +224,29 @@ Singleton {
lastModified: new Date().toISOString(), lastModified: new Date().toISOString(),
cursorPosition: 0, cursorPosition: 0,
scrollPosition: 0 scrollPosition: 0
} };
var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) var newTabsBeingCreated = Object.assign({}, tabsBeingCreated);
newTabsBeingCreated[id] = true newTabsBeingCreated[id] = true;
tabsBeingCreated = newTabsBeingCreated tabsBeingCreated = newTabsBeingCreated;
createEmptyFile(fullPath, function() { createEmptyFile(fullPath, function () {
var newTabs = tabs.slice() var newTabs = tabs.slice();
newTabs.push(newTab) newTabs.push(newTab);
tabs = newTabs tabs = newTabs;
currentTabIndex = tabs.length - 1 currentTabIndex = tabs.length - 1;
var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated);
delete updatedTabsBeingCreated[id] delete updatedTabsBeingCreated[id];
tabsBeingCreated = updatedTabsBeingCreated tabsBeingCreated = updatedTabsBeingCreated;
saveMetadata() saveMetadata();
}) });
return newTab return newTab;
} }
function createTabForFile(path) { function createTabForFile(path) {
var id = Date.now() var id = Date.now();
var fileName = path.split('/').pop() var fileName = path.split('/').pop();
var newTab = { var newTab = {
id: id, id: id,
@@ -260,34 +256,34 @@ Singleton {
lastModified: new Date().toISOString(), lastModified: new Date().toISOString(),
cursorPosition: 0, cursorPosition: 0,
scrollPosition: 0 scrollPosition: 0
} };
var newTabs = tabs.slice() var newTabs = tabs.slice();
newTabs.push(newTab) newTabs.push(newTab);
tabs = newTabs tabs = newTabs;
currentTabIndex = tabs.length - 1 currentTabIndex = tabs.length - 1;
saveMetadata() saveMetadata();
return newTab return newTab;
} }
function closeTab(tabIndex) { function closeTab(tabIndex) {
if (tabIndex < 0 || tabIndex >= tabs.length) return if (tabIndex < 0 || tabIndex >= tabs.length)
return;
var newTabs = tabs.slice() var newTabs = tabs.slice();
var closedTabId = newTabs[tabIndex] ? newTabs[tabIndex].id : -1 var closedTabId = newTabs[tabIndex] ? newTabs[tabIndex].id : -1;
clearSessionBuffer(closedTabId) clearSessionBuffer(closedTabId);
if (conflictTabId === closedTabId) if (conflictTabId === closedTabId)
clearConflict() clearConflict();
if (newTabs.length <= 1) { if (newTabs.length <= 1) {
var id = Date.now() var id = Date.now();
var filePath = "notepad-files/untitled-" + id + ".txt" var filePath = "notepad-files/untitled-" + id + ".txt";
var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) var newTabsBeingCreated = Object.assign({}, tabsBeingCreated);
newTabsBeingCreated[id] = true newTabsBeingCreated[id] = true;
tabsBeingCreated = newTabsBeingCreated tabsBeingCreated = newTabsBeingCreated;
createEmptyFile(baseDir + "/" + filePath, function() { createEmptyFile(baseDir + "/" + filePath, function () {
newTabs[0] = { newTabs[0] = {
id: id, id: id,
title: I18n.tr("Untitled"), title: I18n.tr("Untitled"),
@@ -296,110 +292,129 @@ Singleton {
lastModified: new Date().toISOString(), lastModified: new Date().toISOString(),
cursorPosition: 0, cursorPosition: 0,
scrollPosition: 0 scrollPosition: 0
} };
currentTabIndex = 0 currentTabIndex = 0;
tabs = newTabs tabs = newTabs;
var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated);
delete updatedTabsBeingCreated[id] delete updatedTabsBeingCreated[id];
tabsBeingCreated = updatedTabsBeingCreated tabsBeingCreated = updatedTabsBeingCreated;
saveMetadata() saveMetadata();
}) });
return return;
} else { } else {
var tabToDelete = newTabs[tabIndex] var tabToDelete = newTabs[tabIndex];
if (tabToDelete && tabToDelete.isTemporary) { if (tabToDelete && tabToDelete.isTemporary) {
deleteFile(baseDir + "/" + tabToDelete.filePath) deleteFile(baseDir + "/" + tabToDelete.filePath);
} }
newTabs.splice(tabIndex, 1) newTabs.splice(tabIndex, 1);
if (currentTabIndex >= newTabs.length) { if (currentTabIndex >= newTabs.length) {
currentTabIndex = newTabs.length - 1 currentTabIndex = newTabs.length - 1;
} else if (currentTabIndex > tabIndex) { } else if (currentTabIndex > tabIndex) {
currentTabIndex -= 1 currentTabIndex -= 1;
} }
} }
tabs = newTabs tabs = newTabs;
saveMetadata() saveMetadata();
} }
function switchToTab(tabIndex) { function switchToTab(tabIndex) {
if (tabIndex < 0 || tabIndex >= tabs.length) return if (tabIndex < 0 || tabIndex >= tabs.length)
return;
currentTabIndex = tabIndex currentTabIndex = tabIndex;
saveMetadata() saveMetadata();
} }
function reorderTab(fromIndex, toIndex) { function reorderTab(fromIndex, toIndex) {
if (fromIndex < 0 || fromIndex >= tabs.length || toIndex < 0 || toIndex >= tabs.length) if (fromIndex < 0 || fromIndex >= tabs.length || toIndex < 0 || toIndex >= tabs.length)
return return;
if (fromIndex === toIndex) if (fromIndex === toIndex)
return return;
var newTabs = tabs.slice();
var newTabs = tabs.slice() var moved = newTabs.splice(fromIndex, 1)[0];
var moved = newTabs.splice(fromIndex, 1)[0] newTabs.splice(toIndex, 0, moved);
newTabs.splice(toIndex, 0, moved) tabs = newTabs;
tabs = newTabs
if (currentTabIndex === fromIndex) { if (currentTabIndex === fromIndex) {
currentTabIndex = toIndex currentTabIndex = toIndex;
} else if (fromIndex < currentTabIndex && toIndex >= currentTabIndex) { } else if (fromIndex < currentTabIndex && toIndex >= currentTabIndex) {
currentTabIndex-- currentTabIndex--;
} else if (fromIndex > currentTabIndex && toIndex <= currentTabIndex) { } else if (fromIndex > currentTabIndex && toIndex <= currentTabIndex) {
currentTabIndex++ currentTabIndex++;
} }
saveMetadata() saveMetadata();
} }
function saveTabAs(tabIndex, userPath) { function saveTabAs(tabIndex, userPath) {
if (tabIndex < 0 || tabIndex >= tabs.length) return if (tabIndex < 0 || tabIndex >= tabs.length)
return;
var tab = tabs[tabIndex] var tab = tabs[tabIndex];
var fileName = userPath.split('/').pop() var fileName = userPath.split('/').pop();
if (tab.isTemporary) { if (tab.isTemporary) {
var tempPath = baseDir + "/" + tab.filePath var tempPath = baseDir + "/" + tab.filePath;
copyFile(tempPath, userPath) copyFile(tempPath, userPath);
deleteFile(tempPath) deleteFile(tempPath);
} }
var newTabs = tabs.slice() var newTabs = tabs.slice();
newTabs[tabIndex] = Object.assign({}, tab, { newTabs[tabIndex] = Object.assign({}, tab, {
title: fileName, title: fileName,
filePath: userPath, filePath: userPath,
isTemporary: false, isTemporary: false,
lastModified: new Date().toISOString() lastModified: new Date().toISOString()
}) });
tabs = newTabs tabs = newTabs;
saveMetadata() saveMetadata();
}
function renameTab(tabIndex, newTitle) {
if (tabIndex < 0 || tabIndex >= tabs.length)
return;
var trimmed = (newTitle || "").trim();
var tab = tabs[tabIndex];
if (trimmed.length === 0 || trimmed === tab.title)
return;
if (tab.isTemporary) {
updateTabMetadata(tabIndex, {
title: trimmed
});
return;
}
var dir = tab.filePath.substring(0, tab.filePath.lastIndexOf('/') + 1);
var newPath = dir + trimmed;
moveFile(tab.filePath, newPath);
updateTabMetadata(tabIndex, {
title: trimmed,
filePath: newPath
});
} }
function updateTabMetadata(tabIndex, properties) { function updateTabMetadata(tabIndex, properties) {
if (tabIndex < 0 || tabIndex >= tabs.length) return if (tabIndex < 0 || tabIndex >= tabs.length)
return;
var newTabs = tabs.slice() var newTabs = tabs.slice();
var updatedTab = Object.assign({}, newTabs[tabIndex], properties) var updatedTab = Object.assign({}, newTabs[tabIndex], properties);
updatedTab.lastModified = new Date().toISOString() updatedTab.lastModified = new Date().toISOString();
newTabs[tabIndex] = updatedTab newTabs[tabIndex] = updatedTab;
tabs = newTabs tabs = newTabs;
saveMetadata() saveMetadata();
} }
function validateTabs() { function validateTabs() {
var validTabs = [] var validTabs = [];
for (var i = 0; i < tabs.length; i++) { for (var i = 0; i < tabs.length; i++) {
var tab = tabs[i] var tab = tabs[i];
validTabs.push(tab) validTabs.push(tab);
} }
tabs = validTabs tabs = validTabs;
if (tabs.length === 0) { if (tabs.length === 0) {
root.createDefaultTab() root.createDefaultTab();
} }
} }
@@ -411,29 +426,13 @@ Singleton {
preload: true preload: true
onLoaded: { onLoaded: {
callback(text()) callback(text());
destroy() destroy();
} }
onLoadFailed: { onLoadFailed: {
callback("") callback("");
destroy() destroy();
}
}
}
Component {
id: fileExistsComponent
Process {
property string path
property var callback
command: ["test", "-f", path]
Component.onCompleted: running = true
onExited: (exitCode) => {
callback(exitCode === 0)
destroy()
} }
} }
} }
@@ -452,94 +451,46 @@ Singleton {
onSaved: { onSaved: {
if (tabIndex >= 0) { if (tabIndex >= 0) {
root.updateTabMetadata(tabIndex, {}) root.updateTabMetadata(tabIndex, {});
} }
if (creationCallback) { if (creationCallback) {
creationCallback() creationCallback();
} }
destroy() destroy();
} }
onSaveFailed: { onSaveFailed: {
log.error("Failed to save tab content") log.error("Failed to save tab content");
if (creationCallback) { if (creationCallback) {
creationCallback() creationCallback();
} }
destroy() destroy();
} }
} }
} }
function createEmptyFile(path, callback) { function createEmptyFile(path, callback) {
var cleanPath = decodeURI(path.toString()) var cleanPath = decodeURI(path.toString());
if (!cleanPath.startsWith("/")) { if (!cleanPath.startsWith("/")) {
cleanPath = baseDir + "/" + cleanPath cleanPath = baseDir + "/" + cleanPath;
} }
var creator = fileCreatorComponent.createObject(root, { Proc.runCommand("", ["touch", cleanPath], (output, exitCode) => {
filePath: cleanPath, if (callback)
creationCallback: callback callback();
}) });
} }
function copyFile(source, destination) { function copyFile(source, destination) {
copyProcess.source = source Proc.runCommand("", ["cp", source, destination], null);
copyProcess.destination = destination
copyProcess.running = true
} }
function deleteFile(path) { function deleteFile(path) {
deleteProcess.filePath = path Proc.runCommand("", ["rm", "-f", path], null);
deleteProcess.running = true
} }
Component { function moveFile(source, destination) {
id: fileCreatorComponent Proc.runCommand("", ["mv", source, destination], null);
QtObject {
property string filePath
property var creationCallback
Component.onCompleted: {
var touchProcess = touchProcessComponent.createObject(this, {
filePath: filePath,
callback: creationCallback
})
}
}
}
Component {
id: touchProcessComponent
Process {
property string filePath
property var callback
command: ["touch", filePath]
Component.onCompleted: running = true
onExited: (exitCode) => {
if (callback) callback()
destroy()
}
}
}
Process {
id: copyProcess
property string source
property string destination
command: ["cp", source, destination]
}
Process {
id: deleteProcess
property string filePath
command: ["rm", "-f", filePath]
}
Process {
id: mkdirProcess
command: ["mkdir", "-p", root.baseDir, root.filesDir]
} }
} }
+10 -3
View File
@@ -864,7 +864,12 @@ Singleton {
return notepadSlideouts[0]; return notepadSlideouts[0];
} }
// Remembered presentation wins over the configured default until the user
// changes the default in settings (handled below).
readonly property string notepadResolvedMode: SessionData.notepadLastMode || SettingsData.notepadDefaultMode
function openNotepadSlideout() { function openNotepadSlideout() {
SessionData.setNotepadLastMode("slideout");
notepadPopout?.hide(); notepadPopout?.hide();
if (notepadSlideouts.length > 0) { if (notepadSlideouts.length > 0) {
notepadSlideoutForFocusedScreen()?.show(); notepadSlideoutForFocusedScreen()?.show();
@@ -875,6 +880,7 @@ Singleton {
Connections { Connections {
target: SettingsData target: SettingsData
function onNotepadDefaultModeChanged() { function onNotepadDefaultModeChanged() {
SessionData.setNotepadLastMode(SettingsData.notepadDefaultMode);
if (SettingsData.notepadDefaultMode === "popout") { if (SettingsData.notepadDefaultMode === "popout") {
var hadSlideout = false; var hadSlideout = false;
for (var i = 0; i < root.notepadSlideouts.length; i++) { for (var i = 0; i < root.notepadSlideouts.length; i++) {
@@ -893,7 +899,7 @@ Singleton {
} }
function openNotepad() { function openNotepad() {
if (SettingsData.notepadDefaultMode === "popout") { if (notepadResolvedMode === "popout") {
openNotepadPopout(); openNotepadPopout();
return; return;
} }
@@ -901,7 +907,7 @@ Singleton {
} }
function closeNotepad() { function closeNotepad() {
if (SettingsData.notepadDefaultMode === "popout") { if (notepadResolvedMode === "popout") {
notepadPopout?.hide(); notepadPopout?.hide();
return; return;
} }
@@ -911,7 +917,7 @@ Singleton {
} }
function toggleNotepad() { function toggleNotepad() {
if (SettingsData.notepadDefaultMode === "popout") { if (notepadResolvedMode === "popout") {
toggleNotepadPopout(); toggleNotepadPopout();
return; return;
} }
@@ -926,6 +932,7 @@ Singleton {
property string _notepadPendingOpenFilePath: "" property string _notepadPendingOpenFilePath: ""
function openNotepadPopout() { function openNotepadPopout() {
SessionData.setNotepadLastMode("popout");
closeNotepadSlideouts(); closeNotepadSlideouts();
if (notepadPopout) { if (notepadPopout) {
notepadPopout.show(); notepadPopout.show();