diff --git a/src/dlangui/dialogs/filedlg.d b/src/dlangui/dialogs/filedlg.d index 74f78f9d..30e9404d 100644 --- a/src/dlangui/dialogs/filedlg.d +++ b/src/dlangui/dialogs/filedlg.d @@ -65,6 +65,13 @@ enum FileDialogFlag : uint { } +/// File dialog action codes +enum FileDialogActions : int { + ShowInFileManager = 4000, + CreateDirectory = 4001, + DeleteFile = 4002, +} + /// filetype filter entry for FileDialog struct FileFilterEntry { UIString label; @@ -351,6 +358,10 @@ class FileDialog : Dialog, CustomGridCellAdapter { super.handleAction(action); return true; } + if (action.id == FileDialogActions.ShowInFileManager) { + Platform.instance.showInFileManager(action.stringParam); + return true; + } if (action.id == StandardAction.CreateDirectory) { // show editor popup window.showInputBox(UIString("CREATE_NEW_FOLDER"c), UIString("INPUT_NAME_FOR_FOLDER"c), ""d, delegate(dstring s) { @@ -382,6 +393,31 @@ class FileDialog : Dialog, CustomGridCellAdapter { return openDirectory(path, null); } + protected MenuItem getCellPopupMenu(GridWidgetBase source, int col, int row) { + if (row >= 0 && row < _entries.length) { + MenuItem item = new MenuItem(); + DirEntry e = _entries[row]; + // show in explorer action + auto showAction = new Action(FileDialogActions.ShowInFileManager, "ACTION_FILE_SHOW_IN_FILE_MANAGER"c); + showAction.stringParam = e.name; + item.add(showAction); + // create directory action + if (_flags & FileDialogFlag.EnableCreateDirectory) + item.add(ACTION_CREATE_DIRECTORY); + + if (e.isDir) { + //_edFilename.text = ""d; + //_filename = ""; + } else if (e.isFile) { + //string fname = e.name; + //_edFilename.text = toUTF32(baseName(fname)); + //_filename = fname; + } + return item; + } + return null; + } + /// override to implement creation of dialog controls override void initialize() { _roots = getRootPaths; @@ -446,6 +482,8 @@ class FileDialog : Dialog, CustomGridCellAdapter { _fileList.setColTitle(3, "Modified"d); _fileList.showRowHeaders = false; _fileList.rowSelect = true; + _fileList.cellPopupMenu = &getCellPopupMenu; + _fileList.menuItemAction = &handleAction; rightPanel.addChild(_edPath); rightPanel.addChild(_fileList); diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d index 4ea2a073..b06e8307 100644 --- a/src/dlangui/platforms/common/platform.d +++ b/src/dlangui/platforms/common/platform.d @@ -1339,15 +1339,12 @@ class Platform { import std.process; browse(url); return true; - //Log.d("Platform.openURL(", url, ") is called"); - //bool res = false; - //version(Windows) { - // import win32.shellapi; - // ShellExecuteA(null, "open", url.toStringz, null, null, 1); - // res = true; - //} - //// TODO: support other platforms - //return res; + } + + /// show directory or file in OS file manager (explorer, finder, etc...) + bool showInFileManager(string pathName) { + Log.w("showInFileManager is not implemented for current platform"); + return false; } /// handle theme change: e.g. reload some themed resources diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index a109cf4d..4b724f13 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -863,6 +863,39 @@ class Win32Platform : Platform { CloseClipboard(); } + /// show directory or file in OS file manager (explorer, finder, etc...) + override bool showInFileManager(string pathName) { + Log.i("showInFileManager(", pathName, ")"); + import dlangui.core.files; + //import std.process; + import std.path; + import std.string; + + string explorerPath = findExecutablePath("explorer.exe"); + if (!explorerPath.length) { + Log.e("showInFileManager failed - cannot find explorer.exe"); + return false; + } + string normalized = buildNormalizedPath(pathName); + string arg = "/select,\"" ~ normalized ~ "\""; + STARTUPINFO si; + si.cb = si.sizeof; + PROCESS_INFORMATION pi; + Log.i("showInFileManager: ", explorerPath, " ", arg); + arg = "\"" ~ explorerPath ~ "\" " ~ arg; + auto res = CreateProcessW(null, //explorerPath.toUTF16z, + cast(wchar*)arg.toUTF16z, + null, null, false, DETACHED_PROCESS, + null, null, &si, &pi); + if (!res) { + Log.e("showInFileManager failed to run explorer.exe"); + return false; + } + + //auto pid = spawnProcess(explorerPath, [arg], ); + return true; + } + } extern(Windows) diff --git a/src/dlangui/widgets/grid.d b/src/dlangui/widgets/grid.d index ef6033e6..676bd2e7 100644 --- a/src/dlangui/widgets/grid.d +++ b/src/dlangui/widgets/grid.d @@ -55,9 +55,15 @@ module dlangui.widgets.grid; import dlangui.widgets.widget; import dlangui.widgets.controls; import dlangui.widgets.scroll; +import dlangui.widgets.menu; import std.conv; import std.algorithm : equal; +/// cellPopupMenu signal handler interface +interface CellPopupMenuHandler { + MenuItem getCellPopupMenu(GridWidgetBase source, int col, int row); +} + /** * Data provider for GridWidget. */ @@ -238,7 +244,7 @@ interface ViewScrolledHandler { } /// Abstract grid widget -class GridWidgetBase : ScrollWidgetBase, GridModelAdapter { +class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler { /// Callback to handle selection change Listener!CellSelectedHandler cellSelected; @@ -696,6 +702,55 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter { return true; } + /// cell popup menu + Signal!CellPopupMenuHandler cellPopupMenu; + /// popup menu item action + Signal!MenuItemActionHandler menuItemAction; + + protected MenuItem getCellPopupMenu(int col, int row) { + if (cellPopupMenu.assigned) + return cellPopupMenu(this, col, row); + return null; + } + + /// handle popup menu action + protected bool onMenuItemAction(const Action action) { + if (menuItemAction.assigned) + return menuItemAction(action); + return false; + } + + /// returns true if widget can show popup menu (e.g. by mouse right click at point x,y) + override bool canShowPopupMenu(int x, int y) { + int col, row; + Rect rc; + x -= _clientRect.left; + y -= _clientRect.top; + pointToCell(x, y, col, row, rc); + MenuItem item = getCellPopupMenu(col, row); + if (!item) + return false; + return true; + } + + /// shows popup menu at (x,y) + override void showPopupMenu(int xx, int yy) { + int col, row; + Rect rc; + int x = xx - _clientRect.left; + int y = yy - _clientRect.top; + pointToCell(x, y, col, row, rc); + MenuItem menu = getCellPopupMenu(col - _headerCols, row - _headerRows); + if (menu) { + import dlangui.widgets.popup; + menu.updateActionState(this); + PopupMenu popupMenu = new PopupMenu(menu); + popupMenu.menuItemAction = this; + PopupWidget popup = window.showPopup(popupMenu, this, PopupAlign.Point | PopupAlign.Right, xx, yy); + popup.flags = PopupFlags.CloseOnClickOutside; + } + } + /// handle mouse wheel events override bool onMouseEvent(MouseEvent event) { if (visibility != Visibility.Visible) diff --git a/views/res/i18n/std_en.ini b/views/res/i18n/std_en.ini index f9e97414..2e1fe9f2 100644 --- a/views/res/i18n/std_en.ini +++ b/views/res/i18n/std_en.ini @@ -24,3 +24,5 @@ CREATE_FOLDER_ERROR_MESSAGE=Folder creation is failed ACTION_EDITOR_TOGGLE_BOOKMARK=Toggle bookmark ACTION_EDITOR_GOTO_NEXT_BOOKMARK=Go to next bookmark ACTION_EDITOR_GOTO_PREVIOUS_BOOKMARK=Go to previous bookmark + +ACTION_FILE_SHOW_IN_FILE_MANAGER=Show in file manager