#FEATURE by sr
authorsr
Fri, 26 Oct 2018 13:50:02 +0200
changeset 8555 cb50d84d7cb4
parent 8554 89fa49dfd5e2
child 8556 e0d9ebe8cda1
#FEATURE by sr enhanced native file dialog add suffix (if none) from selected filter class: WinWorkstation changed: #nativeFileDialogWithTitle:defaultFilename:owningTopView:filter:filterIndex:trueForSave:trueForMultiSelect:trueForPromptOverwrite: #primGetNativeFileDialogResultByDataAddress: class: WinWorkstation::NativeFileDialogReturnData class definition added: #multiSelectBaseNames #multiSelectBaseNames: #selectedFilterIndex #selectedFilterIndex: #targetFileOrDirectory #targetFileOrDirectory: class: WinWorkstation::NativeFileDialogReturnData class added: #documentation
WinWorkstation.st
--- a/WinWorkstation.st	Fri Oct 26 09:42:08 2018 +0200
+++ b/WinWorkstation.st	Fri Oct 26 13:50:02 2018 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
 COPYRIGHT (c) 1996 by Claus Gittinger
               All Rights Reserved
@@ -46,6 +48,13 @@
 	privateIn:WinWorkstation
 !
 
+Object subclass:#NativeFileDialogReturnData
+	instanceVariableNames:'targetFileOrDirectory multiSelectBaseNames selectedFilterIndex'
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:WinWorkstation
+!
+
 DeviceHandle subclass:#PrinterDeviceContextHandle
 	instanceVariableNames:''
 	classVariableNames:''
@@ -948,7 +957,7 @@
     wchar_t directory[MAX_PATH];
     wchar_t title[MAX_PATH];
     HWND owningWindow;
-    wchar_t filter[MAX_PATH];
+    wchar_t filter[10 * MAX_PATH]; // there could be many filters
     int filterIndex;
     BOOL trueForSave;
     BOOL trueForMultiSelect;
@@ -994,7 +1003,9 @@
         hasResult = GetOpenFileNameW(&ofn);
     }
 
-    if (!hasResult) {
+    if (hasResult) {
+		pFdd->filterIndex = ofn.nFilterIndex;
+	} else {
         ZeroMemory(&pFdd->filename, sizeof(pFdd->filename));
     }
 
@@ -2163,7 +2174,7 @@
                     }
                     goto again;
                 }
-                /* fail evtl. später ändern und in st verzögert aufrufen
+                /* fail evtl. später ändern und in st verzögert aufrufen
                 */
                 console_fprintf(stderr, "WinWorkstation [info]: UnregisterClass %s failed.\n",(char*)ev->ev_arg1);
             }
@@ -16628,8 +16639,11 @@
      returns nil or the full path to the selected file
      see example at the end of the method code"
 
