doublecmd/src/fmain.pas
2025-01-12 22:16:55 +03:00

7269 lines
222 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)}
, uMyDarwin
{$ENDIF}
, Types, LMessages;
type
TForEachViewFunction = procedure (AFileView: TFileView; UserData: Pointer) of object;
{ TfrmMain }
TfrmMain = class(TAloneForm, IFormCommands)
actAddPlugin: 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 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);
{$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 createDarwinAppMenu;
procedure aboutOnClick(Sender: TObject);
procedure optionsOnClick(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 UpdateSelectedDrive(ANoteBook: TFileViewNotebook);
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;
{$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 );
createDarwinAppMenu;
{$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, gDefaultDropEffect) 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.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, gDefaultDropEffect),
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, gDefaultDropEffect) 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);
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');
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
if (QuickViewPanel = nil) then
begin
// Select opposite panel.
case PanelSelected of
fpLeft: SetActiveFrame(fpRight);
fpRight: SetActiveFrame(fpLeft);
else SetActiveFrame(fpLeft);
end;
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 gDriveBar1 and gDriveBar2 and not gHorizontalFilePanels then
begin
pnlDskLeft.Constraints.MinWidth:= pnlLeft.Width;
pnlDskLeft.Constraints.MaxWidth:= pnlLeft.Width;
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 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;
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;
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:= NormalizePathDelimiters(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.createDarwinAppMenu;
var
appMenu: TMenuItem;
aboutItem: TMenuItem;
sepItem: TMenuItem;
prefItem: TMenuItem;
begin
appMenu:= TMenuItem.Create(mnuMain);
appMenu.Caption:= '';
mnuMain.Items.Insert(0, appMenu);
aboutItem:= TMenuItem.Create(mnuMain);
aboutItem.Caption:= 'About ' + Application.Title;
aboutItem.OnClick:= @aboutOnClick;
appMenu.Add(aboutItem);
sepItem := TMenuItem.Create(mnuMain);
sepItem.Caption := '-';
appMenu.Add(sepItem);
prefItem := TMenuItem.Create(mnuMain);
prefItem.Caption := 'Preferences...';
prefItem.OnClick := @optionsOnClick;
prefItem.Shortcut := ShortCut(VK_OEM_COMMA, [ssMeta]);
appMenu.Add(prefItem);
end;
procedure TfrmMain.aboutOnClick(Sender: TObject);
begin
Commands.cm_About([]);
end;
procedure TfrmMain.optionsOnClick(Sender: TObject);
begin
Commands.cm_Options([]);
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.