package main import ( "os" "os/exec" "runtime" "strings" "time" qt "github.com/mappu/miqt/qt6" "github.com/mappu/miqt/qt6/mainthread" ) const AutoRefreshInterval = 1 * time.Second func NewStatusDelegate(status string) *qt.QWidget { mw := qt.NewQWidget2() layout := qt.NewQHBoxLayout(mw) layout.SetContentsMargins(4, 4, 4, 4) layout.SetSpacing(8) statusCircle := qt.NewQWidget2() statusCircle.SetFixedSize2(12, 12) var color string = "red" if strings.Contains(status, "Up") { color = "green" } statusCircle.SetStyleSheet("background-color: " + color + "; border-radius: 6px;") statusLabel := qt.NewQLabel3(status) layout.AddWidget(statusCircle) layout.AddWidget(statusLabel.QWidget) layout.AddStretch() return mw } func openTerminal(container_id string) { popupCommand("docker exec -it " + container_id + " sh -c '[ -x /bin/bash ] && exec /bin/bash || exec /bin/sh'") } func popupCommand(command string) { switch runtime.GOOS { case "darwin": exec.Command("open", "-a", "Terminal", "--", "sh", "-c", command).Start() case "linux": exec.Command("x-terminal-emulator", "-e", "sh -c \""+command+"\"").Start() case "windows": exec.Command("start", "cmd", "/k", command).Start() default: panic("Opening a terminal is not supported on " + runtime.GOOS) } } func openLogs(container_id string) { popupCommand("docker logs -f " + container_id) } type DockerGUITab struct { *qt.QWidget tree *qt.QTreeWidget search_bar *qt.QLineEdit } type DockerGUI struct { *qt.QMainWindow toolbar *qt.QToolBar start_action *qt.QAction stop_action *qt.QAction remove_action *qt.QAction create_network_action *qt.QAction remove_network_action *qt.QAction create_volume_action *qt.QAction remove_volume_action *qt.QAction terminal_action *qt.QAction pull_image_action *qt.QAction remove_image_action *qt.QAction logs_action *qt.QAction auto_refresh_checkbox *qt.QCheckBox tab_widget *qt.QTabWidget containers_tab *qt.QWidget images_tab *qt.QWidget networks_tab *qt.QWidget volumes_tab *qt.QWidget containers_tree *qt.QTreeWidget images_tree *qt.QTreeWidget networks_tree *qt.QTreeWidget volumes_tree *qt.QTreeWidget containers_searchbar *qt.QLineEdit images_searchbar *qt.QLineEdit networks_searchbar *qt.QLineEdit volumes_searchbar *qt.QLineEdit refresh_timer *time.Ticker } func NewDockerGUI() *DockerGUI { var self DockerGUI self.QMainWindow = qt.NewQMainWindow2() self.SetWindowTitle("Qocker - Docker Graphical User Interface") self.SetGeometry(100, 100, 1000, 600) // Create central widget and layout central_widget := qt.NewQWidget2() self.SetCentralWidget(central_widget) mainLayout := qt.NewQVBoxLayout(central_widget) // Create toolbar self.create_toolbar() // Create tab widget self.tab_widget = qt.NewQTabWidget2() mainLayout.AddWidget(self.tab_widget.QWidget) // Create tabs self.containers_tab = qt.NewQWidget2() self.images_tab = qt.NewQWidget2() self.networks_tab = qt.NewQWidget2() self.volumes_tab = qt.NewQWidget2() self.tab_widget.AddTab(self.containers_tab, "Containers") self.tab_widget.AddTab(self.images_tab, "Images") self.tab_widget.AddTab(self.networks_tab, "Networks") self.tab_widget.AddTab(self.volumes_tab, "Volumes") // Connect tab change to toolbar update self.tab_widget.OnCurrentChanged(self.update_toolbar_buttons) // Create tree widgets for each tab self.containers_tree = self.create_tree_widget("ID", "Name", "Image", "Status", "Ports") self.images_tree = self.create_tree_widget("ID", "Repository", "Tag", "Size") self.networks_tree = self.create_tree_widget("ID", "Name", "Driver") self.volumes_tree = self.create_tree_widget("Name", "Driver", "Mountpoint") self.containers_tree.OnItemDoubleClicked(func(item *qt.QTreeWidgetItem, column int) { self.open_terminal() }) // Add search bars self.containers_searchbar = self.create_searchbar_widget(self.containers_tree, "Search containers...") self.images_searchbar = self.create_searchbar_widget(self.images_tree, "Search images...") self.networks_searchbar = self.create_searchbar_widget(self.networks_tree, "Search networks...") self.volumes_searchbar = self.create_searchbar_widget(self.volumes_tree, "Search volumes...") // Add tree widgets to tabs self.setup_tab(self.containers_tab, self.containers_tree, self.containers_searchbar) self.setup_tab(self.images_tab, self.images_tree, self.images_searchbar) self.setup_tab(self.networks_tab, self.networks_tree, self.networks_searchbar) self.setup_tab(self.volumes_tab, self.volumes_tree, self.volumes_searchbar) // Create menu bar self.create_menu_bar() //.Setup auto-refresh self.setup_auto_refresh() // Populate data self.refresh_data() // Update toolbar buttons for initial state self.update_toolbar_buttons(0) // override QMainWindow.createPopupMenu self.OnCreatePopupMenu(func(super func() *qt.QMenu) *qt.QMenu { filtered_menu := super() filtered_menu.RemoveAction(self.toolbar.ToggleViewAction()) return filtered_menu }) return &self } func (self *DockerGUI) create_tree_widget(headers ...string) *qt.QTreeWidget { tree := qt.NewQTreeWidget2() tree.SetHeaderLabels(headers) tree.SetContextMenuPolicy(qt.CustomContextMenu) tree.OnCustomContextMenuRequested(self.show_context_menu) tree.SetSortingEnabled(true) header := tree.Header() header.SetSectionResizeMode(qt.QHeaderView__Interactive) header.SetSortIndicator(0, qt.DescendingOrder) header.SetSortIndicatorShown(true) header.OnSortIndicatorChanged(func(col int, order qt.SortOrder) { self.sort_tree_widget(tree, col, order) }) return tree } func (self *DockerGUI) sort_tree_widget(tree *qt.QTreeWidget, column int, order qt.SortOrder) { tree.SortItems(column, order) } // Add search bar func (self *DockerGUI) create_searchbar_widget(tree *qt.QTreeWidget, search_placeholder string) *qt.QLineEdit { search_bar := qt.NewQLineEdit2() search_bar.SetPlaceholderText(search_placeholder) search_bar.OnTextChanged(func(text string) { self.filter_tree(tree, text) }) return search_bar } func (self *DockerGUI) setup_tab(tab *qt.QWidget, tree *qt.QTreeWidget, search_bar *qt.QLineEdit) { layout := qt.NewQVBoxLayout(tab) layout.AddWidget(search_bar.QWidget) layout.AddWidget(tree.QWidget) } func (self *DockerGUI) filter_tree(tree *qt.QTreeWidget, text string) { text = strings.ToLower(text) for i := 0; i < tree.TopLevelItemCount(); i++ { item := tree.TopLevelItem(i) match := false for j := 0; j < item.ColumnCount(); j++ { if strings.Contains(strings.ToLower(item.Text(j)), text) { match = true break } } item.SetHidden(!match) } } func (self *DockerGUI) create_toolbar() { self.toolbar = qt.NewQToolBar3() self.toolbar.SetMovable(false) // Make toolbar fixed self.AddToolBar(qt.TopToolBarArea, self.toolbar) // Common actions refresh_action := qt.NewQAction6(qt.QIcon_FromTheme("view-refresh"), "Refresh", self.QObject) refresh_action.OnTriggered(self.refresh_data) self.toolbar.AddAction(refresh_action) // Add auto-refresh checkbox self.auto_refresh_checkbox = qt.NewQCheckBox3("Auto-refresh") self.auto_refresh_checkbox.SetChecked(true) self.toolbar.AddWidget(self.auto_refresh_checkbox.QWidget) // Add separator self.toolbar.AddSeparator() // Container-specific actions self.start_action = qt.NewQAction6(qt.QIcon_FromTheme("media-playback-start"), "Start", self.QObject) self.start_action.OnTriggered(self.start_container) self.toolbar.AddAction(self.start_action) self.stop_action = qt.NewQAction6(qt.QIcon_FromTheme("media-playback-stop"), "Stop", self.QObject) self.stop_action.OnTriggered(self.stop_container) self.toolbar.AddAction(self.stop_action) self.remove_action = qt.NewQAction6(qt.QIcon_FromTheme("edit-delete"), "Remove", self.QObject) self.remove_action.OnTriggered(self.remove_container) self.toolbar.AddAction(self.remove_action) // Image-specific actions self.pull_image_action = qt.NewQAction6(qt.QIcon_FromTheme("download"), "Pull Image", self.QObject) self.pull_image_action.OnTriggered(self.pull_image) self.toolbar.AddAction(self.pull_image_action) self.remove_image_action = qt.NewQAction6(qt.QIcon_FromTheme("edit-delete"), "Remove Image", self.QObject) self.remove_image_action.OnTriggered(self.remove_image) self.toolbar.AddAction(self.remove_image_action) // Network-specific actions self.create_network_action = qt.NewQAction6(qt.QIcon_FromTheme("list-add"), "Create Network", self.QObject) self.create_network_action.OnTriggered(self.create_network) self.toolbar.AddAction(self.create_network_action) self.remove_network_action = qt.NewQAction6(qt.QIcon_FromTheme("edit-delete"), "Remove Network", self.QObject) self.remove_network_action.OnTriggered(self.remove_network) self.toolbar.AddAction(self.remove_network_action) // Volume-specific actions self.create_volume_action = qt.NewQAction6(qt.QIcon_FromTheme("list-add"), "Create Volume", self.QObject) self.create_volume_action.OnTriggered(self.create_volume) self.toolbar.AddAction(self.create_volume_action) self.remove_volume_action = qt.NewQAction6(qt.QIcon_FromTheme("edit-delete"), "Remove Volume", self.QObject) self.remove_volume_action.OnTriggered(self.remove_volume) self.toolbar.AddAction(self.remove_volume_action) // Add terminal action self.terminal_action = qt.NewQAction6(qt.QIcon_FromTheme("utilities-terminal"), "Open Terminal", self.QObject) self.terminal_action.OnTriggered(self.open_terminal) self.toolbar.AddAction(self.terminal_action) // Add logs action self.logs_action = qt.NewQAction6(qt.QIcon_FromTheme("document-open"), "Open Logs", self.QObject) self.logs_action.OnTriggered(self.open_logs) self.toolbar.AddAction(self.logs_action) } func (self *DockerGUI) update_toolbar_buttons(index int) { // Show actions based on the current tab // Containers tab self.start_action.SetVisible(index == 0) self.stop_action.SetVisible(index == 0) self.remove_action.SetVisible(index == 0) self.terminal_action.SetVisible(index == 0) self.logs_action.SetVisible(index == 0) // Images tab self.pull_image_action.SetVisible(index == 1) self.remove_image_action.SetVisible(index == 1) // Networks tab self.create_network_action.SetVisible(index == 2) self.remove_network_action.SetVisible(index == 2) // Volumes tab self.create_volume_action.SetVisible(index == 3) self.remove_volume_action.SetVisible(index == 3) } func (self *DockerGUI) update_visible_tabs(index int) { for i := 0; i < self.tab_widget.Count(); i++ { self.tab_widget.TabBar().SetTabVisible(i, (i == index)) } } func (self *DockerGUI) create_menu_bar() { menubar := self.MenuBar() file_menu := menubar.AddMenuWithTitle("File") exit_action := qt.NewQAction5("Exit", self.QObject) exit_action.OnTriggered(func() { self.Close() }) file_menu.AddAction(exit_action) docker_menu := menubar.AddMenuWithTitle("Docker") refresh_action := qt.NewQAction5("Refresh", self.QObject) refresh_action.OnTriggered(self.refresh_data) docker_menu.AddAction(refresh_action) } func (self *DockerGUI) show_context_menu(position *qt.QPoint) { context_menu := qt.NewQMenu2() current_tab := self.tab_widget.CurrentWidget() // Add refresh action to context menu refresh_action := qt.NewQAction5("Refresh", self.QObject) refresh_action.OnTriggered(self.refresh_data) context_menu.AddAction(refresh_action) context_menu.AddSeparator() if current_tab == self.containers_tab { terminal_action := qt.NewQAction5("Terminal", self.QObject) terminal_action.OnTriggered(func() { self.handle_action("Terminal") }) context_menu.AddAction(terminal_action) logs_action := qt.NewQAction5("Logs", self.QObject) logs_action.OnTriggered(func() { self.open_logs() }) context_menu.AddAction(logs_action) context_menu.AddSeparator() start_action := qt.NewQAction5("Start", self.QObject) start_action.OnTriggered(func() { self.handle_action("Start") }) context_menu.AddAction(start_action) stop_action := qt.NewQAction5("Stop", self.QObject) stop_action.OnTriggered(func() { self.handle_action("Stop") }) context_menu.AddAction(stop_action) remove_action := qt.NewQAction5("Remove", self.QObject) remove_action.OnTriggered(func() { self.handle_action("Remove") }) context_menu.AddAction(remove_action) } else if current_tab == self.images_tab { pull_action := qt.NewQAction5("Pull", self.QObject) pull_action.OnTriggered(self.pull_image) context_menu.AddAction(pull_action) context_menu.AddSeparator() remove_action := qt.NewQAction5("Remove", self.QObject) remove_action.OnTriggered(self.remove_image) context_menu.AddAction(remove_action) } else if current_tab == self.networks_tab { remove_action := qt.NewQAction5("Remove", self.QObject) remove_action.OnTriggered(func() { self.handle_action("Remove") }) context_menu.AddAction(remove_action) } else if current_tab == self.volumes_tab { remove_action := qt.NewQAction5("Remove", self.QObject) remove_action.OnTriggered(func() { self.handle_action("Remove") }) context_menu.AddAction(remove_action) } context_menu.ExecWithPos(current_tab.MapToGlobalWithQPoint(position)) } func (self *DockerGUI) setup_auto_refresh() { self.refresh_timer = time.NewTicker(AutoRefreshInterval) go func() { for { _, ok := <-self.refresh_timer.C if !ok { return } mainthread.Wait(func() { if !self.auto_refresh_checkbox.IsChecked() { return } self.refresh_data() }) } }() } func (self *DockerGUI) handle_action(action string) { current_tab := self.tab_widget.CurrentWidget() if current_tab == self.containers_tab { selected_items := self.containers_tree.SelectedItems() if len(selected_items) == 0 { return } container_id := selected_items[0].Text(0) if action == "Terminal" { self.open_terminal() } else if action == "Start" { exec.Command("docker", "start", container_id).Run() } else if action == "Stop" { exec.Command("docker", "stop", container_id).Run() } else if action == "Remove" { exec.Command("docker", "rm", "-f", container_id).Run() } } else if current_tab == self.networks_tab { selected_items := self.networks_tree.SelectedItems() if len(selected_items) == 0 { return } network_id := selected_items[0].Text(0) if action == "Remove" { exec.Command("docker", "network", "rm", network_id).Run() } } else if current_tab == self.volumes_tab { selected_items := self.volumes_tree.SelectedItems() if len(selected_items) == 0 { return } volume_name := selected_items[0].Text(0) if action == "Remove" { exec.Command("docker", "volume", "rm", volume_name).Run() } } self.refresh_data() } func (self *DockerGUI) refresh_data() { self.refresh_containers() self.refresh_images() self.refresh_networks() self.refresh_volumes() } func (self *DockerGUI) refresh_containers() { scroll_position := self.containers_tree.VerticalScrollBar().Value() selected_items := self.get_selected_items(self.containers_tree) self.containers_tree.Clear() output, err := exec.Command("docker", "ps", "-a", "--format", "{{.ID}}\\t{{.Names}}\\t{{.Image}}\\t{{.Status}}\\t{{.Ports}}").Output() if err != nil { panic(err) } containers := strings.Split(strings.TrimSpace(string(output)), "\n") for _, container := range containers { parts := strings.Split(container, "\t") id := parts[0] name := parts[1] image := parts[2] status := parts[3] ports := "" if len(parts) > 4 { ports = parts[4] } item := qt.NewQTreeWidgetItem2([]string{id, name, image, "", ports}) // Empty string for status column status_widget := NewStatusDelegate(status) self.containers_tree.AddTopLevelItem(item) self.containers_tree.SetItemWidget(item, 3, status_widget) } self.filter_tree(self.containers_tree, self.containers_searchbar.Text()) self.restore_selection(self.containers_tree, selected_items) qt.QTimer_SingleShot(0, func() { self.containers_tree.VerticalScrollBar().SetValue(scroll_position) }) } func (self *DockerGUI) refresh_images() { scroll_position := self.images_tree.VerticalScrollBar().Value() selected_items := self.get_selected_items(self.images_tree) self.images_tree.Clear() output, err := exec.Command("docker", "images", "--format", "{{.ID}}\\t{{.Repository}}\\t{{.Tag}}\\t{{.Size}}").Output() if err != nil { panic(err) } images := strings.Split(strings.TrimSpace(string(output)), "\n") for _, image := range images { parts := strings.Split(image, "\t") id := parts[0] repository := parts[1] tag := parts[2] size := parts[3] item := qt.NewQTreeWidgetItem2([]string{id, repository, tag, size}) self.images_tree.AddTopLevelItem(item) } self.filter_tree(self.images_tree, self.images_searchbar.Text()) self.restore_selection(self.images_tree, selected_items) qt.QTimer_SingleShot(0, func() { self.images_tree.VerticalScrollBar().SetValue(scroll_position) }) } func (self *DockerGUI) refresh_networks() { scroll_position := self.networks_tree.VerticalScrollBar().Value() selected_items := self.get_selected_items(self.networks_tree) self.networks_tree.Clear() output, err := exec.Command("docker", "network", "ls", "--format", "{{.ID}}\\t{{.Name}}\\t{{.Driver}}").Output() if err != nil { panic(err) } networks := strings.Split(strings.TrimSpace(string(output)), "\n") for _, network := range networks { parts := strings.Split(network, "\t") id := parts[0] name := parts[1] driver := parts[2] item := qt.NewQTreeWidgetItem2([]string{id, name, driver}) self.networks_tree.AddTopLevelItem(item) } self.filter_tree(self.networks_tree, self.networks_searchbar.Text()) self.restore_selection(self.networks_tree, selected_items) qt.QTimer_SingleShot(0, func() { self.networks_tree.VerticalScrollBar().SetValue(scroll_position) }) } func (self *DockerGUI) refresh_volumes() { scroll_position := self.volumes_tree.VerticalScrollBar().Value() selected_items := self.get_selected_items(self.volumes_tree) self.volumes_tree.Clear() output, err := exec.Command("docker", "volume", "ls", "--format", "{{.Name}}\\t{{.Driver}}\\t{{.Mountpoint}}").Output() if err != nil { panic(err) } volumes := strings.Split(strings.TrimSpace(string(output)), "\n") for _, volume := range volumes { parts := strings.Split(volume, "\t") name := parts[0] driver := parts[1] mountpoint := parts[2] item := qt.NewQTreeWidgetItem2([]string{name, driver, mountpoint}) self.volumes_tree.AddTopLevelItem(item) } self.filter_tree(self.volumes_tree, self.volumes_searchbar.Text()) self.restore_selection(self.volumes_tree, selected_items) qt.QTimer_SingleShot(0, func() { self.volumes_tree.VerticalScrollBar().SetValue(scroll_position) }) } func (self *DockerGUI) get_selected_items(tree *qt.QTreeWidget) []string { selItems := tree.SelectedItems() ret := make([]string, 0, len(selItems)) for _, itm := range selItems { ret = append(ret, itm.Text(0)) } return ret } func (self *DockerGUI) restore_selection(tree *qt.QTreeWidget, selected_items []string) { rmatch := map[string]struct{}{} for _, itm := range selected_items { rmatch[itm] = struct{}{} } for i := 0; i < tree.TopLevelItemCount(); i++ { item := tree.TopLevelItem(i) if _, ok := rmatch[item.Text(0)]; ok { item.SetSelected(true) } } } func (self *DockerGUI) start_container() { selected_items := self.containers_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select a container to start.") return } for _, item := range selected_items { container_id := item.Text(0) err := exec.Command("docker", "start", container_id).Wait() if err != nil { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to start container "+container_id+": "+err.Error()) } } self.refresh_containers() } func (self *DockerGUI) stop_container() { selected_items := self.containers_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select a container to stop.") return } for _, item := range selected_items { container_id := item.Text(0) err := exec.Command("docker", "stop", container_id).Run() if err != nil { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to stop container "+container_id+": "+err.Error()) } } self.refresh_containers() } func (self *DockerGUI) remove_container() { selected_items := self.containers_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select a container to remove.") return } for _, item := range selected_items { container_id := item.Text(0) reply := qt.QMessageBox_Question5(self.QWidget, "Confirm Removal", "Are you sure you want to remove container "+container_id+"?", qt.QMessageBox__Yes|qt.QMessageBox__No, qt.QMessageBox__No, ) if reply != qt.QMessageBox__Yes { continue } err := exec.Command("docker", "rm", "-f", container_id).Run() if err != nil { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to remove container "+container_id+": "+err.Error()) } } self.refresh_containers() } func (self *DockerGUI) pull_image() { image_name := qt.QInputDialog_GetText(self.QWidget, "Pull Image", "Enter image name (e.g., ubuntu:latest):") if image_name == "" { return } err := exec.Command("docker", "pull", image_name).Run() if err == nil { qt.QMessageBox_Information(self.QWidget, "Success", "Image \""+image_name+"\" pulled successfully.") } else { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to pull image: "+err.Error()) } self.refresh_images() } func (self *DockerGUI) remove_image() { selected_items := self.images_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select an image to remove.") return } for _, item := range selected_items { image_id := item.Text(0) reply := qt.QMessageBox_Question5(self.QWidget, "Confirm Removal", "Are you sure you want to remove image "+image_id+"?", qt.QMessageBox__Yes|qt.QMessageBox__No, qt.QMessageBox__No, ) if reply != qt.QMessageBox__Yes { continue } err := exec.Command("docker", "rmi", image_id).Run() if err == nil { qt.QMessageBox_Information(self.QWidget, "Success", "Image \""+image_id+"\" removed successfully.") } else { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to remove image "+image_id+": "+err.Error()) } } self.refresh_images() } func (self *DockerGUI) create_network() { network_name := qt.QInputDialog_GetText(self.QWidget, "Create Network", "Enter network name:") if network_name == "" { return } err := exec.Command("docker", "network", "create", network_name).Run() if err == nil { qt.QMessageBox_Information(self.QWidget, "Success", "Network \""+network_name+"\" created successfully.") } else { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to create network: "+err.Error()) } self.refresh_networks() } func (self *DockerGUI) remove_network() { selected_items := self.networks_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select a network to remove.") return } for _, item := range selected_items { network_name := item.Text(1) // Assuming the network name is in the second column reply := qt.QMessageBox_Question5(self.QWidget, "Confirm Removal", "Are you sure you want to remove network "+network_name+"?", qt.QMessageBox__Yes|qt.QMessageBox__No, qt.QMessageBox__No, ) if reply != qt.QMessageBox__Yes { continue } err := exec.Command("docker", "network", "rm", network_name).Run() if err == nil { qt.QMessageBox_Information(self.QWidget, "Success", "Network \""+network_name+"\" removed successfully.") } else { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to remove network "+network_name+": "+err.Error()) } } self.refresh_networks() } func (self *DockerGUI) create_volume() { volume_name := qt.QInputDialog_GetText(self.QWidget, "Create Volume", "Enter volume name:") if volume_name == "" { return } err := exec.Command("docker", "volume", "create", volume_name).Run() if err == nil { qt.QMessageBox_Information(self.QWidget, "Success", "Volume \""+volume_name+"\" created successfully.") } else { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to create volume "+volume_name+": "+err.Error()) } self.refresh_volumes() } func (self *DockerGUI) remove_volume() { selected_items := self.volumes_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select a volume to remove.") return } for _, item := range selected_items { volume_name := item.Text(0) // Assuming the volume name is in the first column reply := qt.QMessageBox_Question5(self.QWidget, "Confirm Removal", "Are you sure you want to remove volume "+volume_name+"?", qt.QMessageBox__Yes|qt.QMessageBox__No, qt.QMessageBox__No, ) if reply != qt.QMessageBox__Yes { continue } err := exec.Command("docker", "volume", "rm", volume_name).Run() if err == nil { qt.QMessageBox_Information(self.QWidget, "Success", "Volume \""+volume_name+"\" removed successfully.") } else { qt.QMessageBox_Critical(self.QWidget, "Error", "Failed to remove volume "+volume_name+": "+err.Error()) } } self.refresh_volumes() } func (self *DockerGUI) open_terminal() { selected_items := self.containers_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select a container to open terminal.") return } container_id := selected_items[0].Text(0) openTerminal(container_id) } func (self *DockerGUI) show_terminal_error(error_message string) { qt.QMessageBox_Critical(self.QWidget, "Error", error_message) } func (self *DockerGUI) open_logs() { selected_items := self.containers_tree.SelectedItems() if len(selected_items) == 0 { qt.QMessageBox_Warning(self.QWidget, "No Selection", "Please select a container to open logs.") return } container_id := selected_items[0].Text(0) openLogs(container_id) } func (self *DockerGUI) show_logs_error(error_message string) { qt.QMessageBox_Critical(self.QWidget, "Error", error_message) } func main() { qt.NewQApplication(os.Args) window := NewDockerGUI() window.Show() os.Exit(qt.QApplication_Exec()) }