session rename: double-click to rename sessions in tree
This commit is contained in:
parent
2267c57b54
commit
63cf13b891
114
gui/main.qml
114
gui/main.qml
|
|
@ -146,6 +146,36 @@ ApplicationWindow {
|
|||
ollie.switchAgent(parentId, agentId)
|
||||
}
|
||||
|
||||
// Rename tracking
|
||||
property int renamingIndex: -1
|
||||
property string renamingText: ""
|
||||
|
||||
function startRename(index) {
|
||||
var item = sessionTreeModel.get(index)
|
||||
if (item.type === "session") {
|
||||
renamingIndex = index
|
||||
renamingText = item.displayName
|
||||
}
|
||||
}
|
||||
|
||||
function commitRename() {
|
||||
if (renamingIndex < 0) return
|
||||
var item = sessionTreeModel.get(renamingIndex)
|
||||
var newName = renamingText.trim()
|
||||
if (newName !== "" && newName !== item.id) {
|
||||
if (ollie.renameSession(item.id, newName)) {
|
||||
sessionTreeModel.set(renamingIndex, { id: newName, displayName: newName })
|
||||
}
|
||||
}
|
||||
renamingIndex = -1
|
||||
renamingText = ""
|
||||
}
|
||||
|
||||
function cancelRename() {
|
||||
renamingIndex = -1
|
||||
renamingText = ""
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ollie
|
||||
function onSessionsChanged() {
|
||||
|
|
@ -500,27 +530,95 @@ ApplicationWindow {
|
|||
}
|
||||
visible: height > 0
|
||||
|
||||
// Click disambiguation: timer-based single vs double click
|
||||
property int _clickCount: 0
|
||||
Timer {
|
||||
id: clickTimer
|
||||
interval: 300
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
parent._clickCount = 0
|
||||
if (type === "session" && index !== renamingIndex) {
|
||||
toggleExpand(index)
|
||||
} else if (type === "agent") {
|
||||
activateAgent(parentId, agentId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: false
|
||||
onClicked: function() {
|
||||
if (renamingIndex >= 0) return
|
||||
parent._clickCount++
|
||||
if (parent._clickCount === 1) {
|
||||
clickTimer.start()
|
||||
} else if (parent._clickCount === 2) {
|
||||
clickTimer.stop()
|
||||
parent._clickCount = 0
|
||||
if (type === "session") {
|
||||
startRename(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Indent + expand/collapse indicator
|
||||
Label {
|
||||
Item {
|
||||
Layout.preferredWidth: (level || 0) * 16 + 16
|
||||
Layout.preferredHeight: 28
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: type === "session" ? (expanded ? "▼" : "▶") : ""
|
||||
font.pixelSize: theme.fontSize > 0 ? theme.fontSize * 0.7 : 10
|
||||
color: theme.textColor
|
||||
opacity: 0.6
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
// Name
|
||||
Label {
|
||||
// Name area
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 28
|
||||
|
||||
TextField {
|
||||
anchors.fill: parent
|
||||
text: (index === renamingIndex) ? renamingText : ""
|
||||
visible: index === renamingIndex
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pointSize: theme.fontSize > 0 ? theme.fontSize : Qt.application.font.pointSize
|
||||
color: theme.textColor
|
||||
background: Rectangle {
|
||||
color: theme.baseColor
|
||||
border.color: theme.highlightColor
|
||||
radius: 2
|
||||
}
|
||||
Keys.onReturnPressed: commitRename()
|
||||
Keys.onEscapePressed: cancelRename()
|
||||
onAccepted: commitRename()
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
forceActiveFocus()
|
||||
selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors.fill: parent
|
||||
text: displayName || ""
|
||||
color: theme.textColor
|
||||
font.pointSize: theme.fontSize > 0 ? theme.fontSize : Qt.application.font.pointSize
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
visible: index !== renamingIndex
|
||||
}
|
||||
}
|
||||
|
||||
// State dot
|
||||
|
|
@ -538,14 +636,6 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (type === "session") {
|
||||
toggleExpand(index)
|
||||
} else if (type === "agent") {
|
||||
activateAgent(parentId, agentId)
|
||||
}
|
||||
}
|
||||
|
||||
highlighted: (type === "agent" && agentId === ollie.activeAgentId && parentId === ollie.activeSessionId)
|
||||
|
||||
function parentSessionExpanded(pid) {
|
||||
|
|
|
|||
|
|
@ -271,6 +271,42 @@ bool Ollie9pClient::createSession(const QString &cwd, const QString &name, const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Ollie9pClient::renameSession(const QString &sessionId, const QString &newName)
|
||||
{
|
||||
if (sessionId.isEmpty() || newName.isEmpty()) return false;
|
||||
|
||||
// Use Twstat to rename the session directory.
|
||||
// We need to open the directory and write its stat.
|
||||
// 9p doesn't have a direct "mv" command, but we can use stat/rdwr
|
||||
// to read the current stat, modify the name, and write it back.
|
||||
// However, plan9port's 9p doesn't support wstat directly.
|
||||
//
|
||||
// Alternative: use our own ollie-9p which has a mv command.
|
||||
QString bin = QStandardPaths::findExecutable("ollie-9p");
|
||||
if (bin.isEmpty()) {
|
||||
qDebug() << "renameSession: ollie-9p not found, cannot rename";
|
||||
return false;
|
||||
}
|
||||
|
||||
QProcess proc;
|
||||
proc.start(bin, {"-a", serverAddr(), "mv", "session/" + sessionId, "session/" + newName});
|
||||
proc.waitForFinished(5000);
|
||||
|
||||
if (proc.exitCode() != 0) {
|
||||
qDebug() << "renameSession failed:" << QString::fromUtf8(proc.readAllStandardError()).trimmed();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update active session ID if we renamed the active session
|
||||
if (m_activeSessionId == sessionId) {
|
||||
m_activeSessionId = newName;
|
||||
emit activeSessionIdChanged();
|
||||
}
|
||||
|
||||
refreshSessions();
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Root data loading (lazy) ---
|
||||
|
||||
void Ollie9pClient::ensureRootDataLoaded()
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ public:
|
|||
Q_INVOKABLE void loadRootAgents();
|
||||
Q_INVOKABLE QStringList getAvailableModels(const QString &backend) const;
|
||||
Q_INVOKABLE bool createSession(const QString &cwd, const QString &name, const QString &backend, const QString &model, const QString &agent, const QString &remote);
|
||||
Q_INVOKABLE bool renameSession(const QString &sessionId, const QString &newName);
|
||||
|
||||
signals:
|
||||
void sessionsChanged();
|
||||
|
|
|
|||
Reference in New Issue