-    |dialogTitle defaultBaseName defaultDirectory owningViewId windowGroup filterString null
-     dataAddressAndThreadAddress dataAddress returnValue|
+    |dialogTitle defaultBaseName defaultDirectory owningViewId windowGroup filterString filterArrayOrPairs 
+     null filterStringParts
+     dataAddressAndThreadAddress dataAddress returnValue 
+     nativeFileDialogReturnData targetFileOrDirectory multiSelectBaseNames selectedSuffixInfo selectedSuffix
+     needsSlash|
 
     dialogTitleArg notEmptyOrNil ifTrue:[
         dialogTitle := dialogTitleArg asUnicode16String.
@@ -16655,21 +16669,36 @@
     ].
 
     filterStringOrArrayOfPairs notEmptyOrNil ifTrue:[
-        filterStringOrArrayOfPairs isString ifTrue:[
-            filterString := filterStringOrArrayOfPairs.
-        ] ifFalse:[
-            null := (String new:1) 
-                at:1 put:Character null; 
-                yourself. 
-
-            filterString := ((filterStringOrArrayOfPairs 
-                collect:[:eachPair | 
-                    eachPair first, null, eachPair second, null
-                ]) 
-                    asStringWith:''), null.
+        null := (String new:1) 
+            at:1 put:Character null; 
+            yourself.          
+
+        filterStringOrArrayOfPairs notNil ifTrue:[
+            filterStringOrArrayOfPairs isString ifTrue:[
+                filterString := filterStringOrArrayOfPairs.
+                filterArrayOrPairs := OrderedCollection new.
+                filterStringParts := filterStringOrArrayOfPairs subStrings:null.
+
+                1 
+                    to:filterStringParts size 
+                    by:2 
+                    do:[:index |
+                        filterArrayOrPairs 
+                            add:(Array 
+                                with:(filterStringParts at:index) 
+                                with:(filterStringParts at:index + 1)).
+                    ].
+            ] ifFalse:[
+                filterArrayOrPairs := filterStringOrArrayOfPairs.    
+                filterString := ((filterStringOrArrayOfPairs 
+                    collect:[:eachPair | 
+                        eachPair first, null, eachPair second, null
+                    ]) 
+                        asStringWith:''), null.
+            ].
+
+            filterString := filterString asUnicode16String.
         ].
-
-        filterString := filterString asUnicode16String.
     ].
 
     [
@@ -16723,10 +16752,48 @@
     ].
 
     returnValue isEmptyOrNil ifTrue:[
+        "dialog was aborted"    
         ^ nil
     ].
 
-    ^ returnValue
+    nativeFileDialogReturnData := returnValue.
+    targetFileOrDirectory := nativeFileDialogReturnData targetFileOrDirectory.
+    multiSelectBaseNames := nativeFileDialogReturnData multiSelectBaseNames.     
+    multiSelectBaseNames notEmptyOrNil ifTrue:[
+        needsSlash := targetFileOrDirectory last ~= $\.
+
+        ^ (multiSelectBaseNames 
+            subStrings:$|)
+                reject:[:each | each isEmptyOrNil]
+                thenCollect:[:each | 
+                    needsSlash ifTrue:[
+                        targetFileOrDirectory, '\', each
+                    ] ifFalse:[
+                        targetFileOrDirectory, each
+                    ]
+                ]
+    ].
+
+    (filterArrayOrPairs notEmptyOrNil
+    and:[targetFileOrDirectory asFilename suffix isEmptyOrNil]) ifTrue:[ 
+        selectedSuffixInfo := filterArrayOrPairs 
+            at:nativeFileDialogReturnData selectedFilterIndex
+            ifAbsent:nil. 
+
+        selectedSuffixInfo notNil ifTrue:[
+            selectedSuffix := (selectedSuffixInfo second 
+                subStrings:'.') 
+                    lastIfEmpty:nil.
+
+            (selectedSuffix notNil 
+            and:[selectedSuffix ~= '*']) ifTrue:[
+                ^ targetFileOrDirectory, '.', selectedSuffix
+            ].
+
+        ].
+    ].
+
+    ^ targetFileOrDirectory
 
     "
     ########### example1 without owning view ##########
@@ -16745,7 +16812,7 @@
                 'All', null, '*.*', null,
                 null
             filterIndex:3
-            trueForSave:false
+            trueForSave:true
             trueForMultiSelect:nil         
             trueForPromptOverwrite:nil
 
@@ -16824,7 +16891,7 @@
     "
 
     "Created: / 25-10-2018 / 10:54:52 / sr"
-    "Modified: / 26-10-2018 / 09:35:38 / sr"
+    "Modified: / 26-10-2018 / 13:48:31 / sr"
 !
 
 primCloseNativeFileDialogByDataAddress:dataAddress
@@ -16861,7 +16928,8 @@
      returns an empty string if the file dialog was canceled
      returns the full path to the user selected file"
 
-    |targetFileOrNil multiSelectValues needsSlash|
+    |targetFileOrNil multiSelectValues selectedFilterIndex
+     nativeFileDialogReturnData|
 
 %{  /* STACK: 100000 */
     if (__isExternalAddress(dataAddress)) {
@@ -16870,24 +16938,28 @@
         if (pFdd->fileDialogDidReturn) {
             targetFileOrNil = __MKU16STRING(pFdd->filename);
 
-            if ((!pFdd->trueForSave) && pFdd->trueForMultiSelect) {
-			    int len;
-				int pos;
-				
-                wchar_t buffer[1000 * MAX_PATH]; // big buffer to support multiselect
-                ZeroMemory(buffer, sizeof(buffer));    
-
-                len = wcslen(pFdd->filename);
-                pos = len + 1;
-
-                while ((len = wcslen(&pFdd->filename[pos])) > 0) {
-                    wcscat(buffer, &pFdd->filename[pos]);
-                    wcscat(buffer, L"|");
-                    pos = pos + len + 1;      
-                    wprintf(L"char '%ls'\n", buffer);
-                }
-
-                multiSelectValues = __MKU16STRING(buffer);     
+            if (pFdd->trueForSave) {
+                selectedFilterIndex = __MKINT(pFdd->filterIndex);        
+            } else {
+                if (pFdd->trueForMultiSelect) {
+                    int len;
+                    int pos;
+
+                    wchar_t buffer[1000 * MAX_PATH]; // big buffer to support multiselect
+                    ZeroMemory(buffer, sizeof(buffer));    
+
+                    len = wcslen(pFdd->filename);
+                    pos = len + 1;
+
+                    while ((len = wcslen(&pFdd->filename[pos])) > 0) {
+                        wcscat(buffer, &pFdd->filename[pos]);
+                        wcscat(buffer, L"|");
+                        pos = pos + len + 1;      
+                        wprintf(L"char '%ls'\n", buffer);
+                    }
+
+                    multiSelectValues = __MKU16STRING(buffer);  
+                }
             }
 
             free(pFdd);
@@ -16899,24 +16971,16 @@
         ^ nil
     ].
     targetFileOrNil isEmpty ifTrue:[
-        ^ ''
-    ].
-    multiSelectValues isEmptyOrNil ifTrue:[
-        ^ targetFileOrNil
-    ].
-
-    needsSlash := targetFileOrNil last ~= $\.
-
-    ^ (multiSelectValues 
-        subStrings:$|)
-            reject:[:each | each isEmptyOrNil]
-            thenCollect:[:each | 
-                needsSlash ifTrue:[
-                    targetFileOrNil, '\', each
-                ] ifFalse:[
-                    targetFileOrNil, each
-                ].
-            ]
+        ^ '' "/ to exit the while nil loop (indicated file dialog abort)
+    ].
+
+    ^ NativeFileDialogReturnData new
+        targetFileOrDirectory:targetFileOrNil;
+        multiSelectBaseNames:multiSelectValues;
+        selectedFilterIndex:selectedFilterIndex;
+        yourself
+
+    "Modified (comment): / 26-10-2018 / 13:34:50 / sr"
 !
 
 primNativeFileDialogWithTitle:dialogTitle
@@ -19692,7 +19756,7 @@
     }
 %}
     "
-     (StandardSystemView new label:'äöü') open
+     (StandardSystemView new label:'äöü') open
     "
 !
 
@@ -20076,6 +20140,73 @@
     ^ workY
 ! !
 
+!WinWorkstation::NativeFileDialogReturnData class methodsFor:'documentation'!
+
+documentation
+"
+    This class is used for the native file dialog.
+    Its just a better Dictionary to collect all required return data from the native file dialog
+
+    [author:]
+        sr
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!WinWorkstation::NativeFileDialogReturnData methodsFor:'accessing'!
+
+multiSelectBaseNames
+    "when multiselect is on, here are the baseNames collected,
+     their directory is kept in targetFileOrDirectory"
+    ^ multiSelectBaseNames
+
+    "Modified (comment): / 26-10-2018 / 13:30:04 / sr"
+!
+
+multiSelectBaseNames:something                   
+    "when multiselect is on, here are the baseNames collected,
+     their directory is kept in targetFileOrDirectory"
+    multiSelectBaseNames := something.
+
+    "Modified (comment): / 26-10-2018 / 13:30:09 / sr"
+!
+
+selectedFilterIndex
+    "this is the index of the filter, which was selected by user (1 based).
+     only present when save (not open)"
+    ^ selectedFilterIndex
+
+    "Modified (comment): / 26-10-2018 / 13:30:48 / sr"
+!
+
+selectedFilterIndex:something                   
+    "this is the index of the filter, which was selected by user (1 based).
+     only present when save (not open)"
+    selectedFilterIndex := something.
+
+    "Modified (comment): / 26-10-2018 / 13:30:55 / sr"
+!
+
+targetFileOrDirectory
+    "the selected file or when mutliselect the directory"
+    ^ targetFileOrDirectory
+
+    "Modified (comment): / 26-10-2018 / 13:31:13 / sr"
+!
+
+targetFileOrDirectory:something
+    "the selected file or when mutliselect the directory"
+    targetFileOrDirectory := something.
+
+    "Modified (comment): / 26-10-2018 / 13:31:16 / sr"
+! !
+
 !WinWorkstation::PrinterDeviceContextHandle class methodsFor:'documentation'!
 
 documentation