Kanashius Posted February 21 Posted February 21 (edited) I've looked into it and implemented the copy/move operation. I pushed a commit to github. https://github.com/AutoIt-Community/files-au3/commit/f4e33a7aa41a5db28aca1f783b06fc0236525dec I hope this is what you had in mind Edited February 21 by Kanashius My Website: Kanashius Webside (Some of my Programs you can find there)
WildByDesign Posted February 21 Author Posted February 21 51 minutes ago, Kanashius said: I hope this is what you had in mind This is seriously awesome! 😁 Not only did you prove that it is possible to run these file operations in a separate sub-process, but you did it in such a well organized way. I am speechless! The sub-process starts/ends only when needed, does its job perfectly and does not hinder the performance of the main GUI process. I tested it by copying a few GB's of files and folders and it was perfect. This is incredible work, @Kanashius. I see only one area of concern at the moment. I'll comment in the code below: If $sTargetPathAbs<>Default Then ; determine if IFileOperation needs to copy or move files Switch $iFinalEffect Case $DROPEFFECT_COPY __FilesOperation_DoInSub($__FileOperation_Copy, $sTargetPathAbs, $arPaths) ; we need a response here from _IFileOperationFile from sub-process from __FileOperations_SubCopyOrMove Case $DROPEFFECT_MOVE __FilesOperation_DoInSub($__FileOperation_Move, $sTargetPathAbs, $arPaths) ; we need a response here from _IFileOperationFile from sub-process from __FileOperations_SubCopyOrMove ; especially here because we don't want to send DROPEFFECT_NONE and __SetPerformedDropEffect back to ; source of drag (whether it's File Explorer, etc.) until file operation is complete $tEffect.iEffect = $DROPEFFECT_NONE __SetPerformedDropEffect($pDataObject, $DROPEFFECT_NONE) EndSwitch EndIf From what I can tell, you already have the structure in place to send/receive messages between the main process and the sub-process. I just don't fully understand it all yet. I think what we need there is for the sub-process to send the result from _IFileOperationFile. Although I don't think we need to hold up the process at that very point. The main thing is that I don't think we want to send: __SetPerformedDropEffect($pDataObject, $DROPEFFECT_NONE) ... until after the file operation (move) is complete because that is what tells the source of the drag or copy (eg. File Explorer) what happened and how it should (or should not) handle the file operation on its end. I'll have to test more and see. But we definitely need to be careful with Move. Copy is not an issue. Other than that concern, I am absolutely shocked and surprised with how awesome you just made this with multi-process file operations. I feel just like a little kid walking into a candy store right now. 😆 On a side note, I have made some great progress with the IFileOperation stuff recently. We don't need to worry about updating the IFileOperation stuff yet though. We probably need to wait until all of the dust settles from all of these recent changes. Kanashius 1
Kanashius Posted February 21 Posted February 21 I'm glad you like it 1 hour ago, WildByDesign said: From what I can tell, you already have the structure in place to send/receive messages between the main process and the sub-process. I just don't fully understand it all yet. I think what we need there is for the sub-process to send the result from _IFileOperationFile I changed it to sent the __SetPerformedDropEffect. The objects are already at the main process, so that process should handle it. I've put it in the "Successful copy/move" part, so it is only done, when the operation was successful. Maybe that should change. Currently the Local $iResult = _IFileOperationFile is handled as a bool for success/failure, if it carries more data, it could also be returned and sent with __IPC_SubSendCmd($bResult?$__FileOperation_Successful:$__FileOperation_Failed, $iResult) to make it available in the main process. I also thought about doing a little refactoring soonish. Orienting myself in the project was a little bit confusing, so doing stuff like: functions/global variable names start with the filename, they are in,... I think that would be a good starting point to give the project a littlebit of clarity on the structure side. WildByDesign 1 My Website: Kanashius Webside (Some of my Programs you can find there)
WildByDesign Posted February 22 Author Posted February 22 8 hours ago, Kanashius said: I changed it to sent the __SetPerformedDropEffect. The objects are already at the main process, so that process should handle it. I've put it in the "Successful copy/move" part, so it is only done, when the operation was successful. Maybe that should change. Currently the Local $iResult = _IFileOperationFile is handled as a bool for success/failure, if it carries more data, it could also be returned and sent with __IPC_SubSendCmd($bResult?$__FileOperation_Successful:$__FileOperation_Failed, $iResult) to make it available in the main process. I finally got a chance to spend some time testing it more thoroughly with your multi-process file operation changes. The more times that I test drag and drop with larger sets of files, the more impressed I am. It works so incredibly well. I also needed to spend some time thinking about what data we needed to send and whether or not it mattered if we sent it immediately or if we waited until the file operation was truly complete. I think the fact that we are sending DROPEFFECT_NONE doesn't matter as much when we send it. With the Fix drop messaging to sender commit, it is giving errors on the line with "$tEffect.iEffect = $DROPEFFECT_NONE" which I believe was line 100. I don't have the exact error right now but it was referring to not being an object. That is when I started thinking, "Do we really need to send it after?". That is when I decided to revert back to the Implement Copy/Move over IPC at a different process commit which was your initial multi-process commit. I spent quite a bit more time testing larger drag and drop operations here. Everything worked perfectly well. Do you think that we should just revert the Fix drop messaging to sender commit? It seems that maybe it does not have access to the IDataObject ($pDataObject) there anyway. I'm not sure if it just can't access it there or if the data object was already released at that point. But I am thinking that we may not need that commit. 8 hours ago, Kanashius said: I also thought about doing a little refactoring soonish. Orienting myself in the project was a little bit confusing, so doing stuff like: functions/global variable names start with the filename, they are in,... I think that would be a good starting point to give the project a littlebit of clarity on the structure side. If you would like to do some refactoring, that would be fantastic. I think that we may need to wait until these pull requests are accepted and merged though because there are a lot of structural changes with the shell-dodragdrop branch and of course with your IPC additions as well. I know that Sven has been quite busy this week and may not be able to review and merge until next week. Unless you want to do the review and merge. I've got so many great ideas and changes ready to go once all of the dust settles from these big changes. Kanashius 1
Kanashius Posted February 22 Posted February 22 1 hour ago, WildByDesign said: Do you think that we should just revert the Fix drop messaging to sender commit? Yes, I'am not sure, what sending the effect should change at the senders end. Except ending the drag/drop. 1 hour ago, WildByDesign said: if the data object was already released at that point Probably yes, because the callback returned, so it was probably freed. Same for $piEffect. 1 hour ago, WildByDesign said: I've got so many great ideas and changes ready to go once all of the dust settles from these big changes. I cannot wait WildByDesign and SOLVE-SMART 2 My Website: Kanashius Webside (Some of my Programs you can find there)
WildByDesign Posted February 24 Author Posted February 24 We have some instances of IFileOperation used in the main.au3 script as well. I'm not sure if we need multi-process for all of them or not. There are two instances of IFileOperation in _PasteItems() function which basically follow through with a CopyItems into either TreeView or ListView. I personally think that we should use multi-process here because Paste has the potential to be a larger set of files to copy. I believe the remaining instances of IFileOperation in main.au3 are for deleting items. I'm not certain if we need multi-process for deleting files. But then again, deleting files can also potentially be a lot of larger files and take some time. Anything that takes more time should be in a separate process. @Kanashius What do you think about this? If you believe that it should be multi-process, would you please be willing to extend your IPC to these areas as well?
Kanashius Posted February 24 Posted February 24 1 hour ago, WildByDesign said: If you believe that it should be multi-process, would you please be willing to extend your IPC to these areas as well? Yes, everything that may take longer than 1 or 2 seconds should be put in a process to prevent the application from freezing. I will look into it WildByDesign 1 My Website: Kanashius Webside (Some of my Programs you can find there)
WildByDesign Posted Thursday at 03:07 PM Author Posted Thursday at 03:07 PM (edited) There is a weird bug that should be simple but I cannot figure it out. When you navigate to a directory that is slower to load (250ms), I made it so that it hides the ListView to simulate _GUICtrlListView_DeleteAllItems since that is happening behind the scenes already. The reason why I did that is because it would never show those files disappearing until after the ListView loading was complete. So I did it to make it look cleaner. I also made it so that it shows the MCID_WAIT cursor during that slower load time. So when you navigate to a slower directory such as System32, that all works perfectly. The problem is that the MCID_WAIT cursor does not show when you hit the Refresh button when you are already in System32. The interesting thing is that I can tell that it is running through the _ListViewLoadWait() function properly and hiding the ListView. It just seems that, for whatever reason, it does not want to show the MCID_WAIT when clicking Refresh on that slow loading directory (System32). You will need to run the code from the fix-item-count branch because it fixes some other things in the Loading Callback that prevented the _ListViewLoadWait() function from working properly. Func _ListViewLoadWait() If $bLoadStatus Then ; override GUI with loading/waiting cursor on directories that are slower to load $bCursorOverride = True GUISetCursor($MCID_WAIT, 1, $g_hGUI) GUISetCursor($MCID_WAIT, 1, _GUIFrame_GetHandle($iFrame_A, 2)) GUICtrlSetState($idListview, $GUI_HIDE) ; clear statusbar item count $g_aText[0] = "" _WinAPI_RedrawWindow($g_hStatus) EndIf AdlibUnRegister("_ListViewLoadWait") EndFunc ;==>_ListViewLoadWait So whether you navigate to System32 or hit Refresh while on System32, it does run through this function and hides the ListView as intended. What is failing on Refresh (on System32): GUISetCursor overriding the cursor to MCID_WAIT Clearing the item count on the statusbar I am thoroughly puzzled over this issue. 🙃 EDIT: It looks like the problem is that the GUI is hung up during this time until System32 has loaded. It looks like this may not be fixable. Edited Thursday at 07:03 PM by WildByDesign
WildByDesign Posted Sunday at 12:17 AM Author Posted Sunday at 12:17 AM Should we have support for languages other than English? If yes, what is the best way to do that in AutoIt?
argumentum Posted Sunday at 03:07 AM Posted Sunday at 03:07 AM 2 hours ago, WildByDesign said: Should we have support for languages other than English? Si, Ja, Oui oui The question is: do you know the intricacies of other languages 🤔 There are languages that are "right to left" and some that are top to bottom ?. I guess one of those who speak/type in that language would know better. So yes. It'd be beautiful to attend to all languages. I just don't know how. If one of those ( too strange to English speakers ) languages are brought up by a user, we'll discover it then 🤷♂️ WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Kanashius Posted Sunday at 11:36 AM Posted Sunday at 11:36 AM 7 hours ago, argumentum said: I just don't know how I would go for a key/value approach with maps. So a function to set the language. Then a file with a bunch of keys/values (could be an ini, which is already implemented in AutoIt). The Values would be in the StringFormat style. Then a function to load the correct string (for performance probably a loading function to load them once and not open the language file all the time) and a function to get the language string for a specific key. The key should be basically the entire string without any non a-zA-Z, so there are no conflicts and you can see, what string is requested there. (Very long strings could just use the start). expandcollapse popupGlobal $__Lang__LangMap[] ; This is the lang.ini. Could also be split into multiple files, if it gets to large ; google translated arabic, so sorry for that ;) #cs [en] thisIsALongSentence=This is a long sentence. exampleNumberIs=Example number is %i. [de] thisIsALongSentence=Dies ist ein langer Satz. exampleNumberIs=Beispielzahl ist %i. [egy] RightToLeft=true thisIsALongSentence=هذه جملة طويلة. exampleNumberIs=الرقم المثالي هو %i. #ce __Lang_Init() ConsoleWrite(__Lang_Get("thisIsALongSentence")&@crlf) ConsoleWrite(__Lang_Get("exampleNumberIs", 5)&@crlf) __Lang_Init("de") ConsoleWrite(__Lang_Get("thisIsALongSentence")&@crlf) ConsoleWrite(__Lang_Get("exampleNumberIs", 5)&@crlf) ; If __Lang_IsRTL() Then GUICtrlCreateLabel("", 5, 5, 100, 100, BitOR($SS_NOTIFY, $SS_RIGHT)) Func __Lang_Init($sLang=Default, $sLangIni = "lang.ini") If $sLang=Default Then Local $arSections = IniReadSectionNames($sLangIni) If @error Or UBound($arSections)<2 Then Return SetError(1, 2, False) $sLang = $arSections[1] EndIf Local $arLang = IniReadSection($sLangIni, $sLang) If @error Then Return SetError(2, 0, False) Local $mLangMap[] For $i=1 To UBound($arLang)-1 $mLangMap[$arLang[$i][0]] = $arLang[$i][1] Next $__Lang__LangMap = $mLangMap EndFunc Func __Lang_IsRTL() Return MapExists($__Lang__LangMap, "RightToLeft") And StringLower($__Lang__LangMap["RightToLeft"]) = "true" EndFunc Func __Lang_Get($sKey, $vParam1 = Default, $vParam2 = Default, $vParam3 = Default, $vParam4 = Default, $vParam5 = Default, _ $vParam6 = Default, $vParam7 = Default, $vParam8 = Default, $vParam9 = Default, $vParam10 = Default, _ $vParam11 = Default, $vParam12 = Default, $vParam13 = Default, $vParam14 = Default, $vParam15 = Default, _ $vParam16 = Default, $vParam17 = Default, $vParam18 = Default, $vParam19 = Default, $vParam20 = Default, _ $vParam21 = Default, $vParam22 = Default, $vParam23 = Default, $vParam24 = Default, $vParam25 = Default, _ $vParam26 = Default, $vParam27 = Default, $vParam28 = Default, $vParam29 = Default, $vParam30 = Default, _ $vParam31 = Default, $vParam32 = Default) ; StringFormat is limited to 32 params, too If Not MapExists($__Lang__LangMap, $sKey) Then Return SetError(1, 1, "") Local $arArgs[@NumParams+1] $arArgs[0] = "CallArgArray" ; This is required, otherwise, Call() will not recognize the array as containing arguments $arArgs[1] = $__Lang__LangMap[$sKey] For $i=1 To @NumParams-1 $arArgs[$i+1] = Eval("vParam"&$i) Next Local $sVal = Call("StringFormat", $arArgs) If @error Then Return SetError(2, @error, "") Return $sVal EndFunc To add automatic changes for labels,... when changing the language, something like this could work to avoid a restart. But that would require a lot of functions to update all the different types of controls,... I think a restart would be simpler. Local $idLabel = GuiCtrlCreateLabel("", 5, 5) __Lang_AddKey("exampleNumberIs", __Lang_GetCtrlLabelCallbackMap($idLabel), 5) Func __Lang_GetCtrlLabelCallbackMap($idCtrl) Local $mCallBack[] $mCallBack["GuiCtrlSetData"] = [$idCtrl] $mCallBack["GUICtrlSetStyle"] = [$idCtrl, __Lang_IsRTL()?$SS_RIGHT:$SS_LEFT] EndFunc Func __Lang_AddKey($sKey, $mCallBack, $vParam1 = Default, $vParam2 = Default, $vParam3 = Default, $vParam4 = Default, $vParam5 = Default, _ $vParam6 = Default, $vParam7 = Default, $vParam8 = Default, $vParam9 = Default, $vParam10 = Default, _ $vParam11 = Default, $vParam12 = Default, $vParam13 = Default, $vParam14 = Default, $vParam15 = Default, _ $vParam16 = Default, $vParam17 = Default, $vParam18 = Default, $vParam19 = Default, $vParam20 = Default, _ $vParam21 = Default, $vParam22 = Default, $vParam23 = Default, $vParam24 = Default, $vParam25 = Default, _ $vParam26 = Default, $vParam27 = Default, $vParam28 = Default, $vParam29 = Default, $vParam30 = Default, _ $vParam31 = Default, $vParam32 = Default) ; add $sKey, $mCallBack and the params (as array) to a map to store them and call the callback functions,... ; when language is changed, the callback functions can be called again ; just needs a way to delete them later... so some identifier, which may get returned by __Lang_AddKey (e.g. MapAppend result or something) EndFunc Hope this helps, LG Kanashius argumentum and WildByDesign 2 My Website: Kanashius Webside (Some of my Programs you can find there)
WildByDesign Posted Sunday at 12:25 PM Author Posted Sunday at 12:25 PM 29 minutes ago, Kanashius said: I would go for a key/value approach with maps. So a function to set the language. Then a file with a bunch of keys/values (could be an ini, which is already implemented in AutoIt). The Values would be in the StringFormat style. Then a function to load the correct string (for performance probably a loading function to load them once and not open the language file all the time) and a function to get the language string for a specific key. The key should be basically the entire string without any non a-zA-Z, so there are no conflicts and you can see, what string is requested there. (Very long strings could just use the start). This is a really smart approach. Very well thought out. I figured it is something we should think about now since we are only going to continue adding more visible GUI options that would be dependant on language. And of course, many of the contributors to Files Au3 are not English speaking as their first language. So you all deserve to have your own languages supported. I think that if we have the language structure in place (.ini or whichever), it will be easy for anyone to help adding languages as needed. 47 minutes ago, Kanashius said: To add automatic changes for labels,... when changing the language, something like this could work to avoid a restart. But that would require a lot of functions to update all the different types of controls,... I think a restart would be simpler. Changing languages without restart would certainly be nice. But you're right, it would take a lot of extra work changing menu text and everything. Maybe a simple restart at first and a longer term goal of not needing a restart.
WildByDesign Posted Sunday at 12:33 PM Author Posted Sunday at 12:33 PM (edited) For what it's worth, when I was still learning AutoIt I had to come up with more own strings/languages idea for another project: expandcollapse popup$OSLanguage = @OSLang $MUILang = @MUILang $OSLanguageCode = $OSLanguage $OSLanguageName = $MUILang ; check if muilang is blank to use oslang instead If $MUILang = "" Then $OSLang = $OSLanguage Else $OSLang = $MUILang EndIf If $OSLang = '0409' Then $OSLanguageCode = 'en-US' $OSLanguageName = 'English - United States' $softName = 'Software name' ; ... more variables with strings ElseIf $OSLang = '0407' Then $OSLanguageCode = 'de-DE' $OSLanguageName = 'Deutsch - Deutschland' $softName = 'Software name' ; ... more variables with strings ElseIf $OSLang = '0421' Then $OSLanguageCode = 'id-ID' $OSLanguageName = 'Indonesian - Indonesia' $softName = 'Software name' ; ... more variables with strings ElseIf $OSLang = '0816' Then $OSLanguageCode = 'pt-PT' $OSLanguageName = 'Português - Portugal' $softName = 'Software name' ; ... more variables with strings ElseIf $OSLang = '0416' Then $OSLanguageCode = 'pt-BR' $OSLanguageName = 'Português - Brasil' $softName = 'Software name' ; ... more variables with strings ElseIf $OSLang = '0419' Then $OSLanguageCode = 'ru-RU' $OSLanguageName = 'Русский - Россия' $softName = 'Software name' ; ... more variables with strings ElseIf $OSLang = '042A' Then $OSLanguageCode = 'vi-VN' $OSLanguageName = 'Tiếng Việt' $softName = 'Software name' ; ... more variables with strings Else ; fall back to English if there are no other matching languages $OSLanguageCode = @OSLang $OSLanguageName = @MUILang $softName = 'Software name' ; ... more variables with strings EndIf This was run on GUI startup. Each language had a list of like 20 strings attached to those variables. It was really simplistic but it worked well. The only downside was that it was internal only, so there was no outside .ini file. EDIT: Clearly this was before I knew about Switch Case... 😄 Edited Sunday at 12:35 PM by WildByDesign argumentum 1
Kanashius Posted 19 hours ago Posted 19 hours ago This might be of interest to you My Website: Kanashius Webside (Some of my Programs you can find there)
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now