mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
7314 lines
223 KiB
ObjectPascal
7314 lines
223 KiB
ObjectPascal
{
|
|
Double Commander
|
|
-------------------------------------------------------------------------
|
|
Licence : GNU GPL v 2.0
|
|
Copyright (C) 2006-2023 Alexander Koblov (Alexx2000@mail.ru)
|
|
|
|
Main Dialog window
|
|
|
|
based on:
|
|
|
|
Seksi Commander (radekc.regnet.cz)
|
|
----------------------------
|
|
Licence : GNU GPL v 2.0
|
|
Author : radek.cervinka@centrum.cz
|
|
|
|
Main Dialog window and other stuff
|
|
|
|
contributors:
|
|
|
|
|
|
based on (heavy rewriten):
|
|
|
|
main Unit of PFM : Peter's File Manager
|
|
---------------------------------------
|
|
|
|
Copyright : Peter Cernoch 2002
|
|
Contact : pcernoch@volny.cz
|
|
Licence : GNU GPL v 2.0
|
|
|
|
contributors:
|
|
|
|
Copyright (C) 2008 Vitaly Zotov (vitalyzotov@mail.ru)
|
|
|
|
}
|
|
|
|
unit fMain;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
ufavoritetabs, Graphics, Forms, Menus, Controls, StdCtrls, ExtCtrls, ActnList,
|
|
Buttons, SysUtils, Classes, SynEdit, LCLType, ComCtrls, LResources,
|
|
KASToolBar, KASComboBox, uFilePanelSelect, uBriefFileView, VTEmuCtl, VTEmuPty,
|
|
uFileView, uFileSource, uFileViewNotebook, uFile, LCLVersion, KASToolPanel,
|
|
uOperationsManager, uFileSourceOperation, uDrivesList, DCClassesUtf8,
|
|
DCXmlConfig, uDrive, uDriveWatcher, uDCVersion, uMainCommands, uFormCommands,
|
|
uOperationsPanel, KASToolItems, uKASToolItemsExtended, uCmdLineParams, uOSForms
|
|
{$IF DEFINED(LCLQT)}
|
|
, Qt4, QtWidgets
|
|
{$ELSEIF DEFINED(LCLQT5)}
|
|
, Qt5, QtWidgets
|
|
{$ELSEIF DEFINED(LCLQT6)}
|
|
, Qt6, QtWidgets
|
|
{$ELSEIF DEFINED(LCLGTK2)}
|
|
, Glib2, Gtk2
|
|
{$ELSEIF DEFINED(DARWIN)}
|
|
, CocoaMenus
|
|
, uMyDarwin
|
|
{$ENDIF}
|
|
, Types, LMessages;
|
|
|
|
type
|
|
|
|
TForEachViewFunction = procedure (AFileView: TFileView; UserData: Pointer) of object;
|
|
|
|
{ TfrmMain }
|
|
|
|
TfrmMain = class(TAloneForm, IFormCommands)
|
|
actAddPlugin: TAction;
|
|
actMapNetworkDrive: TAction;
|
|
actShowTabsList: TAction;
|
|
actSaveFileDetailsToFile: TAction;
|
|
actLoadList: TAction;
|
|
actExtractFiles: TAction;
|
|
actAddPathToCmdLine: TAction;
|
|
actFileAssoc: TAction;
|
|
actFocusCmdLine: TAction;
|
|
actContextMenu: TAction;
|
|
actCopyNamesToClip: TAction;
|
|
actCopyFullNamesToClip: TAction;
|
|
actCutToClipboard: TAction;
|
|
actCopyToClipboard: TAction;
|
|
actSyncChangeDir: TAction;
|
|
actChangeDirToRoot: TAction;
|
|
actCountDirContent: TAction;
|
|
actCheckSumVerify: TAction;
|
|
actCheckSumCalc: TAction;
|
|
actClearLogFile: TAction;
|
|
actClearLogWindow: TAction;
|
|
actChangeDir: TAction;
|
|
actAddFilenameToCmdLine: TAction;
|
|
actAddPathAndFilenameToCmdLine: TAction;
|
|
actCopyNoAsk: TAction;
|
|
actChangeDirToParent: TAction;
|
|
actEditPath: TAction;
|
|
actHorizontalFilePanels: TAction;
|
|
actGoToFirstEntry: TAction;
|
|
actGoToLastEntry: TAction;
|
|
actGoToNextEntry: TAction;
|
|
actGoToPrevEntry: TAction;
|
|
actGoToFirstFile: TAction;
|
|
actGoToLastFile: TAction;
|
|
actCompareDirectories: TAction;
|
|
actCmdLineNext: TAction;
|
|
actCmdLinePrev: TAction;
|
|
actBriefView: TAction;
|
|
actColumnsView: TAction;
|
|
actChangeDirToHome: TAction;
|
|
actCopyFileDetailsToClip: TAction;
|
|
actFlatView: TAction;
|
|
actFlatViewSel: TAction;
|
|
actConfigDirHotList: TAction;
|
|
actCopyPathOfFilesToClip: TAction;
|
|
actCopyPathNoSepOfFilesToClip: TAction;
|
|
actDoAnyCmCommand: TAction;
|
|
actCloseDuplicateTabs: TAction;
|
|
actCopyAllTabsToOpposite: TAction;
|
|
actConfigTreeViewMenus: TAction;
|
|
actConfigTreeViewMenusColors: TAction;
|
|
actConfigSavePos: TAction;
|
|
actConfigSaveSettings: TAction;
|
|
actExecuteScript: TAction;
|
|
actFocusSwap: TAction;
|
|
actConfigArchivers: TAction;
|
|
actConfigTooltips: TAction;
|
|
actConfigPlugins: TAction;
|
|
actUnmarkCurrentNameExt: TAction;
|
|
actMarkCurrentNameExt: TAction;
|
|
actUnmarkCurrentName: TAction;
|
|
actMarkCurrentName: TAction;
|
|
actUnmarkCurrentPath: TAction;
|
|
actMarkCurrentPath: TAction;
|
|
actTreeView: TAction;
|
|
actFocusTreeView: TAction;
|
|
actToggleFullscreenConsole: TAction;
|
|
actSrcOpenDrives: TAction;
|
|
actRightReverseOrder: TAction;
|
|
actLeftReverseOrder: TAction;
|
|
actRightFlatView: TAction;
|
|
actLeftFlatView: TAction;
|
|
actRightSortByAttr: TAction;
|
|
actRightSortByDate: TAction;
|
|
actRightSortBySize: TAction;
|
|
actRightSortByExt: TAction;
|
|
actRightSortByName: TAction;
|
|
actLeftSortByAttr: TAction;
|
|
actLeftSortByDate: TAction;
|
|
actLeftSortBySize: TAction;
|
|
actLeftSortByExt: TAction;
|
|
actLeftSortByName: TAction;
|
|
actLeftThumbView: TAction;
|
|
actRightThumbView: TAction;
|
|
actRightColumnsView: TAction;
|
|
actLeftColumnsView: TAction;
|
|
actRightBriefView: TAction;
|
|
actLeftBriefView: TAction;
|
|
actWorkWithDirectoryHotlist: TAction;
|
|
actUniversalSingleDirectSort: TAction;
|
|
actViewLogFile: TAction;
|
|
actLoadTabs: TAction;
|
|
actSaveTabs: TAction;
|
|
actSyncDirs: TAction;
|
|
actThumbnailsView: TAction;
|
|
actShellExecute: TAction;
|
|
actRenameTab: TAction;
|
|
actOperationsViewer: TAction;
|
|
actCopyNetNamesToClip: TAction;
|
|
actNetworkDisconnect: TAction;
|
|
actNetworkQuickConnect: TAction;
|
|
actNetworkConnect: TAction;
|
|
actViewHistory: TAction;
|
|
actViewHistoryPrev: TAction;
|
|
actViewHistoryNext: TAction;
|
|
actLoadSelectionFromClip: TAction;
|
|
actLoadSelectionFromFile: TAction;
|
|
actSaveSelectionToFile: TAction;
|
|
actSaveSelection: TAction;
|
|
actRestoreSelection: TAction;
|
|
actSwitchIgnoreList: TAction;
|
|
actTestArchive: TAction;
|
|
actQuickView: TAction;
|
|
actOpenBar: TAction;
|
|
actSetFileProperties: TAction;
|
|
actQuickFilter: TAction;
|
|
actRenameNoAsk: TAction;
|
|
actPanelsSplitterPerPos: TAction;
|
|
actMinimize: TAction;
|
|
actRightEqualLeft: TAction;
|
|
actLeftEqualRight: TAction;
|
|
actPasteFromClipboard: TAction;
|
|
actExchange: TAction;
|
|
actEditComment: TAction;
|
|
actHelpIndex: TAction;
|
|
actVisitHomePage: TAction;
|
|
actKeyboard: TAction;
|
|
actPrevTab: TAction;
|
|
actNextTab: TAction;
|
|
actMoveTabLeft: TAction;
|
|
actMoveTabRight: TAction;
|
|
actActivateTabByIndex: TAction;
|
|
actCloseAllTabs: TAction;
|
|
actSetTabOptionNormal: TAction;
|
|
actSetTabOptionPathLocked: TAction;
|
|
actSetTabOptionPathResets: TAction;
|
|
actSetTabOptionDirsInNewTab: TAction;
|
|
actUnmarkCurrentExtension: TAction;
|
|
actMarkCurrentExtension: TAction;
|
|
actWipe: TAction;
|
|
actOpenDirInNewTab: TAction;
|
|
actTargetEqualSource: TAction;
|
|
actOpen: TAction;
|
|
actQuickSearch: TAction;
|
|
actShowButtonMenu: TAction;
|
|
actOpenArchive: TAction;
|
|
actTransferRight: TAction;
|
|
actTransferLeft: TAction;
|
|
actRightOpenDrives: TAction;
|
|
actLeftOpenDrives: TAction;
|
|
actOpenVirtualFileSystemList: TAction;
|
|
actPackFiles: TAction;
|
|
actCloseTab: TAction;
|
|
actNewTab: TAction;
|
|
actConfigToolbars: TAction;
|
|
actDebugShowCommandParameters: TAction;
|
|
actOpenDriveByIndex: TAction;
|
|
btnF10: TSpeedButton;
|
|
btnF3: TSpeedButton;
|
|
btnF4: TSpeedButton;
|
|
btnF5: TSpeedButton;
|
|
btnF6: TSpeedButton;
|
|
btnF7: TSpeedButton;
|
|
btnF8: TSpeedButton;
|
|
btnF9: TSpeedButton;
|
|
btnLeftDirectoryHotlist: TSpeedButton;
|
|
btnRightDirectoryHotlist: TSpeedButton;
|
|
dskLeft: TKASToolBar;
|
|
dskRight: TKASToolBar;
|
|
edtCommand: TComboBoxWithDelItems;
|
|
imgLstActions: TImageList;
|
|
imgLstDirectoryHotlist: TImageList;
|
|
lblRightDriveInfo: TLabel;
|
|
lblLeftDriveInfo: TLabel;
|
|
lblCommandPath: TLabel;
|
|
mnuDoAnyCmCommand: TMenuItem;
|
|
miConfigArchivers: TMenuItem;
|
|
mnuConfigSavePos: TMenuItem;
|
|
mnuConfigSaveSettings: TMenuItem;
|
|
miLine55: TMenuItem;
|
|
mnuConfigureFavoriteTabs: TMenuItem;
|
|
mnuRewriteFavoriteTabs: TMenuItem;
|
|
mnuCreateNewFavoriteTabs: TMenuItem;
|
|
mnuReloadActiveFavoriteTabs: TMenuItem;
|
|
mnuFavoriteTabs: TMenuItem;
|
|
mnuCloseDuplicateTabs: TMenuItem;
|
|
miCloseDuplicateTabs: TMenuItem;
|
|
mnuTreeView: TMenuItem;
|
|
mnuCmdConfigDirHotlist: TMenuItem;
|
|
mnuLoadTabs: TMenuItem;
|
|
mnuSaveTabs: TMenuItem;
|
|
miLine38: TMenuItem;
|
|
miFlatView: TMenuItem;
|
|
miMakeDir: TMenuItem;
|
|
miWipe: TMenuItem;
|
|
miDelete: TMenuItem;
|
|
miLine50: TMenuItem;
|
|
miCopyFileDetailsToClip: TMenuItem;
|
|
mnuCmdSyncDirs: TMenuItem;
|
|
mnuContextRenameOnly: TMenuItem;
|
|
mnuContextCopy: TMenuItem;
|
|
mnuContextOpen: TMenuItem;
|
|
mnuContextLine1: TMenuItem;
|
|
mnuContextLine2: TMenuItem;
|
|
mnuContextFileProperties: TMenuItem;
|
|
mnuContextDelete: TMenuItem;
|
|
mnuContextView: TMenuItem;
|
|
mnuThumbnailsView: TMenuItem;
|
|
mnuColumnsView: TMenuItem;
|
|
mnuBriefView: TMenuItem;
|
|
miLine33: TMenuItem;
|
|
mnuAllOperStart: TMenuItem;
|
|
mnuAllOperStop: TMenuItem;
|
|
mnuAllOperPause: TMenuItem;
|
|
mnuAllOperProgress: TMenuItem;
|
|
miCompareDirectories: TMenuItem;
|
|
miLine37: TMenuItem;
|
|
miRenameTab: TMenuItem;
|
|
pnlMain: TPanel;
|
|
tbChangeDir: TMenuItem;
|
|
mnuShowHorizontalFilePanels: TMenuItem;
|
|
miLine20: TMenuItem;
|
|
miNetworkDisconnect: TMenuItem;
|
|
miNetworkQuickConnect: TMenuItem;
|
|
miNetworkConnect: TMenuItem;
|
|
mnuNetwork: TMenuItem;
|
|
pnlDskLeft: TPanel;
|
|
pnlDiskLeftInner: TKASToolPanel;
|
|
pnlDskRight: TPanel;
|
|
pnlDiskRightInner: TKASToolPanel;
|
|
Timer: TTimer;
|
|
PanelAllProgress: TPanel;
|
|
pbxRightDrive: TPaintBox;
|
|
pbxLeftDrive: TPaintBox;
|
|
tbPaste: TMenuItem;
|
|
tbCopy: TMenuItem;
|
|
tbCut: TMenuItem;
|
|
tbSeparator: TMenuItem;
|
|
mnuLoadSelectionFromClip: TMenuItem;
|
|
mnuLoadSelectionFromFile: TMenuItem;
|
|
mnuSaveSelectionToFile: TMenuItem;
|
|
mnuRestoreSelection: TMenuItem;
|
|
mnuSaveSelection: TMenuItem;
|
|
miLine47: TMenuItem;
|
|
mnuTestArchive: TMenuItem;
|
|
mnuQuickView: TMenuItem;
|
|
miLine32: TMenuItem;
|
|
miLine14: TMenuItem;
|
|
mnuTabOptionNormal: TMenuItem;
|
|
mnuTabOptionDirsInNewTabs: TMenuItem;
|
|
mnuTabOptions: TMenuItem;
|
|
miTabOptionPathResets: TMenuItem;
|
|
miTabOptionDirsInNewTab: TMenuItem;
|
|
miTabOptionPathLocked: TMenuItem;
|
|
miTabOptionNormal: TMenuItem;
|
|
miTabOptions: TMenuItem;
|
|
miLine19: TMenuItem;
|
|
mnuSetFileProperties: TMenuItem;
|
|
mnuShowOperations: TMenuItem;
|
|
miLine13: TMenuItem;
|
|
miLogClear: TMenuItem;
|
|
miLogHide: TMenuItem;
|
|
miLine25: TMenuItem;
|
|
miLogSelectAll: TMenuItem;
|
|
miLogCopy: TMenuItem;
|
|
miLine24: TMenuItem;
|
|
miTrayIconRestore: TMenuItem;
|
|
miLine8: TMenuItem;
|
|
miTrayIconExit: TMenuItem;
|
|
mnuCheckSumCalc: TMenuItem;
|
|
mnuCheckSumVerify: TMenuItem;
|
|
mnuCountDirContent: TMenuItem;
|
|
miLine22: TMenuItem;
|
|
miLine18: TMenuItem;
|
|
mnuHelpIndex: TMenuItem;
|
|
mnuHelpVisitHomePage: TMenuItem;
|
|
mnuHelpKeyboard: TMenuItem;
|
|
MenuItem2: TMenuItem;
|
|
mnuPrevTab: TMenuItem;
|
|
mnuNextTab: TMenuItem;
|
|
miLine17: TMenuItem;
|
|
miLine16: TMenuItem;
|
|
mnuTabOptionPathLocked: TMenuItem;
|
|
mnuTabOptionPathResets: TMenuItem;
|
|
mnuCloseAllTabs: TMenuItem;
|
|
mnuCloseTab: TMenuItem;
|
|
miLine15: TMenuItem;
|
|
mnuOpenDirInNewTab: TMenuItem;
|
|
mnuNewTab: TMenuItem;
|
|
miCloseAllTabs: TMenuItem;
|
|
miCloseTab: TMenuItem;
|
|
miNewTab: TMenuItem;
|
|
miEditComment: TMenuItem;
|
|
mnuMarkCurrentExtension: TMenuItem;
|
|
mnuTabs: TMenuItem;
|
|
mnuUnmarkCurrentExtension: TMenuItem;
|
|
miSymLink: TMenuItem;
|
|
miHardLink: TMenuItem;
|
|
miCancel: TMenuItem;
|
|
miLine12: TMenuItem;
|
|
miCopy: TMenuItem;
|
|
miMove: TMenuItem;
|
|
mi8020: TMenuItem;
|
|
mi7030: TMenuItem;
|
|
mi6040: TMenuItem;
|
|
mi5050: TMenuItem;
|
|
mi4060: TMenuItem;
|
|
mi3070: TMenuItem;
|
|
mi2080: TMenuItem;
|
|
miCopyFullNamesToClip: TMenuItem;
|
|
miCopyNamesToClip: TMenuItem;
|
|
mnuFileAssoc: TMenuItem;
|
|
nbConsole: TPageControl;
|
|
pgConsole: TTabSheet;
|
|
pnlCmdLine: TPanel;
|
|
MainSplitter: TPanel;
|
|
MainToolBar: TKASToolBar;
|
|
MiddleToolBar: TKASToolBar;
|
|
mnuOpenVFSList: TMenuItem;
|
|
mnuExtractFiles: TMenuItem;
|
|
pmContextMenu: TPopupMenu;
|
|
pmSplitterPercent: TPopupMenu;
|
|
pnlCommand: TPanel;
|
|
pnlKeys: TPanel;
|
|
pnlLeftTools: TPanel;
|
|
pnlRightTools: TPanel;
|
|
pnlRight: TPanel;
|
|
pnlLeft: TPanel;
|
|
btnLeftDrive: TSpeedButton;
|
|
btnLeftHome: TSpeedButton;
|
|
btnLeftUp: TSpeedButton;
|
|
btnLeftRoot: TSpeedButton;
|
|
btnRightDrive: TSpeedButton;
|
|
btnRightHome: TSpeedButton;
|
|
btnRightUp: TSpeedButton;
|
|
btnRightRoot: TSpeedButton;
|
|
LogSplitter: TSplitter;
|
|
pmColumnsMenu: TPopupMenu;
|
|
pmDropMenu: TPopupMenu;
|
|
pmTabMenu: TPopupMenu;
|
|
pmTrayIconMenu: TPopupMenu;
|
|
pmLogMenu: TPopupMenu;
|
|
seLogWindow: TSynEdit;
|
|
btnRightEqualLeft: TSpeedButton;
|
|
btnLeftEqualRight: TSpeedButton;
|
|
ConsoleSplitter: TSplitter;
|
|
tbDelete: TMenuItem;
|
|
tbEdit: TMenuItem;
|
|
mnuMain: TMainMenu;
|
|
pnlNotebooks: TPanel;
|
|
pnlDisk: TKASToolPanel;
|
|
mnuHelp: TMenuItem;
|
|
mnuHelpAbout: TMenuItem;
|
|
mnuShow: TMenuItem;
|
|
mnuShowName: TMenuItem;
|
|
mnuShowExtension: TMenuItem;
|
|
mnuShowTime: TMenuItem;
|
|
mnuShowSize: TMenuItem;
|
|
mnuShowAttrib: TMenuItem;
|
|
miLine7: TMenuItem;
|
|
mnuShowReverse: TMenuItem;
|
|
mnuShowReread: TMenuItem;
|
|
mnuFiles: TMenuItem;
|
|
mnuPackFiles : TMenuItem;
|
|
mnuFilesSplit: TMenuItem;
|
|
mnuFilesCombine: TMenuItem;
|
|
mnuCmd: TMenuItem;
|
|
mnuCmdDirHotlist: TMenuItem;
|
|
miLine2: TMenuItem;
|
|
mnuFilesSpace: TMenuItem;
|
|
mnuFilesAttrib: TMenuItem;
|
|
mnuFilesProperties: TMenuItem;
|
|
miLine6: TMenuItem;
|
|
mnuCmdSwapSourceTarget: TMenuItem;
|
|
mnuCmdTargetIsSource: TMenuItem;
|
|
miLine3: TMenuItem;
|
|
mnuFilesShwSysFiles: TMenuItem;
|
|
miLine1: TMenuItem;
|
|
mnuFilesHardLink: TMenuItem;
|
|
mnuFilesSymLink: TMenuItem;
|
|
mnuConfig: TMenuItem;
|
|
mnuConfigOptions: TMenuItem;
|
|
mnuMark: TMenuItem;
|
|
mnuMarkSGroup: TMenuItem;
|
|
mnuMarkUGroup: TMenuItem;
|
|
mnuMarkSAll: TMenuItem;
|
|
mnuMarkUAll: TMenuItem;
|
|
mnuMarkInvert: TMenuItem;
|
|
miLine5: TMenuItem;
|
|
mnuCmdSearch: TMenuItem;
|
|
mnuCmdAddNewSearch:TMenuItem;
|
|
mnuCmdViewSearches:TMenuItem;
|
|
actionLst: TActionList;
|
|
actExit: TAction;
|
|
actView: TAction;
|
|
actEdit: TAction;
|
|
actCopy: TAction;
|
|
actRename: TAction;
|
|
actMakeDir: TAction;
|
|
actDelete: TAction;
|
|
actAbout: TAction;
|
|
actShowSysFiles: TAction;
|
|
actOptions: TAction;
|
|
mnuFilesCmpCnt: TMenuItem;
|
|
actCompareContents: TAction;
|
|
actShowMainMenu: TAction;
|
|
actRefresh: TAction;
|
|
actSearch: TAction;
|
|
actAddNewSearch: TAction;
|
|
actViewSearches: TAction;
|
|
actDeleteSearches: TAction;
|
|
actConfigSearches: TAction;
|
|
actConfigHotKeys: TAction;
|
|
actDirHotList: TAction;
|
|
actMarkMarkAll: TAction;
|
|
actMarkInvert: TAction;
|
|
actMarkUnmarkAll: TAction;
|
|
pmHotList: TPopupMenu;
|
|
actMarkPlus: TAction;
|
|
actMarkMinus: TAction;
|
|
actSymLink: TAction;
|
|
actHardLink: TAction;
|
|
actReverseOrder: TAction;
|
|
actSortByName: TAction;
|
|
actSortByExt: TAction;
|
|
actSortBySize: TAction;
|
|
actSortByDate: TAction;
|
|
actSortByAttr: TAction;
|
|
miLine4: TMenuItem;
|
|
miExit: TMenuItem;
|
|
actMultiRename: TAction;
|
|
miMultiRename: TMenuItem;
|
|
actCopySamePanel: TAction;
|
|
actRenameOnly: TAction;
|
|
actEditNew: TAction;
|
|
actDirHistory: TAction;
|
|
pmDirHistory: TPopupMenu;
|
|
actShowCmdLineHistory: TAction;
|
|
actRunTerm: TAction;
|
|
miLine9: TMenuItem;
|
|
miRunTerm: TMenuItem;
|
|
actBenchmark: TAction;
|
|
actCalculateSpace: TAction;
|
|
actFileProperties: TAction;
|
|
actFileLinker: TAction;
|
|
actFileSpliter: TAction;
|
|
pmToolBar: TPopupMenu;
|
|
MainTrayIcon: TTrayIcon;
|
|
TreePanel: TPanel;
|
|
TreeSplitter: TSplitter;
|
|
ShellTreeView: TCustomTreeView;
|
|
miLine10: TMenuItem;
|
|
miLine11: TMenuItem;
|
|
miLine21: TMenuItem;
|
|
miLine23: TMenuItem;
|
|
miLine26: TMenuItem;
|
|
miLine39: TMenuItem;
|
|
miLine40: TMenuItem;
|
|
actSetAllTabsOptionNormal: TAction;
|
|
actSetAllTabsOptionPathLocked: TAction;
|
|
actSetAllTabsOptionPathResets: TAction;
|
|
actSetAllTabsOptionDirsInNewTab: TAction;
|
|
actConfigFolderTabs: TAction;
|
|
actLoadFavoriteTabs: TAction;
|
|
actConfigFavoriteTabs: TAction;
|
|
actSaveFavoriteTabs: TAction;
|
|
actReloadFavoriteTabs: TAction;
|
|
actNextFavoriteTabs: TAction;
|
|
actPreviousFavoriteTabs: TAction;
|
|
pmFavoriteTabs: TPopupMenu;
|
|
mnuRenameTab: TMenuItem;
|
|
mnuConfigFolderTabs: TMenuItem;
|
|
mnuConfigFavoriteTabs: TMenuItem;
|
|
mnuConfigurationFavoriteTabs: TMenuItem;
|
|
mnuSaveFavoriteTabs: TMenuItem;
|
|
mnuLoadFavoriteTabs: TMenuItem;
|
|
mnuConfigurationFolderTabs: TMenuItem;
|
|
mnuSetAllTabsOptionNormal: TMenuItem;
|
|
mnuSetAllTabsOptionPathLocked: TMenuItem;
|
|
mnuSetAllTabsOptionPathResets: TMenuItem;
|
|
mnuSetAllTabsOptionDirsInNewTab: TMenuItem;
|
|
miConfigFolderTabs: TMenuItem;
|
|
miConfigFavoriteTabs: TMenuItem;
|
|
miNextTab: TMenuItem;
|
|
miPrevTab: TMenuItem;
|
|
miSaveTabs: TMenuItem;
|
|
miLoadTabs: TMenuItem;
|
|
miSaveFavoriteTabs: TMenuItem;
|
|
miLoadFavoriteTabs: TMenuItem;
|
|
miSetAllTabsOptionNormal: TMenuItem;
|
|
miSetAllTabsOptionPathLocked: TMenuItem;
|
|
miSetAllTabsOptionPathResets: TMenuItem;
|
|
miSetAllTabsOptionDirsInNewTab: TMenuItem;
|
|
miOpenDirInNewTab: TMenuItem;
|
|
actResaveFavoriteTabs: TAction;
|
|
procedure actExecute(Sender: TObject);
|
|
procedure btnF3MouseWheelDown(Sender: TObject; Shift: TShiftState;
|
|
{%H-}MousePos: TPoint; var {%H-}Handled: Boolean);
|
|
procedure btnF3MouseWheelUp(Sender: TObject; Shift: TShiftState;
|
|
{%H-}MousePos: TPoint; var {%H-}Handled: Boolean);
|
|
procedure btnF8MouseDown(Sender: TObject; Button: TMouseButton;
|
|
{%H-}Shift: TShiftState; X, Y: Integer);
|
|
procedure ConsoleSplitterMoved(Sender: TObject);
|
|
procedure dskToolButtonMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure FormKeyUp( Sender: TObject; var {%H-}Key: Word; Shift: TShiftState) ;
|
|
procedure FormResize(Sender: TObject);
|
|
procedure lblDriveInfoResize(Sender: TObject);
|
|
function MainToolBarToolItemShortcutsHint(Sender: TObject; ToolItem: TKASNormalItem): String;
|
|
procedure mnuAllOperStartClick(Sender: TObject);
|
|
procedure mnuAllOperStopClick(Sender: TObject);
|
|
procedure mnuAllOperPauseClick(Sender: TObject);
|
|
procedure mnuAllOperProgressClick(Sender: TObject);
|
|
procedure btnF8Click(Sender: TObject);
|
|
procedure btnLeftClick(Sender: TObject);
|
|
procedure btnLeftDirectoryHotlistClick(Sender: TObject);
|
|
procedure btnRightClick(Sender: TObject);
|
|
procedure btnRightDirectoryHotlistClick(Sender: TObject);
|
|
procedure btnDriveMouseUp(Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer);
|
|
procedure ConsoleSplitterCanResize(Sender: TObject; var NewSize: Integer;
|
|
var {%H-}Accept: Boolean);
|
|
procedure dskLeftRightToolButtonDragDrop(Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: Integer);
|
|
procedure dskToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
procedure lblAllProgressPctClick(Sender: TObject);
|
|
procedure MainToolBarToolButtonDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
procedure MainToolBarToolButtonDragOver(Sender, Source: TObject; X,
|
|
Y: Integer; State: TDragState; var Accept: Boolean;
|
|
NumberOfButton: Integer);
|
|
procedure MainToolBarToolButtonMouseDown(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
procedure MainToolBarToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
|
|
procedure miLogMenuClick(Sender: TObject);
|
|
procedure miTrayIconExitClick(Sender: TObject);
|
|
procedure miTrayIconRestoreClick(Sender: TObject);
|
|
procedure PanelButtonClick(Button: TSpeedButton; FileView: TFileView);
|
|
procedure pnlDiskResize(Sender: TObject);
|
|
procedure ShellTreeViewSelect;
|
|
procedure ShellTreeViewKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure ShellTreeViewMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure tbDeleteClick(Sender: TObject);
|
|
procedure dskLeftToolButtonClick(Sender: TObject);
|
|
procedure dskRightToolButtonClick(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
|
|
procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
|
|
procedure FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
|
|
procedure FormWindowStateChange(Sender: TObject);
|
|
procedure MainSplitterDblClick(Sender: TObject);
|
|
procedure MainSplitterMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure MainSplitterMouseMove(Sender: TObject; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
procedure MainSplitterMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure MainTrayIconClick(Sender: TObject);
|
|
procedure lblDriveInfoDblClick(Sender: TObject);
|
|
procedure MainToolBarDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
procedure MainToolBarDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
function MainToolBarLoadButtonGlyph(ToolItem: TKASToolItem;
|
|
iIconSize: Integer; clBackColor: TColor): TBitmap;
|
|
function MainToolBarLoadButtonOverlay(ToolItem: TKASToolItem;
|
|
iIconSize: Integer; clBackColor: TColor): TBitmap;
|
|
procedure MainToolBarMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure frmMainClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
procedure frmMainAfterShow(Sender: TObject);
|
|
procedure frmMainShow(Sender: TObject);
|
|
procedure mnuDropClick(Sender: TObject);
|
|
procedure mnuSplitterPercentClick(Sender: TObject);
|
|
procedure mnuTabMenuExecute(Sender: TObject);
|
|
procedure mnuTabMenuClick(Sender: TObject);
|
|
procedure nbPageAfterMouseDown(Data: PtrInt);
|
|
procedure nbPageMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure nbPageChanged(Sender: TObject);
|
|
procedure nbPageMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure NotebookDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
procedure NotebookDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
procedure NotebookCloseTabClicked(Sender: TObject);
|
|
procedure pmDropMenuClose(Sender: TObject);
|
|
procedure FormKeyPress(Sender: TObject; var Key: Char);
|
|
procedure edtCommandKeyUp(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
|
|
procedure FormKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure pmToolBarPopup(Sender: TObject);
|
|
|
|
procedure ShellTreeViewAdvancedCustomDrawItem(Sender: TCustomTreeView;
|
|
Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;
|
|
var PaintImages, DefaultDraw: Boolean);
|
|
|
|
procedure pnlLeftResize(Sender: TObject);
|
|
procedure pnlLeftRightDblClick(Sender: TObject);
|
|
procedure pnlNotebooksResize(Sender: TObject);
|
|
procedure pnlRightResize(Sender: TObject);
|
|
procedure sboxDrivePaint(Sender: TObject);
|
|
procedure PaintDriveFreeBar(Sender: TObject; const bIndUseGradient: boolean;
|
|
const pIndForeColor, pIndThresholdForeColor, pIndBackColor: TColor);
|
|
procedure seLogWindowSpecialLineColors(Sender: TObject; Line: integer;
|
|
var Special: boolean; var FG, BG: TColor);
|
|
|
|
procedure FileViewFreeAsync(Data: PtrInt);
|
|
function FileViewAutoSwitch(FileSource: IFileSource; var FileView: TFileView; Reason: TChangePathReason; const NewPath: String): Boolean;
|
|
function FileViewBeforeChangePath(FileView: TFileView; NewFileSource: IFileSource; Reason: TChangePathReason; const NewPath : String): Boolean;
|
|
procedure FileViewAfterChangePath(FileView: TFileView);
|
|
procedure FileViewActivate(FileView: TFileView);
|
|
procedure FileViewFilesChanged(FileView: TFileView);
|
|
procedure edtCommandKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure edtCommandExit(Sender: TObject);
|
|
procedure tbChangeDirClick(Sender: TObject);
|
|
procedure tbCopyClick(Sender: TObject);
|
|
procedure tbEditClick(Sender: TObject);
|
|
procedure OnUniqueInstanceMessage(Sender: TObject; Params: TCommandLineParams);
|
|
procedure tbPasteClick(Sender: TObject);
|
|
procedure AllProgressOnUpdateTimer(Sender: TObject);
|
|
procedure OperationManagerNotify(Item: TOperationsManagerItem;
|
|
Event: TOperationManagerEvent);
|
|
{$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)}
|
|
private
|
|
QEventHook: QObject_hookH;
|
|
function QObjectEventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
|
|
{$ENDIF}
|
|
{$IF DEFINED(LCLGTK2)}
|
|
procedure WindowStateUpdate(Data: PtrInt);
|
|
{$ENDIF}
|
|
private
|
|
{ Private declarations }
|
|
FMainSplitterPos: Double;
|
|
PanelSelected: TFilePanelSelect;
|
|
DrivesList : TDrivesList;
|
|
MainSplitterHintWnd: THintWindow;
|
|
HiddenToTray: Boolean;
|
|
HidingTrayIcon: Boolean; // @true if the icon is in the process of hiding
|
|
nbLeft, nbRight: TFileViewNotebook;
|
|
cmdConsole: TVirtualTerminal;
|
|
FCommands: TMainCommands;
|
|
FInitializedView: Boolean;
|
|
{en
|
|
Used to pass drag&drop parameters to pmDropMenu. Single variable
|
|
can be used, because the user can do only one menu popup at a time. }
|
|
FDropParams: TDropParams;
|
|
FDrivesListPopup: TDrivesListPopup;
|
|
FOperationsPanel: TOperationsPanel;
|
|
FSyncChangeParent: Boolean;
|
|
FSyncChangeDir: String;
|
|
sStaticTitleBarString: String;
|
|
|
|
// frost_asm begin
|
|
// mainsplitter
|
|
MainSplitterLeftMouseBtnDown: Boolean;
|
|
MainSplitterMouseDownX, MainSplitterMouseDownY: Integer;
|
|
FResizingFilePanels: Boolean;
|
|
// lastWindowState
|
|
lastWindowState:TWindowState;
|
|
// frost_asm end
|
|
// for dragging buttons and etc
|
|
NumberOfMoveButton, NumberOfNewMoveButton: integer;
|
|
Draging : boolean;
|
|
FUpdateDiskCount: Boolean;
|
|
FModalOperationResult: Boolean;
|
|
|
|
FRestoredLeft: Integer;
|
|
FRestoredTop: Integer;
|
|
FRestoredWidth: Integer;
|
|
FRestoredHeight: Integer;
|
|
FDelayedEventCtr: Integer;
|
|
FDelayedWMMove, FDelayedWMSize: Boolean;
|
|
|
|
procedure DelayedEvent(Data: PtrInt);
|
|
|
|
procedure CheckCommandLine(ShiftEx: TShiftState; var Key: Word);
|
|
function ExecuteCommandFromEdit(sCmd: String; bRunInTerm: Boolean): Boolean;
|
|
procedure SetMainSplitterPos(AValue: Double);
|
|
procedure SetPanelSelected(AValue: TFilePanelSelect);
|
|
procedure UpdateActionIcons;
|
|
procedure UpdateHotDirIcons;
|
|
procedure TypeInCommandLine(Str: String);
|
|
procedure AddSpecialButtons(dskPanel: TKASToolBar);
|
|
procedure HideToTray;
|
|
procedure RestoreFromTray;
|
|
procedure ShowTrayIcon(bShow: Boolean);
|
|
procedure HideTrayIconDelayed(Data: PtrInt);
|
|
|
|
procedure PopupDragDropMenu(var DropParams: TDropParams);
|
|
procedure CloseNotebook(ANotebook: TFileViewNotebook);
|
|
|
|
procedure DriveListDriveSelected(Sender: TObject; ADriveIndex: Integer;
|
|
APanel: TFilePanelSelect);
|
|
procedure DriveListClose(Sender: TObject);
|
|
function FindMatchingDrive(Address, Path: String): Integer;
|
|
procedure UpdateDriveToolbarSelection(DriveToolbar: TKAStoolBar; FileView: TFileView);
|
|
procedure UpdateDriveButtonSelection(DriveButton: TSpeedButton; FileView: TFileView);
|
|
procedure UpdateSelectedDrive(ANoteBook: TFileViewNotebook);
|
|
{$IF DEFINED(MSWINDOWS)}
|
|
procedure OnDriveIconLoaded(Data: PtrInt);
|
|
{$ENDIF}
|
|
procedure OnDriveGetFreeSpace(Data: PtrInt);
|
|
procedure OnDriveWatcherEvent(EventType: TDriveWatcherEvent; const ADrive: PDrive);
|
|
procedure AppActivate(Sender: TObject);
|
|
procedure AppDeActivate(Sender: TObject);
|
|
procedure AppEndSession(Sender: TObject);
|
|
procedure AppThemeChange(Sender: TObject);
|
|
procedure AppQueryEndSession(var Cancel: Boolean);
|
|
procedure AppException(Sender: TObject; E: Exception);
|
|
procedure AppShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo);
|
|
{en
|
|
Convert toolbar configuration from .bar file to global config.
|
|
}
|
|
procedure ConvertToolbarBarConfig(BarFileName: String);
|
|
procedure ConvertIniToolbarItem(Loader: TKASToolBarIniLoader; var Item: TKASToolItem; const Shortcut: String);
|
|
procedure CreateDefaultToolbar;
|
|
procedure EditToolbarButton(Toolbar: TKASToolBar; Button: TKASToolButton);
|
|
procedure ToolbarExecuteCommand(ToolItem: TKASToolItem);
|
|
procedure ToolbarExecuteProgram(ToolItem: TKASToolItem);
|
|
procedure LeftDriveBarExecuteDrive(ToolItem: TKASToolItem);
|
|
procedure RightDriveBarExecuteDrive(ToolItem: TKASToolItem);
|
|
procedure SetDragCursor(Shift: TShiftState);
|
|
{$IFDEF DARWIN}
|
|
procedure GlobalMacOSKeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure OpenNewWindow(Sender: TObject);
|
|
{$ENDIF}
|
|
|
|
protected
|
|
procedure CreateWnd; override;
|
|
procedure DoFirstShow; override;
|
|
procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
|
|
const AXProportion, AYProportion: Double); override;
|
|
|
|
procedure WMMove(var Message: TLMMove); message LM_MOVE;
|
|
procedure WMSize(var message: TLMSize); message LM_Size;
|
|
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
procedure AfterConstruction; override;
|
|
Function ActiveFrame: TFileView; // get Active frame
|
|
Function NotActiveFrame: TFileView; // get NotActive frame :)
|
|
function ActiveNotebook: TFileViewNotebook;
|
|
function NotActiveNotebook: TFileViewNotebook;
|
|
function FrameLeft: TFileView;
|
|
function FrameRight: TFileView;
|
|
procedure ForEachView(CallbackFunction: TForEachViewFunction; UserData: Pointer);
|
|
procedure GetListOpenedPaths(const APaths:TStringList);
|
|
//check selected count and generate correct msg, parameters is lng indexs
|
|
Function GetFileDlgStr(sLngOne, sLngMulti : String; Files: TFiles):String;
|
|
procedure HotDirSelected(Sender:TObject);
|
|
procedure HotDirActualSwitchToDir(Index:longint);
|
|
procedure HistorySelected(Sender:TObject);
|
|
procedure HistorySomeSelected(Sender:TObject);
|
|
procedure ViewHistorySelected(Sender:TObject);
|
|
procedure ViewHistoryPrevSelected(Sender:TObject);
|
|
procedure ViewHistoryNextSelected(Sender:TObject);
|
|
procedure CreatePopUpDirHistory(UseTreeViewMenu: Boolean; FromPathIndex: Integer);
|
|
procedure ShowFileViewHistory(const Params: array of string);
|
|
procedure ShowFileViewHistory(const Params: array of string; FromFileSourceIndex, FromPathIndex, ToFileSourceIndex, ToPathIndex: Integer);
|
|
procedure miHotAddOrConfigClick(Sender: TObject);
|
|
procedure OnCopyOutTempStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState);
|
|
|
|
{en
|
|
Returns @true if copy operation has been successfully started.
|
|
}
|
|
function CopyFiles(SourceFileSource, TargetFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String;
|
|
bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload;
|
|
{en
|
|
Returns @true if move operation has been successfully started.
|
|
}
|
|
function MoveFiles(SourceFileSource, TargetFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String;
|
|
bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload;
|
|
function CopyFiles(sDestPath: String; bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload; // this is for F5 and Shift+F5
|
|
function MoveFiles(sDestPath: String; bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload;
|
|
procedure GetDestinationPathAndMask(SourceFiles: TFiles;
|
|
TargetFileSource: IFileSource;
|
|
EnteredPath: String; BaseDir: String;
|
|
out DestPath, DestMask: String); overload;
|
|
procedure GetDestinationPathAndMask(SourceFiles: TFiles;
|
|
SourceFileSource: IFileSource;
|
|
var TargetFileSource: IFileSource;
|
|
EnteredPath: String; BaseDir: String;
|
|
out DestPath, DestMask: String); overload;
|
|
procedure SetActiveFrame(panel: TFilePanelSelect);
|
|
procedure SetActiveFrame(FileView: TFileView);
|
|
procedure UpdateFileView;
|
|
procedure UpdateShellTreeView;
|
|
procedure UpdateTreeViewPath;
|
|
procedure UpdateTreeView;
|
|
procedure UpdateDiskCount;
|
|
procedure UpdateSelectedDrives;
|
|
procedure UpdateGUIFunctionKeys;
|
|
procedure UpdateMainTitleBar;
|
|
procedure CreateDiskPanel(dskPanel : TKASToolBar);
|
|
procedure SetPanelDrive(aPanel: TFilePanelSelect; Drive: PDrive; ActivateIfNeeded: Boolean);
|
|
function CreateFileView(sType: String; Page: TFileViewPage; AConfig: TXmlConfig; ANode: TXmlNode): TFileView;
|
|
procedure AssignEvents(AFileView: TFileView);
|
|
function RemovePage(ANoteBook: TFileViewNotebook; iPageIndex:Integer; CloseLocked: Boolean = True; ConfirmCloseLocked: integer = 0; ShowButtonAll: Boolean = False): LongInt;
|
|
procedure LoadTabsXml(AConfig: TXmlConfig; ABranch:string; ANoteBook: TFileViewNotebook);
|
|
procedure SaveTabsXml(AConfig: TXmlConfig; ABranch:string; ANoteBook: TFileViewNotebook; ASaveHistory: boolean);
|
|
procedure LoadTheseTabsWithThisConfig(Config: TXmlConfig; ABranch:string; Source, Destination:TTabsConfigLocation; DestinationToKeep : TTabsConfigLocation; var TabsAlreadyDestroyedFlags:TTabsFlagsAlreadyDestroyed);
|
|
procedure ToggleConsole;
|
|
procedure UpdateWindowView;
|
|
procedure MinimizeWindow;
|
|
procedure RestoreWindow;
|
|
procedure LoadTabs;
|
|
procedure LoadTabsCommandLine(Params: TCommandLineParams);
|
|
procedure AddTab(ANoteBook: TFileViewNotebook; aPath: String);
|
|
{$IF DEFINED(DARWIN)}
|
|
procedure OnNSServiceOpenWithNewTab( filenames:TStringList );
|
|
function NSServiceMenuIsReady(): boolean;
|
|
function NSServiceMenuGetFilenames(): TStringList;
|
|
procedure NSThemeChangedHandler();
|
|
{$ENDIF}
|
|
procedure LoadWindowState;
|
|
procedure SaveWindowState;
|
|
|
|
procedure LoadToolbar(AToolBar: TKASToolBar);
|
|
procedure SaveToolBar(AToolBar: TKASToolBar);
|
|
|
|
procedure ShowLogWindow(Data: PtrInt);
|
|
function IsCommandLineVisible: Boolean;
|
|
procedure ShowCommandLine(AFocus: Boolean);
|
|
procedure ConfigSaveSettings(bForce: Boolean);
|
|
procedure ShowDrivesList(APanel: TFilePanelSelect);
|
|
procedure ExecuteCommandLine(bRunInTerm: Boolean);
|
|
procedure UpdatePrompt;
|
|
procedure UpdateFreeSpace(Panel: TFilePanelSelect; Clear: Boolean);
|
|
procedure ReLoadTabs(ANoteBook: TFileViewNotebook);
|
|
procedure ShowOptionsLayout(Data: PtrInt);
|
|
procedure ToggleFullscreenConsole;
|
|
|
|
{en
|
|
This function is called from various points to handle dropping files
|
|
into the panel. It converts drop effects available on the system
|
|
into TDragDropOperation operations.
|
|
Handles freeing DropParams. }
|
|
procedure DropFiles(var DropParams: TDropParams);
|
|
|
|
{en
|
|
Performs all drag&drop actions.
|
|
Frees DropParams.
|
|
}
|
|
procedure DoDragDropOperation(Operation: TDragDropOperation;
|
|
var DropParams: TDropParams);
|
|
|
|
|
|
property Drives: TDrivesList read DrivesList;
|
|
property SyncChangeDir: String write FSyncChangeDir;
|
|
property Commands: TMainCommands read FCommands implements IFormCommands;
|
|
property SelectedPanel: TFilePanelSelect read PanelSelected write SetPanelSelected;
|
|
property LeftTabs: TFileViewNotebook read nbLeft;
|
|
property RightTabs: TFileViewNotebook read nbRight;
|
|
property MainSplitterPos: Double read FMainSplitterPos write SetMainSplitterPos;
|
|
property StaticTitle: String read sStaticTitleBarString write sStaticTitleBarString;
|
|
end;
|
|
|
|
var
|
|
frmMain: TfrmMain;
|
|
Cons: TCustomPtyDevice = nil;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses
|
|
Themes, uFileProcs, uShellContextMenu, fTreeViewMenu, uSearchResultFileSource,
|
|
Math, LCLIntf, Dialogs, uGlobs, uLng, uMasks, fCopyMoveDlg, uQuickViewPanel,
|
|
uShowMsg, uDCUtils, uLog, uGlobsPaths, LCLProc, uOSUtils, uPixMapManager, LazUTF8,
|
|
uDragDropEx, uKeyboard, uFileSystemFileSource, fViewOperations, uMultiListFileSource,
|
|
uFileSourceOperationTypes, uFileSourceCopyOperation, uFileSourceMoveOperation,
|
|
uFileSourceProperty, uFileSourceExecuteOperation, uArchiveFileSource, uThumbFileView,
|
|
uShellExecute, fSymLink, fHardLink, uExceptions, uUniqueInstance, Clipbrd, ShellCtrls,
|
|
uFileSourceOperationOptionsUI, uDebug, uHotkeyManager, uFileSourceUtil, uTempFileSystemFileSource,
|
|
Laz2_XMLRead, DCOSUtils, DCStrUtils, fOptions, fOptionsFrame, fOptionsToolbar, uClassesEx,
|
|
uHotDir, uFileSorting, DCBasicTypes, foptionsDirectoryHotlist, uConnectionManager,
|
|
fOptionsToolbarBase, fOptionsToolbarMiddle, fEditor, uColumns, StrUtils, uSysFolders,
|
|
uColumnsFileView, dmHigh, uFileSourceOperationMisc
|
|
{$IFDEF MSWINDOWS}
|
|
, uShellFileSource, uNetworkThread
|
|
{$ENDIF}
|
|
;
|
|
|
|
const
|
|
HotkeysCategory = 'Main';
|
|
DCToolItemClipboardHeader = 'DOUBLECMD#TOOLBAR#XMLDATA';
|
|
TCToolbarClipboardHeader = 'TOTALCMD#BAR#DATA';
|
|
DCToolbarClipboardHeader = 'DOUBLECMD#BAR#DATA';
|
|
|
|
{$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
|
|
var
|
|
LastActiveWindow: TCustomForm = nil;
|
|
{$ENDIF}
|
|
|
|
{$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)}
|
|
var
|
|
CloseQueryResult: Boolean = False;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF LCLGTK2}
|
|
var
|
|
MinimizedWindowButton: Boolean = False;
|
|
{$ENDIF}
|
|
|
|
var
|
|
FunctionButtonsCaptions: array[0..7] of record
|
|
ACaption: String;
|
|
ACommand: String;
|
|
end =
|
|
((ACaption: ''; ACommand: 'cm_View'),
|
|
(ACaption: ''; ACommand: 'cm_Edit'),
|
|
(ACaption: ''; ACommand: 'cm_Copy'),
|
|
(ACaption: ''; ACommand: 'cm_Rename'),
|
|
(ACaption: ''; ACommand: 'cm_MakeDir'),
|
|
(ACaption: ''; ACommand: 'cm_Delete'),
|
|
(ACaption: ''; ACommand: 'cm_RunTerm'),
|
|
(ACaption: ''; ACommand: 'cm_Exit'));
|
|
|
|
type
|
|
|
|
{ TFreeSpaceData }
|
|
|
|
TFreeSpaceData = class
|
|
Path: String;
|
|
Result: Boolean;
|
|
OnFinish: TDataEvent;
|
|
Panel: TFilePanelSelect;
|
|
FileSource: IFileSource;
|
|
FreeSize, TotalSize : Int64;
|
|
procedure GetFreeSpaceInThread;
|
|
end;
|
|
|
|
{ TShellTreeView }
|
|
|
|
TShellTreeView = class(ShellCtrls.TShellTreeView)
|
|
protected
|
|
function CanExpand(Node: TTreeNode): Boolean; override;
|
|
function ShellTreeViewSort(Node1, Node2: TTreeNode): Integer;
|
|
end;
|
|
|
|
function HistoryIndexesToTag(aFileSourceIndex, aPathIndex: Integer): Longint;
|
|
begin
|
|
Result := (aFileSourceIndex << 16) or aPathIndex;
|
|
end;
|
|
|
|
procedure HistoryIndexesFromTag(aTag: Longint; out aFileSourceIndex, aPathIndex: Integer);
|
|
begin
|
|
aFileSourceIndex := aTag >> 16;
|
|
aPathIndex := aTag and ((1<<16) - 1);
|
|
end;
|
|
|
|
{ TFreeSpaceData }
|
|
|
|
procedure TFreeSpaceData.GetFreeSpaceInThread;
|
|
begin
|
|
Result:= FileSource.GetFreeSpace(Path, FreeSize, TotalSize);
|
|
if Assigned(Application) and not (AppDoNotCallAsyncQueue in Application.Flags) then
|
|
Application.QueueAsyncCall(OnFinish, PtrInt(Self));
|
|
end;
|
|
|
|
{ TShellTreeView }
|
|
|
|
function TShellTreeView.CanExpand(Node: TTreeNode): Boolean;
|
|
begin
|
|
Result:= inherited CanExpand(Node);
|
|
if Result then Node.CustomSort(@ShellTreeViewSort);
|
|
end;
|
|
|
|
function TShellTreeView.ShellTreeViewSort(Node1, Node2: TTreeNode): Integer;
|
|
begin
|
|
Result:= CompareStrings(Node1.Text, Node2.Text, gSortNatural, gSortSpecial, gSortCaseSensitivity);
|
|
end;
|
|
|
|
{ TfrmMain }
|
|
|
|
procedure TfrmMain.FormCreate(Sender: TObject);
|
|
|
|
function CreateNotebook(aParent: TWinControl; aSide: TFilePanelSelect): TFileViewNotebook;
|
|
begin
|
|
Result := TFileViewNotebook.Create(aParent, aSide);
|
|
Result.Align := alClient;
|
|
Result.Options := [nboHidePageListPopup];
|
|
{$if lcl_fullversion >= 1070000}
|
|
Result.Options := Result.Options + [nboDoChangeOnSetIndex];
|
|
{$endif}
|
|
|
|
Result.OnCloseTabClicked := @NotebookCloseTabClicked;
|
|
Result.OnMouseDown := @nbPageMouseDown;
|
|
Result.OnMouseUp := @nbPageMouseUp;
|
|
Result.OnChange := @nbPageChanged;
|
|
Result.OnDblClick := @pnlLeftRightDblClick;
|
|
Result.OnDragOver:= @NotebookDragOver;
|
|
Result.OnDragDrop:= @NotebookDragDrop;
|
|
end;
|
|
|
|
function GenerateTitle(): String;
|
|
var
|
|
R: Integer;
|
|
ARevision, AServerName: String;
|
|
begin
|
|
if Length(UniqueInstance.ServernameByUser) > 0 then
|
|
AServerName := ' [' + UniqueInstance.ServernameByUser + ']'
|
|
else begin
|
|
AServerName := EmptyStr;
|
|
end;
|
|
|
|
if TryStrToInt(dcRevision, R) then
|
|
ARevision:= '~' + dcRevision
|
|
else begin
|
|
ARevision:= EmptyStr;
|
|
end;
|
|
|
|
Result := Format('%s%s %s%s',
|
|
['Double Commander',
|
|
AServerName,
|
|
Copy2Space(dcVersion),
|
|
ARevision]
|
|
);
|
|
end;
|
|
|
|
var
|
|
HMMainForm: THMForm;
|
|
I: Integer;
|
|
begin
|
|
Application.OnException := @AppException;
|
|
Application.OnActivate := @AppActivate;
|
|
Application.OnDeActivate := @AppDeActivate;
|
|
Application.OnShowHint := @AppShowHint;
|
|
Application.OnEndSession := @AppEndSession;
|
|
Application.OnQueryEndSession := @AppQueryEndSession;
|
|
|
|
{$IF DEFINED(DARWIN)}
|
|
// in LCL's DARWIN implements, there is no way but to Use LCL's method of dropping files
|
|
// from external applications
|
|
frmMain.OnDropFiles := @FormDropFiles;
|
|
AllowDropFiles := true; // DARWIN support external DragDragSource only, not DragDragTarget
|
|
{$ELSE}
|
|
// Use LCL's method of dropping files from external
|
|
// applications if we don't support it ourselves.
|
|
if not IsExternalDraggingSupported then
|
|
frmMain.OnDropFiles := @FormDropFiles;
|
|
AllowDropFiles := not uDragDropEx.IsExternalDraggingSupported;
|
|
{$ENDIF}
|
|
|
|
{$IF DEFINED(DARWIN)}
|
|
// MainForm receives in Mac OS closing events on system shortcut Command-Q
|
|
// See details at http://doublecmd.sourceforge.net/mantisbt/view.php?id=712
|
|
Application.MainForm.OnClose := @frmMainClose;
|
|
Application.MainForm.OnCloseQuery := @FormCloseQuery;
|
|
// support closing windows with Command+W
|
|
Application.AddOnKeyDownBeforeHandler( @GlobalMacOSKeyDownHandler );
|
|
{$ENDIF}
|
|
|
|
ConvertToolbarBarConfig(gpCfgDir + 'default.bar');
|
|
CreateDefaultToolbar;
|
|
sStaticTitleBarString := GenerateTitle();
|
|
|
|
// Remove the initial caption of the button, which is just a text of the associated action.
|
|
// The text would otherwise be briefly shown before the drive button was updated.
|
|
btnLeftDrive.Caption := '';
|
|
btnRightDrive.Caption := '';
|
|
|
|
//Have the correct button label to indicate root
|
|
btnLeftRoot.Caption:=DirectorySeparator;
|
|
btnRightRoot.Caption:=DirectorySeparator;
|
|
|
|
for I := 0 to pnlKeys.ControlCount - 1 do
|
|
FunctionButtonsCaptions[I].ACaption := pnlKeys.Controls[I].Caption;
|
|
|
|
{$IF DEFINED(LCLGTK2)}
|
|
// Workaround: "Layout and line"
|
|
// http://doublecmd.sourceforge.net/mantisbt/view.php?id=573
|
|
TreePanel.Visible := False;
|
|
pnlLeftTools.Visible := False;
|
|
pnlRightTools.Visible := False;
|
|
PanelAllProgress.Visible := False;
|
|
{$ENDIF}
|
|
|
|
InitPropStorage(Self);
|
|
|
|
PanelSelected:=fpLeft;
|
|
|
|
seLogWindow.FixDefaultKeystrokes;
|
|
|
|
HMMainForm := HotMan.Register(Self, HotkeysCategory);
|
|
HotMan.Register(edtCommand, 'Command Line');
|
|
|
|
nbLeft := CreateNotebook(pnlLeft, fpLeft);
|
|
nbRight := CreateNotebook(pnlRight, fpRight);
|
|
|
|
FDrivesListPopup := TDrivesListPopup.Create(Self, Self);
|
|
FDrivesListPopup.OnDriveSelected := @DriveListDriveSelected;
|
|
FDrivesListPopup.OnClose := @DriveListClose;
|
|
|
|
//NOTE: we don't check gOnlyOneAppInstance anymore, because cmdline option "--client" was implemented,
|
|
// so, we should always listen for the messages
|
|
if Assigned(UniqueInstance) then
|
|
UniqueInstance.OnMessage:= @OnUniqueInstanceMessage;
|
|
|
|
MainFormCreate(Self);
|
|
|
|
// Load command line history
|
|
edtCommand.Items.Assign(glsCmdLineHistory);
|
|
|
|
// Initialize actions.
|
|
actShowSysFiles.Checked := uGlobs.gShowSystemFiles;
|
|
actHorizontalFilePanels.Checked := gHorizontalFilePanels;
|
|
|
|
MainToolBar.AddToolItemExecutor(TKASCommandItem, @ToolbarExecuteCommand);
|
|
MainToolBar.AddToolItemExecutor(TKASProgramItem, @ToolbarExecuteProgram);
|
|
|
|
MiddleToolBar.AddToolItemExecutor(TKASCommandItem, @ToolbarExecuteCommand);
|
|
MiddleToolBar.AddToolItemExecutor(TKASProgramItem, @ToolbarExecuteProgram);
|
|
|
|
// Use the same tooltips for some left and right panel butttons.
|
|
btnRightDirectoryHotlist.Hint := btnLeftDirectoryHotlist.Hint;
|
|
btnRightHome.Hint := btnLeftHome.Hint;
|
|
btnRightRoot.Hint := btnLeftRoot.Hint;
|
|
btnRightUp.Hint := btnLeftUp.Hint;
|
|
|
|
{ *HotKeys* }
|
|
if (HotMan.Forms.Count = 0) or (HotMan.Version < hkVersion) then
|
|
LoadDefaultHotkeyBindings;
|
|
|
|
// Register action list for main form hotkeys.
|
|
HMMainForm.RegisterActionList(actionlst);
|
|
{ *HotKeys* }
|
|
|
|
UpdateActionIcons;
|
|
|
|
{$IF DEFINED(LCLCOCOA)}
|
|
// 1. TCustomTabControl.GetControlClassDefaultSize() return 200 for Default Width
|
|
// 2. on Cocoa, it is likely to cause TCocoaTabControl not wide enough to
|
|
// accommodate all tabs loaded in LoadTabsXml() during startup.
|
|
// 3. when setting PageIndex in LoadTabsXml(), it will cause an extra tab switch.
|
|
// 4. and it will cause an extra directory to be monitored in FileView.
|
|
// 5. the issue can be effectively avoided by setting a larger width.
|
|
nbLeft.Width:= 2048;
|
|
nbRight.Width:= 2048;
|
|
{$ENDIF}
|
|
|
|
LoadTabs;
|
|
|
|
// Must be after LoadTabs
|
|
TDriveWatcher.Initialize(GetWindowHandle(Application.MainForm));
|
|
TDriveWatcher.AddObserver(@OnDriveWatcherEvent);
|
|
|
|
{$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)}
|
|
// Fixes bug - [0000033] "DC cancels shutdown in KDE"
|
|
// http://doublecmd.sourceforge.net/mantisbt/view.php?id=33
|
|
QEventHook:= QObject_hook_create(TQtWidget(Self.Handle).Widget);
|
|
QObject_hook_hook_events(QEventHook, @QObjectEventFilter);
|
|
{$ENDIF}
|
|
|
|
OperationsManager.AddEventsListener([omevOperationAdded, omevOperationRemoved],
|
|
@OperationManagerNotify);
|
|
|
|
UpdateWindowView;
|
|
gFavoriteTabsList.AssociatedMainMenuItem := mnuFavoriteTabs;
|
|
gFavoriteTabsList.RefreshAssociatedMainMenu;
|
|
|
|
// Update selected drive and free space before main form is shown,
|
|
// otherwise there is a bit of delay.
|
|
UpdateTreeView;
|
|
UpdateTreeViewPath;
|
|
UpdateSelectedDrives;
|
|
UpdateFreeSpace(fpLeft, True);
|
|
UpdateFreeSpace(fpRight, True);
|
|
|
|
ThemeServices.OnThemeChange:= @AppThemeChange;
|
|
|
|
{$IF DEFINED(DARWIN)}
|
|
InitNSServiceProvider( @OnNSServiceOpenWithNewTab, @NSServiceMenuIsReady, @NSServiceMenuGetFilenames );
|
|
InitNSThemeChangedObserver( @NSThemeChangedHandler );
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrmMain.btnLeftClick(Sender: TObject);
|
|
begin
|
|
PanelButtonClick(Sender as TSpeedButton, FrameLeft);
|
|
end;
|
|
|
|
procedure TfrmMain.actExecute(Sender: TObject);
|
|
var
|
|
cmd: string;
|
|
begin
|
|
cmd := (Sender as TAction).Name;
|
|
cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3);
|
|
Commands.Commands.ExecuteCommand(cmd, []);
|
|
end;
|
|
|
|
procedure TfrmMain.btnF3MouseWheelDown(Sender: TObject; Shift: TShiftState;
|
|
MousePos: TPoint; var Handled: Boolean);
|
|
begin
|
|
if (ssCtrl in Shift) and (gFonts[dcfFunctionButtons].Size > gFonts[dcfFunctionButtons].MinValue) then
|
|
begin
|
|
Dec(gFonts[dcfFunctionButtons].Size);
|
|
UpdateGUIFunctionKeys;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.btnF3MouseWheelUp(Sender: TObject; Shift: TShiftState;
|
|
MousePos: TPoint; var Handled: Boolean);
|
|
begin
|
|
if (ssCtrl in Shift) and (gFonts[dcfFunctionButtons].Size < gFonts[dcfFunctionButtons].MaxValue) then
|
|
begin
|
|
Inc(gFonts[dcfFunctionButtons].Size);
|
|
UpdateGUIFunctionKeys;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.btnF8MouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
Point: TPoint;
|
|
begin
|
|
if Button = mbRight then
|
|
begin
|
|
Point := (Sender as TControl).ClientToScreen(Classes.Point(X, Y));
|
|
ShowTrashContextMenu(Self, Point.X, Point.Y, nil);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ConsoleSplitterMoved(Sender: TObject);
|
|
var
|
|
AHeight: Integer;
|
|
begin
|
|
AHeight:= nbConsole.Height + nbConsole.Tag - pnlCommand.Height;
|
|
if AHeight > 0 then
|
|
begin
|
|
nbConsole.Height := AHeight;
|
|
cmdConsole.Visible:= True;
|
|
end
|
|
else begin
|
|
cmdConsole.Hide;
|
|
nbConsole.Height := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.dskToolButtonMouseDown(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
ANotebook: TFileViewNotebook;
|
|
begin
|
|
if Button = mbMiddle then
|
|
begin
|
|
if Sender is TKASToolButton then
|
|
begin
|
|
if TKASToolButton(Sender).ToolBar = dskLeft then
|
|
begin
|
|
ANotebook:= nbLeft;
|
|
end
|
|
else if gDriveBar2 then
|
|
begin
|
|
ANotebook:= nbRight;
|
|
end
|
|
else begin
|
|
ANotebook:= ActiveNotebook;
|
|
end;
|
|
Commands.DoNewTab(ANotebook);
|
|
TKASToolButton(Sender).Click;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.mnuAllOperStopClick(Sender: TObject);
|
|
begin
|
|
OperationsManager.StopAll;
|
|
end;
|
|
|
|
procedure TfrmMain.mnuAllOperPauseClick(Sender: TObject);
|
|
begin
|
|
OperationsManager.PauseAll;
|
|
end;
|
|
|
|
procedure TfrmMain.mnuAllOperProgressClick(Sender: TObject);
|
|
begin
|
|
ShowOperationsViewer;
|
|
end;
|
|
|
|
procedure TfrmMain.mnuAllOperStartClick(Sender: TObject);
|
|
begin
|
|
OperationsManager.UnPauseAll;
|
|
end;
|
|
|
|
procedure TfrmMain.btnF8Click(Sender: TObject);
|
|
begin
|
|
if GetKeyShiftStateEx * KeyModifiersShortcut = [ssShift] then
|
|
Commands.cm_Delete(['trashcan=reversesetting'])
|
|
else
|
|
Commands.cm_Delete([]);
|
|
end;
|
|
|
|
{ TfrmMain.btnLeftDirectoryHotlistClick}
|
|
//To make appear the Directory Hotlist popup menu when pressing "*" button on left
|
|
//
|
|
procedure TfrmMain.btnLeftDirectoryHotlistClick(Sender: TObject);
|
|
var P:TPoint;
|
|
begin
|
|
if tb_activate_panel_on_click in gDirTabOptions then SetActiveFrame(fpLeft);
|
|
gDirectoryHotlist.PopulateMenuWithHotDir(pmHotList,@HotDirSelected,@miHotAddOrConfigClick,mpHOTDIRSWITHCONFIG,0);
|
|
p := Classes.Point(btnLeftDirectoryHotlist.Left,btnLeftDirectoryHotlist.Height);
|
|
p := pnlLeftTools.ClientToScreen(p);
|
|
pmHotList.PopUp(P.x,P.y);
|
|
end;
|
|
|
|
procedure TfrmMain.btnRightClick(Sender: TObject);
|
|
begin
|
|
PanelButtonClick(Sender as TSpeedButton, FrameRight);
|
|
end;
|
|
|
|
{ TfrmMain.btnRightDirectoryHotlistClick}
|
|
//To make appear the Directory Hotlist popup menu when pressing "*" button on right
|
|
//
|
|
procedure TfrmMain.btnRightDirectoryHotlistClick(Sender: TObject);
|
|
var P:TPoint;
|
|
begin
|
|
if tb_activate_panel_on_click in gDirTabOptions then SetActiveFrame(fpRight);
|
|
gDirectoryHotlist.PopulateMenuWithHotDir(pmHotList,@HotDirSelected,@miHotAddOrConfigClick,mpHOTDIRSWITHCONFIG,0);
|
|
p := Classes.Point(btnRightDirectoryHotlist.Left,btnRightDirectoryHotlist.Height);
|
|
p := pnlRightTools.ClientToScreen(p);
|
|
pmHotList.PopUp(P.x,P.y);
|
|
end;
|
|
|
|
procedure TfrmMain.btnDriveMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
pt: TPoint;
|
|
begin
|
|
if Button = mbRight then
|
|
with Sender as TSpeedButton do
|
|
begin
|
|
if (Tag >= 0) and (Tag < DrivesList.Count) then
|
|
begin
|
|
pt.X := X;
|
|
pt.Y := Y;
|
|
pt := ClientToScreen(pt);
|
|
ShowDriveContextMenu(Parent, DrivesList[Tag], pt.X, pt.Y, nil);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ConsoleSplitterCanResize(Sender: TObject;
|
|
var NewSize: Integer; var Accept: Boolean);
|
|
begin
|
|
// ConsoleSplitter is trying to resize pnlCommand,
|
|
// so NewSize is the new size of pnlCommand.
|
|
// Instead, resize nbConsole by the same difference.
|
|
nbConsole.Tag := NewSize;
|
|
end;
|
|
|
|
procedure TfrmMain.ConvertToolbarBarConfig(BarFileName: String);
|
|
var
|
|
ToolBarLoader: TKASToolBarIniLoader;
|
|
MainToolBarNode: TXmlNode;
|
|
begin
|
|
MainToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/MainToolbar', False);
|
|
if not Assigned(MainToolBarNode) then
|
|
begin
|
|
if mbFileExists(BarFileName) then
|
|
begin
|
|
ToolBarLoader := TKASToolBarIniLoader.Create(Commands.Commands);
|
|
try
|
|
ToolBarLoader.Load(BarFileName, MainToolBar, nil, @ConvertIniToolbarItem);
|
|
SaveToolBar(MainToolBar);
|
|
SaveGlobs; // Save toolbar and hotkeys
|
|
mbRenameFile(BarFileName, BarFileName + '.obsolete');
|
|
finally
|
|
ToolBarLoader.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.dskRightToolButtonClick(Sender: TObject);
|
|
var
|
|
FileView : TFileView;
|
|
begin
|
|
if gDriveBar2 then
|
|
FileView := FrameRight
|
|
else
|
|
FileView := ActiveFrame;
|
|
PanelButtonClick(Sender as TKASToolButton, FileView);
|
|
end;
|
|
|
|
procedure TfrmMain.dskLeftRightToolButtonDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
var
|
|
ToolItem: TKASToolItem;
|
|
SourceFiles: TFiles;
|
|
TargetFileSource: IFileSource;
|
|
TargetPath: String;
|
|
begin
|
|
if Sender is TKASToolButton then
|
|
begin
|
|
SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles;
|
|
try
|
|
ToolItem := TKASToolButton(Sender).ToolItem;
|
|
if ToolItem is TKASDriveItem then
|
|
begin
|
|
TargetPath := TKASDriveItem(ToolItem).Drive^.Path;
|
|
TargetFileSource := ParseFileSource(TargetPath, ActiveFrame.FileSource);
|
|
TargetPath := IncludeTrailingPathDelimiter(TargetPath);
|
|
if not Assigned(TargetFileSource) then
|
|
TargetFileSource := TFileSystemFileSource.GetFileSource;
|
|
case GetDropEffectByKeyAndMouse(GetKeyShiftStateEx, mbLeft) of
|
|
DropCopyEffect:
|
|
Self.CopyFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop);
|
|
DropMoveEffect:
|
|
Self.MoveFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop);
|
|
end;
|
|
end;
|
|
finally
|
|
SourceFiles.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.dskToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
btnDriveMouseUp(Sender, Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TfrmMain.EditToolbarButton(Toolbar: TKASToolBar;
|
|
Button: TKASToolButton);
|
|
var
|
|
Editor: TOptionsEditor;
|
|
Options: IOptionsDialog;
|
|
EditorClass: TOptionsEditorClass;
|
|
begin
|
|
if ToolBar = MainToolBar then
|
|
EditorClass := TfrmOptionsToolbar
|
|
else begin
|
|
EditorClass := TfrmOptionsToolbarMiddle;
|
|
end;
|
|
Options := ShowOptions(EditorClass);
|
|
Application.ProcessMessages;
|
|
Editor := Options.GetEditor(EditorClass);
|
|
if Assigned(Button) then
|
|
begin
|
|
(Editor as TfrmOptionsToolbarBase).SelectButton(Button.Tag);
|
|
end;
|
|
Application.ProcessMessages;
|
|
if Editor.CanFocus then Editor.SetFocus;
|
|
end;
|
|
|
|
procedure TfrmMain.lblAllProgressPctClick(Sender: TObject);
|
|
begin
|
|
ShowOperationsViewer;
|
|
end;
|
|
|
|
procedure TfrmMain.MainToolBarToolButtonDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
var
|
|
I: LongWord;
|
|
SelectedFiles: TFiles = nil;
|
|
Param: string;
|
|
ToolItem: TKASToolItem;
|
|
Toolbar: TKASToolBar;
|
|
begin
|
|
Toolbar:= (Sender as TKASToolButton).ToolBar;
|
|
if (ssShift in GetKeyShiftState) then
|
|
// Button was moved.
|
|
SaveToolBar(Toolbar)
|
|
else
|
|
if (Sender is TKASToolButton) and not Draging then
|
|
begin
|
|
ToolItem := TKASToolButton(Sender).ToolItem;
|
|
if ToolItem is TKASProgramItem then
|
|
begin
|
|
SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles;
|
|
try
|
|
if SelectedFiles.Count > 0 then
|
|
begin
|
|
Param:= EmptyStr;
|
|
for I := 0 to SelectedFiles.Count - 1 do
|
|
begin
|
|
// Workaround for not fully implemented TMultiListFileSource.
|
|
if ActiveFrame.FileSource.IsClass(TMultiListFileSource) then
|
|
Param := Param + QuoteStr(SelectedFiles[I].FullPath) + ' '
|
|
else
|
|
Param := Param + QuoteStr(ActiveFrame.CurrentAddress + SelectedFiles[I].FullPath) + ' ';
|
|
end;
|
|
|
|
TKASProgramItem(ToolItem).Command := ReplaceEnvVars(ReplaceTilde(TKASProgramItem(ToolItem).Command));
|
|
Param := PrepareParameter(Param, nil, []);
|
|
|
|
if not (Commands.Commands.ExecuteCommand(TKASProgramItem(ToolItem).Command, [Param]) = cfrSuccess) then
|
|
ProcessExtCommandFork(TKASProgramItem(ToolItem).Command, Param, TKASProgramItem(ToolItem).StartPath);
|
|
end;
|
|
finally
|
|
FreeAndNil(SelectedFiles);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.MainToolBarToolButtonDragOver(Sender, Source: TObject; X,
|
|
Y: Integer; State: TDragState; var Accept: Boolean; NumberOfButton: Integer);
|
|
var
|
|
aFile: TFile;
|
|
tmp: Integer;
|
|
ToolItem: TKASProgramItem;
|
|
Toolbar: TKASToolBar;
|
|
begin
|
|
Toolbar:= (Sender as TKASToolButton).ToolBar;
|
|
if (ssShift in GetKeyShiftState) then
|
|
begin
|
|
if not (Source is TKASToolButton) and not Draging then
|
|
begin
|
|
aFile := ActiveFrame.CloneActiveFile;
|
|
try
|
|
if Assigned(aFile) and aFile.IsNameValid then
|
|
begin
|
|
ToolItem := TKASProgramItem.Create;
|
|
ToolItem.Command := aFile.FullPath;
|
|
ToolItem.StartPath := aFile.Path;
|
|
ToolItem.Icon := aFile.FullPath;
|
|
ToolItem.Hint := ExtractOnlyFileName(aFile.Name);
|
|
// ToolItem.Text := ExtractOnlyFileName(aFile.Name);
|
|
Toolbar.InsertButton(Sender as TKASToolButton, ToolItem);
|
|
|
|
NumberOfMoveButton := (Sender as TSpeedButton).Tag;
|
|
NumberOfNewMoveButton := (Sender as TSpeedButton).Tag-1;
|
|
Draging := True;
|
|
Accept := True;
|
|
end
|
|
else
|
|
begin
|
|
Accept := False;
|
|
Exit;
|
|
end;
|
|
finally
|
|
FreeAndNil(aFile);
|
|
end;
|
|
end;
|
|
if (Source is TKASToolButton) and (Toolbar <> TKASToolButton(Source).ToolBar) then
|
|
begin
|
|
Accept := False;
|
|
Exit;
|
|
end;
|
|
if (NumberOfMoveButton <> (Sender as TSpeedButton).Tag) then
|
|
begin
|
|
Draging := True;
|
|
if Source is TSpeedButton then
|
|
Toolbar.MoveButton((Source as TSpeedButton).Tag, (Sender as TSpeedButton).Tag)
|
|
else
|
|
begin
|
|
tmp:= (Sender as TSpeedButton).Tag;
|
|
Toolbar.MoveButton(NumberOfNewMoveButton, (Sender as TSpeedButton).Tag);
|
|
NumberOfNewMoveButton := tmp;
|
|
end;
|
|
NumberOfMoveButton := (Sender as TSpeedButton).Tag;
|
|
Accept := True;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Accept := not Draging and
|
|
(Sender is TKASToolButton) and
|
|
(TKASToolButton(Sender).ToolItem is TKASProgramItem);
|
|
if Accept then
|
|
begin
|
|
aFile := ActiveFrame.CloneActiveFile;
|
|
try
|
|
Accept := Assigned(aFile) and aFile.IsNameValid;
|
|
finally
|
|
FreeAndNil(aFile);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.MainToolBarToolButtonMouseDown(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if (ssShift in Shift) and (Button = mbLeft) then
|
|
begin
|
|
(Sender as TKASToolButton).BeginDrag(False, 5);
|
|
NumberOfMoveButton:= (Sender as TKASToolButton).Tag;
|
|
end;
|
|
Draging:= False;
|
|
end;
|
|
|
|
procedure TfrmMain.MainToolBarToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if Button = mbRight then
|
|
MainToolBarMouseUp(Sender, Button, Shift, X, Y);
|
|
end;
|
|
|
|
function TfrmMain.MainToolBarToolItemShortcutsHint(Sender: TObject;
|
|
ToolItem: TKASNormalItem): String;
|
|
begin
|
|
if Sender = MainToolBar then
|
|
Result := ShortcutsToText(TfrmOptionsToolbar.GetShortcuts(ToolItem))
|
|
else
|
|
Result := ShortcutsToText(TfrmOptionsToolbarMiddle.GetShortcuts(ToolItem));
|
|
end;
|
|
|
|
procedure TfrmMain.miLogMenuClick(Sender: TObject);
|
|
begin
|
|
case (Sender as TMenuItem).Tag of
|
|
0:
|
|
seLogWindow.CopyToClipboard;
|
|
1:
|
|
seLogWindow.SelectAll;
|
|
2:
|
|
Commands.cm_ClearLogWindow([]);
|
|
3:
|
|
ShowLogWindow(PtrInt(False));
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.miTrayIconExitClick(Sender: TObject);
|
|
begin
|
|
RestoreFromTray;
|
|
Close;
|
|
end;
|
|
|
|
procedure TfrmMain.miTrayIconRestoreClick(Sender: TObject);
|
|
begin
|
|
RestoreFromTray;
|
|
end;
|
|
|
|
procedure TfrmMain.PanelButtonClick(Button: TSpeedButton; FileView: TFileView);
|
|
begin
|
|
with FileView do
|
|
begin
|
|
if Button.Caption = DirectorySeparator then
|
|
Commands.DoChangeDirToRoot(FileView)
|
|
else if Button.Caption = '..' then
|
|
ChangePathToParent(True)
|
|
else if Button.Caption = '~' then
|
|
SetFileSystemPath(FileView, GetHomeDir);
|
|
end;
|
|
|
|
if tb_activate_panel_on_click in gDirTabOptions then
|
|
SetActiveFrame(FileView);
|
|
end;
|
|
|
|
procedure TfrmMain.pnlDiskResize(Sender: TObject);
|
|
var
|
|
ADelta, AWidth: Integer;
|
|
begin
|
|
if not gDriveBarSyncWidth then
|
|
begin
|
|
if gDriveBar1 and gDriveBar2 then
|
|
begin
|
|
if gHorizontalFilePanels then
|
|
ADelta:= 0
|
|
else begin
|
|
ADelta:= MainSplitter.Width;
|
|
ADelta+= IfThen(MiddleToolBar.Visible, MiddleToolBar.Width);
|
|
end;
|
|
AWidth:= Max(0, (pnlDisk.ClientWidth - ADelta) div 2);
|
|
end
|
|
else begin
|
|
AWidth:= Max(0, pnlDisk.ClientWidth);
|
|
end;
|
|
pnlDskLeft.Constraints.MinWidth:= AWidth;
|
|
pnlDskLeft.Constraints.MaxWidth:= AWidth;
|
|
pnlDskRight.Constraints.MinWidth:= AWidth;
|
|
pnlDskRight.Constraints.MaxWidth:= AWidth;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ShellTreeViewSelect;
|
|
begin
|
|
ShellTreeView.Tag := 1;
|
|
try
|
|
SetFileSystemPath(ActiveFrame, (ShellTreeView as TShellTreeView).Path);
|
|
finally
|
|
ShellTreeView.Tag := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ShellTreeViewKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
if Key = VK_RETURN then ShellTreeViewSelect;
|
|
end;
|
|
|
|
procedure TfrmMain.ShellTreeViewMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
AFile: TFile;
|
|
AFiles: TFiles;
|
|
APoint: TPoint;
|
|
AFileName: String;
|
|
begin
|
|
{$IF DEFINED(MSWINDOWS)}
|
|
if Button = mbRight then
|
|
try
|
|
AFileName:= ExcludeTrailingBackslash((ShellTreeView as TShellTreeView).Path);
|
|
AFile:= TFileSystemFileSource.CreateFileFromFile(AFileName);
|
|
try
|
|
AFiles:= TFiles.Create(AFile.Path);
|
|
AFiles.Add(AFile);
|
|
APoint := ShellTreeView.ClientToScreen(Classes.Point(X, Y));
|
|
ShowContextMenu(ShellTreeView, AFiles, APoint.X, APoint.Y, False, nil);
|
|
finally
|
|
FreeAndNil(AFiles);
|
|
end;
|
|
except
|
|
on E: EContextMenuException do
|
|
ShowException(E)
|
|
else;
|
|
end;
|
|
{$ENDIF}
|
|
if Button = mbLeft then
|
|
ShellTreeViewSelect;
|
|
end;
|
|
|
|
procedure TfrmMain.FormDestroy(Sender: TObject);
|
|
begin
|
|
DCDebug('Destroying main form');
|
|
|
|
if Assigned(HotMan) then
|
|
begin
|
|
HotMan.UnRegister(edtCommand);
|
|
HotMan.UnRegister(Self);
|
|
end;
|
|
|
|
OperationsManager.RemoveEventsListener([omevOperationAdded, omevOperationRemoved],
|
|
@OperationManagerNotify);
|
|
|
|
TDriveWatcher.RemoveObserver(@OnDriveWatcherEvent);
|
|
TDriveWatcher.Finalize;
|
|
DCDebug('Drive watcher finished');
|
|
|
|
// Close all tabs.
|
|
CloseNotebook(LeftTabs);
|
|
CloseNotebook(RightTabs);
|
|
|
|
FreeAndNil(DrivesList);
|
|
|
|
{$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)}
|
|
QObject_hook_destroy(QEventHook);
|
|
{$ENDIF}
|
|
|
|
DCDebug('Main form destroyed');
|
|
end;
|
|
|
|
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: boolean);
|
|
var
|
|
Index: Integer;
|
|
AForm: TfrmEditor;
|
|
begin
|
|
if OperationsManager.OperationsCount > 0 then
|
|
begin
|
|
CanClose := MessageDlg(rsMsgFileOperationsActive,
|
|
rsMsgFileOperationsActiveLong + LineEnding + rsMsgConfirmQuit,
|
|
mtConfirmation, [mbYes, mbNo], 0, mbNo) = mrYes;
|
|
end
|
|
else if gConfirmQuit then
|
|
begin
|
|
CanClose := MessageDlg('', rsMsgConfirmQuit,
|
|
mtConfirmation, [mbYes, mbNo], 0, mbNo) = mrYes;
|
|
end
|
|
else begin
|
|
CanClose := True;
|
|
end;
|
|
|
|
if CanClose then
|
|
begin
|
|
for Index:= 0 to Screen.FormCount - 1 do
|
|
begin
|
|
if Screen.Forms[Index] is TfrmEditor then
|
|
begin
|
|
AForm:= TfrmEditor(Screen.Forms[Index]);
|
|
if AForm.Editor.Modified then
|
|
begin
|
|
if Assigned(AForm.OnCloseQuery) then
|
|
begin
|
|
AForm.ShowOnTop;
|
|
AForm.OnCloseQuery(AForm, CanClose);
|
|
if not CanClose then Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)}
|
|
CloseQueryResult:= CanClose;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrmMain.FormDropFiles(Sender: TObject; const FileNames: array of String);
|
|
var
|
|
TargetFileView: TFileView = nil;
|
|
TargetControl: TControl;
|
|
I: Integer;
|
|
Files: TFiles = nil;
|
|
FileNamesList: TStringList = nil;
|
|
Point: TPoint;
|
|
DropParams: TDropParams;
|
|
begin
|
|
Point.x := 0;
|
|
Point.y := 0;
|
|
TargetControl := FindLCLControl(Mouse.CursorPos);
|
|
while TargetControl <> nil do
|
|
begin
|
|
if TargetControl = FrameLeft then
|
|
begin
|
|
// drop on left panel
|
|
TargetFileView := FrameLeft;
|
|
break;
|
|
end
|
|
else if TargetControl = FrameRight then
|
|
begin
|
|
// drop on right panel
|
|
TargetFileView := FrameRight;
|
|
break;
|
|
end;
|
|
|
|
TargetControl := TargetControl.Parent;
|
|
end;
|
|
|
|
if Assigned(TargetFileView) then
|
|
try
|
|
// fill file list by files
|
|
FileNamesList := TStringList.Create;
|
|
for I := Low(FileNames) to High(FileNames) do
|
|
begin
|
|
if Length(FileNames[I]) > 0 then
|
|
FileNamesList.Add(FileNames[I]);
|
|
end;
|
|
|
|
if FileNamesList.Count > 0 then
|
|
try
|
|
Files := TFileSystemFileSource.CreateFilesFromFileList(
|
|
ExtractFilePath(FileNamesList[0]), FileNamesList);
|
|
|
|
if Files.Count > 0 then
|
|
begin
|
|
GetCursorPos(Point);
|
|
|
|
DropParams := TDropParams.Create(
|
|
Files,
|
|
GetDropEffectByKeyAndMouse(GetKeyShiftState, mbLeft),
|
|
Point, False,
|
|
nil, TargetFileView,
|
|
TargetFileView.FileSource,
|
|
TargetFileView.CurrentPath);
|
|
|
|
DropFiles(DropParams);
|
|
end;
|
|
|
|
except
|
|
on e: EFileNotFound do
|
|
MessageDlg(e.Message, mtError, [mbOK], 0);
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(Files);
|
|
FreeAndNil(FileNamesList);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.DropFiles(var DropParams: TDropParams);
|
|
begin
|
|
if Assigned(DropParams) then
|
|
begin
|
|
if DropParams.Files.Count > 0 then
|
|
begin
|
|
case DropParams.DropEffect of
|
|
|
|
DropMoveEffect:
|
|
DropParams.TargetPanel.DoDragDropOperation(ddoMove, DropParams);
|
|
|
|
DropCopyEffect:
|
|
DropParams.TargetPanel.DoDragDropOperation(ddoCopy, DropParams);
|
|
|
|
DropLinkEffect:
|
|
DropParams.TargetPanel.DoDragDropOperation(ddoSymLink, DropParams);
|
|
|
|
DropAskEffect:
|
|
begin
|
|
// Ask the user what he would like to do by displaying a menu.
|
|
// Returns immediately after showing menu.
|
|
PopupDragDropMenu(DropParams);
|
|
end;
|
|
|
|
else
|
|
FreeAndNil(DropParams);
|
|
|
|
end;
|
|
end
|
|
else
|
|
FreeAndNil(DropParams);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.DoDragDropOperation(Operation: TDragDropOperation;
|
|
var DropParams: TDropParams);
|
|
var
|
|
SourceFileName, TargetFileName: string;
|
|
begin
|
|
try
|
|
with DropParams do
|
|
begin
|
|
if Assigned(TargetFileSource) then
|
|
begin
|
|
|
|
{$IF DEFINED(MSWINDOWS)}
|
|
// If drop from external application and from temporary directory then
|
|
// in most cases it is a drop from archiver application that extracting
|
|
// files via temporary directory and requires run operation in the main thread
|
|
// See http://doublecmd.sourceforge.net/mantisbt/view.php?id=1124
|
|
if (GetDragDropType = ddtExternal) and (Operation in [ddoMove, ddoCopy]) and
|
|
IsInPath(GetTempDir, DropParams.Files[0].FullPath, True, True) then
|
|
begin
|
|
if gShowDialogOnDragDrop then
|
|
begin
|
|
case Operation of
|
|
ddoMove: SourceFileName := GetFileDlgStr(rsMsgRenSel, rsMsgRenFlDr, DropParams.Files);
|
|
ddoCopy: SourceFileName := GetFileDlgStr(rsMsgCpSel, rsMsgCpFlDr, DropParams.Files);
|
|
end;
|
|
if MessageDlg(SourceFileName, mtConfirmation, [mbOK, mbCancel], 0) <> mrOK then
|
|
Exit;
|
|
end;
|
|
case Operation of
|
|
ddoMove: Self.MoveFiles(TFileSystemFileSource.GetFileSource,
|
|
TargetFileSource, Files, TargetPath, False, ModalQueueId);
|
|
ddoCopy: Self.CopyFiles(TFileSystemFileSource.GetFileSource,
|
|
TargetFileSource, Files, TargetPath, False, ModalQueueId);
|
|
end;
|
|
end else
|
|
{$ENDIF}
|
|
|
|
case Operation of
|
|
|
|
ddoMove:
|
|
if GetDragDropType = ddtInternal then
|
|
begin
|
|
if Self.MoveFiles(SourcePanel.FileSource,
|
|
TargetFileSource,
|
|
Files, TargetPath,
|
|
gShowDialogOnDragDrop) then
|
|
begin
|
|
SourcePanel.MarkFiles(False);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Self.MoveFiles(TFileSystemFileSource.GetFileSource,
|
|
TargetFileSource,
|
|
Files, TargetPath,
|
|
gShowDialogOnDragDrop);
|
|
end;
|
|
|
|
ddoCopy:
|
|
if GetDragDropType = ddtInternal then
|
|
begin
|
|
if Self.CopyFiles(SourcePanel.FileSource,
|
|
TargetFileSource,
|
|
Files, TargetPath,
|
|
gShowDialogOnDragDrop) then
|
|
begin
|
|
SourcePanel.MarkFiles(False);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Self.CopyFiles(TFileSystemFileSource.GetFileSource,
|
|
TargetFileSource,
|
|
Files, TargetPath,
|
|
gShowDialogOnDragDrop);
|
|
end;
|
|
|
|
ddoSymLink, ddoHardLink:
|
|
begin
|
|
// Only for filesystem.
|
|
if ((GetDragDropType = ddtExternal) or
|
|
(SourcePanel.FileSource.IsClass(TFileSystemFileSource)))
|
|
and (TargetFileSource.IsClass(TFileSystemFileSource)) then
|
|
begin
|
|
// TODO: process multiple files
|
|
|
|
SourceFileName := Files.Items[0].FullPath;
|
|
TargetFileName := TargetPath + ExtractFileName(SourceFileName);
|
|
|
|
if ((Operation = ddoSymLink) and
|
|
ShowSymLinkForm(Self, SourceFileName, TargetFileName, TargetPath))
|
|
or ((Operation = ddoHardLink) and
|
|
ShowHardLinkForm(Self, SourceFileName, TargetFileName, TargetPath))
|
|
then
|
|
TargetFileSource.Reload(TargetPath);
|
|
end
|
|
else
|
|
begin
|
|
msgWarning(rsMsgErrNotSupported);
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
msgWarning(rsMsgErrNotSupported);
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(DropParams);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
|
|
begin
|
|
// Either left or right panel has to be focused.
|
|
if not FrameLeft.Focused and
|
|
not FrameRight.Focused then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
// Check for certain Ascii keys.
|
|
if (not ((Length(UTF8Key) = 1) and (UTF8Key[1] in ['-', '*', '+', #0..#32]))) then
|
|
begin
|
|
if (gKeyTyping[ktmNone] = ktaCommandLine)
|
|
{$IFDEF MSWINDOWS}
|
|
// Allow entering international characters with Ctrl+Alt on Windows,
|
|
// if there is no action for Ctrl+Alt and command line typing has no modifiers.
|
|
or (HasKeyboardAltGrKey and
|
|
(GetKeyShiftStateEx * KeyModifiersShortcutNoText = [ssCtrl, ssAlt]) and
|
|
(gKeyTyping[ktmCtrlAlt] = ktaNone))
|
|
{$ENDIF}
|
|
then
|
|
begin
|
|
TypeInCommandLine(UTF8Key);
|
|
UTF8Key := '';
|
|
end;
|
|
end
|
|
end;
|
|
|
|
{$IF DEFINED(LCLGTK2)}
|
|
procedure TfrmMain.WindowStateUpdate(Data: PtrInt);
|
|
begin
|
|
Resizing(lastWindowState);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TfrmMain.FormWindowStateChange(Sender: TObject);
|
|
begin
|
|
if FUpdateDiskCount and (WindowState <> wsMinimized) then
|
|
begin
|
|
UpdateDiskCount;
|
|
FUpdateDiskCount:= False;
|
|
end;
|
|
|
|
{$IF DEFINED(LCLGTK2)}
|
|
if MinimizedWindowButton then
|
|
begin
|
|
MinimizedWindowButton:= False;
|
|
Application.QueueAsyncCall(@WindowStateUpdate, 0);
|
|
Exit;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
if WindowState = wsMinimized then
|
|
begin // Minimized
|
|
MainToolBar.Top:= 0; // restore toolbar position
|
|
if not HiddenToTray then
|
|
begin
|
|
{$IF DEFINED(LCLGTK2)}
|
|
MinimizedWindowButton:= True;
|
|
{$ENDIF}
|
|
if gMinimizeToTray or gAlwaysShowTrayIcon then
|
|
begin
|
|
HideToTray;
|
|
end;
|
|
end
|
|
else begin
|
|
// If we get wsMinimized while HiddenToTray is true,
|
|
// then this means it was sent by LCL when a hidden, minimized window was shown.
|
|
// We don't react to this message in this case.
|
|
HiddenToTray := False;
|
|
{$IF DEFINED(LCLGTK2)}
|
|
Application.QueueAsyncCall(@WindowStateUpdate, 0);
|
|
{$ENDIF}
|
|
end;
|
|
end
|
|
else
|
|
begin // Not minimized
|
|
// save window state before minimize for
|
|
// future loading after restore from tray
|
|
lastWindowState:=WindowState;
|
|
HiddenToTray := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.MainSplitterDblClick(Sender: TObject);
|
|
begin
|
|
// To prevent MainSplitterMouseUp processing
|
|
MainSplitterLeftMouseBtnDown:=false;
|
|
MainSplitter.ParentColor:=true;
|
|
// Set splitter to 50/50
|
|
Commands.DoPanelsSplitterPerPos(50);
|
|
end;
|
|
|
|
procedure TfrmMain.MainSplitterMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if (Button=mbLeft) and (not MainSplitterLeftMouseBtnDown) then
|
|
begin
|
|
// Under Linux MainSplitter.Color:=clBlack Doesn't work
|
|
MainSplitter.ParentColor:=true;
|
|
MainSplitter.Color:=ColorToRGB(clBlack);
|
|
|
|
MainSplitterMouseDownX:=X;
|
|
MainSplitterMouseDownY:=Y;
|
|
MainSplitterLeftMouseBtnDown:=true;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.MainSplitterMouseMove(Sender: TObject; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
var
|
|
Rect: TRect;
|
|
sHint: String;
|
|
Delta: Integer;
|
|
APoint: TPoint;
|
|
Moved: Boolean = False;
|
|
begin
|
|
if MainSplitterLeftMouseBtnDown then
|
|
begin
|
|
if not gHorizontalFilePanels and
|
|
(MainSplitter.Left + X > MainSplitter.Width) and
|
|
(MainSplitter.Left + X + MainSplitter.Width < pnlNotebooks.Width) then
|
|
begin
|
|
MainSplitter.Left := MainSplitter.Left + X - MainSplitterMouseDownX;
|
|
Moved := True;
|
|
end
|
|
else if gHorizontalFilePanels and
|
|
(MainSplitter.Top + Y > MainSplitter.Height) and
|
|
(MainSplitter.Top + Y + MainSplitter.Height < pnlNotebooks.Height) then
|
|
begin
|
|
MainSplitter.Top := MainSplitter.Top + Y - MainSplitterMouseDownY;
|
|
Moved := True;
|
|
end;
|
|
|
|
if Moved then
|
|
begin
|
|
// create hint
|
|
if not Assigned(MainSplitterHintWnd) then
|
|
begin
|
|
MainSplitterHintWnd := THintWindow.Create(nil);
|
|
MainSplitterHintWnd.Color := Application.HintColor;
|
|
end;
|
|
|
|
// calculate percent
|
|
if not gHorizontalFilePanels then
|
|
begin
|
|
Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Width);
|
|
FMainSplitterPos:= MainSplitter.Left * 100 / (pnlNotebooks.Width-MainSplitter.Width - Delta);
|
|
end
|
|
else begin
|
|
Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Height);
|
|
FMainSplitterPos:= MainSplitter.Top * 100 / (pnlNotebooks.Height-MainSplitter.Height - Delta);
|
|
end;
|
|
|
|
// generate hint text
|
|
sHint:= FloatToStrF(FMainSplitterPos, ffFixed, 15, 1) + '%';
|
|
|
|
// calculate hint position
|
|
Rect:= MainSplitterHintWnd.CalcHintRect(200, sHint, nil);
|
|
APoint:= Mouse.CursorPos;
|
|
with Rect do
|
|
begin
|
|
Right:= APoint.X + 8 + Right;
|
|
Bottom:= APoint.Y + 12 + Bottom;
|
|
Left:= APoint.X + 8;
|
|
Top:= APoint.Y + 12;
|
|
end;
|
|
|
|
// show hint
|
|
MainSplitterHintWnd.ActivateHint(Rect, sHint);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.MainSplitterMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
// hide and destroy hint
|
|
if Assigned(MainSplitterHintWnd) then
|
|
begin
|
|
MainSplitterHintWnd.Hide;
|
|
FreeAndNil(MainSplitterHintWnd);
|
|
end;
|
|
|
|
if (MainSplitterLeftMouseBtnDown) then
|
|
begin
|
|
MainSplitter.ParentColor:=true;
|
|
MainSplitterLeftMouseBtnDown:=false;
|
|
|
|
if not FResizingFilePanels then
|
|
begin
|
|
FResizingFilePanels := True;
|
|
if not gHorizontalFilePanels then
|
|
pnlLeft.Width := MainSplitter.Left
|
|
else
|
|
pnlLeft.Height := MainSplitter.Top;
|
|
FResizingFilePanels := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.MainTrayIconClick(Sender: TObject);
|
|
begin
|
|
// Only react to clicks if the icon is not scheduled to be hidden.
|
|
if not HidingTrayIcon then
|
|
begin
|
|
if WindowState = wsMinimized then
|
|
begin
|
|
RestoreFromTray;
|
|
end
|
|
else
|
|
begin
|
|
MinimizeWindow;
|
|
HideToTray;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TfrmMain.lblDriveInfoDblClick }
|
|
//Shows the Directory Hotlist at the cursor position after double-clicking the panel.
|
|
//This is NOT like TC but was here as legacy in DC. Let it there for respect to original authors.
|
|
//Double-clicking on the "FPathLabel" of the "TFileViewHeader" does the same as in TC and is implemented now.
|
|
//
|
|
procedure TfrmMain.lblDriveInfoDblClick(Sender: TObject);
|
|
begin
|
|
if tb_activate_panel_on_click in gDirTabOptions then
|
|
begin
|
|
if Sender = lblRightDriveInfo then
|
|
SetActiveFrame(fpRight)
|
|
else if Sender = lblLeftDriveInfo then
|
|
SetActiveFrame(fpLeft);
|
|
end;
|
|
Commands.cm_DirHotList(['position=cursor']);
|
|
end;
|
|
|
|
procedure TfrmMain.LeftDriveBarExecuteDrive(ToolItem: TKASToolItem);
|
|
var
|
|
DriveItem: TKASDriveItem;
|
|
begin
|
|
DriveItem := ToolItem as TKASDriveItem;
|
|
SetPanelDrive(fpLeft, DriveItem.Drive, True);
|
|
end;
|
|
|
|
procedure TfrmMain.MainToolBarDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
var
|
|
aFile: TFile;
|
|
ToolItem: TKASProgramItem;
|
|
Toolbar: TKASToolBar absolute Sender;
|
|
begin
|
|
if not (Source is TSpeedButton) and not Draging then
|
|
begin
|
|
aFile := ActiveFrame.CloneActiveFile;
|
|
try
|
|
if Assigned(aFile) and aFile.IsNameValid then
|
|
begin
|
|
ToolItem := TKASProgramItem.Create;
|
|
ToolItem.Command := GetToolbarFilenameToSave(tpmeCommand, aFile.FullPath);
|
|
ToolItem.StartPath := GetToolbarFilenameToSave(tpmeStartingPath, aFile.Path);
|
|
ToolItem.Hint := ExtractOnlyFileName(aFile.Name);
|
|
// ToolItem.Text := ExtractOnlyFileName(aFile.Name);
|
|
ToolItem.Icon := GetToolbarFilenameToSave(tpmeIcon, aFile.FullPath);
|
|
Toolbar.AddButton(ToolItem);
|
|
end;
|
|
finally
|
|
FreeAndNil(aFile);
|
|
end;
|
|
end;
|
|
SaveToolBar(Toolbar);
|
|
Draging := False;
|
|
end;
|
|
|
|
procedure TfrmMain.MainToolBarDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
var
|
|
aFile: TFile;
|
|
begin
|
|
if (Source is TSpeedButton) then
|
|
Accept := False
|
|
else begin
|
|
aFile := ActiveFrame.CloneActiveFile;
|
|
try
|
|
Accept := Assigned(aFile) and aFile.IsNameValid;
|
|
finally
|
|
FreeAndNil(aFile);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.MainToolBarLoadButtonGlyph(ToolItem: TKASToolItem;
|
|
iIconSize: Integer; clBackColor: TColor): TBitmap;
|
|
begin
|
|
if ToolItem is TKASNormalItem then
|
|
Result := PixMapManager.LoadBitmapEnhanced(TKASNormalItem(ToolItem).Icon, iIconSize, True, clBackColor, nil)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TfrmMain.MainToolBarLoadButtonOverlay(ToolItem: TKASToolItem;
|
|
iIconSize: Integer; clBackColor: TColor): TBitmap;
|
|
begin
|
|
if ToolItem is TKASMenuItem then
|
|
Result := PixMapManager.LoadBitmapEnhanced('emblem-symbolic-link', iIconSize, True, clBackColor, nil)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TfrmMain.tbDeleteClick(Sender: TObject);
|
|
var
|
|
Toolbar: TKASToolBar;
|
|
Button: TKASToolButton;
|
|
begin
|
|
Button := TKASToolButton(pmToolBar.Tag);
|
|
if Assigned(Button) then
|
|
begin
|
|
if msgYesNo(Format(rsMsgDelSel, [Button.Hint])) then
|
|
begin
|
|
Toolbar:= Button.ToolBar;
|
|
ToolBar.RemoveButton(Button);
|
|
SaveToolBar(Toolbar);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.dskLeftToolButtonClick(Sender: TObject);
|
|
begin
|
|
PanelButtonClick(Sender as TKASToolButton, FrameLeft);
|
|
end;
|
|
|
|
procedure TfrmMain.MainToolBarMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
Point : TPoint;
|
|
begin
|
|
case Button of
|
|
mbRight:
|
|
begin
|
|
Point.X := X;
|
|
Point.Y := Y;
|
|
Point := (Sender as TControl).ClientToScreen(Point);
|
|
if Sender is TKASToolButton then
|
|
begin
|
|
pmToolBar.Tag := PtrInt(Sender);
|
|
pmToolBar.PopupComponent := TKASToolButton(Sender).ToolBar;
|
|
end
|
|
else begin
|
|
pmToolBar.Tag := 0;
|
|
pmToolBar.PopupComponent := TComponent(Sender);
|
|
end;
|
|
pmToolBar.PopUp(Point.X, Point.Y);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.frmMainClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
begin
|
|
// Process all queued asynchronous events before closing
|
|
// (frmMainAfterShow, nbPageAfterMouseDown, etc.).
|
|
Application.ProcessMessages;
|
|
|
|
if tb_close_duplicate_when_closing in gDirTabOptions then
|
|
begin
|
|
Commands.cm_CloseDuplicateTabs(['LeftTabs']);
|
|
Commands.cm_CloseDuplicateTabs(['RightTabs']);
|
|
end;
|
|
|
|
if gSaveConfiguration then ConfigSaveSettings(False);
|
|
|
|
FreeAndNil(Cons);
|
|
|
|
Application.Terminate;
|
|
end;
|
|
|
|
procedure TfrmMain.frmMainAfterShow(Sender: TObject);
|
|
begin
|
|
OnPaint := nil;
|
|
if Assigned(ActiveFrame) then
|
|
ActiveFrame.SetFocus
|
|
else begin
|
|
DCDebug('ActiveFrame = nil');
|
|
end;
|
|
HiddenToTray := False;
|
|
end;
|
|
|
|
procedure TfrmMain.frmMainShow(Sender: TObject);
|
|
begin
|
|
DCDebug('frmMain.frmMainShow');
|
|
{$IF NOT (DEFINED(LCLWIN32) or DEFINED(LCLGTK2) or DEFINED(LCLCOCOA) OR (DEFINED(DARWIN) and DEFINED(LCLQT)))}
|
|
OnPaint := @frmMainAfterShow;
|
|
{$ELSE}
|
|
Application.QueueAsyncCall(TDataEvent(@frmMainAfterShow), 0);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrmMain.mnuDropClick(Sender: TObject);
|
|
var
|
|
DropParamsRef: TDropParams;
|
|
begin
|
|
if (Sender is TMenuItem) and Assigned(FDropParams) then
|
|
begin
|
|
// Make a copy of the reference to parameters and clear FDropParams,
|
|
// so that they're not destroyed if pmDropMenuClose is called while we're processing.
|
|
DropParamsRef := FDropParams;
|
|
FDropParams := nil; // release ownership
|
|
|
|
with DropParamsRef do
|
|
begin
|
|
if (Sender as TMenuItem).Name = 'miMove' then
|
|
begin
|
|
TargetPanel.DoDragDropOperation(ddoMove, DropParamsRef);
|
|
end
|
|
else if (Sender as TMenuItem).Name = 'miCopy' then
|
|
begin
|
|
TargetPanel.DoDragDropOperation(ddoCopy, DropParamsRef);
|
|
end
|
|
else if (Sender as TMenuItem).Name = 'miSymLink' then
|
|
begin
|
|
TargetPanel.DoDragDropOperation(ddoSymLink, DropParamsRef);
|
|
end
|
|
else if (Sender as TMenuItem).Name = 'miHardLink' then
|
|
begin
|
|
TargetPanel.DoDragDropOperation(ddoHardLink, DropParamsRef);
|
|
end
|
|
else if (Sender as TMenuItem).Name = 'miCancel' then
|
|
begin
|
|
FreeAndNil(DropParamsRef);
|
|
end;
|
|
end; //with
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.PopupDragDropMenu(var DropParams: TDropParams);
|
|
begin
|
|
// Disposing of the params is handled in pmDropMenuClose or mnuDropClick.
|
|
if Assigned(DropParams) then
|
|
begin
|
|
FDropParams := DropParams;
|
|
DropParams := nil;
|
|
pmDropMenu.PopUp(FDropParams.ScreenDropPoint.X,
|
|
FDropParams.ScreenDropPoint.Y);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.pmDropMenuClose(Sender: TObject);
|
|
begin
|
|
// Free drop parameters given to drop menu.
|
|
FreeAndNil(FDropParams);
|
|
end;
|
|
|
|
procedure TfrmMain.mnuSplitterPercentClick(Sender: TObject);
|
|
begin
|
|
with (Sender as TMenuItem) do
|
|
begin
|
|
Commands.DoPanelsSplitterPerPos(Tag);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.mnuTabMenuExecute(Sender: TObject);
|
|
begin
|
|
(Sender as TAction).OnExecute:= @actExecute;
|
|
end;
|
|
|
|
procedure TfrmMain.mnuTabMenuClick(Sender: TObject);
|
|
var
|
|
Cmd: String;
|
|
MenuItem: TMenuItem;
|
|
NoteBook: TFileViewNotebook;
|
|
begin
|
|
MenuItem := (Sender as TMenuItem);
|
|
NoteBook := (pmTabMenu.Parent as TFileViewNotebook);
|
|
|
|
// pmTabMenu.Tag stores tab page nr where the menu was activated.
|
|
|
|
if MenuItem = miCloseTab then
|
|
Commands.DoCloseTab(NoteBook, pmTabMenu.Tag)
|
|
else if MenuItem = miRenameTab then
|
|
Commands.DoRenameTab(NoteBook.Page[pmTabMenu.Tag])
|
|
else if MenuItem = miTabOptionNormal then
|
|
NoteBook.Page[pmTabMenu.Tag].LockState := tlsNormal
|
|
else if MenuItem = miTabOptionPathLocked then
|
|
NoteBook.Page[pmTabMenu.Tag].LockState := tlsPathLocked
|
|
else if MenuItem = miTabOptionPathResets then
|
|
NoteBook.Page[pmTabMenu.Tag].LockState := tlsPathResets
|
|
else if MenuItem = miTabOptionDirsInNewTab then
|
|
NoteBook.Page[pmTabMenu.Tag].LockState := tlsDirsInNewTab
|
|
else
|
|
begin
|
|
Cmd:= MenuItem.Action.Name;
|
|
Cmd:= 'cm_' + Copy(Cmd, 4, Length(Cmd) - 3);
|
|
|
|
Commands.Commands.ExecuteCommand(Cmd, NoteBook.Name);
|
|
end;
|
|
// On click first the OnClick and then the Action.OnExecute is called
|
|
MenuItem.Action.OnExecute:= @mnuTabMenuExecute;
|
|
end;
|
|
|
|
procedure TfrmMain.nbPageAfterMouseDown(Data: PtrInt);
|
|
var
|
|
Notebook: TFileViewNotebook;
|
|
begin
|
|
if TObject(Data) is TFileViewNotebook then
|
|
begin
|
|
Notebook := TObject(Data) as TFileViewNotebook;
|
|
|
|
if (Notebook = nbLeft) and (FrameLeft <> nil) then
|
|
begin
|
|
if PanelSelected = fpLeft then // same panel
|
|
FrameLeft.SetFocus
|
|
else if (tb_activate_panel_on_click in gDirTabOptions) then
|
|
SetActiveFrame(fpLeft)
|
|
else
|
|
FrameRight.SetFocus;
|
|
end;
|
|
if (Notebook = nbRight) and (FrameRight <> nil) then
|
|
begin
|
|
if PanelSelected = fpRight then // same panel
|
|
FrameRight.SetFocus
|
|
else if (tb_activate_panel_on_click in gDirTabOptions) then
|
|
SetActiveFrame(fpRight)
|
|
else
|
|
FrameLeft.SetFocus;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.nbPageMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
{$IFNDEF LCLCOCOA}
|
|
begin
|
|
{$ELSE}
|
|
var
|
|
Notebook: TFileViewNotebook;
|
|
TabNr: Integer;
|
|
begin
|
|
Notebook := TFileViewNotebook(Sender);
|
|
TabNr := Notebook.IndexOfPageAt(Point(X, Y));
|
|
if TabNr <> -1 then Notebook.ActivePageIndex := TabNr;
|
|
{$ENDIF}
|
|
Application.QueueAsyncCall(@nbPageAfterMouseDown, PtrInt(Sender));
|
|
end;
|
|
|
|
procedure TfrmMain.nbPageChanged(Sender: TObject);
|
|
var
|
|
Notebook: TFileViewNotebook;
|
|
Page: TFileViewPage;
|
|
begin
|
|
Notebook := Sender as TFileViewNotebook;
|
|
Page := Notebook.ActivePage;
|
|
if Assigned(Page) then
|
|
begin
|
|
if Page.LockState = tlsPathResets then // if locked with directory change
|
|
ChooseFileSource(Page.FileView, Page.LockPath);
|
|
|
|
// Update selected drive only on non-active panel,
|
|
// because active panel is updated on focus change.
|
|
if (PanelSelected <> Notebook.Side) and
|
|
not (tb_activate_panel_on_click in gDirTabOptions) then
|
|
begin
|
|
UpdateSelectedDrive(Notebook);
|
|
UpdateFreeSpace(Notebook.Side, True);
|
|
end;
|
|
end;
|
|
|
|
QuickViewClose;
|
|
if Visible then
|
|
UpdatePrompt;
|
|
UpdateTreeViewPath;
|
|
UpdateMainTitleBar;
|
|
end;
|
|
|
|
procedure TfrmMain.nbPageMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
PopUpPoint: TPoint;
|
|
NoteBook: TFileViewNotebook;
|
|
TabNr: Integer;
|
|
begin
|
|
NoteBook := Sender as TFileViewNotebook;
|
|
|
|
case Button of
|
|
|
|
mbMiddle:
|
|
begin
|
|
TabNr := NoteBook.IndexOfPageAt(Point(X, Y));
|
|
if TabNr <> -1 then
|
|
begin
|
|
Commands.DoCloseTab(NoteBook, TabNr);
|
|
end;
|
|
end;
|
|
|
|
mbRight:
|
|
begin
|
|
TabNr := NoteBook.IndexOfPageAt(Point(X, Y));
|
|
if TabNr <> -1 then
|
|
begin
|
|
PopUpPoint := NoteBook.ClientToScreen(Point(X, Y));
|
|
|
|
// Check tab options items.
|
|
case NoteBook.Page[TabNr].LockState of
|
|
tlsNormal:
|
|
miTabOptionNormal.Checked := True;
|
|
tlsPathLocked:
|
|
miTabOptionPathLocked.Checked := True;
|
|
tlsDirsInNewTab:
|
|
miTabOptionDirsInNewTab.Checked := True;
|
|
tlsPathResets:
|
|
miTabOptionPathResets.Checked := True;
|
|
end;
|
|
|
|
pmTabMenu.Parent := NoteBook;
|
|
pmTabMenu.Tag := TabNr;
|
|
pmTabMenu.PopUp(PopUpPoint.x, PopUpPoint.y);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.NotebookDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
var
|
|
ATabIndex: Integer;
|
|
TargetPath: String;
|
|
SourceFiles: TFiles;
|
|
TargetFileSource: IFileSource;
|
|
ANotebook: TFileViewNotebook absolute Sender;
|
|
begin
|
|
if (Source is TWinControl) and (TWinControl(Source).Parent is TFileView) then
|
|
begin
|
|
ATabIndex := ANotebook.IndexOfPageAt(Classes.Point(X, Y));
|
|
if (ATabIndex > -1) then
|
|
begin
|
|
SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles;
|
|
try
|
|
begin
|
|
TargetPath := ANotebook.View[ATabIndex].CurrentPath;
|
|
TargetFileSource := ANotebook.View[ATabIndex].FileSource;
|
|
case GetDropEffectByKeyAndMouse(GetKeyShiftStateEx, mbLeft) of
|
|
DropCopyEffect:
|
|
Self.CopyFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop);
|
|
DropMoveEffect:
|
|
Self.MoveFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop);
|
|
end;
|
|
end;
|
|
finally
|
|
SourceFiles.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.NotebookDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
var
|
|
ATabIndex: Integer;
|
|
APage: TFileViewPage;
|
|
ANotebook: TFileViewNotebook absolute Sender;
|
|
begin
|
|
Accept := False;
|
|
if (Source is TWinControl) and (TWinControl(Source).Parent is TFileView) then
|
|
begin
|
|
ATabIndex := ANotebook.IndexOfPageAt(Classes.Point(X, Y));
|
|
if (ATabIndex > -1) then
|
|
begin
|
|
APage:= ANotebook.Page[ATabIndex];
|
|
Accept := (APage.FileView <> TWinControl(Source).Parent) and
|
|
((APage.LockState = tlsNormal) or (APage.LockPath = APage.FileView.CurrentPath));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.NotebookCloseTabClicked(Sender: TObject);
|
|
begin
|
|
with (Sender As TFileViewPage) do
|
|
if PageIndex <> -1 then
|
|
begin
|
|
RemovePage(Notebook, PageIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ConvertIniToolbarItem(Loader: TKASToolBarIniLoader; var Item: TKASToolItem; const Shortcut: String);
|
|
procedure ConvertHotkeys(CommandItem: TKASCommandItem; Hotkeys: THotkeys; SearchHotkey: THotkey);
|
|
var
|
|
Hotkey: THotkey;
|
|
begin
|
|
Hotkey := Hotkeys.FindByContents(SearchHotkey);
|
|
if Assigned(Hotkey) then
|
|
begin
|
|
Hotkey.Command := 'cm_ExecuteToolbarItem';
|
|
Hotkey.Params := nil;
|
|
SetValue(Hotkey.Params, 'ToolItemID', CommandItem.ID);
|
|
end;
|
|
end;
|
|
var
|
|
HMForm: THMForm;
|
|
Hotkey: THotkey;
|
|
CommandItem: TKASCommandItem;
|
|
MenuItem: TKASMenuItem;
|
|
BarFileName: String;
|
|
begin
|
|
if Item is TKASCommandItem then
|
|
begin
|
|
CommandItem := TKASCommandItem(Item);
|
|
// Convert toolbar hotkey to use ID as parameter.
|
|
if Shortcut <> '' then
|
|
begin
|
|
Hotkey := THotkey.Create;
|
|
try
|
|
Hotkey.Command := 'cm_Int_RunCommandFromBarFile';
|
|
AddString(Hotkey.Shortcuts, Shortcut);
|
|
Hotkey.Params := Hotkey.Shortcuts;
|
|
HMForm := HotMan.Forms.Find('Main');
|
|
if Assigned(HMForm) then
|
|
ConvertHotkeys(CommandItem, HMForm.Hotkeys, Hotkey);
|
|
finally
|
|
Hotkey.Free;
|
|
end;
|
|
end;
|
|
|
|
if ((CommandItem.Command = 'cm_OpenBar') or
|
|
(CommandItem.Command = 'cm_ShowButtonMenu')) and
|
|
(Length(CommandItem.Params) > 0) then
|
|
begin
|
|
BarFileName := CommandItem.Params[0];
|
|
if Pos(PathDelim, BarFileName) <> 0 then
|
|
BarFileName := GetCmdDirFromEnvVar(BarFileName)
|
|
else
|
|
BarFileName := gpCfgDir + BarFileName;
|
|
if mbFileExists(BarFileName) then
|
|
begin
|
|
MenuItem := TKASMenuItem.Create;
|
|
MenuItem.Assign(Item); // Copy whatever is possible from Command item
|
|
Loader.Load(BarFileName, nil, MenuItem, @ConvertIniToolbarItem);
|
|
mbRenameFile(BarFileName, BarFileName + '.obsolete');
|
|
Item.Free;
|
|
Item := MenuItem;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FormKeyPress(Sender: TObject; var Key: Char);
|
|
var
|
|
ModifierKeys: TShiftState;
|
|
begin
|
|
// Either left or right panel has to be focused.
|
|
if not FrameLeft.Focused and
|
|
not FrameRight.Focused then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
ModifierKeys := GetKeyShiftStateEx;
|
|
|
|
if gCmdLine and // If command line is enabled
|
|
(GetKeyTypingAction(ModifierKeys) = ktaCommandLine) and
|
|
not ((Key in ['-', '*', '+', #0..#32]) and (Trim(edtCommand.Text) = '')) then
|
|
begin
|
|
TypeInCommandLine(Key);
|
|
Key := #0;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.ActiveFrame: TFileView;
|
|
begin
|
|
case PanelSelected of
|
|
fpLeft:
|
|
Result := FrameLeft;
|
|
fpRight:
|
|
Result := FrameRight;
|
|
else
|
|
assert(false,'Bad active frame');
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.NotActiveFrame: TFileView;
|
|
begin
|
|
case PanelSelected of
|
|
fpRight:
|
|
Result := FrameLeft;
|
|
fpLeft:
|
|
Result := FrameRight;
|
|
else
|
|
assert(false,'Bad active frame');
|
|
Result:=FrameLeft;// only for compilator warning;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.ActiveNotebook: TFileViewNotebook;
|
|
begin
|
|
case PanelSelected of
|
|
fpLeft:
|
|
Result := nbLeft;
|
|
fpRight:
|
|
Result := nbRight;
|
|
else
|
|
assert(false,'Bad active notebook');
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.NotActiveNotebook: TFileViewNotebook;
|
|
begin
|
|
case PanelSelected of
|
|
fpLeft:
|
|
Result := nbRight;
|
|
fpRight:
|
|
Result := nbLeft;
|
|
else
|
|
assert(false,'Bad active notebook');
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.FrameLeft: TFileView;
|
|
begin
|
|
Result := nbLeft.ActiveView;
|
|
end;
|
|
|
|
function TfrmMain.FrameRight: TFileView;
|
|
begin
|
|
Result := nbRight.ActiveView;
|
|
end;
|
|
|
|
procedure TfrmMain.ForEachView(CallbackFunction: TForEachViewFunction; UserData: Pointer);
|
|
procedure EnumerateNotebook(ANoteBook: TFileViewNotebook);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to ANoteBook.PageCount - 1 do
|
|
CallbackFunction(ANoteBook.View[i], UserData);
|
|
end;
|
|
begin
|
|
EnumerateNotebook(nbLeft);
|
|
EnumerateNotebook(nbRight);
|
|
end;
|
|
|
|
procedure TfrmMain.GetListOpenedPaths(const APaths: TStringList);
|
|
|
|
procedure GetNotebookPaths(ANoteBook: TFileViewNotebook);
|
|
var
|
|
S: String;
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to ANoteBook.PageCount - 1 do
|
|
begin
|
|
S:= ANoteBook.View[I].CurrentPath;
|
|
APaths.Add(S);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
APaths.Clear;
|
|
GetNotebookPaths(nbLeft);
|
|
GetNotebookPaths(nbRight);
|
|
end;
|
|
|
|
procedure TfrmMain.AppException(Sender: TObject; E: Exception);
|
|
begin
|
|
WriteExceptionToErrorFile;
|
|
ShowExceptionDialog;
|
|
end;
|
|
|
|
procedure TfrmMain.AppShowHint(var HintStr: string; var CanShow: Boolean;
|
|
var HintInfo: THintInfo);
|
|
begin
|
|
// Refresh monitor list
|
|
Screen.UpdateMonitors;
|
|
// Show hint only when application is active
|
|
CanShow:= Application.Active;
|
|
end;
|
|
|
|
constructor TfrmMain.Create(TheOwner: TComponent);
|
|
{$IF DEFINED(DARWIN)}
|
|
procedure setMacOSAppMenu();
|
|
begin
|
|
macOS_AppMenuIntf.aboutItem:= mnuHelpAbout;
|
|
macOS_AppMenuIntf.preferencesItem:= mnuConfigOptions;
|
|
end;
|
|
|
|
procedure setMacOSDockMenu();
|
|
var
|
|
dockMenu: TMenuItem;
|
|
newItem: TMenuItem;
|
|
begin
|
|
dockMenu:= TMenuItem.Create(self);
|
|
newItem:= TMenuItem.Create(dockMenu);
|
|
newItem.Caption:= rsMnuNewWindow;
|
|
newItem.OnClick:= @OpenNewWindow;
|
|
dockMenu.Add(newItem);
|
|
macOS_DockMenuIntf.customMenus:= dockMenu;
|
|
end;
|
|
{$ENDIF}
|
|
begin
|
|
FMainSplitterPos := 50.0;
|
|
inherited Create(TheOwner);
|
|
FCommands := TMainCommands.Create(Self, actionLst);
|
|
|
|
if Assigned(Application.Icon) then begin
|
|
MainTrayIcon.Icon.Assign(Application.Icon);
|
|
end;
|
|
|
|
Screen.Cursors[crArrowCopy] := LoadCursorFromLazarusResource('ArrowCopy');
|
|
Screen.Cursors[crArrowMove] := LoadCursorFromLazarusResource('ArrowMove');
|
|
Screen.Cursors[crArrowLink] := LoadCursorFromLazarusResource('ArrowLink');
|
|
|
|
{$IF DEFINED(DARWIN)}
|
|
setMacOSAppMenu;
|
|
setMacOSDockMenu;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrmMain.AfterConstruction;
|
|
begin
|
|
FResizingFilePanels:= True;
|
|
inherited AfterConstruction;
|
|
FResizingFilePanels:= False;
|
|
pnlNotebooksResize(pnlNotebooks);
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateActionIcons;
|
|
var
|
|
I: Integer;
|
|
imgIndex: Integer;
|
|
iconsDir: String;
|
|
fileName: String;
|
|
iconImg: TPicture;
|
|
actionName: TComponentName;
|
|
begin
|
|
if not gIconsInMenus then Exit;
|
|
|
|
actionLst.Images := nil;
|
|
pmTabMenu.Images := nil;
|
|
mnuMain.Images := nil;
|
|
imgLstActions.Clear;
|
|
|
|
// Temporarily while feature is not implemented
|
|
// http://doublecmd.sourceforge.net/mantisbt/view.php?id=11
|
|
fileName := IntToStr(gIconsInMenusSize);
|
|
iconsDir := gpPixmapPath + 'dctheme' + PathDelim + fileName;
|
|
iconsDir := iconsDir + 'x' + fileName + PathDelim + 'actions';
|
|
if not mbDirectoryExists(iconsDir) then Exit;
|
|
|
|
iconImg := TPicture.Create;
|
|
try
|
|
imgLstActions.Width := gIconsInMenusSize;
|
|
imgLstActions.Height := gIconsInMenusSize;
|
|
|
|
actionLst.Images := imgLstActions;
|
|
pmTabMenu.Images := imgLstActions;
|
|
mnuMain.Images := imgLstActions;
|
|
|
|
for I:= 0 to actionLst.ActionCount - 1 do
|
|
begin
|
|
actionName := UTF8LowerCase(actionLst.Actions[I].Name);
|
|
fileName := iconsDir + PathDelim + 'cm_' + UTF8Copy(actionName, 4, Length(actionName) - 3) + '.png';
|
|
if mbFileExists(fileName) then
|
|
try
|
|
iconImg.LoadFromFile(fileName);
|
|
imgIndex := imgLstActions.Add(iconImg.Bitmap, nil);
|
|
if imgIndex >= 0 then
|
|
begin
|
|
TAction(actionLst.Actions[I]).ImageIndex := imgIndex;
|
|
end;
|
|
except
|
|
// Skip
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(iconImg);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateHotDirIcons;
|
|
var
|
|
I: Integer;
|
|
iconsDir: String;
|
|
fileName: String;
|
|
iconImg: TPicture;
|
|
begin
|
|
pmHotList.Images:=nil; { TODO -oDB : The images of popup menu in configuration should also be nilled to be correct }
|
|
imgLstDirectoryHotlist.Clear;
|
|
|
|
fileName := IntToStr(gIconsInMenusSize);
|
|
iconsDir := gpPixmapPath + 'dctheme' + PathDelim + fileName;
|
|
iconsDir := iconsDir + 'x' + fileName + PathDelim + 'actions';
|
|
if not mbDirectoryExists(iconsDir) then Exit;
|
|
|
|
iconImg := TPicture.Create;
|
|
try
|
|
fileName := IntToStr(gIconsInMenusSize);
|
|
iconsDir := gpPixmapPath + 'dctheme' + PathDelim + fileName;
|
|
iconsDir := iconsDir + 'x' + fileName + PathDelim + 'dirhotlist';
|
|
imgLstDirectoryHotlist.Width := gIconsInMenusSize;
|
|
imgLstDirectoryHotlist.Height := gIconsInMenusSize;
|
|
pmHotList.Images:=imgLstDirectoryHotlist;
|
|
|
|
for I:=0 to pred(length(ICONINDEXNAME)) do
|
|
begin
|
|
filename:=iconsDir+PathDelim+ICONINDEXNAME[I]+'.png';
|
|
if mbFileExists(fileName) then
|
|
try
|
|
iconImg.LoadFromFile(fileName);
|
|
imgLstDirectoryHotlist.Add(iconImg.Bitmap, nil);
|
|
except
|
|
// Skip
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(iconImg);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.CreateDefaultToolbar;
|
|
var
|
|
AToolbar: TKASToolBar;
|
|
|
|
procedure AddCommand(const Command: String);
|
|
var
|
|
CommandItem: TKASCommandItem;
|
|
begin
|
|
CommandItem := TKASCommandItem.Create(Commands.Commands);
|
|
CommandItem.Icon := UTF8LowerCase(Command);
|
|
CommandItem.Command := Command;
|
|
// Leave CommandItem.Hint empty. It will be loaded at startup based on language.
|
|
AToolbar.AddButton(CommandItem);
|
|
end;
|
|
|
|
procedure AddSeparator(Style: Boolean = False);
|
|
var
|
|
SeparatorItem: TKASSeparatorItem;
|
|
begin
|
|
SeparatorItem:= TKASSeparatorItem.Create;
|
|
SeparatorItem.Style:= Style;
|
|
AToolbar.AddButton(SeparatorItem);
|
|
end;
|
|
|
|
var
|
|
MainToolBarNode: TXmlNode;
|
|
begin
|
|
if MainToolBar.ButtonCount = 0 then
|
|
begin
|
|
MainToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + MainToolBar.Name, False);
|
|
if not Assigned(MainToolBarNode) then
|
|
begin
|
|
AToolbar := MainToolBar;
|
|
AddCommand('cm_Refresh');
|
|
AddCommand('cm_RunTerm');
|
|
AddCommand('cm_Options');
|
|
AddSeparator;
|
|
AddCommand('cm_BriefView');
|
|
AddCommand('cm_ColumnsView');
|
|
AddCommand('cm_ThumbnailsView');
|
|
AddSeparator;
|
|
AddCommand('cm_FlatView');
|
|
AddSeparator;
|
|
AddCommand('cm_ViewHistoryPrev');
|
|
AddCommand('cm_ViewHistoryNext');
|
|
AddSeparator;
|
|
AddCommand('cm_MarkPlus');
|
|
AddCommand('cm_MarkMinus');
|
|
AddCommand('cm_MarkInvert');
|
|
AddSeparator;
|
|
AddCommand('cm_PackFiles');
|
|
AddCommand('cm_ExtractFiles');
|
|
AddSeparator;
|
|
AddCommand('cm_NetworkConnect');
|
|
AddCommand('cm_Search');
|
|
AddCommand('cm_MultiRename');
|
|
AddCommand('cm_SyncDirs');
|
|
AddCommand('cm_CopyFullNamesToClip');
|
|
SaveToolBar(MainToolBar);
|
|
end;
|
|
end;
|
|
if MiddleToolBar.ButtonCount = 0 then
|
|
begin
|
|
MainToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + MiddleToolBar.Name, False);
|
|
if not Assigned(MainToolBarNode) then
|
|
begin
|
|
AToolbar := MiddleToolBar;
|
|
AddCommand('cm_View');
|
|
AddCommand('cm_Edit');
|
|
AddCommand('cm_Copy');
|
|
AddCommand('cm_Rename');
|
|
AddSeparator(True);
|
|
AddCommand('cm_PackFiles');
|
|
AddCommand('cm_MakeDir');
|
|
SaveToolBar(MiddleToolBar);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.GetFileDlgStr(sLngOne, sLngMulti: String; Files: TFiles): String;
|
|
begin
|
|
if Files.Count = 0 then
|
|
raise Exception.Create(rsMsgNoFilesSelected);
|
|
|
|
if Files.Count > 1 then
|
|
Result := Format(sLngMulti, [Files.Count])
|
|
else
|
|
Result := Format(sLngOne, [Files[0].Name]);
|
|
end;
|
|
|
|
procedure TfrmMain.miHotAddOrConfigClick(Sender: TObject);
|
|
begin
|
|
with Sender as TComponent do Commands.cm_WorkWithDirectoryHotlist(['action='+HOTLISTMAGICWORDS[tag], 'source='+QuoteStr(ActiveFrame.CurrentLocation), 'target='+QuoteStr(NotActiveFrame.CurrentLocation), 'index=0']);
|
|
end;
|
|
|
|
procedure TfrmMain.CreatePopUpDirHistory(UseTreeViewMenu: Boolean;
|
|
FromPathIndex: Integer);
|
|
var
|
|
I, Finish: Integer;
|
|
MenuItem: TMenuItem;
|
|
begin
|
|
pmDirHistory.Items.Clear;
|
|
|
|
if UseTreeViewMenu then
|
|
Finish:= glsDirHistory.Count - 1
|
|
else begin
|
|
Finish:= Min(FromPathIndex + gDirHistoryCount, glsDirHistory.Count - 1);
|
|
end;
|
|
|
|
if (not UseTreeViewMenu) and (FromPathIndex > 0) then
|
|
begin
|
|
MenuItem := TMenuItem.Create(pmDirHistory);
|
|
MenuItem.Caption := '...';
|
|
MenuItem.OnClick := @HistorySomeSelected;
|
|
MenuItem.Tag := Max(0, FromPathIndex - gDirHistoryCount - 1);
|
|
pmDirHistory.Items.Add(MenuItem);
|
|
end;
|
|
|
|
for I:= FromPathIndex to Finish do
|
|
begin
|
|
MenuItem:= TMenuItem.Create(pmDirHistory);
|
|
MenuItem.Caption:= glsDirHistory[I].Replace('&','&&');
|
|
MenuItem.Hint:= glsDirHistory[I];
|
|
MenuItem.OnClick:= @HistorySelected;
|
|
pmDirHistory.Items.Add(MenuItem);
|
|
end;
|
|
|
|
if (not UseTreeViewMenu) and (Finish < glsDirHistory.Count - 1) then
|
|
begin
|
|
MenuItem := TMenuItem.Create(pmDirHistory);
|
|
MenuItem.Caption := '...';
|
|
MenuItem.OnClick := @HistorySomeSelected;
|
|
MenuItem.Tag := Finish + 1;
|
|
pmDirHistory.Items.Add(MenuItem);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ShowFileViewHistory(const Params: array of string);
|
|
begin
|
|
ShowFileViewHistory(Params, -1, -1, -1, -1);
|
|
end;
|
|
|
|
procedure TfrmMain.ShowFileViewHistory(const Params: array of string; FromFileSourceIndex, FromPathIndex, ToFileSourceIndex, ToPathIndex: Integer);
|
|
const
|
|
MaxItemsShown = 20;
|
|
var
|
|
ItemsBackward: Integer = 0;
|
|
ItemsForward: Integer = 0;
|
|
|
|
function GoBack(var FileSourceIndex, PathIndex: Integer): Boolean;
|
|
begin
|
|
if PathIndex = 0 then
|
|
begin
|
|
if FileSourceIndex = 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Dec(FileSourceIndex);
|
|
PathIndex := ActiveFrame.PathsCount[FileSourceIndex] - 1;
|
|
Result := True;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Dec(PathIndex);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
function GoForward(var FileSourceIndex, PathIndex: Integer): Boolean;
|
|
begin
|
|
if PathIndex = ActiveFrame.PathsCount[FileSourceIndex] - 1 then
|
|
begin
|
|
if FileSourceIndex = ActiveFrame.FileSourcesCount - 1 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Inc(FileSourceIndex);
|
|
PathIndex := 0;
|
|
Result := True;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Inc(PathIndex);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure AddCaptionItem(s: String);
|
|
var
|
|
mi: TMenuItem;
|
|
begin
|
|
mi := TMenuItem.Create(pmDirHistory);
|
|
mi.Caption := s;
|
|
mi.Enabled := False;
|
|
pmDirHistory.Items.Add(mi);
|
|
end;
|
|
|
|
procedure FindBoundsBackward;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
GoBack(ToFileSourceIndex, ToPathIndex);
|
|
|
|
FromFileSourceIndex := ToFileSourceIndex;
|
|
FromPathIndex := ToPathIndex;
|
|
|
|
for i := 0 to MaxItemsShown - 1 do
|
|
begin
|
|
if GoBack(FromFileSourceIndex, FromPathIndex) then
|
|
Inc(ItemsBackward);
|
|
end;
|
|
end;
|
|
|
|
procedure FindBoundsFromCenter;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FromFileSourceIndex := ActiveFrame.CurrentFileSourceIndex;
|
|
FromPathIndex := ActiveFrame.CurrentPathIndex;
|
|
ToFileSourceIndex := FromFileSourceIndex;
|
|
ToPathIndex := FromPathIndex;
|
|
|
|
for i := 0 to (MaxItemsShown div 2) - 1 do
|
|
begin
|
|
if GoBack(FromFileSourceIndex, FromPathIndex) then
|
|
Inc(ItemsBackward);
|
|
if GoForward(ToFileSourceIndex, ToPathIndex) then
|
|
Inc(ItemsForward);
|
|
end;
|
|
|
|
for i := ItemsForward to (MaxItemsShown div 2) - 1 do
|
|
begin
|
|
if GoBack(FromFileSourceIndex, FromPathIndex) then
|
|
Inc(ItemsBackward);
|
|
end;
|
|
|
|
for i := ItemsBackward to (MaxItemsShown div 2) - 1 do
|
|
begin
|
|
if GoForward(ToFileSourceIndex, ToPathIndex) then
|
|
Inc(ItemsForward);
|
|
end;
|
|
end;
|
|
|
|
procedure FindBoundsForward;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
GoForward(FromFileSourceIndex, FromPathIndex);
|
|
|
|
ToFileSourceIndex := FromFileSourceIndex;
|
|
ToPathIndex := FromPathIndex;
|
|
|
|
for i := 0 to MaxItemsShown - 1 do
|
|
begin
|
|
if GoForward(ToFileSourceIndex, ToPathIndex) then
|
|
Inc(ItemsForward);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
bUseTreeViewMenu: boolean = false;
|
|
bUsePanel: boolean = false; // As opposed as the other popup, for that one, by legacy, the position of the popup is the cursor position instead of top left corner of active panel.
|
|
p: TPoint;
|
|
iWantedWidth: integer = 0;
|
|
iWantedHeight: integer = 0;
|
|
sMaybeMenuItem: TMenuItem = nil;
|
|
I: Integer;
|
|
mi: TMenuItem;
|
|
begin
|
|
pmDirHistory.Items.Clear;
|
|
p.x := 0;
|
|
p.y := 0;
|
|
|
|
if FromFileSourceIndex <> -1 then
|
|
FindBoundsForward
|
|
else if ToFileSourceIndex <> - 1 then
|
|
FindBoundsBackward
|
|
else
|
|
FindBoundsFromCenter;
|
|
|
|
if (FromFileSourceIndex > 0) or (FromPathIndex > 0) then
|
|
begin
|
|
mi := TMenuItem.Create(pmDirHistory);
|
|
mi.Caption := '...';
|
|
mi.OnClick := @ViewHistoryPrevSelected;
|
|
mi.Tag := HistoryIndexesToTag(FromFileSourceIndex, FromPathIndex);
|
|
pmDirHistory.Items.Add(mi);
|
|
end;
|
|
|
|
for i := 0 to ItemsForward + ItemsBackward do
|
|
begin
|
|
mi := TMenuItem.Create(pmDirHistory);
|
|
pmDirHistory.Items.Add(mi);
|
|
|
|
mi.Caption := ActiveFrame.Path[FromFileSourceIndex, FromPathIndex].Replace('&','&&');
|
|
mi.OnClick := @ViewHistorySelected;
|
|
// Remember indexes into history.
|
|
mi.Tag := HistoryIndexesToTag(FromFileSourceIndex, FromPathIndex);
|
|
// Mark current history position.
|
|
if (FromFileSourceIndex = ActiveFrame.CurrentFileSourceIndex) and
|
|
(FromPathIndex = ActiveFrame.CurrentPathIndex) then
|
|
mi.Checked := True;
|
|
|
|
if not GoForward(FromFileSourceIndex, FromPathIndex) then
|
|
Break;
|
|
|
|
// Add separator and address of a file source as a caption.
|
|
if FromPathIndex = 0 then
|
|
begin
|
|
AddCaptionItem('-');
|
|
AddCaptionItem('- ' + ActiveFrame.FileSources[FromFileSourceIndex].CurrentAddress.Replace('&','&&') + ' -');
|
|
end;
|
|
end;
|
|
|
|
if (ToFileSourceIndex < ActiveFrame.FileSourcesCount - 1) or
|
|
(ToPathIndex < ActiveFrame.PathsCount[ToFileSourceIndex] - 1) then
|
|
begin
|
|
mi := TMenuItem.Create(pmDirHistory);
|
|
mi.Caption := '...';
|
|
mi.OnClick := @ViewHistoryNextSelected;
|
|
mi.Tag := HistoryIndexesToTag(ToFileSourceIndex, ToPathIndex);
|
|
pmDirHistory.Items.Add(mi);
|
|
end;
|
|
|
|
Application.ProcessMessages;
|
|
|
|
// 1. Let's parse our parameters.
|
|
Commands.DoParseParametersForPossibleTreeViewMenu(Params, gUseTreeViewMenuWithViewHistory, gUseTreeViewMenuWithViewHistory, bUseTreeViewMenu, bUsePanel, p);
|
|
|
|
// 2. Show the appropriate menu.
|
|
if bUseTreeViewMenu then
|
|
begin
|
|
if not bUsePanel then
|
|
iWantedHeight := 0
|
|
else
|
|
begin
|
|
iWantedWidth := frmMain.ActiveFrame.Width;
|
|
iWantedHeight := frmMain.ActiveFrame.Height;
|
|
end;
|
|
|
|
sMaybeMenuItem := GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu(pmDirHistory, tvmcViewHistory, p.X, p.Y, iWantedWidth, iWantedHeight);
|
|
if sMaybeMenuItem <> nil then sMaybeMenuItem.OnClick(sMaybeMenuItem);
|
|
end
|
|
else
|
|
begin
|
|
pmDirHistory.Popup(p.X, p.Y);
|
|
end;
|
|
end;
|
|
|
|
{ TfrmMain.HotDirActualSwitchToDir }
|
|
// Actual routine called when user click the item from the Directory Hotlist popup menu to switch to a hot directory
|
|
// The index received is the index from the "gDirectoryHotlist" to read hotdir entry from.
|
|
//
|
|
procedure TfrmMain.HotDirActualSwitchToDir(Index:longint);
|
|
var
|
|
aPath: String;
|
|
isSHIFTDown, isCTRLDown: boolean;
|
|
PossibleCommande,PossibleParam: string;
|
|
PosFirstSpace: integer;
|
|
Editor: TOptionsEditor;
|
|
Options: IOptionsDialog;
|
|
begin
|
|
// This handler is used by HotDir AND SpecialDir.
|
|
// HotDirs AND SpecialDirs are only supported by filesystem.
|
|
|
|
// If the index is larger or equal to "TAGOFFSET_FORCHANGETOSPECIALDIR", it means it's a "SpecialDir" and we'll change accordingly
|
|
if (Index < TAGOFFSET_FORCHANGETOSPECIALDIR) AND (Index >= 0) then
|
|
begin
|
|
isSHIFTDown:=((GetKeyState(VK_SHIFT) AND $80) <> 0);
|
|
if not isSHIFTDown then //if SHIFT is NOT down, it's to change directory
|
|
begin
|
|
case gDirectoryHotlist.HotDir[Index].Dispatcher of
|
|
hd_CHANGEPATH:
|
|
begin
|
|
isCTRLDown:=((GetKeyState(VK_CONTROL) AND $80) <> 0); //if CTRL is down, it's to request to DON'T CHANGE TARGET even if in the directoryhotlist entry it was requesting to do so
|
|
|
|
aPath := gDirectoryHotlist.HotDir[Index].HotDirPath;
|
|
if aPath<>'' then
|
|
begin
|
|
case gDirectoryHotlist.HotDir[Index].HotDirPathSort of
|
|
1: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_NAME,STR_ASCENDING]); //Name, a-z
|
|
2: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_NAME,STR_DESCENDING]); //Name, z-a
|
|
3: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_EXTENSION,STR_ASCENDING]); //Ext, a-z
|
|
4: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_EXTENSION,STR_DESCENDING]); //Ext, z-a
|
|
5: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_SIZE,STR_DESCENDING]); //Size 9-0
|
|
6: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_SIZE,STR_ASCENDING]); //Size 0-9
|
|
7: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_DESCENDING]); //Date 9-0
|
|
8: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_ASCENDING]); //Date 0-9
|
|
end;
|
|
|
|
aPath := mbExpandFileName(aPath);
|
|
ChooseFileSource(ActiveFrame, aPath);
|
|
|
|
if (not isCTRLDown) then //We don't change target folder if CTRL key is pressed
|
|
begin
|
|
aPath := gDirectoryHotlist.HotDir[Index].HotDirTarget;
|
|
if aPath<>'' then
|
|
begin
|
|
case gDirectoryHotlist.HotDir[Index].HotDirTargetSort of
|
|
1: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_NAME,STR_ASCENDING]); //Name, a-z
|
|
2: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_NAME,STR_DESCENDING]); //Name, z-a
|
|
3: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_EXTENSION,STR_ASCENDING]); //Ext, a-z
|
|
4: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_EXTENSION,STR_DESCENDING]); //Ext, z-a
|
|
5: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_SIZE,STR_DESCENDING]); //Size 9-0
|
|
6: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_SIZE,STR_ASCENDING]); //Size 0-9
|
|
7: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_DESCENDING]); //Date 9-0
|
|
8: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_ASCENDING]); //Date 0-9
|
|
end;
|
|
|
|
aPath := mbExpandFileName(aPath);
|
|
ChooseFileSource(NotActiveFrame, aPath);
|
|
end;
|
|
end;
|
|
end;
|
|
end; //hd_CHANGEPATH:
|
|
|
|
hd_COMMAND:
|
|
begin
|
|
PosFirstSpace:=pos(' ',gDirectoryHotlist.HotDir[Index].HotDirPath);
|
|
|
|
if PosFirstSpace=0 then
|
|
begin
|
|
PossibleCommande:=gDirectoryHotlist.HotDir[Index].HotDirPath;
|
|
PossibleParam:='';
|
|
end
|
|
else
|
|
begin
|
|
PossibleCommande:=leftstr(gDirectoryHotlist.HotDir[Index].HotDirPath,(PosFirstSpace-1));
|
|
PossibleParam:=rightstr(gDirectoryHotlist.HotDir[Index].HotDirPath,length(gDirectoryHotlist.HotDir[Index].HotDirPath)-PosFirstSpace);
|
|
end;
|
|
|
|
Commands.Commands.ExecuteCommand(PossibleCommande, SplitString(PossibleParam,' '));
|
|
end;
|
|
end; //case gDirectoryHotlist.HotDir[Index].Dispatcher of
|
|
end
|
|
else
|
|
begin //if SHIFT IS down, it's to EDIT current selected entry from the Directory Hotlist that the current selected popup menu selection is pointing.
|
|
Options := ShowOptions(TfrmOptionsDirectoryHotlist);
|
|
Editor := Options.GetEditor(TfrmOptionsDirectoryHotlist);
|
|
Application.ProcessMessages;
|
|
if Editor.CanFocus then Editor.SetFocus;
|
|
TfrmOptionsDirectoryHotlist(Editor).SubmitToAddOrConfigToHotDirDlg(ACTION_DIRECTLYCONFIGENTRY,ActiveFrame.CurrentPath,NotActiveFrame.CurrentPath,Index);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if Index>=0 then
|
|
begin
|
|
//So it's a SpecialDir...
|
|
Index:=Index-TAGOFFSET_FORCHANGETOSPECIALDIR;
|
|
aPath := mbExpandFileName((gSpecialDirList.SpecialDir[Index].PathValue));
|
|
ChooseFileSource(ActiveFrame, aPath);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.HotDirSelected(Sender: TObject);
|
|
begin
|
|
HotDirActualSwitchToDir((Sender as TMenuItem).Tag);
|
|
end;
|
|
|
|
procedure TfrmMain.HistorySelected(Sender: TObject);
|
|
var
|
|
aPath: String;
|
|
begin
|
|
// This handler is used by DirHistory.
|
|
aPath := (Sender as TMenuItem).Hint;
|
|
aPath := mbExpandFileName(aPath);
|
|
ChooseFileSource(ActiveFrame, aPath);
|
|
end;
|
|
|
|
procedure TfrmMain.HistorySomeSelected(Sender: TObject);
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
if Sender is TMenuItem then
|
|
begin
|
|
P:= ActiveFrame.ClientToScreen(Classes.Point(0, 0));
|
|
CreatePopUpDirHistory(False, TMenuItem(Sender).Tag);
|
|
pmDirHistory.Popup(P.X, P.Y);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ViewHistorySelected(Sender: TObject);
|
|
var
|
|
FileSourceIndex, PathIndex: Integer;
|
|
begin
|
|
if Sender is TMenuItem then
|
|
begin
|
|
HistoryIndexesFromTag((Sender as TMenuItem).Tag, FileSourceIndex, PathIndex);
|
|
ActiveFrame.GoToHistoryIndex(FileSourceIndex, PathIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ViewHistoryPrevSelected(Sender:TObject);
|
|
var
|
|
FileSourceIndex, PathIndex: Integer;
|
|
begin
|
|
if Sender is TMenuItem then
|
|
begin
|
|
HistoryIndexesFromTag((Sender as TMenuItem).Tag, FileSourceIndex, PathIndex);
|
|
ShowFileViewHistory([], -1, -1, FileSourceIndex, PathIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ViewHistoryNextSelected(Sender:TObject);
|
|
var
|
|
FileSourceIndex, PathIndex: Integer;
|
|
begin
|
|
if Sender is TMenuItem then
|
|
begin
|
|
HistoryIndexesFromTag((Sender as TMenuItem).Tag, FileSourceIndex, PathIndex);
|
|
ShowFileViewHistory([], FileSourceIndex, PathIndex, -1, -1);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.edtCommandKeyUp(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
if (key=VK_Down) and (Shift=[ssCtrl]) and (edtCommand.Items.Count>0) then
|
|
begin
|
|
Key:=0;
|
|
edtCommand.DroppedDown:=True;
|
|
edtCommand.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.OnCopyOutTempStateChanged(Operation: TFileSourceOperation;
|
|
State: TFileSourceOperationState);
|
|
begin
|
|
FModalOperationResult:= Operation.Result = fsorFinished;
|
|
end;
|
|
|
|
function TfrmMain.CopyFiles(SourceFileSource, TargetFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String;
|
|
bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier): Boolean;
|
|
var
|
|
BaseDir: String;
|
|
sDestination: String;
|
|
sDstMaskTemp: String;
|
|
FileSource: IFileSource;
|
|
TargetFiles: TFiles = nil;
|
|
CopyDialog: TfrmCopyDlg = nil;
|
|
OperationTemp: Boolean = False;
|
|
OperationType: TFileSourceOperationType;
|
|
OperationClass: TFileSourceOperationClass;
|
|
Operation: TFileSourceCopyOperation = nil;
|
|
OperationOptionsUIClass: TFileSourceOperationOptionsUIClass = nil;
|
|
begin
|
|
Result := False;
|
|
try
|
|
if SourceFiles.Count = 0 then
|
|
Exit;
|
|
|
|
if (SourceFiles.Count = 1) and
|
|
((not (SourceFiles[0].IsDirectory or SourceFiles[0].IsLinkToDirectory)) or
|
|
(TargetPath = ''))
|
|
then
|
|
sDestination := TargetPath + ReplaceInvalidChars(SourceFiles[0].Name)
|
|
else
|
|
sDestination := TargetPath + '*.*';
|
|
|
|
// If same file source and address
|
|
if (fsoCopy in SourceFileSource.GetOperationsTypes) and
|
|
(fsoCopy in TargetFileSource.GetOperationsTypes) and
|
|
SourceFileSource.Equals(TargetFileSource) and
|
|
SameText(SourceFileSource.GetCurrentAddress, TargetFileSource.GetCurrentAddress) then
|
|
begin
|
|
OperationType := fsoCopy;
|
|
FileSource := SourceFileSource;
|
|
OperationClass := SourceFileSource.GetOperationClass(fsoCopy);
|
|
end
|
|
else if TargetFileSource.IsClass(TFileSystemFileSource) and
|
|
(fsoCopyOut in SourceFileSource.GetOperationsTypes) then
|
|
begin
|
|
OperationType := fsoCopyOut;
|
|
FileSource := SourceFileSource;
|
|
OperationClass := SourceFileSource.GetOperationClass(fsoCopyOut);
|
|
end
|
|
else if SourceFileSource.IsClass(TFileSystemFileSource) and
|
|
(fsoCopyIn in TargetFileSource.GetOperationsTypes) then
|
|
begin
|
|
OperationType := fsoCopyIn;
|
|
FileSource := TargetFileSource;
|
|
OperationClass := TargetFileSource.GetOperationClass(fsoCopyIn);
|
|
end
|
|
else if (fsoCopyOut in SourceFileSource.GetOperationsTypes) and
|
|
(fsoCopyIn in TargetFileSource.GetOperationsTypes) then
|
|
begin
|
|
OperationTemp := True;
|
|
OperationType := fsoCopyOut;
|
|
FileSource := SourceFileSource;
|
|
OperationClass := SourceFileSource.GetOperationClass(fsoCopyOut);
|
|
if (fspCopyOutOnMainThread in SourceFileSource.Properties) or
|
|
(fspCopyInOnMainThread in TargetFileSource.Properties) then
|
|
begin
|
|
QueueIdentifier:= ModalQueueId;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
msgWarning(rsMsgErrNotSupported);
|
|
Exit;
|
|
end;
|
|
|
|
if bShowDialog then
|
|
begin
|
|
if Assigned(OperationClass) then
|
|
OperationOptionsUIClass := OperationClass.GetOptionsUIClass;
|
|
|
|
CopyDialog := TfrmCopyDlg.Create(Self, cmdtCopy, FileSource, OperationOptionsUIClass);
|
|
CopyDialog.edtDst.Text := sDestination;
|
|
CopyDialog.edtDst.ReadOnly := OperationTemp;
|
|
CopyDialog.lblCopySrc.Caption := GetFileDlgStr(rsMsgCpSel, rsMsgCpFlDr, SourceFiles);
|
|
|
|
if OperationTemp and (QueueIdentifier = ModalQueueId) then
|
|
begin
|
|
CopyDialog.QueueIdentifier:= QueueIdentifier;
|
|
CopyDialog.btnAddToQueue.Visible:= False;
|
|
CopyDialog.btnCreateSpecialQueue.Visible:= False;
|
|
CopyDialog.btnOptions.Visible:= False;
|
|
end;
|
|
|
|
while True do
|
|
begin
|
|
if CopyDialog.ShowModal = mrCancel then
|
|
Exit;
|
|
|
|
sDestination := CopyDialog.edtDst.Text;
|
|
|
|
if SourceFileSource.IsClass(TArchiveFileSource) then
|
|
BaseDir := ExtractFilePath(SourceFileSource.CurrentAddress)
|
|
else begin
|
|
BaseDir := SourceFiles.Path;
|
|
end;
|
|
|
|
GetDestinationPathAndMask(SourceFiles, SourceFileSource,
|
|
TargetFileSource, sDestination,
|
|
BaseDir, TargetPath, sDstMaskTemp);
|
|
|
|
if (TargetFileSource = nil) or (Length(TargetPath) = 0) then
|
|
begin
|
|
MessageDlg(rsMsgInvalidPath, rsMsgErrNotSupported, mtWarning, [mbOK], 0);
|
|
Continue;
|
|
end;
|
|
|
|
if HasPathInvalidCharacters(TargetPath) then
|
|
MessageDlg(rsMsgInvalidPath, Format(rsMsgInvalidPathLong, [TargetPath]),
|
|
mtWarning, [mbOK], 0)
|
|
else
|
|
Break;
|
|
end;
|
|
|
|
QueueIdentifier := CopyDialog.QueueIdentifier;
|
|
end
|
|
else
|
|
GetDestinationPathAndMask(SourceFiles, TargetFileSource, sDestination,
|
|
SourceFiles.Path, TargetPath, sDstMaskTemp);
|
|
|
|
// Copy via temp directory
|
|
if OperationTemp then
|
|
begin
|
|
// Execute both operations in one new queue
|
|
if QueueIdentifier = FreeOperationsQueueId then
|
|
QueueIdentifier := OperationsManager.GetNewQueueIdentifier;
|
|
// Save real target
|
|
sDestination := TargetPath;
|
|
FileSource := TargetFileSource;
|
|
TargetFiles := SourceFiles.Clone;
|
|
// Replace target by temp directory
|
|
TargetFileSource := TTempFileSystemFileSource.Create();
|
|
TargetPath := TargetFileSource.GetRootDir;
|
|
ChangeFileListRoot(TargetPath, TargetFiles);
|
|
end;
|
|
|
|
case OperationType of
|
|
fsoCopy:
|
|
begin
|
|
// Copy within the same file source.
|
|
Operation := SourceFileSource.CreateCopyOperation(
|
|
SourceFiles,
|
|
TargetPath) as TFileSourceCopyOperation;
|
|
end;
|
|
fsoCopyOut:
|
|
// CopyOut to filesystem.
|
|
Operation := SourceFileSource.CreateCopyOutOperation(
|
|
TargetFileSource,
|
|
SourceFiles,
|
|
TargetPath) as TFileSourceCopyOperation;
|
|
fsoCopyIn:
|
|
// CopyIn from filesystem.
|
|
Operation := TargetFileSource.CreateCopyInOperation(
|
|
SourceFileSource,
|
|
SourceFiles,
|
|
TargetPath) as TFileSourceCopyOperation;
|
|
end;
|
|
|
|
if Assigned(Operation) then
|
|
begin
|
|
// Set operation options based on settings in dialog.
|
|
Operation.RenameMask := sDstMaskTemp;
|
|
|
|
if Assigned(CopyDialog) then
|
|
CopyDialog.SetOperationOptions(Operation);
|
|
|
|
if OperationTemp and (QueueIdentifier = ModalQueueId) then
|
|
begin
|
|
Operation.AddStateChangedListener([fsosStopped], @OnCopyOutTempStateChanged);
|
|
end;
|
|
|
|
// Start operation.
|
|
OperationsManager.AddOperation(Operation, QueueIdentifier, False, True);
|
|
Result := True;
|
|
end
|
|
else
|
|
msgWarning(rsMsgNotImplemented);
|
|
|
|
// Copy via temp directory
|
|
if OperationTemp and Result and ((QueueIdentifier <> ModalQueueId) or FModalOperationResult) then
|
|
begin
|
|
// CopyIn from temp filesystem
|
|
Operation := FileSource.CreateCopyInOperation(
|
|
TargetFileSource,
|
|
TargetFiles,
|
|
sDestination) as TFileSourceCopyOperation;
|
|
|
|
Result := Assigned(Operation);
|
|
if Result then
|
|
begin
|
|
if Assigned(CopyDialog) then
|
|
CopyDialog.SetOperationOptions(Operation);
|
|
|
|
// Start operation.
|
|
OperationsManager.AddOperation(Operation, QueueIdentifier, False, True);
|
|
end;
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(TargetFiles);
|
|
FreeAndNil(SourceFiles);
|
|
FreeAndNil(CopyDialog);
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.MoveFiles(SourceFileSource, TargetFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String;
|
|
bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean;
|
|
var
|
|
sDestination: String;
|
|
sDstMaskTemp: String;
|
|
Operation: TFileSourceMoveOperation;
|
|
bMove: Boolean;
|
|
MoveDialog: TfrmCopyDlg = nil;
|
|
begin
|
|
Result := False;
|
|
try
|
|
// Special case for Search Result File Source
|
|
if SourceFileSource.IsClass(TSearchResultFileSource) then begin
|
|
SourceFileSource:= ISearchResultFileSource(SourceFileSource).FileSource;
|
|
end;
|
|
// Only allow moving within the same file source.
|
|
if (SourceFileSource.IsInterface(TargetFileSource) or
|
|
TargetFileSource.IsInterface(SourceFileSource)) and
|
|
(SourceFileSource.CurrentAddress = TargetFileSource.CurrentAddress) and
|
|
(fsoMove in SourceFileSource.GetOperationsTypes) and
|
|
(fsoMove in TargetFileSource.GetOperationsTypes) then
|
|
begin
|
|
bMove := True;
|
|
end
|
|
else if ((fsoCopyOut in SourceFileSource.GetOperationsTypes) and
|
|
(fsoCopyIn in TargetFileSource.GetOperationsTypes)) then
|
|
begin
|
|
bMove := False; // copy + delete through temporary file system
|
|
msgWarning(rsMsgNotImplemented);
|
|
Exit;
|
|
end
|
|
else
|
|
begin
|
|
msgWarning(rsMsgErrNotSupported);
|
|
Exit;
|
|
end;
|
|
|
|
if SourceFiles.Count = 0 then
|
|
Exit;
|
|
|
|
if (SourceFiles.Count = 1) and
|
|
(not (SourceFiles[0].IsDirectory or SourceFiles[0].IsLinkToDirectory))
|
|
then
|
|
sDestination := TargetPath + ExtractFileName(SourceFiles[0].Name)
|
|
else
|
|
sDestination := TargetPath + '*.*';
|
|
|
|
if bShowDialog then
|
|
begin
|
|
MoveDialog := TfrmCopyDlg.Create(Self, cmdtMove, SourceFileSource,
|
|
SourceFileSource.GetOperationClass(fsoMove).GetOptionsUIClass);
|
|
MoveDialog.edtDst.Text := sDestination;
|
|
MoveDialog.lblCopySrc.Caption := GetFileDlgStr(rsMsgRenSel, rsMsgRenFlDr, SourceFiles);
|
|
|
|
while True do
|
|
begin
|
|
if MoveDialog.ShowModal = mrCancel then
|
|
Exit;
|
|
|
|
sDestination := MoveDialog.edtDst.Text;
|
|
|
|
GetDestinationPathAndMask(SourceFiles, SourceFileSource,
|
|
TargetFileSource, sDestination,
|
|
SourceFiles.Path, TargetPath, sDstMaskTemp);
|
|
|
|
if (TargetFileSource = nil) or (Length(TargetPath) = 0) then
|
|
begin
|
|
MessageDlg(EmptyStr, rsMsgInvalidPath, mtWarning, [mbOK], 0);
|
|
Continue;
|
|
end;
|
|
|
|
if HasPathInvalidCharacters(TargetPath) then
|
|
MessageDlg(rsMsgInvalidPath, Format(rsMsgInvalidPathLong, [TargetPath]),
|
|
mtWarning, [mbOK], 0)
|
|
else
|
|
Break;
|
|
end;
|
|
|
|
QueueIdentifier := MoveDialog.QueueIdentifier;
|
|
end
|
|
else
|
|
GetDestinationPathAndMask(SourceFiles, TargetFileSource, sDestination,
|
|
SourceFiles.Path, TargetPath, sDstMaskTemp);
|
|
|
|
if bMove then
|
|
begin
|
|
Operation := SourceFileSource.CreateMoveOperation(
|
|
SourceFiles, TargetPath) as TFileSourceMoveOperation;
|
|
|
|
if Assigned(Operation) then
|
|
begin
|
|
// Set operation options based on settings in dialog.
|
|
Operation.RenameMask := sDstMaskTemp;
|
|
|
|
if Assigned(MoveDialog) then
|
|
MoveDialog.SetOperationOptions(Operation);
|
|
|
|
// Start operation.
|
|
OperationsManager.AddOperation(Operation, QueueIdentifier, False, True);
|
|
Result := True;
|
|
end
|
|
else
|
|
msgWarning(rsMsgNotImplemented);
|
|
end
|
|
else
|
|
begin
|
|
// Use CopyOut, CopyIn operations.
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(SourceFiles);
|
|
FreeAndNil(MoveDialog);
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.CopyFiles(sDestPath: String; bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean;
|
|
var
|
|
FileSource: IFileSource;
|
|
SourceFiles: TFiles = nil;
|
|
begin
|
|
SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles;
|
|
if Assigned(SourceFiles) then
|
|
begin
|
|
if Length(sDestPath) > 0 then
|
|
FileSource := NotActiveFrame.FileSource
|
|
else begin
|
|
FileSource := ActiveFrame.FileSource;
|
|
end;
|
|
try
|
|
Result := CopyFiles(ActiveFrame.FileSource, FileSource,
|
|
SourceFiles, sDestPath, bShowDialog, QueueIdentifier);
|
|
if Result then
|
|
ActiveFrame.MarkFiles(False);
|
|
|
|
finally
|
|
FreeAndNil(SourceFiles);
|
|
end;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TfrmMain.MoveFiles(sDestPath: String; bShowDialog: Boolean;
|
|
QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean;
|
|
var
|
|
SourceFiles: TFiles = nil;
|
|
begin
|
|
SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles;
|
|
if Assigned(SourceFiles) then
|
|
begin
|
|
try
|
|
Result := MoveFiles(ActiveFrame.FileSource, NotActiveFrame.FileSource,
|
|
SourceFiles, sDestPath, bShowDialog, QueueIdentifier);
|
|
if Result then
|
|
ActiveFrame.MarkFiles(False);
|
|
|
|
finally
|
|
FreeAndNil(SourceFiles);
|
|
end;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TfrmMain.GetDestinationPathAndMask(SourceFiles: TFiles;
|
|
TargetFileSource: IFileSource;
|
|
EnteredPath: String; BaseDir: String;
|
|
out DestPath, DestMask: String);
|
|
var
|
|
AbsolutePath: String;
|
|
begin
|
|
if TargetFileSource.GetPathType(EnteredPath) = ptAbsolute then
|
|
AbsolutePath := EnteredPath
|
|
else
|
|
begin
|
|
// This only work for filesystem for now.
|
|
if TargetFileSource.IsClass(TFileSystemFileSource) then
|
|
AbsolutePath := BaseDir + EnteredPath
|
|
else
|
|
AbsolutePath := PathDelim{TargetFileSource.GetRoot} + EnteredPath;
|
|
end;
|
|
|
|
AbsolutePath := NormalizePathDelimiters(AbsolutePath); // normalize path delimiters
|
|
AbsolutePath := ExpandAbsolutePath(AbsolutePath);
|
|
|
|
if Length(AbsolutePath) = 0 then Exit;
|
|
|
|
// If the entered path ends with a path delimiter
|
|
// treat it as a path to a not yet existing directory
|
|
// which should be created.
|
|
if (AbsolutePath[Length(AbsolutePath)] = PathDelim) or
|
|
((TargetFileSource.IsClass(TFileSystemFileSource)) and
|
|
mbDirectoryExists(AbsolutePath)) then
|
|
begin
|
|
// Destination is a directory.
|
|
DestPath := AbsolutePath;
|
|
DestMask := '*.*';
|
|
end
|
|
else
|
|
begin
|
|
// Destination is a file name or mask.
|
|
DestPath := ExtractFilePath(AbsolutePath);
|
|
DestMask := ExtractFileName(AbsolutePath);
|
|
|
|
if (SourceFiles.Count > 1) and not ContainsWildcards(DestMask) then
|
|
begin
|
|
// Assume it is a path to a directory because cannot put multiple
|
|
// files/directories into one file.
|
|
DestPath := AbsolutePath;
|
|
DestMask := '*.*';
|
|
end
|
|
// For convenience, treat '*' as "whole file name".
|
|
// To remove extension '*.' can be used.
|
|
else if DestMask = '*' then
|
|
DestMask := '*.*';
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.GetDestinationPathAndMask(SourceFiles: TFiles;
|
|
SourceFileSource: IFileSource; var TargetFileSource: IFileSource;
|
|
EnteredPath: String; BaseDir: String; out DestPath, DestMask: String);
|
|
var
|
|
FileSourceIndex, PathIndex: Integer;
|
|
begin
|
|
// If it is a file source root and we trying to copy/move to parent directory
|
|
if StrBegins(EnteredPath, '..') and SourceFileSource.IsPathAtRoot(SourceFiles.Path) then
|
|
begin
|
|
// Change to previous file source and last path.
|
|
FileSourceIndex := ActiveFrame.CurrentFileSourceIndex - 1;
|
|
if FileSourceIndex < 0 then
|
|
TargetFileSource := nil // No parent file sources.
|
|
else
|
|
begin
|
|
PathIndex := ActiveFrame.PathsCount[FileSourceIndex] - 1;
|
|
if PathIndex < 0 then
|
|
TargetFileSource := nil // No paths.
|
|
else
|
|
begin
|
|
TargetFileSource := ActiveFrame.FileSources[FileSourceIndex];
|
|
// Determine destination type
|
|
if (Length(EnteredPath) = 2) or (EnteredPath[Length(EnteredPath)] = PathDelim) then
|
|
EnteredPath:= EmptyStr // Destination is a directory
|
|
else
|
|
EnteredPath:= ExtractFileName(EnteredPath); // Destination is a file name or mask
|
|
// Combine destination path
|
|
EnteredPath := ActiveFrame.Path[FileSourceIndex, PathIndex] + EnteredPath;
|
|
end;
|
|
end;
|
|
end;
|
|
// Target file source is valid
|
|
if Assigned(TargetFileSource) then
|
|
begin
|
|
GetDestinationPathAndMask(SourceFiles, TargetFileSource,
|
|
EnteredPath, BaseDir, DestPath, DestMask);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.SetDragCursor(Shift: TShiftState);
|
|
begin
|
|
FrameLeft.SetDragCursor(Shift);
|
|
FrameRight.SetDragCursor(Shift);
|
|
end;
|
|
|
|
procedure TfrmMain.CreateWnd;
|
|
begin
|
|
// Must be before CreateWnd
|
|
LoadWindowState;
|
|
|
|
inherited CreateWnd;
|
|
|
|
// Save real main form handle
|
|
Application.MainForm.Tag:= Handle;
|
|
end;
|
|
|
|
procedure TfrmMain.DoFirstShow;
|
|
var
|
|
ANode: TXmlNode;
|
|
begin
|
|
inherited DoFirstShow;
|
|
|
|
// Load window state
|
|
ANode := gConfig.FindNode(gConfig.RootNode, 'MainWindow/Position', True);
|
|
|
|
if gConfig.GetValue(ANode, 'Maximized', True) then
|
|
Self.WindowState := wsMaximized;
|
|
|
|
lastWindowState := WindowState;
|
|
end;
|
|
|
|
procedure TfrmMain.WMMove(var Message: TLMMove);
|
|
begin
|
|
inherited WMMove(Message);
|
|
|
|
if not (csDestroying in ComponentState) then
|
|
begin
|
|
FDelayedWMMove := True;
|
|
Inc(FDelayedEventCtr);
|
|
Application.QueueAsyncCall(@DelayedEvent, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.WMSize(var message: TLMSize);
|
|
begin
|
|
// https://github.com/doublecmd/doublecmd/issues/736
|
|
if (Message.Width > High(Int16)) or (Message.Height > High(Int16)) then
|
|
begin
|
|
DCDebug('TfrmMain.WMSize invalid size %u x %u', [Message.Width, Message.Height]);
|
|
Exit;
|
|
end;
|
|
|
|
inherited WMSize(Message);
|
|
|
|
if not (csDestroying in ComponentState) then
|
|
begin
|
|
FDelayedWMSize := True;
|
|
Inc(FDelayedEventCtr);
|
|
Application.QueueAsyncCall(@DelayedEvent, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
|
|
const AXProportion, AYProportion: Double);
|
|
begin
|
|
if AMode in [lapAutoAdjustWithoutHorizontalScrolling, lapAutoAdjustForDPI] then
|
|
begin
|
|
DisableAutoSizing;
|
|
try
|
|
// ScaleFontsPPI(AYProportion);
|
|
BorderSpacing.AutoAdjustLayout(AXProportion, AYProportion);
|
|
Constraints.AutoAdjustLayout(AXProportion, AYProportion);
|
|
finally
|
|
EnableAutoSizing;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FormKeyUp( Sender: TObject; var Key: Word;
|
|
Shift: TShiftState) ;
|
|
begin
|
|
SetDragCursor(Shift);
|
|
end;
|
|
|
|
procedure TfrmMain.FormResize(Sender: TObject);
|
|
begin
|
|
UpdatePrompt;
|
|
end;
|
|
|
|
procedure TfrmMain.lblDriveInfoResize(Sender: TObject);
|
|
begin
|
|
with TLabel(Sender) do
|
|
begin
|
|
if Canvas.TextWidth(Caption) > Width then
|
|
Alignment:= taLeftJustify
|
|
else begin
|
|
Alignment:= taCenter;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FormKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
ShiftEx : TShiftState;
|
|
CmdText : String;
|
|
begin
|
|
SetDragCursor(Shift);
|
|
|
|
// Either left or right panel has to be focused.
|
|
if not FrameLeft.Focused and
|
|
not FrameRight.Focused then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
ShiftEx := GetKeyShiftStateEx;
|
|
|
|
case Key of
|
|
VK_BACK:
|
|
if IsCommandLineVisible and
|
|
(GetKeyTypingAction(ShiftEx) = ktaCommandLine) and (edtCommand.Text <> '') then
|
|
begin
|
|
// Delete last character.
|
|
CmdText := edtCommand.Text;
|
|
UTF8Delete(CmdText, UTF8Length(CmdText), 1);
|
|
edtCommand.Text := CmdText;
|
|
|
|
edtCommand.SetFocus;
|
|
edtCommand.SelStart := UTF8Length(edtCommand.Text) + 1;
|
|
Key := 0;
|
|
end;
|
|
|
|
VK_ESCAPE:
|
|
if IsCommandLineVisible and
|
|
(GetKeyTypingAction(ShiftEx) = ktaCommandLine) and
|
|
(edtCommand.Text <> '') then
|
|
begin
|
|
edtCommand.Text := '';
|
|
Key := 0;
|
|
end;
|
|
|
|
VK_RETURN, VK_SELECT:
|
|
if IsCommandLineVisible and
|
|
(GetKeyTypingAction(ShiftEx) = ktaCommandLine) and
|
|
(edtCommand.Text <> '') then
|
|
begin
|
|
// execute command line (in terminal with Shift)
|
|
ExecuteCommandLine(Shift = [ssShift]);
|
|
Key := 0;
|
|
end;
|
|
|
|
VK_SPACE:
|
|
if (GetKeyTypingAction(ShiftEx) = ktaCommandLine) and (edtCommand.Text <> '') then
|
|
begin
|
|
TypeInCommandLine(' ');
|
|
Key := 0;
|
|
end;
|
|
|
|
VK_TAB:
|
|
begin
|
|
// Select opposite panel.
|
|
case PanelSelected of
|
|
fpLeft: SetActiveFrame(fpRight);
|
|
fpRight: SetActiveFrame(fpLeft);
|
|
else SetActiveFrame(fpLeft);
|
|
end;
|
|
Key := 0;
|
|
end;
|
|
end;
|
|
|
|
CheckCommandLine(ShiftEx, Key);
|
|
end;
|
|
|
|
procedure TfrmMain.pmToolBarPopup(Sender: TObject);
|
|
var
|
|
sText: String;
|
|
sDir: String;
|
|
bPaste: Boolean;
|
|
ToolItem: TKASToolItem;
|
|
Button: TKASToolButton;
|
|
begin
|
|
Button := TKASToolButton(pmToolBar.Tag);
|
|
tbSeparator.Visible:= Assigned(Button);
|
|
tbCut.Visible:= Assigned(Button);
|
|
tbCopy.Visible:= Assigned(Button);
|
|
tbChangeDir.Visible:= False;
|
|
tbDelete.Visible:= Assigned(Button);
|
|
if Assigned(Button) then
|
|
begin
|
|
ToolItem := Button.ToolItem;
|
|
if ToolItem is TKASProgramItem then
|
|
begin
|
|
sDir := TKASProgramItem(ToolItem).StartPath;
|
|
sDir:= PrepareParameter(sDir, nil, [ppoNormalizePathDelims, ppoReplaceTilde]);
|
|
tbChangeDir.Caption := 'CD ' + sDir;
|
|
tbChangeDir.Visible := True;
|
|
end;
|
|
end;
|
|
|
|
sText:= Clipboard.AsText;
|
|
bPaste:= StrBegins(sText, DCToolItemClipboardHeader) or
|
|
StrBegins(sText, DCToolbarClipboardHeader) or
|
|
StrBegins(sText, TCToolbarClipboardHeader);
|
|
if bPaste then
|
|
tbSeparator.Visible:= True;
|
|
tbPaste.Visible:= bPaste;
|
|
end;
|
|
|
|
procedure TfrmMain.ShellTreeViewAdvancedCustomDrawItem(Sender: TCustomTreeView;
|
|
Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;
|
|
var PaintImages, DefaultDraw: Boolean);
|
|
begin
|
|
Node.ImageIndex:= 0;
|
|
Node.SelectedIndex:= 0;
|
|
end;
|
|
|
|
procedure TfrmMain.pnlLeftResize(Sender: TObject);
|
|
begin
|
|
if gDriveBarSyncWidth then
|
|
begin
|
|
if gDriveBar1 and gDriveBar2 and not gHorizontalFilePanels then
|
|
begin
|
|
pnlDskLeft.Constraints.MinWidth:= pnlLeft.Width;
|
|
pnlDskLeft.Constraints.MaxWidth:= pnlLeft.Width;
|
|
end;
|
|
end;
|
|
|
|
// Put splitter after left panel.
|
|
if not gHorizontalFilePanels then
|
|
begin
|
|
MainSplitter.Left := pnlLeft.Width;
|
|
MainSplitter.Top := pnlLeft.Top;
|
|
MainSplitter.Height := pnlLeft.Height;
|
|
MainSplitter.Width := 3;
|
|
end
|
|
else
|
|
begin
|
|
MainSplitter.Top := pnlLeft.Height;
|
|
MainSplitter.Left := pnlLeft.Left;
|
|
MainSplitter.Width := pnlLeft.Width;
|
|
MainSplitter.Height := 3;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.pnlLeftRightDblClick(Sender: TObject);
|
|
var
|
|
APanel: TPanel;
|
|
APoint: TPoint;
|
|
FileViewNotebook: TFileViewNotebook;
|
|
begin
|
|
if Sender is TPanel then
|
|
begin
|
|
APanel := Sender as TPanel;
|
|
if APanel = pnlLeft then
|
|
begin
|
|
APoint := FrameLeft.ClientToScreen(Classes.Point(0, FrameLeft.Top));
|
|
if Mouse.CursorPos.Y < APoint.Y then Commands.DoNewTab(nbLeft);
|
|
end
|
|
else if APanel = pnlRight then
|
|
begin
|
|
APoint := FrameRight.ClientToScreen(Classes.Point(0, FrameRight.Top));
|
|
if Mouse.CursorPos.Y < APoint.Y then Commands.DoNewTab(nbRight);
|
|
end;
|
|
end;
|
|
if Sender is TFileViewNotebook then
|
|
begin
|
|
FileViewNotebook:= Sender as TFileViewNotebook;
|
|
if FileViewNotebook.DoubleClickPageIndex < 0 then
|
|
Commands.DoNewTab(FileViewNotebook)
|
|
else
|
|
begin
|
|
case gDirTabActionOnDoubleClick of
|
|
tadc_Nothing: begin end;
|
|
tadc_CloseTab: Commands.DoCloseTab(FileViewNotebook, FileViewNotebook.DoubleClickPageIndex);
|
|
tadc_FavoriteTabs: Commands.cm_LoadFavoriteTabs(['position=cursor']);
|
|
tadc_TabsPopup:
|
|
begin
|
|
if FileViewNotebook.DoubleClickPageIndex<>-1 then
|
|
begin
|
|
// Check tab options items.
|
|
case FileViewNotebook.Page[FileViewNotebook.DoubleClickPageIndex].LockState of
|
|
tlsNormal: miTabOptionNormal.Checked := True;
|
|
tlsPathLocked: miTabOptionPathLocked.Checked := True;
|
|
tlsDirsInNewTab: miTabOptionDirsInNewTab.Checked := True;
|
|
tlsPathResets: miTabOptionPathResets.Checked := True;
|
|
end;
|
|
pmTabMenu.Parent := FileViewNotebook;
|
|
pmTabMenu.Tag := FileViewNotebook.DoubleClickPageIndex;
|
|
pmTabMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.pnlNotebooksResize(Sender: TObject);
|
|
var
|
|
Delta: Integer;
|
|
begin
|
|
if not FResizingFilePanels then
|
|
begin
|
|
FResizingFilePanels := True;
|
|
if not gHorizontalFilePanels then
|
|
begin
|
|
pnlLeft.BorderSpacing.Bottom:= 0;
|
|
Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Width);
|
|
pnlLeft.BorderSpacing.Right:= 4 - (pnlNotebooks.Width - Delta) mod 2;
|
|
pnlLeft.Width := Round(Double(pnlNotebooks.Width - pnlLeft.BorderSpacing.Right - Delta) * FMainSplitterPos / 100.0);
|
|
end
|
|
else begin
|
|
pnlLeft.BorderSpacing.Right:= 0;
|
|
Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Height);
|
|
pnlLeft.BorderSpacing.Bottom:= 4 - (pnlNotebooks.Height - Delta) mod 2;
|
|
pnlLeft.Height := Round(Double(pnlNotebooks.Height - pnlLeft.BorderSpacing.Bottom - Delta) * FMainSplitterPos / 100.0);
|
|
end;
|
|
FResizingFilePanels := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.pnlRightResize(Sender: TObject);
|
|
var
|
|
AWidth: Integer;
|
|
begin
|
|
if gDriveBarSyncWidth then
|
|
begin
|
|
if gDriveBar1 and not gHorizontalFilePanels then
|
|
begin
|
|
if gDriveBar2 then
|
|
AWidth := pnlRight.Width + 1
|
|
else begin
|
|
AWidth := pnlNotebooks.Width - 2;
|
|
end;
|
|
if AWidth < 0 then AWidth := 0;
|
|
pnlDskRight.Constraints.MinWidth := AWidth;
|
|
pnlDskRight.Constraints.MaxWidth := AWidth;
|
|
end
|
|
else if gHorizontalFilePanels and not gDriveBar2 then
|
|
begin
|
|
AWidth := Max(0, pnlNotebooks.Width - 2);
|
|
pnlDskRight.Constraints.MinWidth := AWidth;
|
|
pnlDskRight.Constraints.MaxWidth := AWidth;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.sboxDrivePaint(Sender: TObject);
|
|
begin
|
|
with gColors.FreeSpaceInd^ do
|
|
PaintDriveFreeBar(Sender, gIndUseGradient, ForeColor, ThresholdForeColor, BackColor);
|
|
end;
|
|
|
|
procedure TfrmMain.PaintDriveFreeBar(Sender: TObject; const bIndUseGradient: boolean;
|
|
const pIndForeColor, pIndThresholdForeColor, pIndBackColor: TColor);
|
|
const OccupiedThresholdPercent = 90;
|
|
var
|
|
pbxDrive: TPaintBox absolute Sender;
|
|
FillPercentage: PtrInt;
|
|
i: Integer;
|
|
AColor, AColor2: TColor;
|
|
ARect: TRect;
|
|
begin
|
|
FillPercentage:= pbxDrive.Tag;
|
|
if FillPercentage <> -1 then
|
|
begin
|
|
pbxDrive.Canvas.Brush.Color:= clBlack;
|
|
pbxDrive.Canvas.FrameRect(0, 0, pbxDrive.Width - 1, pbxDrive.Height - 1);
|
|
|
|
ARect.Top := 1;
|
|
ARect.Bottom := pbxDrive.Height - 2;
|
|
|
|
if not bIndUseGradient then
|
|
begin
|
|
ARect.Left := 1;
|
|
ARect.Right := 1 + FillPercentage * (pbxDrive.Width - 2) div 100;
|
|
if FillPercentage <= OccupiedThresholdPercent then
|
|
AColor := pIndForeColor
|
|
else
|
|
AColor := pIndThresholdForeColor;
|
|
pbxDrive.Canvas.GradientFill(ARect, LightColor(AColor, 25), DarkColor(AColor, 25), gdVertical);
|
|
ARect.Left := ARect.Right + 1;
|
|
ARect.Right := pbxDrive.Width - 2;
|
|
AColor := pIndBackColor;
|
|
pbxDrive.Canvas.GradientFill(ARect, DarkColor(AColor, 25), LightColor(AColor, 25), gdVertical);
|
|
end
|
|
else
|
|
begin
|
|
ARect.Right := 1;
|
|
for i := 0 to FillPercentage - 1 do
|
|
begin
|
|
if i <= OccupiedThresholdPercent then
|
|
AColor:= RGB((i * 255) div OccupiedThresholdPercent, 255, 0)
|
|
else
|
|
AColor:= RGB(255, ((100 - i) * 255) div (100 - OccupiedThresholdPercent), 0);
|
|
AColor2:= DarkColor(AColor, 50);
|
|
|
|
ARect.Left := ARect.Right;
|
|
ARect.Right := 1 + (i + 1) * (pbxDrive.Width - 2) div 100;
|
|
|
|
pbxDrive.Canvas.GradientFill(ARect, AColor, AColor2, gdVertical);
|
|
end;
|
|
ARect.Left := ARect.Right;
|
|
ARect.Right := pbxDrive.Width - 2;
|
|
pbxDrive.Canvas.GradientFill(ARect, clSilver, clWhite, gdVertical);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.seLogWindowSpecialLineColors(Sender: TObject; Line: integer;
|
|
var Special: boolean; var FG, BG: TColor);
|
|
var
|
|
LogMsgTypeObject: TObject;
|
|
LogMsgType : TLogMsgType absolute LogMsgTypeObject;
|
|
begin
|
|
LogMsgTypeObject := seLogWindow.Lines.Objects[Line-1];
|
|
Special := True;
|
|
with gColors.Log^ do
|
|
begin
|
|
case LogMsgType of
|
|
lmtInfo:
|
|
FG := InfoColor;
|
|
lmtSuccess:
|
|
FG := SuccessColor;
|
|
lmtError:
|
|
FG := ErrorColor
|
|
else
|
|
FG := clWindowText;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FileViewFreeAsync(Data: PtrInt);
|
|
var
|
|
FileView: TFileView absolute Data;
|
|
begin
|
|
FileView.Free;
|
|
end;
|
|
|
|
function TfrmMain.FileViewAutoSwitch(FileSource: IFileSource; var FileView: TFileView;
|
|
Reason: TChangePathReason; const NewPath: String): Boolean;
|
|
var
|
|
AName: String;
|
|
Index: Integer;
|
|
AWidth: Integer;
|
|
Percent: Double;
|
|
Page: TFileViewPage;
|
|
AClientWidth: Integer;
|
|
RestoreFocus: Boolean;
|
|
ColSe: TPanelColumnsClass;
|
|
DefaultView: TFileSourceFields;
|
|
begin
|
|
Result:= True;
|
|
|
|
if FileSource.Equals(FileView.FileSource) then
|
|
Exit;
|
|
|
|
Page:= TFileViewPage(FileView.NotebookPage);
|
|
|
|
if Page.Tag > 0 then Exit;
|
|
|
|
Page.Tag:= MaxInt;
|
|
try
|
|
RestoreFocus:= (ActiveFrame = FileView);
|
|
if (fspDefaultView in FileSource.Properties) then
|
|
begin
|
|
AName:= '<' + FileSource.FileSystem + '>';
|
|
ColSe:= ColSet.GetColumnSet(AName, FileSource.FileSystem);
|
|
if (ColSe = nil) then
|
|
begin
|
|
if FileSource.GetDefaultView(DefaultView) then
|
|
begin
|
|
AWidth:= 0;
|
|
for Index:= 0 to High(DefaultView) do
|
|
begin
|
|
AWidth += DefaultView[Index].Width;
|
|
end;
|
|
AClientWidth:= FileView.ClientWidth;
|
|
// Scale columns width
|
|
if AWidth < AClientWidth then
|
|
begin
|
|
for Index:= 0 to High(DefaultView) do
|
|
begin
|
|
Percent:= DefaultView[Index].Width / AWidth;
|
|
DefaultView[Index].Width:= Floor(AClientWidth * Percent);
|
|
end;
|
|
end;
|
|
ColSe:= TPanelColumnsClass.Create;
|
|
for Index:= 0 to High(DefaultView) do
|
|
begin
|
|
with DefaultView[Index] do
|
|
ColSe.Add(Header, Content, Width, Align);
|
|
end;
|
|
ColSe.FileSystem:= FileSource.FileSystem;
|
|
ColSe.Name:= AName;
|
|
ColSet.Add(ColSe);
|
|
end;
|
|
end;
|
|
if Assigned(ColSe) then
|
|
begin
|
|
// Save current file view type
|
|
Page.BackupViewClass := TFileViewClass(FileView.ClassType);
|
|
|
|
if (FileView is TColumnsFileView) then
|
|
begin
|
|
// Save current columns set name
|
|
Page.BackupColumnSet:= TColumnsFileView(FileView).ActiveColm;
|
|
TColumnsFileView(Page.FileView).SetColumnSet(ColSe.Name);
|
|
end
|
|
else begin
|
|
Result:= False;
|
|
Page.RemoveComponent(FileView);
|
|
Application.QueueAsyncCall(@FileViewFreeAsync, PtrInt(FileView));
|
|
FileView:= TColumnsFileView.Create(Page, FileView, ColSe.Name);
|
|
if Assigned(Page.OnChangeFileView) then Page.OnChangeFileView(FileView);
|
|
if RestoreFocus then Page.FileView.SetFocus;
|
|
end;
|
|
Page.BackupViewMode:= FileSource.FileSystem;
|
|
end;
|
|
end
|
|
else if (Length(Page.BackupViewMode) > 0) then
|
|
begin
|
|
Page.BackupViewMode:= EmptyStr;
|
|
// Restore previous file view type
|
|
if (FileView is Page.BackupViewClass) then
|
|
begin
|
|
if (FileView is TColumnsFileView) then
|
|
TColumnsFileView(FileView).SetColumnSet(Page.BackupColumnSet)
|
|
end
|
|
else begin
|
|
Result:= False;
|
|
Page.RemoveComponent(FileView);
|
|
Application.QueueAsyncCall(@FileViewFreeAsync, PtrInt(FileView));
|
|
if Page.BackupViewClass <> TColumnsFileView then
|
|
FileView:= Page.BackupViewClass.Create(Page, FileView)
|
|
else begin
|
|
FileView:= TColumnsFileView.Create(Page, FileView, Page.BackupColumnSet);
|
|
end;
|
|
if Assigned(Page.OnChangeFileView) then Page.OnChangeFileView(FileView);
|
|
end;
|
|
if RestoreFocus then Page.FileView.SetFocus;
|
|
end;
|
|
if not Result then
|
|
begin
|
|
case Reason of
|
|
cprAdd:
|
|
FileView.AddFileSource(FileSource, NewPath);
|
|
cprRemove:
|
|
FileView.RemoveCurrentFileSource;
|
|
end;
|
|
end;
|
|
finally
|
|
Page.Tag:= 0;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.FileViewBeforeChangePath(FileView: TFileView;
|
|
NewFileSource: IFileSource; Reason: TChangePathReason; const NewPath: String
|
|
): Boolean;
|
|
var
|
|
i: Integer;
|
|
AFileSource: IFileSource;
|
|
ANoteBook: TFileViewNotebook;
|
|
Page, NewPage: TFileViewPage;
|
|
PageAlreadyExists: Boolean = False;
|
|
tlsLockStateToEvaluate: TTabLockState;
|
|
begin
|
|
Result:= True;
|
|
if FileView.NotebookPage is TFileViewPage then
|
|
begin
|
|
Page := FileView.NotebookPage as TFileViewPage;
|
|
|
|
tlsLockStateToEvaluate:=Page.LockState;
|
|
if tlsLockStateToEvaluate=tlsPathLocked then
|
|
if MsgBox(Format(rsMsgTabForOpeningInNewTab,[Page.Caption]), [msmbYes, msmbCancel], msmbCancel, msmbCancel) = mmrYes then
|
|
tlsLockStateToEvaluate:=tlsDirsInNewTab;
|
|
|
|
case tlsLockStateToEvaluate of
|
|
tlsPathLocked:
|
|
Result := False; // do not change directory in this tab
|
|
|
|
tlsDirsInNewTab:
|
|
begin
|
|
Result := False; // do not change directory in this tab
|
|
|
|
if Assigned(NewFileSource) then
|
|
begin
|
|
ANoteBook := Page.Notebook;
|
|
|
|
if tb_reusing_tab_when_possible in gDirTabOptions then
|
|
begin
|
|
for i := 0 to ANotebook.PageCount - 1 do
|
|
begin
|
|
NewPage := ANotebook.Page[i];
|
|
PageAlreadyExists := Assigned(NewPage.FileView) and
|
|
mbCompareFileNames(NewPage.FileView.CurrentAddress, NewFileSource.CurrentAddress) and
|
|
mbCompareFileNames(NewPage.FileView.CurrentPath, NewPath);
|
|
if PageAlreadyExists then
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
if not PageAlreadyExists then
|
|
begin
|
|
// Open in a new page, cloned view.
|
|
NewPage := ANotebook.NewPage(Page.FileView);
|
|
NewPage.FileView.AddFileSource(NewFileSource, NewPath);
|
|
end;
|
|
NewPage.MakeActive;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if Result and Assigned(NewFileSource) then
|
|
begin
|
|
if not FileViewAutoSwitch(NewFileSource, FileView, Reason, NewPath) then
|
|
Exit(False);
|
|
end;
|
|
|
|
if actSyncChangeDir.Checked and (FileView = NotActiveFrame) then
|
|
begin
|
|
if not Result then
|
|
actSyncChangeDir.Checked:= False
|
|
else begin
|
|
if Assigned(NewFileSource) and not NewFileSource.SetCurrentWorkingDirectory(NewPath) then
|
|
begin
|
|
actSyncChangeDir.Checked:= False;
|
|
Exit(False);
|
|
end
|
|
else if not FSyncChangeParent then
|
|
begin
|
|
if Assigned(NewFileSource) then
|
|
AFileSource:= NewFileSource
|
|
else begin
|
|
AFileSource:= FileView.FileSource;
|
|
end;
|
|
if not AFileSource.FileSystemEntryExists(ExcludeTrailingBackslash(NewPath)) then
|
|
begin
|
|
actSyncChangeDir.Checked:= False;
|
|
Exit(False);
|
|
end;
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FileViewAfterChangePath(FileView: TFileView);
|
|
var
|
|
S: String;
|
|
Index: Integer;
|
|
Page: TFileViewPage;
|
|
ANoteBook : TFileViewNotebook;
|
|
begin
|
|
if FileView.NotebookPage is TFileViewPage then
|
|
begin
|
|
Page := FileView.NotebookPage as TFileViewPage;
|
|
ANoteBook := Page.Notebook;
|
|
|
|
if Page.IsActive then
|
|
begin
|
|
if Assigned(FileView.FileSource) then
|
|
begin
|
|
if FileView.FileSource.IsClass(TFileSystemFileSource) then
|
|
begin
|
|
// Store only first 255 items
|
|
if glsDirHistory.Count > $FF then begin
|
|
glsDirHistory.Delete(glsDirHistory.Count - 1);
|
|
end;
|
|
Index:= glsDirHistory.IndexOf(FileView.CurrentPath);
|
|
if Index = -1 then
|
|
glsDirHistory.Insert(0, FileView.CurrentPath)
|
|
else begin
|
|
glsDirHistory.Move(Index, 0);
|
|
end;
|
|
UpdateTreeViewPath;
|
|
UpdateMainTitleBar;
|
|
end;
|
|
|
|
if actSyncChangeDir.Checked and (FileView = ActiveFrame) then
|
|
begin
|
|
S:= ExcludeTrailingBackslash(FileView.CurrentPath);
|
|
// Go to child directory
|
|
if Length(S) > Length(FSyncChangeDir) then
|
|
begin
|
|
FSyncChangeParent:= False;
|
|
if ExtractFileDir(S) = FSyncChangeDir then
|
|
NotActiveFrame.CurrentPath:= NotActiveFrame.CurrentPath + ExtractFileName(S)
|
|
else
|
|
actSyncChangeDir.Checked:= False;
|
|
end
|
|
// Go to parent directory
|
|
else begin
|
|
FSyncChangeParent:= True;
|
|
if S = ExtractFileDir(FSyncChangeDir) then
|
|
NotActiveFrame.ChangePathToParent(True)
|
|
else
|
|
actSyncChangeDir.Checked:= False;
|
|
end;
|
|
if actSyncChangeDir.Checked then
|
|
FSyncChangeDir:= S
|
|
else begin
|
|
FSyncChangeDir:= EmptyStr;
|
|
end;
|
|
end;
|
|
|
|
UpdateSelectedDrive(ANoteBook);
|
|
UpdatePrompt;
|
|
end;
|
|
// Update page hint
|
|
ANoteBook.Hint := FileView.CurrentPath;
|
|
end;
|
|
|
|
{if (fspDirectAccess in FileView.FileSource.GetProperties) then
|
|
begin
|
|
if gTermWindow and Assigned(Cons) then
|
|
Cons.Terminal.SetCurrentDir(FileView.CurrentPath);
|
|
end;}
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.FileViewActivate(FileView: TFileView);
|
|
var
|
|
Page: TFileViewPage;
|
|
begin
|
|
if FileView.NotebookPage is TFileViewPage then
|
|
begin
|
|
Page := FileView.NotebookPage as TFileViewPage;
|
|
SelectedPanel := Page.Notebook.Side;
|
|
UpdateSelectedDrive(Page.Notebook);
|
|
UpdateFreeSpace(Page.Notebook.Side, False);
|
|
end;
|
|
UpdateFileView;
|
|
end;
|
|
|
|
procedure TfrmMain.FileViewFilesChanged(FileView: TFileView);
|
|
var
|
|
Page: TFileViewPage;
|
|
begin
|
|
if FileView.NotebookPage is TFileViewPage then
|
|
begin
|
|
Page := FileView.NotebookPage as TFileViewPage;
|
|
|
|
if Page.IsActive then
|
|
begin
|
|
UpdateFreeSpace(Page.Notebook.Side, False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.SetActiveFrame(panel: TFilePanelSelect);
|
|
begin
|
|
SelectedPanel:= panel;
|
|
SetActiveFrame(ActiveFrame);
|
|
end;
|
|
|
|
procedure TfrmMain.SetActiveFrame(FileView: TFileView);
|
|
begin
|
|
FileView.SetFocus;
|
|
if (fspDirectAccess in FileView.FileSource.GetProperties) then
|
|
begin
|
|
if gTermWindow and Assigned(Cons) then
|
|
Cons.SetCurrentDir(FileView.CurrentPath);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateFileView;
|
|
var
|
|
AFileView: TFileView;
|
|
begin
|
|
AFileView:= ActiveFrame;
|
|
if AFileView is TColumnsFileView then
|
|
actColumnsView.Checked:= True
|
|
else if AFileView is TBriefFileView then
|
|
actBriefView.Checked:= True
|
|
else if AFileView is TThumbFileView then
|
|
actThumbnailsView.Checked:= True;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateShellTreeView;
|
|
begin
|
|
actTreeView.Checked := gSeparateTree;
|
|
TreeSplitter.Visible := gSeparateTree;
|
|
TreePanel.Visible := gSeparateTree;
|
|
|
|
if gSeparateTree and (ShellTreeView = nil) then
|
|
begin
|
|
ShellTreeView := TShellTreeView.Create(TreePanel);
|
|
ShellTreeView.Parent := TreePanel;
|
|
ShellTreeView.Align := alClient;
|
|
ShellTreeView.ScrollBars := ssAutoBoth;
|
|
|
|
with ShellTreeView as TShellTreeView do
|
|
begin
|
|
UpdateTreeView;
|
|
ReadOnly := True;
|
|
RightClickSelect := True;
|
|
FileSortType := fstNone;
|
|
PopulateWithBaseFiles;
|
|
CustomSort(@ShellTreeViewSort);
|
|
|
|
Images := TImageList.Create(Self);
|
|
Images.Width := gIconsSize;
|
|
Images.Height := gIconsSize;
|
|
Images.Add(PixMapManager.GetFolderIcon(gIconsSize, ShellTreeView.Color), nil);
|
|
|
|
OnKeyDown := @ShellTreeViewKeyDown;
|
|
OnMouseUp := @ShellTreeViewMouseUp;
|
|
OnAdvancedCustomDrawItem := @ShellTreeViewAdvancedCustomDrawItem;
|
|
|
|
ExpandSignType := tvestPlusMinus;
|
|
Options := Options - [tvoThemedDraw];
|
|
Options := Options + [tvoReadOnly, tvoRightClickSelect];
|
|
end;
|
|
end;
|
|
|
|
if gSeparateTree then
|
|
begin
|
|
with gColors.FilePanel^ do
|
|
begin
|
|
ShellTreeView.Font.Color := ForeColor;
|
|
ShellTreeView.BackgroundColor := BackColor;
|
|
ShellTreeView.SelectionColor := CursorColor;
|
|
end;
|
|
FontOptionsToFont(gFonts[dcfMain], ShellTreeView.Font);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateTreeViewPath;
|
|
begin
|
|
if (ShellTreeView = nil) then Exit;
|
|
if (ShellTreeView.Tag <> 0) then Exit;
|
|
if (fspDirectAccess in ActiveFrame.FileSource.Properties) then
|
|
try
|
|
(ShellTreeView as TShellTreeView).Path := ActiveFrame.CurrentPath;
|
|
except
|
|
// Skip
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateTreeView;
|
|
begin
|
|
if (ShellTreeView = nil) then Exit;
|
|
with (ShellTreeView as TShellTreeView) do
|
|
begin
|
|
if gShowSystemFiles then
|
|
ObjectTypes:= ObjectTypes + [otHidden]
|
|
else begin
|
|
ObjectTypes:= ObjectTypes - [otHidden];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function CompareDrives(Item1, Item2: Pointer): Integer;
|
|
begin
|
|
Result := CompareText(PDrive(Item1)^.DisplayName, PDrive(Item2)^.DisplayName);
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateDiskCount;
|
|
var
|
|
I: Integer;
|
|
Drive: PDrive;
|
|
begin
|
|
DrivesList.Free;
|
|
DrivesList := TDriveWatcher.GetDrivesList;
|
|
DrivesList.Sort(@CompareDrives);
|
|
|
|
{ Delete drives that in drives black list }
|
|
for I:= DrivesList.Count - 1 downto 0 do
|
|
begin
|
|
Drive := DrivesList[I];
|
|
if (gDriveBlackListUnmounted and not Drive^.IsMounted) or
|
|
MatchesMaskList(Drive^.Path, gDriveBlackList) or
|
|
MatchesMaskList(Drive^.DeviceId, gDriveBlackList) then
|
|
DrivesList.Remove(I);
|
|
end;
|
|
|
|
{$IF DEFINED(MSWINDOWS)}
|
|
if (not (cimDrive in gCustomIcons)) then
|
|
begin
|
|
for I:= DrivesList.Count - 1 downto 0 do
|
|
begin
|
|
Drive := DrivesList[I];
|
|
if Drive^.DriveType = dtNetwork then
|
|
begin
|
|
with TNetworkDriveLoader.Create(Drive, dskRight.GlyphSize, clBtnFace, @OnDriveIconLoaded) do
|
|
Start;
|
|
end;
|
|
end;
|
|
end;
|
|
if (Win32MajorVersion > 5) then
|
|
begin
|
|
TShellFileSource.ListDrives(DrivesList, gUpperCaseDriveLetter);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
UpdateDriveList(DrivesList);
|
|
|
|
// Add virtual drive
|
|
New(Drive);
|
|
FillChar(Drive^, SizeOf(TDrive), 0);
|
|
Drive^.IsMounted:= True;
|
|
Drive^.DriveType:= dtVirtual;
|
|
Drive^.Path:= 'vfs:' + PathDelim;
|
|
Drive^.DisplayName:= PathDelim + PathDelim;
|
|
Drive^.DriveLabel:= StripHotkey(actOpenVirtualFileSystemList.Caption);
|
|
Drive^.FileSystem:= 'VFS';
|
|
DrivesList.Add(Drive);
|
|
|
|
// create drives drop down menu
|
|
FDrivesListPopup.UpdateDrivesList(DrivesList);
|
|
|
|
// create drives left/right panels
|
|
if gDriveBar1 then
|
|
begin
|
|
CreateDiskPanel(dskRight);
|
|
if gDriveBar2 then
|
|
CreateDiskPanel(dskLeft);
|
|
end;
|
|
dskLeft.AddToolItemExecutor(TKASDriveItem, @LeftDriveBarExecuteDrive);
|
|
dskRight.AddToolItemExecutor(TKASDriveItem, @RightDriveBarExecuteDrive);
|
|
|
|
if gSeparateTree and Assigned(ShellTreeView) then
|
|
begin
|
|
TShellTreeView(ShellTreeView).PopulateWithBaseFiles;
|
|
UpdateTreeViewPath;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.AddSpecialButtons(dskPanel: TKASToolBar);
|
|
procedure AddItem(FromButton: TSpeedButton);
|
|
var
|
|
Button: TKASToolButton;
|
|
ToolItem: TKASNormalItem;
|
|
begin
|
|
ToolItem := TKASNormalItem.Create;
|
|
ToolItem.Text := FromButton.Caption;
|
|
ToolItem.Hint := FromButton.Hint;
|
|
Button := dskPanel.AddButton(ToolItem);
|
|
Button.GroupIndex := 0;
|
|
end;
|
|
begin
|
|
AddItem(btnLeftRoot);
|
|
AddItem(btnLeftUp);
|
|
AddItem(btnLeftHome);
|
|
end;
|
|
|
|
procedure TfrmMain.CreateDiskPanel(dskPanel: TKASToolBar);
|
|
var
|
|
I, Count: Integer;
|
|
Drive : PDrive;
|
|
BitmapTmp: Graphics.TBitmap;
|
|
ToolItem: TKASDriveItem;
|
|
Button: TKASToolButton;
|
|
begin
|
|
dskPanel.BeginUpdate;
|
|
try
|
|
dskPanel.Clear;
|
|
dskPanel.Flat := gDriveBarFlat;
|
|
Count := DrivesList.Count - 1;
|
|
|
|
for I := 0 to Count do
|
|
begin
|
|
Drive := DrivesList.Items[I];
|
|
|
|
ToolItem := TKASDriveItem.Create;
|
|
ToolItem.Drive := Drive;
|
|
ToolItem.Text := Drive^.DisplayName;
|
|
ToolItem.Hint := GetDriveLabelOrStatus(Drive);
|
|
Button := dskPanel.AddButton(ToolItem);
|
|
|
|
// Set drive icon.
|
|
BitmapTmp := PixMapManager.GetDriveIcon(Drive, dskPanel.GlyphSize, clBtnFace, False);
|
|
Button.Glyph.Assign(BitmapTmp);
|
|
FreeAndNil(BitmapTmp);
|
|
|
|
{Set Buttons Transparent. Is need? }
|
|
Button.Glyph.Transparent := True;
|
|
Button.Transparent := True;
|
|
{/Set Buttons Transparent}
|
|
Button.Layout := blGlyphLeft;
|
|
end; // for
|
|
|
|
// Add special buttons
|
|
if not gDrivesListButton then
|
|
AddSpecialButtons(dskPanel);
|
|
|
|
finally
|
|
dskPanel.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.CreateFileView(sType: String; Page: TFileViewPage; AConfig: TXmlConfig; ANode: TXmlNode): TFileView;
|
|
var
|
|
FileViewFlags: TFileViewFlags = [];
|
|
begin
|
|
// This function should be changed to a separate TFileView factory.
|
|
|
|
if gDelayLoadingTabs then
|
|
FileViewFlags := [fvfDelayLoadingFiles];
|
|
if sType = 'columns' then
|
|
Result := TColumnsFileView.Create(Page, AConfig, ANode, FileViewFlags)
|
|
else if sType = 'brief' then
|
|
Result := TBriefFileView.Create(Page, AConfig, ANode, FileViewFlags)
|
|
else if sType = 'thumbnails' then
|
|
Result := TThumbFileView.Create(Page, AConfig, ANode, FileViewFlags)
|
|
else begin
|
|
DCDebug(rsMsgLogError + 'Invalid file view type "%s"', [sType]);
|
|
Result := TColumnsFileView.Create(Page, AConfig, ANode, FileViewFlags);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.AssignEvents(AFileView: TFileView);
|
|
begin
|
|
with AFileView do
|
|
begin
|
|
OnBeforeChangePath := @FileViewBeforeChangePath;
|
|
OnAfterChangePath := @FileViewAfterChangePath;
|
|
OnActivate := @FileViewActivate;
|
|
OnFileListChanged := @FileViewFilesChanged;
|
|
end;
|
|
end;
|
|
|
|
// We ask the closing locked tab confirmation according to...
|
|
// ConfirmCloseLocked = 0 ...option "tb_confirm_close_locked_tab".
|
|
// ConfirmCloseLocked = 1 ...no matter the option, we ask confirmation
|
|
// ConfirmCloseLocked = 2 ...no matter the option, we do not ask confirmation
|
|
function TfrmMain.RemovePage(ANoteBook: TFileViewNotebook; iPageIndex:Integer; CloseLocked: Boolean = True; ConfirmCloseLocked: integer = 0; ShowButtonAll: Boolean = False): LongInt;
|
|
var
|
|
UserAnswer: TMyMsgResult;
|
|
begin
|
|
Result:= -1;
|
|
if (ANoteBook.PageCount > 1) and
|
|
(iPageIndex >= 0) and
|
|
(iPageIndex < ANoteBook.PageCount) then
|
|
begin
|
|
if (ANoteBook.Page[iPageIndex].LockState <> tlsNormal) AND (((ConfirmCloseLocked=0) AND (tb_confirm_close_locked_tab in gDirTabOptions)) OR (ConfirmCloseLocked=1)) then
|
|
begin
|
|
if CloseLocked then
|
|
begin
|
|
if ShowButtonAll then
|
|
UserAnswer := MsgBox(Format(rsMsgCloseLockedTab, [ANoteBook.Page[iPageIndex].Caption]), [msmbYes, msmbAll, msmbNo, msmbCancel], msmbYes, msmbCancel)
|
|
else
|
|
UserAnswer := MsgBox(Format(rsMsgCloseLockedTab, [ANoteBook.Page[iPageIndex].Caption]), [msmbYes, msmbNo, msmbCancel], msmbYes, msmbCancel);
|
|
|
|
case UserAnswer of
|
|
mmrNo:
|
|
Exit(1);
|
|
mmrCancel, mmrNone:
|
|
Exit(2);
|
|
end
|
|
end
|
|
else
|
|
Exit(1);
|
|
end;
|
|
QuickViewClose;
|
|
ANoteBook.RemovePage(iPageIndex);
|
|
|
|
if UserAnswer=mmrAll then Result:=3 else Result:= 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ReLoadTabs(ANoteBook: TFileViewNotebook);
|
|
var
|
|
I : Integer;
|
|
begin
|
|
for I := 0 to ANoteBook.PageCount - 1 do
|
|
begin
|
|
ANoteBook.View[I].UpdateView;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.LoadTabsXml(AConfig: TXmlConfig; ABranch:string; ANoteBook: TFileViewNotebook);
|
|
// default was ABranch: 'Tabs/OpenedTabs/'
|
|
var
|
|
sPath, sViewType: String;
|
|
iActiveTab: Integer;
|
|
Page: TFileViewPage;
|
|
AFileView: TFileView;
|
|
AFileViewFlags: TFileViewFlags;
|
|
aFileSource: IFileSource;
|
|
RootNode, TabNode, ViewNode: TXmlNode;
|
|
begin
|
|
RootNode := AConfig.FindNode(AConfig.RootNode,ABranch);
|
|
|
|
if Assigned(RootNode) then
|
|
begin
|
|
TabNode := RootNode.FirstChild;
|
|
while Assigned(TabNode) do
|
|
begin
|
|
if TabNode.CompareName('Tab') = 0 then
|
|
begin
|
|
Page := nil;
|
|
AFileView := nil;
|
|
|
|
ViewNode := AConfig.FindNode(TabNode, 'FileView', False);
|
|
if Assigned(ViewNode) then
|
|
begin
|
|
// File view has its own configuration.
|
|
if AConfig.TryGetAttr(ViewNode, 'Type', sViewType) then
|
|
begin
|
|
Page := ANoteBook.AddPage;
|
|
Page.LoadConfiguration(AConfig, TabNode);
|
|
AFileView := CreateFileView(sViewType, Page, AConfig, ViewNode);
|
|
end
|
|
else
|
|
DCDebug('File view type not specified in configuration: ' + AConfig.GetPathFromNode(ViewNode) + '.');
|
|
end
|
|
// Else try old configuration.
|
|
else if AConfig.TryGetValue(TabNode, 'Path', sPath) then
|
|
begin
|
|
sPath := GetDeepestExistingPath(sPath);
|
|
if sPath <> EmptyStr then
|
|
begin
|
|
Page := ANoteBook.AddPage;
|
|
Page.LoadConfiguration(AConfig, TabNode);
|
|
AFileView := CreateFileView('columns', Page, AConfig, TabNode);
|
|
AFileView.AddFileSource(TFileSystemFileSource.GetFileSource, sPath);
|
|
end;
|
|
end
|
|
else
|
|
DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(TabNode) + '.');
|
|
|
|
if Assigned(Page) then
|
|
begin
|
|
if (not Assigned(AFileView)) or (AFileView.FileSourcesCount = 0) then
|
|
begin
|
|
ANoteBook.RemovePage(Page);
|
|
end
|
|
else
|
|
begin
|
|
if (Page.LockState in [tlsPathLocked, tlsPathResets, tlsDirsInNewTab]) and (Page.LockPath = '') then
|
|
Page.LockPath := AFileView.CurrentPath;
|
|
// Assign events after loading file source.
|
|
AssignEvents(AFileView);
|
|
end;
|
|
end;
|
|
end;
|
|
TabNode := TabNode.NextSibling;
|
|
end;
|
|
end;
|
|
// Create at least one tab.
|
|
if ANoteBook.PageCount = 0 then
|
|
begin
|
|
Page := ANoteBook.AddPage;
|
|
aFileSource := TFileSystemFileSource.GetFileSource;
|
|
if gDelayLoadingTabs then
|
|
AFileViewFlags := [fvfDelayLoadingFiles]
|
|
else
|
|
AFileViewFlags := [];
|
|
AFileView := TColumnsFileView.Create(Page, aFileSource, gpExePath, AFileViewFlags);
|
|
Commands.DoSortByFunctions(AFileView, ColSet.GetColumnSet('Default').GetColumnFunctions(0));
|
|
AssignEvents(AFileView);
|
|
end
|
|
else if Assigned(RootNode) then
|
|
begin
|
|
// read active tab index
|
|
iActiveTab := AConfig.GetValue(RootNode, 'ActiveTab', 0);
|
|
// set active tab
|
|
if (iActiveTab >= 0) and (iActiveTab < ANoteBook.PageCount) then
|
|
begin
|
|
if ANoteBook.PageIndex = iActiveTab then
|
|
nbPageChanged(ANoteBook)
|
|
else
|
|
ANoteBook.PageIndex := iActiveTab;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TfrmMain.SaveTabsXml(AConfig: TXmlConfig;ABranch:string; ANoteBook: TFileViewNotebook; ASaveHistory:boolean);
|
|
// default was: 'Tabs/OpenedTabs'
|
|
var
|
|
I: Integer;
|
|
TabsSection: String;
|
|
Page: TFileViewPage;
|
|
RootNode, TabNode, ViewNode: TXmlNode;
|
|
begin
|
|
RootNode := AConfig.FindNode(AConfig.RootNode, ABranch, True);
|
|
if ANoteBook = nbLeft then
|
|
TabsSection := 'Left'
|
|
else
|
|
TabsSection := 'Right';
|
|
RootNode := AConfig.FindNode(RootNode, TabsSection, True);
|
|
|
|
AConfig.ClearNode(RootNode);
|
|
AConfig.AddValue(RootNode, 'ActiveTab', ANoteBook.PageIndex);
|
|
|
|
for I:= 0 to ANoteBook.PageCount - 1 do
|
|
begin
|
|
TabNode := AConfig.AddNode(RootNode, 'Tab');
|
|
ViewNode := AConfig.AddNode(TabNode, 'FileView');
|
|
|
|
Page := ANoteBook.Page[I];
|
|
Page.SaveConfiguration(AConfig, TabNode);
|
|
Page.FileView.SaveConfiguration(AConfig, ViewNode, ASaveHistory);
|
|
end;
|
|
end;
|
|
|
|
{ TfrmMain.LoadTheseTabsWithThisConfig }
|
|
// Will have tabs section from Xml from either left or right and store it back on actual form on left, right, active, inactive, both or none, with setting keep or not etc.
|
|
// The "ABranch" *must* include the trailing slash when calling here.
|
|
procedure TfrmMain.LoadTheseTabsWithThisConfig(Config: TXmlConfig; ABranch:string; Source, Destination:TTabsConfigLocation; DestinationToKeep : TTabsConfigLocation; var TabsAlreadyDestroyedFlags:TTabsFlagsAlreadyDestroyed);
|
|
var
|
|
sSourceSectionName: string;
|
|
CheckNode: TXmlNode;
|
|
begin
|
|
if Destination<>tclNone then
|
|
begin
|
|
QuickViewClose;
|
|
|
|
// 1. Normalize our destination side and destination to keep in case params specified active/inactive
|
|
if ((Destination=tclActive) and (ActiveFrame=FrameLeft)) OR ((Destination=tclInactive) and (NotActiveFrame=FrameLeft)) then Destination:=tclLeft;
|
|
if ((Destination=tclActive) and (ActiveFrame=FrameRight)) OR ((Destination=tclInactive) and (NotActiveFrame=FrameRight)) then Destination:=tclRight;
|
|
if ((DestinationToKeep=tclActive) and (ActiveFrame=FrameLeft)) OR ((DestinationToKeep=tclInactive) and (NotActiveFrame=FrameLeft)) then DestinationToKeep:=tclLeft;
|
|
if ((DestinationToKeep=tclActive) and (ActiveFrame=FrameRight)) OR ((DestinationToKeep=tclInactive) and (NotActiveFrame=FrameRight)) then DestinationToKeep:=tclRight;
|
|
|
|
// 2. Setup our source section name.
|
|
case Source of
|
|
tclLeft: sSourceSectionName := 'Left';
|
|
tclRight: sSourceSectionName := 'Right';
|
|
end;
|
|
|
|
// 3. Actual load infos from config file.
|
|
if (Destination=tclLeft) OR (Destination=tclBoth) then
|
|
begin
|
|
CheckNode := Config.FindNode(Config.RootNode, ABranch + sSourceSectionName);
|
|
if Assigned(CheckNode) then
|
|
begin
|
|
if (DestinationToKeep<>tclLeft) AND (DestinationToKeep<>tclBoth) AND (not(tfadLeft in TabsAlreadyDestroyedFlags)) then
|
|
begin
|
|
frmMain.LeftTabs.DestroyAllPages;
|
|
TabsAlreadyDestroyedFlags := TabsAlreadyDestroyedFlags + [tfadLeft]; // To don't delete it twice in case both target are left.
|
|
end;
|
|
end;
|
|
LoadTabsXml(Config, ABranch + sSourceSectionName, LeftTabs);
|
|
end;
|
|
|
|
if (Destination=tclRight) OR (Destination=tclBoth) then
|
|
begin
|
|
CheckNode := Config.FindNode(Config.RootNode, ABranch + sSourceSectionName);
|
|
if Assigned(CheckNode) then
|
|
begin
|
|
if (DestinationToKeep<>tclRight) AND (DestinationToKeep<>tclBoth) AND (not(tfadRight in TabsAlreadyDestroyedFlags)) then
|
|
begin
|
|
frmMain.RightTabs.DestroyAllPages;
|
|
TabsAlreadyDestroyedFlags := TabsAlreadyDestroyedFlags + [tfadRight]; // To don't delete it twice in case both target are right.
|
|
end;
|
|
LoadTabsXml(Config, ABranch + sSourceSectionName, RightTabs);
|
|
end;
|
|
end;
|
|
|
|
// 4. Refresh content of tabs.
|
|
case Destination of
|
|
tclLeft: FrameLeft.Flags := FrameLeft.Flags - [fvfDelayLoadingFiles];
|
|
tclRight: FrameRight.Flags := FrameRight.Flags - [fvfDelayLoadingFiles];
|
|
tclBoth:
|
|
begin
|
|
FrameLeft.Flags := FrameLeft.Flags - [fvfDelayLoadingFiles];
|
|
FrameRight.Flags := FrameRight.Flags - [fvfDelayLoadingFiles];
|
|
end;
|
|
end;
|
|
end; // if Destination<>tclNone then
|
|
end;
|
|
|
|
procedure TfrmMain.ToggleConsole;
|
|
begin
|
|
if gTermWindow then
|
|
begin
|
|
if not Assigned(cmdConsole) then
|
|
begin
|
|
cmdConsole:= TVirtualTerminal.Create(pgConsole);
|
|
cmdConsole.Parent:= pgConsole;
|
|
cmdConsole.Align:= alClient;
|
|
cmdConsole.ShowHint:= False;
|
|
end;
|
|
FontOptionsToFont(gFonts[dcfConsole], cmdConsole.Font); //We set the font here because if we're coming back from configuration the font in options, we'll later pass here to affect that font if ever displayed.
|
|
if not Assigned(Cons) then
|
|
begin
|
|
Cons:= TPtyDevice.Create(Self);
|
|
cmdConsole.PtyDevice:= Cons;
|
|
Cons.Connected:= True;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if Assigned(cmdConsole) then
|
|
begin
|
|
cmdConsole.Hide;
|
|
FreeAndNil(cmdConsole);
|
|
end;
|
|
FreeAndNil(Cons);
|
|
end;
|
|
|
|
nbConsole.Visible:= gTermWindow;
|
|
ConsoleSplitter.Visible:= gTermWindow;
|
|
end;
|
|
|
|
procedure TfrmMain.ShowOptionsLayout(Data: PtrInt);
|
|
begin
|
|
ShowOptions('TfrmOptionsLayout');
|
|
end;
|
|
|
|
procedure TfrmMain.ToggleFullscreenConsole;
|
|
begin
|
|
if not gTermWindow then
|
|
begin
|
|
if MessageDlg(rsMsgTerminalDisabled, mtWarning, [mbYes, mbNo], 0, mbYes) = mrYes then
|
|
Application.QueueAsyncCall(@ShowOptionsLayout, 0);
|
|
end
|
|
else if nbConsole.Height < (nbConsole.Height + pnlNotebooks.Height - 1) then
|
|
begin
|
|
nbConsole.Height := nbConsole.Height + pnlNotebooks.Height;
|
|
if not cmdConsole.Visible then cmdConsole.Visible:= True;
|
|
if cmdConsole.CanFocus then cmdConsole.SetFocus;
|
|
end
|
|
else begin
|
|
cmdConsole.Hide;
|
|
nbConsole.Height := 0;
|
|
if ActiveFrame.CanFocus then ActiveFrame.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.ToolbarExecuteCommand(ToolItem: TKASToolItem);
|
|
var
|
|
CommandItem: TKASCommandItem;
|
|
CommandFuncResult: TCommandFuncResult;
|
|
begin
|
|
if not Draging then
|
|
begin
|
|
CommandItem := ToolItem as TKASCommandItem;
|
|
CommandFuncResult:=Commands.Commands.ExecuteCommand(CommandItem.Command, CommandItem.Params);
|
|
if gToolbarReportErrorWithCommands AND (CommandFuncResult=cfrNotFound) then
|
|
begin
|
|
MsgError(Format(rsMsgCommandNotFound, [CommandItem.Command]));
|
|
end;
|
|
end;
|
|
Draging := False;
|
|
end;
|
|
|
|
procedure TfrmMain.ToolbarExecuteProgram(ToolItem: TKASToolItem);
|
|
var
|
|
ProgramItem: TKASProgramItem;
|
|
CommandExecResult: boolean;
|
|
begin
|
|
if not Draging then
|
|
begin
|
|
ProgramItem := ToolItem as TKASProgramItem;
|
|
CommandExecResult:=ProcessExtCommandFork(ProgramItem.Command, ProgramItem.Params, ProgramItem.StartPath);
|
|
if gToolbarReportErrorWithCommands AND (CommandExecResult=FALSE) then
|
|
MsgError(Format(rsMsgProblemExecutingCommand,[ProgramItem.Command]));
|
|
end;
|
|
Draging := False;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateWindowView;
|
|
|
|
procedure UpdateNoteBook(NoteBook: TFileViewNotebook);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
NoteBook.ShowTabs := ((NoteBook.PageCount > 1) or (tb_always_visible in gDirTabOptions)) and gDirectoryTabs;
|
|
|
|
if tb_show_close_button in gDirTabOptions then
|
|
begin
|
|
NoteBook.Options := NoteBook.Options + [nboShowCloseButtons];
|
|
end
|
|
else
|
|
begin
|
|
NoteBook.Options := NoteBook.Options - [nboShowCloseButtons];
|
|
end;
|
|
|
|
if nbcMultiline in NoteBook.GetCapabilities then
|
|
NoteBook.MultiLine := tb_multiple_lines in gDirTabOptions;
|
|
|
|
case gDirTabPosition of
|
|
tbpos_top: NoteBook.TabPosition := tpTop;
|
|
tbpos_bottom: NoteBook.TabPosition := tpBottom;
|
|
else NoteBook.TabPosition := tpTop;
|
|
end;
|
|
|
|
if FInitializedView then
|
|
begin
|
|
// Update all tabs
|
|
for I := 0 to NoteBook.PageCount - 1 do
|
|
begin
|
|
NoteBook.View[I].UpdateView;
|
|
end;
|
|
// Update active tab
|
|
if Assigned(NoteBook.ActiveView) then
|
|
begin
|
|
NoteBook.ActiveView.ApplySettings;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure AnchorHorizontalBetween(AControl, ALeftSibling, ARightSibling: TControl);
|
|
begin
|
|
AControl.Anchors := AControl.Anchors + [akLeft, akRight];
|
|
AControl.AnchorSide[akLeft].Control := ALeftSibling;
|
|
AControl.AnchorSide[akLeft].Side := asrRight;
|
|
AControl.AnchorSide[akRight].Control := ARightSibling;
|
|
AControl.AnchorSide[akRight].Side := asrLeft;
|
|
end;
|
|
|
|
procedure AnchorHorizontal(AControl, ASibling: TControl);
|
|
begin
|
|
AControl.Anchors := AControl.Anchors + [akLeft, akRight];
|
|
AControl.AnchorSide[akLeft].Control := ASibling;
|
|
AControl.AnchorSide[akLeft].Side := asrLeft;
|
|
AControl.AnchorSide[akRight].Control := ASibling;
|
|
AControl.AnchorSide[akRight].Side := asrRight;
|
|
end;
|
|
|
|
procedure AnchorFreeSpace(LeftControl, RightControl: TControl; ExcludeVert: Boolean);
|
|
begin
|
|
if gDrivesListButton then
|
|
begin
|
|
AnchorHorizontalBetween(LeftControl, btnLeftDrive, btnLeftDirectoryHotlist);
|
|
AnchorHorizontalBetween(RightControl, btnRightDrive, btnRightDirectoryHotlist);
|
|
|
|
if not ExcludeVert then
|
|
begin
|
|
LeftControl.AnchorVerticalCenterTo(pnlLeftTools);
|
|
RightControl.AnchorVerticalCenterTo(pnlRightTools);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
AnchorHorizontal(LeftControl, pnlLeftTools);
|
|
AnchorHorizontal(RightControl, pnlRightTools);
|
|
|
|
if not ExcludeVert then
|
|
begin
|
|
LeftControl.AnchorSide[akTop].Control := pnlLeftTools;
|
|
LeftControl.AnchorSide[akTop].Side := asrTop;
|
|
RightControl.AnchorSide[akTop].Control := pnlRightTools;
|
|
RightControl.AnchorSide[akTop].Side := asrTop;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
HMForm: THMForm;
|
|
FunButton: TSpeedButton;
|
|
Hotkey: THotkey;
|
|
begin
|
|
DisableAutoSizing;
|
|
try
|
|
if gHorizontalFilePanels then
|
|
begin
|
|
pnlLeft.Align := alTop;
|
|
pnlLeft.BorderSpacing.Right := 0;
|
|
pnlLeft.BorderSpacing.Bottom := 3;
|
|
MainSplitter.Cursor := crVSplit;
|
|
MiddleToolBar.Align:= alTop;
|
|
MiddleToolBar.Top:= pnlLeft.Height + 1;
|
|
end
|
|
else
|
|
begin
|
|
pnlLeft.Align := alLeft;
|
|
pnlLeft.BorderSpacing.Right := 3;
|
|
pnlLeft.BorderSpacing.Bottom := 0;
|
|
MainSplitter.Cursor := crHSplit;
|
|
MiddleToolBar.Align:= alLeft;
|
|
MiddleToolBar.Left:= pnlLeft.Width + 1;
|
|
end;
|
|
|
|
(* Middle Tool Bar *)
|
|
MiddleToolbar.Visible:= gMiddleToolBar;
|
|
MiddleToolbar.Flat:= gMiddleToolBarFlat;
|
|
MiddleToolbar.GlyphSize:= gMiddleToolBarIconSize;
|
|
MiddleToolbar.ShowCaptions:= gMiddleToolBarShowCaptions;
|
|
MiddleToolbar.SetButtonSize(gMiddleToolBarButtonSize, gMiddleToolBarButtonSize);
|
|
LoadToolbar(MiddleToolBar);
|
|
|
|
pnlLeftResize(pnlLeft);
|
|
pnlNotebooksResize(pnlNotebooks);
|
|
|
|
(* Disk Panels *)
|
|
if gHorizontalFilePanels and gDriveBar1 and gDriveBar2 then
|
|
begin
|
|
dskLeft.Parent := pnlDiskLeftInner;
|
|
dskRight.Parent := pnlDiskRightInner;
|
|
end
|
|
else
|
|
begin
|
|
dskLeft.Parent := pnlDskLeft;
|
|
dskRight.Parent := pnlDskRight;
|
|
end;
|
|
|
|
pnlDiskResize(pnlDisk);
|
|
pnlRightResize(pnlRight);
|
|
|
|
dskLeft.GlyphSize:= gDiskIconsSize;
|
|
dskRight.GlyphSize:= gDiskIconsSize;
|
|
dskLeft.ButtonHeight:= gDiskIconsSize + 6;
|
|
dskRight.ButtonHeight:= gDiskIconsSize + 6;
|
|
|
|
pnlDiskLeftInner.Visible := gHorizontalFilePanels and gDriveBar1 and gDriveBar2;
|
|
pnlDiskRightInner.Visible := gHorizontalFilePanels and gDriveBar1 and gDriveBar2;
|
|
pnlDskLeft.Visible := not gHorizontalFilePanels and gDriveBar1 and gDriveBar2;
|
|
pnlDskRight.Visible := gDriveBar1 and (not gHorizontalFilePanels or not gDriveBar2);
|
|
pnlDisk.Visible := pnlDskLeft.Visible or pnlDskRight.Visible;
|
|
|
|
if gHorizontalFilePanels and gDriveBar1 and gDriveBar2 then
|
|
begin
|
|
pnlLeftTools.Top := pnlDiskLeftInner.Height + 1;
|
|
pnlRightTools.Top := pnlDiskRightInner.Height + 1;
|
|
end;
|
|
|
|
// Create disk panels after assigning parent.
|
|
UpdateDiskCount; // Update list of showed drives
|
|
(*/ Disk Panels *)
|
|
|
|
FDrivesListPopup.UpdateView;
|
|
|
|
(*Main menu*)
|
|
Commands.DoShowMainMenu(gMainMenu);
|
|
|
|
(*Main Tool Bar*)
|
|
MainToolBar.Visible:= gButtonBar;
|
|
MainToolBar.Flat:= gToolBarFlat;
|
|
MainToolBar.GlyphSize:= gToolBarIconSize;
|
|
MainToolBar.ShowCaptions:= gToolBarShowCaptions;
|
|
MainToolBar.SetButtonSize(gToolBarButtonSize, gToolBarButtonSize);
|
|
LoadToolbar(MainToolBar);
|
|
|
|
btnLeftDrive.Visible := gDrivesListButton;
|
|
btnLeftDrive.Flat := gInterfaceFlat;
|
|
btnLeftRoot.Visible := gDrivesListButton;
|
|
btnLeftRoot.Flat := gInterfaceFlat;
|
|
btnLeftUp.Visible := gDrivesListButton;
|
|
btnLeftUp.Flat := gInterfaceFlat;
|
|
btnLeftHome.Visible := gDrivesListButton;
|
|
btnLeftHome.Flat := gInterfaceFlat;
|
|
btnLeftDirectoryHotlist.Visible := gDrivesListButton;
|
|
btnLeftDirectoryHotlist.Flat := gInterfaceFlat;
|
|
btnLeftEqualRight.Visible := gDrivesListButton;
|
|
btnLeftEqualRight.Flat:= gInterfaceFlat;
|
|
lblLeftDriveInfo.Visible:= gDriveFreeSpace;
|
|
pbxLeftDrive.Visible := gDriveInd;
|
|
pnlLeftTools.Visible:= gDrivesListButton or gDriveFreeSpace or gDriveInd;
|
|
pnlLeftTools.DoubleBuffered := True;
|
|
|
|
btnRightDrive.Visible := gDrivesListButton;
|
|
btnRightDrive.Flat := gInterfaceFlat;
|
|
btnRightRoot.Visible := gDrivesListButton;
|
|
btnRightRoot.Flat := gInterfaceFlat;
|
|
btnRightUp.Visible := gDrivesListButton;
|
|
btnRightUp.Flat := gInterfaceFlat;
|
|
btnRightHome.Visible := gDrivesListButton;;
|
|
btnRightHome.Flat := gInterfaceFlat;
|
|
btnRightDirectoryHotlist.Visible := gDrivesListButton;
|
|
btnRightDirectoryHotlist.Flat := gInterfaceFlat;
|
|
btnRightEqualLeft.Visible := gDrivesListButton;
|
|
btnRightEqualLeft.Flat:= gInterfaceFlat;
|
|
lblRightDriveInfo.Visible:= gDriveFreeSpace;
|
|
pbxRightDrive.Visible := gDriveInd;
|
|
pnlRightTools.Visible:= gDrivesListButton or gDriveFreeSpace or gDriveInd;
|
|
pnlRightTools.DoubleBuffered := True;
|
|
|
|
// Free space indicator.
|
|
if gDriveFreeSpace then
|
|
begin
|
|
AnchorFreeSpace(lblLeftDriveInfo, lblRightDriveInfo, gDriveInd);
|
|
if gDriveInd then
|
|
begin
|
|
lblLeftDriveInfo.AnchorSide[akTop].Side := asrTop;
|
|
lblRightDriveInfo.AnchorSide[akTop].Side := asrTop;
|
|
end;
|
|
end;
|
|
|
|
// Drive free space indicator
|
|
if gDriveInd then
|
|
begin
|
|
AnchorFreeSpace(pbxLeftDrive, pbxRightDrive, gDriveFreeSpace);
|
|
if gDriveFreeSpace then
|
|
begin
|
|
pbxLeftDrive.AnchorSide[akTop].Control := lblLeftDriveInfo;
|
|
pbxLeftDrive.AnchorSide[akTop].Side := asrBottom;
|
|
pbxRightDrive.AnchorSide[akTop].Control := lblRightDriveInfo;
|
|
pbxRightDrive.AnchorSide[akTop].Side := asrBottom;
|
|
end;
|
|
end;
|
|
|
|
// Separate tree
|
|
UpdateShellTreeView;
|
|
UpdateTreeView;
|
|
|
|
// Operations panel and menu
|
|
if (gPanelOfOp = False) then
|
|
FreeAndNil(FOperationsPanel)
|
|
else if (FOperationsPanel = nil) then
|
|
begin
|
|
FOperationsPanel := TOperationsPanel.Create(Self);
|
|
FOperationsPanel.Parent := PanelAllProgress;
|
|
FOperationsPanel.DoubleBuffered := True;
|
|
PanelAllProgress.OnResize := @FOperationsPanel.ParentResized;
|
|
end;
|
|
|
|
PanelAllProgress.Visible := gPanelOfOp;
|
|
Timer.Enabled := (gPanelOfOp or gProgInMenuBar) and
|
|
(OperationsManager.OperationsCount > 0);
|
|
|
|
// Log window
|
|
seLogWindow.Visible := gLogWindow;
|
|
LogSplitter.Visible := gLogWindow;
|
|
// Align log window
|
|
seLogWindow.Top := 0;
|
|
LogSplitter.Top := 0;
|
|
FontOptionsToFont(gFonts[dcfLog], seLogWindow.Font);
|
|
|
|
// Command line
|
|
pnlCmdLine.Visible := gCmdLine;
|
|
pnlCommand.Visible := gCmdLine or gTermWindow;
|
|
|
|
// Align command line and terminal window
|
|
pnlCommand.Top := -Height;
|
|
ConsoleSplitter.Top:= -Height;
|
|
ToggleConsole;
|
|
|
|
// Function keys
|
|
pnlKeys.Visible := gKeyButtons;
|
|
if gKeyButtons then
|
|
begin
|
|
pnlKeys.Top:= Height * 2;
|
|
HMForm := HotMan.Forms.Find('Main');
|
|
for I := 0 to pnlKeys.ControlCount - 1 do
|
|
begin
|
|
if pnlKeys.Controls[I] is TSpeedButton then
|
|
begin
|
|
FunButton := pnlKeys.Controls[I] as TSpeedButton;
|
|
FunButton.Flat := gInterfaceFlat;
|
|
if Assigned(HMForm) then
|
|
begin
|
|
Hotkey := HMForm.Hotkeys.FindByCommand(FunctionButtonsCaptions[I].ACommand);
|
|
if Assigned(Hotkey) then
|
|
FunButton.Caption := FunctionButtonsCaptions[I].ACaption + ' ' + ShortcutsToText(Hotkey.Shortcuts);
|
|
end;
|
|
end;
|
|
end;
|
|
UpdateGUIFunctionKeys;
|
|
end;
|
|
|
|
UpdateNoteBook(nbLeft);
|
|
UpdateNoteBook(nbRight);
|
|
|
|
if FInitializedView then
|
|
begin
|
|
UpdateSelectedDrives;
|
|
UpdateFreeSpace(fpLeft, True);
|
|
UpdateFreeSpace(fpRight, True);
|
|
end;
|
|
|
|
UpdateHotDirIcons; // Preferable to be loaded even if not required in popupmenu *because* in the tree it's a must, especially when checking for missing directories
|
|
ShowTrayIcon(gAlwaysShowTrayIcon);
|
|
UpdateMainTitleBar;
|
|
|
|
FInitializedView := True;
|
|
finally
|
|
EnableAutoSizing;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.edtCommandKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
if not edtCommand.DroppedDown and ((Key=VK_UP) or (Key=VK_DOWN)) then
|
|
begin
|
|
ActiveFrame.SetFocus;
|
|
Key:= 0;
|
|
end
|
|
else if edtCommand.DroppedDown and (Key in [VK_RETURN, VK_SELECT, VK_ESCAPE]) then
|
|
begin
|
|
edtCommand.DroppedDown := False;
|
|
Key := 0;
|
|
end
|
|
else
|
|
case Key of
|
|
VK_ESCAPE:
|
|
begin
|
|
if edtCommand.Text <> '' then
|
|
edtCommand.Text := ''
|
|
else
|
|
ActiveFrame.SetFocus;
|
|
Key := 0;
|
|
end;
|
|
|
|
VK_RETURN, VK_SELECT:
|
|
begin
|
|
if (Shift * [ssCtrl, ssAlt, ssMeta, ssAltGr] = []) then
|
|
begin
|
|
ExecuteCommandLine(ssShift in Shift);
|
|
Key := 0;
|
|
end;
|
|
end;
|
|
|
|
VK_TAB:
|
|
begin
|
|
ActiveFrame.SetFocus;
|
|
Key := 0;
|
|
end;
|
|
|
|
VK_PAUSE:
|
|
begin
|
|
{
|
|
if gTermWindow and Assigned(Cons) then
|
|
Cons.Terminal.SendBreak_pty();
|
|
}
|
|
end;
|
|
end;
|
|
|
|
CheckCommandLine(GetKeyShiftStateEx, Key);
|
|
end;
|
|
|
|
procedure TfrmMain.edtCommandExit(Sender: TObject);
|
|
begin
|
|
// Hide command line if it was temporarily shown.
|
|
if (not gCmdLine) and IsCommandLineVisible and (edtCommand.Text = '') then
|
|
begin
|
|
pnlCmdLine.Visible := False;
|
|
pnlCommand.Visible := gTermWindow;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.tbChangeDirClick(Sender: TObject);
|
|
var
|
|
sDir: String;
|
|
ToolItem: TKASToolItem;
|
|
Button: TKASToolButton;
|
|
begin
|
|
Button := TKASToolButton(pmToolBar.Tag);
|
|
if Assigned(Button) then
|
|
begin
|
|
ToolItem := Button.ToolItem;
|
|
if ToolItem is TKASProgramItem then
|
|
begin
|
|
sDir := TKASProgramItem(ToolItem).StartPath;
|
|
sDir := PrepareParameter(sDir, nil, [ppoNormalizePathDelims, ppoReplaceTilde]);
|
|
Commands.cm_ChangeDir([sDir]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.tbCopyClick(Sender: TObject);
|
|
var
|
|
ToolItem: TKASToolItem;
|
|
ItemClone: TKASToolItem = nil;
|
|
Serializer: TKASToolBarSerializer = nil;
|
|
Stream: TStringStream = nil;
|
|
Button: TKASToolButton;
|
|
Toolbar: TKASToolBar;
|
|
begin
|
|
Button := TKASToolButton(pmToolBar.Tag);
|
|
if Assigned(Button) then
|
|
try
|
|
Toolbar := Button.ToolBar;
|
|
ToolItem := Button.ToolItem;
|
|
|
|
// Create a copy so that ID of the button is different.
|
|
if Sender = tbCopy then
|
|
begin
|
|
ItemClone := ToolItem.Clone;
|
|
ToolItem := ItemClone;
|
|
end;
|
|
|
|
Stream := TStringStream.Create('');
|
|
Stream.WriteString(DCToolItemClipboardHeader);
|
|
Serializer := TKASToolBarSerializer.Create;
|
|
Serializer.Serialize(Stream, ToolItem);
|
|
Clipboard.SetFormat(PredefinedClipboardFormat(pcfText), Stream);
|
|
|
|
if Sender = tbCut then
|
|
Toolbar.RemoveButton(Button);
|
|
|
|
SaveToolBar(Toolbar);
|
|
finally
|
|
ItemClone.Free;
|
|
Serializer.Free;
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.tbEditClick(Sender: TObject);
|
|
begin
|
|
EditToolbarButton(TKASToolBar(pmToolBar.PopupComponent), TKASToolButton(pmToolBar.Tag));
|
|
end;
|
|
|
|
procedure TfrmMain.OnUniqueInstanceMessage(Sender: TObject; Params: TCommandLineParams);
|
|
begin
|
|
RestoreWindow;
|
|
LoadTabsCommandLine(Params);
|
|
end;
|
|
|
|
procedure TfrmMain.tbPasteClick(Sender: TObject);
|
|
var
|
|
Data: TStringList = nil;
|
|
ProgramItem: TKASProgramItem;
|
|
ToolItem: TKASToolItem;
|
|
Loader: TKASToolBarLoader = nil;
|
|
Serializer: TKASToolBarSerializer = nil;
|
|
Stream: TStringStream = nil;
|
|
Pasted: Boolean = False;
|
|
Button: TKASToolButton;
|
|
Toolbar: TKASToolBar;
|
|
begin
|
|
Stream := TStringStream.Create('');
|
|
if Clipboard.GetFormat(PredefinedClipboardFormat(pcfText), Stream) then
|
|
try
|
|
Button := TKASToolButton(pmToolBar.Tag);
|
|
Toolbar := TKASToolBar(pmToolBar.PopupComponent);
|
|
|
|
// Cut any trailing zeros.
|
|
while Stream.DataString[Length(Stream.DataString)] = #0 do
|
|
Stream.Size := Stream.Size - 1;
|
|
|
|
if StrBegins(Stream.DataString, TCToolbarClipboardHeader) or
|
|
StrBegins(Stream.DataString, DCToolbarClipboardHeader) then
|
|
begin
|
|
Data:= TStringList.Create;
|
|
Data.Text:= Stream.DataString;
|
|
if Data.Count < 6 then Exit;
|
|
if (Data[0] = TCToolbarClipboardHeader) or
|
|
(Data[0] = DCToolbarClipboardHeader) then
|
|
begin
|
|
ProgramItem := TKASProgramItem.Create;
|
|
ProgramItem.Command := Data[1];
|
|
ProgramItem.Params := Data[2];
|
|
ProgramItem.Icon := Data[3];
|
|
ProgramItem.Hint := Data[4];
|
|
ProgramItem.StartPath := Data[5];
|
|
Toolbar.InsertButton(Button, ProgramItem);
|
|
SaveToolBar(Toolbar);
|
|
Pasted := True;
|
|
end;
|
|
end
|
|
else if StrBegins(Stream.DataString, DCToolItemClipboardHeader) then
|
|
begin
|
|
Stream.Position := Length(DCToolItemClipboardHeader);
|
|
Serializer := TKASToolBarSerializer.Create;
|
|
Loader := TKASToolBarExtendedLoader.Create(Commands.Commands);
|
|
try
|
|
ToolItem := Serializer.Deserialize(Stream, Loader);
|
|
Toolbar.InsertButton(Button, ToolItem);
|
|
SaveToolBar(Toolbar);
|
|
Pasted := True;
|
|
except
|
|
on EXMLReadError do;
|
|
end;
|
|
end;
|
|
|
|
if not Pasted then
|
|
MessageDlg(Application.Title, rsClipboardContainsInvalidToolbarData, mtWarning, [mbOK], 0);
|
|
|
|
finally
|
|
Data.Free;
|
|
Loader.Free;
|
|
Serializer.Free;
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.CheckCommandLine(ShiftEx: TShiftState; var Key: Word);
|
|
var
|
|
ModifierKeys: TShiftState;
|
|
UTF8Char: TUTF8Char;
|
|
KeyTypingModifier: TKeyTypingModifier;
|
|
begin
|
|
for KeyTypingModifier in TKeyTypingModifier do
|
|
begin
|
|
if gKeyTyping[KeyTypingModifier] = ktaCommandLine then
|
|
begin
|
|
ModifierKeys := TKeyTypingModifierToShift[KeyTypingModifier];
|
|
if ((ModifierKeys <> []) and
|
|
(ShiftEx * KeyModifiersShortcutNoText = ModifierKeys))
|
|
{$IFDEF MSWINDOWS}
|
|
// Allow entering international characters with Ctrl+Alt on Windows,
|
|
// if there is no action for Ctrl+Alt and command line typing has no modifiers.
|
|
or (HasKeyboardAltGrKey and
|
|
(ShiftEx * KeyModifiersShortcutNoText = [ssCtrl, ssAlt]) and
|
|
(gKeyTyping[ktmCtrlAlt] = ktaNone) and
|
|
(gKeyTyping[ktmNone] = ktaCommandLine))
|
|
{$ENDIF}
|
|
then
|
|
begin
|
|
if (Key <> VK_SPACE) or (edtCommand.Text <> '') then
|
|
begin
|
|
UTF8Char := VirtualKeyToUTF8Char(Key, ShiftEx - ModifierKeys);
|
|
if (UTF8Char <> '') and
|
|
(not ((Length(UTF8Char) = 1) and (UTF8Char[1] in [#0..#31]))) then
|
|
begin
|
|
TypeInCommandLine(UTF8Char);
|
|
Key := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.ExecuteCommandFromEdit(sCmd: String; bRunInTerm: Boolean): Boolean;
|
|
var
|
|
iIndex: Integer;
|
|
aFile: TFile = nil;
|
|
sDir, sParams: String;
|
|
sFilename: String = '';
|
|
Operation: TFileSourceExecuteOperation = nil;
|
|
begin
|
|
Result:= True;
|
|
|
|
InsertFirstItem(sCmd, edtCommand);
|
|
// only cMaxStringItems(see uGlobs.pas) is stored
|
|
if edtCommand.Items.Count>cMaxStringItems then
|
|
edtCommand.Items.Delete(edtCommand.Items.Count-1);
|
|
edtCommand.DroppedDown:= False;
|
|
|
|
if (fspDirectAccess in ActiveFrame.FileSource.GetProperties) then
|
|
begin
|
|
if FileNameCaseSensitive then
|
|
sDir:= sCmd
|
|
else begin
|
|
sDir:= LowerCase(sCmd);
|
|
end;
|
|
iIndex:= Pos('cd ', sDir);
|
|
if (iIndex = 1) or (sDir = 'cd') then
|
|
begin
|
|
sCmd:= ReplaceEnvVars(sCmd);
|
|
|
|
if (iIndex <> 1) then
|
|
sDir:= GetHomeDir
|
|
else
|
|
begin
|
|
sDir:= RemoveQuotation(Copy(sCmd, iIndex + 3, Length(sCmd)));
|
|
sDir:= mbExpandFileName(Trim(sDir));
|
|
|
|
if (sDir = DirectorySeparator) or (sDir = '..') then
|
|
begin
|
|
if (sDir = DirectorySeparator) then
|
|
Commands.DoChangeDirToRoot(ActiveFrame)
|
|
else begin
|
|
ActiveFrame.ChangePathToParent(True);
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
sDir:= ReplaceTilde(sDir);
|
|
sDir:= GetAbsoluteFileName(ActiveFrame.CurrentPath, sDir);
|
|
if mbFileExists(sDir) then //if user entered an existing file, let's switch to the parent folder AND select that file
|
|
begin
|
|
sFilename:= ExtractFileName(sDir);
|
|
sDir:= ExtractFileDir(sDir);
|
|
end;
|
|
end;
|
|
|
|
// Choose FileSource by path
|
|
ChooseFileSource(ActiveFrame, sDir, True);
|
|
if sFilename <> '' then
|
|
ActiveFrame.SetActiveFile(sFilename);
|
|
|
|
if SameText(ExcludeBackPathDelimiter(ActiveFrame.CurrentPath), sDir) then
|
|
begin
|
|
if gTermWindow and Assigned(Cons) then
|
|
Cons.SetCurrentDir(sDir);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
//Let's see if user typed something like "c:", "X:", etc. and if so, switch active panel to that drive (like TC)
|
|
if (length(sCmd)=2) AND (pos(':',sCmd)=2) then
|
|
begin
|
|
iIndex:=0;
|
|
|
|
while (iIndex<DrivesList.Count) AND (sCmd<>'') do
|
|
begin
|
|
if lowercase(sCmd[1]) = lowercase(PDrive(DrivesList.Items[iIndex])^.DisplayName) then
|
|
begin
|
|
SetPanelDrive(PanelSelected, DrivesList.Items[iIndex],false);
|
|
sCmd:='';
|
|
end;
|
|
inc(iIndex);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
if sCmd<>'' then
|
|
begin
|
|
if gTermWindow and Assigned(Cons) then
|
|
begin
|
|
sCmd:= ReplaceEnvVars(sCmd);
|
|
Cons.WriteStr(sCmd + sLineBreak)
|
|
end
|
|
else
|
|
begin
|
|
try
|
|
SplitCmdLineToCmdParams(sCmd, sCmd, sParams); //TODO:Hum...
|
|
ProcessExtCommandFork(sCmd, sParams, ActiveFrame.CurrentPath, nil, bRunInTerm, bRunInTerm);
|
|
except
|
|
on e: EInvalidCommandLine do
|
|
MessageDlg(rsMsgInvalidCommandLine, rsMsgInvalidCommandLine + ': ' + e.Message, mtError, [mbOK], 0);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
aFile:= ActiveFrame.CloneActiveFile;
|
|
if Assigned(aFile) then
|
|
try
|
|
sCmd:= 'quote' + #32 + sCmd;
|
|
aFile.FullPath:= ActiveFrame.CurrentPath;
|
|
Operation:= ActiveFrame.FileSource.CreateExecuteOperation(
|
|
aFile,
|
|
ActiveFrame.CurrentPath,
|
|
sCmd) as TFileSourceExecuteOperation;
|
|
if Assigned(Operation) then
|
|
begin
|
|
Operation.Execute;
|
|
case Operation.ExecuteOperationResult of
|
|
fseorSuccess:
|
|
begin
|
|
ActiveFrame.Reload(True);
|
|
end;
|
|
fseorError:
|
|
begin
|
|
// Show error message
|
|
if Length(Operation.ResultString) = 0 then
|
|
msgError(rsMsgErrEOpen)
|
|
else
|
|
msgError(Operation.ResultString);
|
|
end;
|
|
fseorSymLink:
|
|
begin
|
|
// Change directory to new path (returned in Operation.ResultString)
|
|
with ActiveFrame do
|
|
begin
|
|
// If path is URI
|
|
if Pos('://', Operation.ResultString) > 0 then
|
|
ChooseFileSource(ActiveFrame, Operation.ResultString)
|
|
else if not mbSetCurrentDir(ExcludeTrailingPathDelimiter(Operation.ResultString)) then
|
|
begin
|
|
// Simply change path
|
|
CurrentPath:= Operation.ResultString;
|
|
end
|
|
else begin
|
|
// Get a new filesystem file source
|
|
AddFileSource(TFileSystemFileSource.GetFileSource, Operation.ResultString);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
FreeAndNil(aFile);
|
|
FreeAndNil(Operation);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.SetMainSplitterPos(AValue: Double);
|
|
begin
|
|
if (AValue >= 0) and (AValue <= 100) then
|
|
FMainSplitterPos:= AValue;
|
|
end;
|
|
|
|
procedure TfrmMain.SetPanelSelected(AValue: TFilePanelSelect);
|
|
begin
|
|
if PanelSelected = AValue then Exit;
|
|
PanelSelected := AValue;
|
|
UpdateTreeViewPath;
|
|
UpdateMainTitleBar;
|
|
UpdatePrompt;
|
|
if actSyncChangeDir.Checked then begin
|
|
FSyncChangeDir:= ExcludeTrailingBackslash(ActiveFrame.CurrentPath);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.TypeInCommandLine(Str: String);
|
|
begin
|
|
Commands.cm_FocusCmdLine([]);
|
|
edtCommand.Text := edtCommand.Text + Str;
|
|
edtCommand.SelStart := UTF8Length(edtCommand.Text) + 1;
|
|
end;
|
|
|
|
//LaBero begin
|
|
//Minimize the main window
|
|
procedure TfrmMain.MinimizeWindow;
|
|
begin
|
|
Self.WindowState := wsMinimized;
|
|
end;
|
|
//LaBero end
|
|
|
|
procedure TfrmMain.RestoreWindow;
|
|
begin
|
|
if HiddenToTray then
|
|
RestoreFromTray
|
|
else
|
|
begin
|
|
WindowState:= lastWindowState;
|
|
BringToFront;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.LoadTabs;
|
|
var
|
|
AConfig: TXmlConfig;
|
|
begin
|
|
if gConfig.FindNode(gConfig.RootNode, 'Tabs/OpenedTabs') <> nil then
|
|
AConfig:= gConfig
|
|
else begin
|
|
AConfig:= TXmlConfig.Create(gpCfgDir + 'tabs.xml', True);
|
|
end;
|
|
|
|
try
|
|
LoadTabsXml(AConfig, 'Tabs/OpenedTabs/Left', nbLeft);
|
|
LoadTabsXml(AConfig, 'Tabs/OpenedTabs/Right', nbRight);
|
|
finally
|
|
if (AConfig <> gConfig) then AConfig.Free;
|
|
end;
|
|
|
|
if not CommandLineParams.ActivePanelSpecified then
|
|
begin
|
|
CommandLineParams.ActivePanelSpecified:= True;
|
|
CommandLineParams.ActiveRight:= gActiveRight;
|
|
end;
|
|
|
|
LoadTabsCommandLine(CommandLineParams);
|
|
|
|
if gDelayLoadingTabs then
|
|
begin
|
|
// Load only the current active tab of each notebook.
|
|
FrameLeft.Flags := FrameLeft.Flags - [fvfDelayLoadingFiles];
|
|
FrameRight.Flags := FrameRight.Flags - [fvfDelayLoadingFiles];
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.LoadTabsCommandLine(Params: TCommandLineParams);
|
|
|
|
procedure LoadPanel(aNoteBook: TFileViewNotebook; aPath: String);
|
|
begin
|
|
if Length(aPath) <> 0 then
|
|
begin
|
|
aPath:= ReplaceEnvVars(ReplaceTilde(aPath));
|
|
if not mbFileSystemEntryExists(aPath) then
|
|
aPath:= GetDeepestExistingPath(aPath);
|
|
if Length(aPath) <> 0 then
|
|
begin
|
|
if Params.NewTab then
|
|
AddTab(aNoteBook, aPath)
|
|
else
|
|
aNoteBook.ActivePage.FileView.ChangePathAndSetActiveFile(aPath)
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
//-- set path for left panel (if set)
|
|
LoadPanel(nbLeft, Params.LeftPath);
|
|
|
|
//-- set path for right panel (if set)
|
|
LoadPanel(nbRight, Params.RightPath);
|
|
|
|
//-- set active panel, if needed
|
|
if Params.ActivePanelSpecified then
|
|
begin
|
|
if Params.ActiveRight then
|
|
SetActiveFrame(fpRight)
|
|
else
|
|
SetActiveFrame(fpLeft);
|
|
end;
|
|
|
|
//-- set path for active panel (if set)
|
|
if ActiveFrame.NotebookPage is TFileViewPage then
|
|
begin
|
|
LoadPanel((ActiveFrame.NotebookPage as TFileViewPage).Notebook, Params.ActivePanelPath);
|
|
end;
|
|
|
|
ActiveFrame.SetFocus;
|
|
end;
|
|
|
|
procedure TfrmMain.AddTab(ANoteBook: TFileViewNotebook; aPath: String);
|
|
var
|
|
Page: TFileViewPage;
|
|
AFileView: TFileView;
|
|
AFileViewFlags: TFileViewFlags;
|
|
aFileSource: IFileSource;
|
|
begin
|
|
Page := ANoteBook.AddPage;
|
|
aFileSource := TFileSystemFileSource.GetFileSource;
|
|
if gDelayLoadingTabs then
|
|
AFileViewFlags := [fvfDelayLoadingFiles]
|
|
else
|
|
AFileViewFlags := [];
|
|
AFileView := TColumnsFileView.Create(Page, aFileSource, aPath, AFileViewFlags);
|
|
AssignEvents(AFileView);
|
|
ANoteBook.PageIndex := ANoteBook.PageCount - 1;
|
|
end;
|
|
|
|
{$IF DEFINED(DARWIN)}
|
|
procedure TfrmMain.OnNSServiceOpenWithNewTab( filenames:TStringList );
|
|
begin
|
|
if Assigned(filenames) and (filenames.Count>0) then
|
|
begin
|
|
AddTab( nbRight, filenames[0] );
|
|
SetActiveFrame(fpRight);
|
|
ActiveFrame.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.NSServiceMenuIsReady(): boolean;
|
|
begin
|
|
Result:= true;
|
|
end;
|
|
|
|
function TfrmMain.NSServiceMenuGetFilenames(): TStringList;
|
|
var
|
|
filenames: TStringList;
|
|
i: Integer;
|
|
files: TFiles;
|
|
activeFile: TFile;
|
|
begin
|
|
Result:= nil;
|
|
filenames:= TStringList.Create;
|
|
|
|
files:= ActiveFrame.CloneSelectedFiles();
|
|
if files.Count>0 then
|
|
begin
|
|
for i:=0 to files.Count-1 do
|
|
begin
|
|
filenames.add( files[i].FullPath );
|
|
end;
|
|
end;
|
|
FreeAndNil( files );
|
|
|
|
if filenames.Count = 0 then
|
|
begin
|
|
activeFile:= ActiveFrame.CloneActiveFile;
|
|
if activeFile.IsNameValid() then
|
|
filenames.add( activeFile.FullPath )
|
|
else
|
|
filenames.add( activeFile.Path );
|
|
FreeAndNil( activeFile );
|
|
end;
|
|
|
|
if filenames.Count>0 then Result:= filenames;
|
|
end;
|
|
|
|
procedure TfrmMain.NSThemeChangedHandler;
|
|
begin
|
|
ThemeServices.IntfDoOnThemeChange;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TfrmMain.LoadWindowState;
|
|
var
|
|
ANode: TXmlNode;
|
|
FPixelsPerInch: Integer;
|
|
begin
|
|
// Load window bounds
|
|
ANode := gConfig.FindNode(gConfig.RootNode, 'MainWindow/Position', True);
|
|
begin
|
|
MainSplitterPos := gConfig.GetValue(ANode, 'Splitter', 50.0);
|
|
FRestoredLeft := gConfig.GetValue(ANode, 'Left', 80);
|
|
FRestoredTop := gConfig.GetValue(ANode, 'Top', 48);
|
|
FRestoredWidth := gConfig.GetValue(ANode, 'Width', 800);
|
|
FRestoredHeight := gConfig.GetValue(ANode, 'Height', 480);
|
|
FPixelsPerInch := gConfig.GetValue(ANode, 'PixelsPerInch', DesignTimePPI);
|
|
if Scaled and (Screen.PixelsPerInch <> FPixelsPerInch) then
|
|
begin
|
|
FRestoredWidth := MulDiv(FRestoredWidth, Screen.PixelsPerInch, FPixelsPerInch);
|
|
FRestoredHeight := MulDiv(FRestoredHeight, Screen.PixelsPerInch, FPixelsPerInch);
|
|
end;
|
|
if gConfig.GetValue(ANode, 'Maximized', True) then
|
|
lastWindowState:= TWindowState.wsMaximized
|
|
else
|
|
lastWindowState:= TWindowState.wsNormal;
|
|
SetBounds(FRestoredLeft, FRestoredTop, FRestoredWidth, FRestoredHeight);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.SaveWindowState;
|
|
var
|
|
ANode: TXmlNode;
|
|
begin
|
|
// Save window bounds and state
|
|
ANode := gConfig.FindNode(gConfig.RootNode, 'MainWindow/Position', True);
|
|
begin
|
|
gConfig.SetValue(ANode, 'Left', FRestoredLeft);
|
|
gConfig.SetValue(ANode, 'Top', FRestoredTop);
|
|
gConfig.SetValue(ANode, 'Width', FRestoredWidth);
|
|
gConfig.SetValue(ANode, 'Height', FRestoredHeight);
|
|
gConfig.SetValue(ANode, 'PixelsPerInch', Screen.PixelsPerInch);
|
|
gConfig.SetValue(ANode, 'Maximized', (WindowState in [wsMaximized,wsFullScreen]));
|
|
gConfig.SetValue(ANode, 'Splitter', FMainSplitterPos);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.LoadToolbar(AToolBar: TKASToolBar);
|
|
var
|
|
ToolBarLoader: TKASToolBarExtendedLoader;
|
|
ToolBarNode: TXmlNode;
|
|
begin
|
|
AToolBar.BeginUpdate;
|
|
ToolBarLoader := TKASToolBarExtendedLoader.Create(Commands.Commands);
|
|
try
|
|
AToolBar.Clear;
|
|
ToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + AToolBar.Name, False);
|
|
if Assigned(ToolBarNode) then
|
|
AToolBar.LoadConfiguration(gConfig, ToolBarNode, ToolBarLoader, tocl_FlushCurrentToolbarContent);
|
|
finally
|
|
ToolBarLoader.Free;
|
|
AToolBar.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.SaveToolBar(AToolBar: TKASToolBar);
|
|
var
|
|
ToolBarNode: TXmlNode;
|
|
begin
|
|
ToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + AToolBar.Name, True);
|
|
gConfig.ClearNode(ToolBarNode);
|
|
AToolBar.SaveConfiguration(gConfig, ToolBarNode);
|
|
end;
|
|
|
|
procedure TfrmMain.ShowLogWindow(Data: PtrInt);
|
|
var
|
|
bShow: Boolean absolute Data;
|
|
begin
|
|
LogSplitter.Visible:= bShow;
|
|
seLogWindow.Visible:= bShow;
|
|
LogSplitter.Top:= seLogWindow.Top - LogSplitter.Height;
|
|
end;
|
|
|
|
procedure TfrmMain.ConfigSaveSettings(bForce: Boolean);
|
|
var
|
|
AConfig: TXmlConfig;
|
|
begin
|
|
try
|
|
DebugLn('Saving configuration');
|
|
|
|
if gSaveCmdLineHistory then
|
|
glsCmdLineHistory.Assign(edtCommand.Items);
|
|
|
|
(* Save all tabs *)
|
|
if gSaveFolderTabs or bForce then
|
|
begin
|
|
AConfig:= TXmlConfig.Create(gpCfgDir + 'tabs.xml');
|
|
try
|
|
SaveTabsXml(AConfig, 'Tabs/OpenedTabs/', nbLeft, gSaveDirHistory);
|
|
SaveTabsXml(AConfig, 'Tabs/OpenedTabs/', nbRight, gSaveDirHistory);
|
|
AConfig.Save;
|
|
finally
|
|
AConfig.Free;
|
|
end;
|
|
gConfig.DeleteNode(gConfig.RootNode, 'Tabs/OpenedTabs');
|
|
end;
|
|
|
|
if gSaveWindowState then SaveWindowState;
|
|
|
|
if gButtonBar then SaveToolBar(MainToolBar);
|
|
|
|
SaveGlobs; // Should be last, writes configuration file
|
|
except
|
|
on E: Exception do
|
|
DebugLn('Cannot save main configuration: ', e.Message);
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.IsCommandLineVisible: Boolean;
|
|
begin
|
|
Result := (edtCommand.Visible and pnlCommand.Visible and pnlCmdLine.Visible);
|
|
end;
|
|
|
|
procedure TfrmMain.ShowCommandLine(AFocus: Boolean);
|
|
begin
|
|
if edtCommand.Visible then
|
|
begin
|
|
// Show temporarily command line on user request.
|
|
if not (gCmdLine and frmMain.IsCommandLineVisible) then
|
|
begin
|
|
pnlCommand.Show;
|
|
pnlCmdLine.Show;
|
|
end;
|
|
if AFocus then edtCommand.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
function TfrmMain.FindMatchingDrive(Address, Path: String): Integer;
|
|
var
|
|
I : Integer;
|
|
DrivePath: String;
|
|
DrivePathLen: PtrInt;
|
|
LongestPathLen: Integer = 0;
|
|
begin
|
|
Result := -1;
|
|
|
|
if Assigned(DrivesList) then
|
|
begin
|
|
Path := UTF8UpperCase(Path);
|
|
|
|
for I := 0 to DrivesList.Count - 1 do
|
|
begin
|
|
if (DrivesList[I]^.DriveType = dtSpecial) and (Length(Address) > 0) then
|
|
begin
|
|
if Pos(Address, DrivesList[I]^.Path) = 1 then
|
|
Exit(I);
|
|
end
|
|
else begin
|
|
DrivePath := UTF8UpperCase(DrivesList[I]^.Path);
|
|
DrivePathLen := UTF8Length(DrivePath);
|
|
if (DrivePathLen > LongestPathLen) and IsInPath(DrivePath, Path, True, True) then
|
|
begin
|
|
LongestPathLen := DrivePathLen;
|
|
Result := I;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateDriveToolbarSelection(DriveToolbar: TKAStoolBar; FileView: TFileView);
|
|
var
|
|
DriveIndex: Integer;
|
|
begin
|
|
DriveIndex := FindMatchingDrive(FileView.CurrentAddress, FileView.CurrentPath);
|
|
if (DriveIndex >= 0) and (DriveIndex < DriveToolbar.ButtonCount) then
|
|
DriveToolbar.Buttons[DriveIndex].Down := True
|
|
else
|
|
// Path not found in toolbar.
|
|
DriveToolbar.UncheckAllButtons;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateDriveButtonSelection(DriveButton: TSpeedButton; FileView: TFileView);
|
|
var
|
|
Drive: PDrive;
|
|
BitmapTmp: Graphics.TBitmap = nil;
|
|
begin
|
|
DriveButton.Tag := FindMatchingDrive(FileView.CurrentAddress, FileView.CurrentPath);
|
|
|
|
if not gDrivesListButton then
|
|
Exit;
|
|
|
|
if DriveButton.Tag >= 0 then
|
|
begin
|
|
Drive := DrivesList[DriveButton.Tag];
|
|
DriveButton.Caption := Drive^.DisplayName;
|
|
BitmapTmp := PixMapManager.GetDriveIcon(Drive, gDiskIconsSize, DriveButton.Color);
|
|
end
|
|
else
|
|
begin
|
|
DriveButton.Caption := '';
|
|
|
|
if FileView.FileSource.IsClass(TArchiveFileSource) then
|
|
BitmapTmp := PixMapManager.GetArchiveIcon(gDiskIconsSize, DriveButton.Color)
|
|
else
|
|
BitmapTmp := PixMapManager.GetDefaultDriveIcon(gDiskIconsSize, DriveButton.Color);
|
|
end;
|
|
|
|
DriveButton.Glyph := BitmapTmp;
|
|
|
|
DriveButton.Width := DriveButton.Glyph.Width
|
|
+ DriveButton.Canvas.TextWidth(DriveButton.Caption) + 24;
|
|
|
|
FreeAndNil(BitmapTmp);
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateSelectedDrive(ANoteBook: TFileViewNotebook);
|
|
var
|
|
FileView: TFileView;
|
|
begin
|
|
FileView := ANoteBook.ActiveView;
|
|
if Assigned(FileView) then
|
|
begin
|
|
// Change left drive toolbar for left drive button.
|
|
if (ANoteBook = nbLeft) then
|
|
begin
|
|
if gDriveBar1 then // If drives toolbar enabled at all
|
|
begin
|
|
if gDriveBar2 then // If showing two toolbars
|
|
UpdateDriveToolbarSelection(dskLeft, FileView)
|
|
else
|
|
// dskRight is the main toolbar.
|
|
UpdateDriveToolbarSelection(dskRight, FileView);
|
|
end;
|
|
UpdateDriveButtonSelection(btnLeftDrive, FileView);
|
|
end
|
|
// Change right drive toolbar for right drive button
|
|
else if (ANoteBook = nbRight) then
|
|
begin
|
|
if gDriveBar1 then
|
|
UpdateDriveToolbarSelection(dskRight, FileView);
|
|
UpdateDriveButtonSelection(btnRightDrive, FileView);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$IF DEFINED(MSWINDOWS)}
|
|
procedure TfrmMain.OnDriveIconLoaded(Data: PtrInt);
|
|
var
|
|
ADrive: TKASDriveItem;
|
|
AIcon: TDriveIcon absolute Data;
|
|
|
|
procedure UpdateDriveIcon(dskPanel: TKASToolBar);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
for Index:= 0 to dskPanel.ButtonCount - 1 do
|
|
begin
|
|
if dskPanel.Buttons[Index].ToolItem is TKASDriveItem then
|
|
begin
|
|
ADrive:= TKASDriveItem(dskPanel.Buttons[Index].ToolItem);
|
|
if SameText(ADrive.Drive^.Path, AIcon.Drive.Path) then
|
|
begin
|
|
dskPanel.Buttons[Index].Glyph.Assign(AIcon.Bitmap);
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if gDriveBar2 then UpdateDriveIcon(dskLeft);
|
|
if gDriveBar1 then UpdateDriveIcon(dskRight);
|
|
AIcon.Free;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TfrmMain.UpdateSelectedDrives;
|
|
begin
|
|
if gDriveBar1 then
|
|
begin
|
|
if gDriveBar2 then
|
|
begin
|
|
UpdateDriveToolbarSelection(dskLeft, FrameLeft);
|
|
UpdateDriveToolbarSelection(dskRight, FrameRight);
|
|
end
|
|
else
|
|
// dskRight is the main toolbar.
|
|
UpdateDriveToolbarSelection(dskRight, ActiveFrame);
|
|
end;
|
|
UpdateDriveButtonSelection(btnLeftDrive, FrameLeft);
|
|
UpdateDriveButtonSelection(btnRightDrive, FrameRight);
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateMainTitleBar;
|
|
var sTmp: String;
|
|
begin
|
|
if gShowCurDirTitleBar and (fspDirectAccess in ActiveFrame.FileSource.Properties) then
|
|
begin
|
|
sTmp := ActiveFrame.CurrentPath;
|
|
Self.Caption:= Format('%s (%s) - %s',
|
|
[GetLastDir(sTmp),
|
|
sTmp,
|
|
sStaticTitleBarString]
|
|
);
|
|
end
|
|
else
|
|
begin
|
|
Self.Caption := sStaticTitleBarString;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateGUIFunctionKeys;
|
|
var
|
|
I: Integer;
|
|
H: Integer = 0;
|
|
AButton: TSpeedButton;
|
|
begin
|
|
for I:= 0 to pnlKeys.ControlCount - 1 do
|
|
begin
|
|
if pnlKeys.Controls[I] is TSpeedButton then
|
|
begin
|
|
AButton:= TSpeedButton(pnlKeys.Controls[I]);
|
|
FontOptionsToFont(gFonts[dcfFunctionButtons], AButton.Font);
|
|
H:= Max(H, AButton.Canvas.TextHeight(AButton.Caption));
|
|
end;
|
|
end;
|
|
pnlKeys.Height := H + 4;
|
|
end;
|
|
|
|
procedure TfrmMain.ShowDrivesList(APanel: TFilePanelSelect);
|
|
var
|
|
p: TPoint;
|
|
ADriveIndex: Integer;
|
|
begin
|
|
if tb_activate_panel_on_click in gDirTabOptions then
|
|
SetActiveFrame(APanel);
|
|
|
|
case APanel of
|
|
fpLeft:
|
|
begin
|
|
p := Classes.Point(btnLeftDrive.Left, btnLeftDrive.Height);
|
|
p := pnlLeftTools.ClientToScreen(p);
|
|
ADriveIndex := btnLeftDrive.Tag;
|
|
end;
|
|
fpRight:
|
|
begin
|
|
p := Classes.Point(btnRightDrive.Left, btnRightDrive.Height);
|
|
p := pnlRightTools.ClientToScreen(p);
|
|
ADriveIndex := btnRightDrive.Tag;
|
|
end;
|
|
end;
|
|
p := ScreenToClient(p);
|
|
FDrivesListPopup.Show(p, APanel, ADriveIndex);
|
|
end;
|
|
|
|
procedure TfrmMain.HideToTray;
|
|
{$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
|
|
var
|
|
ActiveWindow: HWND;
|
|
LCLObject: TObject;
|
|
{$ENDIF}
|
|
begin
|
|
{
|
|
If a modal form is active we have to hide it first before hiding the main form
|
|
to avoid bugs:
|
|
|
|
On GTK2 a modal form loses it's modal state after the main window is
|
|
restored (GTK still says the window is modal and resetting modal state
|
|
doesn't do anything).
|
|
|
|
On QT the tray icon does not receive any mouse events (because the modal
|
|
window has capture) thus preventing the user from restoring the main window.
|
|
So when the main form is hidden the modal window is hidden too.
|
|
}
|
|
{$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
|
|
LastActiveWindow := nil;
|
|
if not Self.Active then // If there is another window active
|
|
begin
|
|
ActiveWindow := GetActiveWindow;
|
|
if ActiveWindow <> 0 then
|
|
begin
|
|
LCLObject := GetLCLOwnerObject(ActiveWindow);
|
|
if Assigned(LCLObject) and
|
|
(LCLObject is TCustomForm) and
|
|
(fsModal in (LCLObject as TCustomForm).FormState) then // only for modal windows
|
|
begin
|
|
LastActiveWindow := LCLObject as TCustomForm;
|
|
{$IFDEF LCLGTK2}
|
|
// Cannot use Hide method, because it closes the modal form.
|
|
// We only want to hide it.
|
|
LastActiveWindow.Visible := False;
|
|
{$ENDIF}
|
|
{$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
|
|
// Have to use QT directly to hide the window for this to work.
|
|
TQtWidget(LastActiveWindow.Handle).setVisible(False);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
Hide;
|
|
ShowTrayIcon(True);
|
|
HiddenToTray := True;
|
|
end;
|
|
|
|
procedure TfrmMain.RestoreFromTray;
|
|
begin
|
|
if lastWindowState=wsMaximized then WindowState:=wsMaximized;
|
|
ShowOnTop;
|
|
|
|
if not gAlwaysShowTrayIcon then
|
|
ShowTrayIcon(False);
|
|
|
|
// After the main form is shown, restore the last active modal form if there was any.
|
|
{$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
|
|
if Assigned(LastActiveWindow) then
|
|
begin
|
|
{$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
|
|
TQtWidget(LastActiveWindow.Handle).setVisible(true);
|
|
{$ENDIF}
|
|
{$IFDEF LCLGTK2}
|
|
LastActiveWindow.Show;
|
|
{$ENDIF}
|
|
LastActiveWindow := nil;
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrmMain.RightDriveBarExecuteDrive(ToolItem: TKASToolItem);
|
|
var
|
|
DriveItem: TKASDriveItem;
|
|
Panel: TFilePanelSelect;
|
|
begin
|
|
DriveItem := ToolItem as TKASDriveItem;
|
|
if gDriveBar2 then
|
|
Panel := fpRight
|
|
else
|
|
Panel := ActiveNotebook.Side;
|
|
SetPanelDrive(Panel, DriveItem.Drive, True);
|
|
end;
|
|
|
|
procedure TfrmMain.ShowTrayIcon(bShow: Boolean);
|
|
begin
|
|
if (bShow <> MainTrayIcon.Visible) and (HidingTrayIcon = False) then
|
|
begin
|
|
if bShow then
|
|
begin
|
|
MainTrayIcon.Visible := True;
|
|
end
|
|
else
|
|
begin
|
|
// ShowTrayIcon might be called from within OnClick event of the icon
|
|
// (MainTrayIconClick->RestoreFromTray->ShowTrayIcon), so the MainTrayIcon
|
|
// cannot be hidden here, because it would be destroyed causing A/V.
|
|
// Hiding it must be delayed until after the mouse click handler of the icon is finished.
|
|
HidingTrayIcon := True;
|
|
Application.QueueAsyncCall(@HideTrayIconDelayed, 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.HideTrayIconDelayed(Data: PtrInt);
|
|
begin
|
|
MainTrayIcon.Visible := False;
|
|
HidingTrayIcon := False;
|
|
end;
|
|
|
|
procedure TfrmMain.ExecuteCommandLine(bRunInTerm: Boolean);
|
|
begin
|
|
mbSetCurrentDir(ActiveFrame.CurrentPath);
|
|
ExecuteCommandFromEdit(edtCommand.Text, bRunInTerm);
|
|
edtCommand.Text := '';
|
|
ActiveFrame.Reload;
|
|
ActiveFrame.SetFocus;
|
|
{$IF DEFINED(LCLGTK) or DEFINED(LCLGTK2)}
|
|
// workaround for GTK
|
|
// edtCommandExit is not always called when losing focus
|
|
edtCommandExit(Self);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrmMain.UpdatePrompt;
|
|
var
|
|
st: String;
|
|
Properties: TFileSourceProperties;
|
|
begin
|
|
if (fsoExecute in ActiveFrame.FileSource.GetOperationsTypes) then
|
|
begin
|
|
with lblCommandPath do
|
|
begin
|
|
Visible := True;
|
|
st := ExcludeTrailingBackslash(ActiveFrame.CurrentPath);
|
|
Hint := st;
|
|
|
|
Caption := MinimizeFilePath(Format(fmtCommandPath, [st]),
|
|
Canvas, pnlCommand.Width div 3);
|
|
end;
|
|
|
|
// Change path in terminal
|
|
if (fspDirectAccess in ActiveFrame.FileSource.GetProperties) then
|
|
begin
|
|
if gTermWindow and Assigned(Cons) then
|
|
Cons.SetCurrentDir(ActiveFrame.CurrentPath);
|
|
end;
|
|
|
|
edtCommand.Visible := True;
|
|
end
|
|
else
|
|
begin
|
|
lblCommandPath.Visible := False;
|
|
edtCommand.Visible := False;
|
|
end;
|
|
// Change program current path
|
|
Properties := ActiveFrame.FileSource.GetProperties;
|
|
if (fspDirectAccess in Properties) and not (fspLinksToLocalFiles in Properties) then
|
|
begin
|
|
mbSetCurrentDir(ActiveFrame.CurrentPath);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.OnDriveGetFreeSpace(Data: PtrInt);
|
|
var
|
|
aFileView: TFileView;
|
|
sboxDrive: TPaintBox;
|
|
lblDriveInfo: TLabel;
|
|
AData: TFreeSpaceData absolute Data;
|
|
begin
|
|
case AData.Panel of
|
|
fpLeft :
|
|
begin
|
|
sboxDrive := pbxLeftDrive;
|
|
aFileView := FrameLeft;
|
|
lblDriveInfo :=lblLeftDriveInfo;
|
|
end;
|
|
fpRight:
|
|
begin
|
|
sboxDrive := pbxRightDrive;
|
|
aFileView := FrameRight;
|
|
lblDriveInfo := lblRightDriveInfo;
|
|
end;
|
|
end;
|
|
if mbCompareFileNames(AData.Path, aFileView.CurrentPath) then
|
|
begin
|
|
if not AData.Result then
|
|
begin
|
|
lblDriveInfo.Caption := '';
|
|
lblDriveInfo.Hint := '';
|
|
sboxDrive.Hint := '';
|
|
sboxDrive.Tag := -1;
|
|
sboxDrive.Invalidate;
|
|
end
|
|
else begin
|
|
if gDriveInd = True then
|
|
begin
|
|
if AData.TotalSize > 0 then
|
|
sboxDrive.Tag := 100 - Round((AData.FreeSize / AData.TotalSize) * 100) // Save busy percent
|
|
else begin
|
|
sboxDrive.Tag := -1;
|
|
end;
|
|
sboxDrive.Invalidate;
|
|
end;
|
|
lblDriveInfo.Hint := Format(rsFreeMsg, [cnvFormatFileSize(AData.FreeSize, uoscHeader), cnvFormatFileSize(AData.TotalSize, uoscHeader)]);
|
|
if gShortFormatDriveInfo then
|
|
lblDriveInfo.Caption := Format(rsFreeMsgShort, [cnvFormatFileSize(AData.FreeSize, uoscHeader)])
|
|
else begin
|
|
lblDriveInfo.Caption := lblDriveInfo.Hint;
|
|
end;
|
|
sboxDrive.Hint := lblDriveInfo.Hint;
|
|
end;
|
|
end;
|
|
AData.Free;
|
|
end;
|
|
|
|
procedure TfrmMain.UpdateFreeSpace(Panel: TFilePanelSelect; Clear: Boolean);
|
|
var
|
|
aFileView: TFileView;
|
|
sboxDrive: TPaintBox;
|
|
lblDriveInfo: TLabel;
|
|
AData: TFreeSpaceData;
|
|
begin
|
|
case Panel of
|
|
fpLeft :
|
|
begin
|
|
sboxDrive := pbxLeftDrive;
|
|
aFileView := FrameLeft;
|
|
lblDriveInfo :=lblLeftDriveInfo;
|
|
end;
|
|
fpRight:
|
|
begin
|
|
sboxDrive := pbxRightDrive;
|
|
aFileView := FrameRight;
|
|
lblDriveInfo := lblRightDriveInfo;
|
|
end;
|
|
end;
|
|
|
|
if Clear then
|
|
begin
|
|
lblDriveInfo.Caption := '';
|
|
lblDriveInfo.Hint := '';
|
|
sboxDrive.Hint := '';
|
|
sboxDrive.Tag := -1;
|
|
sboxDrive.Invalidate;
|
|
end;
|
|
|
|
AData := TFreeSpaceData.Create;
|
|
AData.Panel := Panel;
|
|
AData.Path := aFileView.CurrentPath;
|
|
AData.OnFinish := @OnDriveGetFreeSpace;
|
|
AData.FileSource := aFileView.FileSource;
|
|
TThread.ExecuteInThread(@AData.GetFreeSpaceInThread);
|
|
end;
|
|
|
|
procedure TfrmMain.CloseNotebook(ANotebook: TFileViewNotebook);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to ANotebook.PageCount - 1 do
|
|
ANotebook.View[I].Clear;
|
|
ANotebook.DestroyAllPages;
|
|
end;
|
|
|
|
procedure TfrmMain.DriveListDriveSelected(Sender: TObject; ADriveIndex: Integer;
|
|
APanel: TFilePanelSelect);
|
|
begin
|
|
SetPanelDrive(APanel, DrivesList.Items[ADriveIndex], True);
|
|
end;
|
|
|
|
procedure TfrmMain.DriveListClose(Sender: TObject);
|
|
begin
|
|
SetActiveFrame(SelectedPanel);
|
|
end;
|
|
|
|
procedure TfrmMain.AllProgressOnUpdateTimer(Sender: TObject);
|
|
var
|
|
AllProgressPoint: Integer;
|
|
begin
|
|
if gPanelOfOp = True then
|
|
begin
|
|
FOperationsPanel.UpdateView;
|
|
end;
|
|
|
|
// Show progress in the menu
|
|
if gProgInMenuBar = True then
|
|
begin
|
|
AllProgressPoint:= Round(OperationsManager.AllProgressPoint * 100);
|
|
mnuAllOperProgress.Caption:= IntToStr(AllProgressPoint) + ' %';
|
|
end;
|
|
|
|
Sleep(0);
|
|
end;
|
|
|
|
procedure TfrmMain.OperationManagerNotify(Item: TOperationsManagerItem;
|
|
Event: TOperationManagerEvent);
|
|
begin
|
|
if Event = omevOperationRemoved then
|
|
begin
|
|
// Hide progress bar if there are no operations
|
|
if OperationsManager.OperationsCount = 0 then
|
|
begin
|
|
mnuAllOperProgress.Visible:= False;
|
|
mnuAllOperPause.Visible:= False;
|
|
mnuAllOperStart.Visible:= False;
|
|
mnuAllOperStop.Visible:= False;
|
|
end;
|
|
PlaySound(Item);
|
|
end
|
|
else if Event = omevOperationAdded then
|
|
begin
|
|
if gProgInMenuBar = True then
|
|
begin
|
|
mnuAllOperProgress.Visible:= True;
|
|
mnuAllOperPause.Visible:= True;
|
|
mnuAllOperStart.Visible:= True;
|
|
mnuAllOperStop.Visible:= True;
|
|
end;
|
|
end;
|
|
AllProgressOnUpdateTimer(Timer);
|
|
Timer.Enabled := (gPanelOfOp or gProgInMenuBar) and
|
|
(OperationsManager.OperationsCount > 0);
|
|
end;
|
|
|
|
procedure TfrmMain.SetPanelDrive(aPanel: TFilePanelSelect; Drive: PDrive; ActivateIfNeeded: Boolean);
|
|
var
|
|
Index: Integer;
|
|
DrivePath: String;
|
|
DriveIndex: Integer;
|
|
FoundPath: Boolean = False;
|
|
aFileView, OtherFileView: TFileView;
|
|
begin
|
|
if (Drive^.DriveType in [dtSpecial, dtVirtual]) or IsAvailable(Drive, True) then
|
|
begin
|
|
case aPanel of
|
|
fpLeft:
|
|
begin
|
|
aFileView := FrameLeft;
|
|
OtherFileView := FrameRight;
|
|
end;
|
|
fpRight:
|
|
begin
|
|
aFileView := FrameRight;
|
|
OtherFileView := FrameLeft;
|
|
end;
|
|
end;
|
|
|
|
// Special case for special drive
|
|
if Drive^.DriveType = dtSpecial then
|
|
begin
|
|
ChooseFileSource(aFileView, Drive^.Path);
|
|
if ActivateIfNeeded and (tb_activate_panel_on_click in gDirTabOptions) then
|
|
SetActiveFrame(aPanel);
|
|
Exit;
|
|
end;
|
|
|
|
// Special case for virtual drive
|
|
if Drive^.DriveType = dtVirtual then
|
|
begin
|
|
if Drive^.FileSystem = 'VFS' then
|
|
Commands.DoOpenVirtualFileSystemList(aFileView)
|
|
else begin
|
|
ChooseFileSource(aFileView, GetNetworkPath(Drive));
|
|
if ActivateIfNeeded and (tb_activate_panel_on_click in gDirTabOptions) then
|
|
SetActiveFrame(aPanel);
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
DrivePath:= ExcludeTrailingPathDelimiter(Drive^.Path);
|
|
// Copy path opened in the other panel if the file source and drive match
|
|
// and that path is not already opened in this panel.
|
|
if (not gGoToRoot) and OtherFileView.FileSource.IsClass(TFileSystemFileSource) and
|
|
mbCompareFileNames(ExtractRootDir(OtherFileView.CurrentPath), DrivePath) and
|
|
not mbCompareFileNames(OtherFileView.CurrentPath, aFileView.CurrentPath) then
|
|
begin
|
|
FoundPath:= True;
|
|
SetFileSystemPath(aFileView, OtherFileView.CurrentPath);
|
|
end
|
|
// Open archive parent directory
|
|
else if (gGoToRoot = False) and OtherFileView.FileSource.IsClass(TArchiveFileSource) and
|
|
(not IsInPath(GetTempFolder, OtherFileView.FileSource.CurrentAddress, True, False)) and
|
|
mbCompareFileNames(ExtractRootDir(OtherFileView.FileSource.CurrentAddress), DrivePath) and
|
|
not mbCompareFileNames(ExtractFilePath(OtherFileView.FileSource.CurrentAddress), aFileView.CurrentPath) then
|
|
begin
|
|
FoundPath:= True;
|
|
SetFileSystemPath(aFileView, ExtractFilePath(OtherFileView.FileSource.CurrentAddress));
|
|
end
|
|
// Open latest path from history for chosen drive
|
|
else if (gGoToRoot = False) and aFileView.FileSource.IsClass(TFileSystemFileSource) and
|
|
not mbCompareFileNames(ExtractRootDir(aFileView.CurrentPath), DrivePath) then
|
|
begin
|
|
for Index:= 0 to glsDirHistory.Count - 1 do
|
|
begin
|
|
DriveIndex:= FindMatchingDrive(EmptyStr, glsDirHistory[Index]);
|
|
if (DriveIndex >= 0) and (DriveIndex < DrivesList.Count) then
|
|
begin
|
|
if mbCompareFileNames(Drive^.Path, DrivesList[DriveIndex]^.Path) then
|
|
begin
|
|
if mbDirectoryExists(ExcludeBackPathDelimiter(glsDirHistory[Index])) then
|
|
begin
|
|
SetFileSystemPath(aFileView, glsDirHistory[Index]);
|
|
FoundPath:= True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not FoundPath then begin
|
|
SetFileSystemPath(aFileView, Drive^.Path);
|
|
end;
|
|
|
|
if ActivateIfNeeded and (tb_activate_panel_on_click in gDirTabOptions) then
|
|
SetActiveFrame(aPanel);
|
|
end
|
|
else
|
|
begin
|
|
msgWarning(rsMsgDiskNotAvail);
|
|
|
|
// Restore previous selected button.
|
|
case aPanel of
|
|
fpLeft:
|
|
UpdateSelectedDrive(LeftTabs);
|
|
fpRight:
|
|
UpdateSelectedDrive(RightTabs);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.OnDriveWatcherEvent(EventType: TDriveWatcherEvent; const ADrive: PDrive);
|
|
begin
|
|
// Update disk panel does not work correctly when main
|
|
// window is minimized. So set FUpdateDiskCount flag instead
|
|
// and update disk count later in WindowStateChange event
|
|
if WindowState = wsMinimized then
|
|
FUpdateDiskCount:= True
|
|
else begin
|
|
UpdateDiskCount;
|
|
end;
|
|
|
|
if (FrameLeft = nil) or (FrameRight = nil) then Exit;
|
|
|
|
if (EventType = dweDriveRemoved) and Assigned(ADrive) then
|
|
begin
|
|
if IsInPath(ADrive^.Path, ActiveFrame.CurrentPath, True, True) then
|
|
ActiveFrame.CurrentPath:= GetHomeDir
|
|
else if IsInPath(ADrive^.Path, NotActiveFrame.CurrentPath, True, True) then
|
|
NotActiveFrame.CurrentPath:= GetHomeDir;
|
|
end;
|
|
|
|
UpdateSelectedDrives;
|
|
end;
|
|
|
|
procedure TfrmMain.DelayedEvent(Data: PtrInt);
|
|
begin
|
|
{ discard duplicate calls, accept last call only }
|
|
Dec(FDelayedEventCtr);
|
|
if FDelayedEventCtr > 0 then
|
|
Exit;
|
|
{ update restored bounds }
|
|
if WindowState = wsNormal then
|
|
begin
|
|
if FDelayedWMMove then
|
|
begin
|
|
FRestoredLeft := Left;
|
|
FRestoredTop := Top;
|
|
end;
|
|
if FDelayedWMSize then
|
|
begin
|
|
FRestoredWidth := Width;
|
|
FRestoredHeight := Height;
|
|
end;
|
|
end;
|
|
FDelayedWMMove := False;
|
|
FDelayedWMSize := False;
|
|
|
|
// Sync position and size with real main form
|
|
with BoundsRect do
|
|
Application.MainForm.SetBounds(Left, Top, Width, Height);
|
|
end;
|
|
|
|
procedure TfrmMain.AppActivate(Sender: TObject);
|
|
begin
|
|
if Assigned(FrameLeft) then
|
|
FrameLeft.ReloadIfNeeded;
|
|
if Assigned(FrameRight) then
|
|
FrameRight.ReloadIfNeeded;
|
|
end;
|
|
|
|
procedure TfrmMain.AppDeActivate(Sender: TObject);
|
|
begin
|
|
if Assigned(frmTreeViewMenu) then
|
|
begin
|
|
frmTreeViewMenu.Close;
|
|
end;
|
|
Application.CancelHint;
|
|
end;
|
|
|
|
procedure TfrmMain.AppEndSession(Sender: TObject);
|
|
var
|
|
CloseAction: TCloseAction;
|
|
begin
|
|
frmMainClose(Sender, CloseAction);
|
|
end;
|
|
|
|
procedure TfrmMain.AppThemeChange(Sender: TObject);
|
|
|
|
procedure UpdateNoteBook(NoteBook: TFileViewNotebook);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
for Index := 0 to NoteBook.PageCount - 1 do
|
|
begin
|
|
NoteBook.View[Index].UpdateColor;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
UpdateNoteBook(LeftTabs);
|
|
UpdateNoteBook(RightTabs);
|
|
|
|
ColSet.UpdateStyle;
|
|
gColorExt.UpdateStyle;
|
|
gHighlighters.UpdateStyle;
|
|
|
|
DCDebug('AppThemeChange');
|
|
|
|
for Index:= 0 to Screen.CustomFormCount - 1 do
|
|
begin
|
|
Screen.CustomForms[Index].Perform(CM_THEMECHANGED, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.AppQueryEndSession(var Cancel: Boolean);
|
|
var
|
|
CanClose: Boolean = True;
|
|
begin
|
|
FormCloseQuery(Self, CanClose);
|
|
Cancel := not CanClose;
|
|
end;
|
|
|
|
{$IFDEF DARWIN}
|
|
procedure TfrmMain.GlobalMacOSKeyDownHandler(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
topForm: TCustomForm;
|
|
begin
|
|
if (Key=VK_W) and (Shift=[ssMeta]) then
|
|
begin
|
|
if Sender is TControl then
|
|
begin
|
|
topForm:= GetParentForm( TControl(Sender), true );
|
|
if topForm<>self then
|
|
begin
|
|
topForm.Close;
|
|
Key:= 0;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMain.OpenNewWindow(Sender: TObject);
|
|
begin
|
|
uMyDarwin.openNewInstance;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)}
|
|
function TfrmMain.QObjectEventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
|
|
begin
|
|
Result:= False;
|
|
case QEvent_type(Event) of
|
|
QEventApplicationPaletteChange:
|
|
begin
|
|
ThemeServices.IntfDoOnThemeChange;
|
|
end;
|
|
QEventClose:
|
|
begin
|
|
TQtWidget(Self.Handle).SlotClose;
|
|
Result:= CloseQueryResult;
|
|
if Result then
|
|
QEvent_accept(Event)
|
|
else
|
|
QEvent_ignore(Event);
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
initialization
|
|
{$I DragCursors.lrs}
|
|
TFormCommands.RegisterCommandsForm(TfrmMain, HotkeysCategory, @rsHotkeyCategoryMain);
|
|
|
|
end.
|
|
|