summaryrefslogtreecommitdiff
path: root/UMain.pas
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-07 20:34:49 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-07 20:34:49 +0200
commitecde167da74c86bc047aaf84c5e548cf65a5da98 (patch)
treea015dfda84f28a65811e3aa0d369f8f211ec8c60 /UMain.pas
downloadtuxcmd-ecde167da74c86bc047aaf84c5e548cf65a5da98.tar.xz
Diffstat (limited to 'UMain.pas')
-rw-r--r--UMain.pas6128
1 files changed, 6128 insertions, 0 deletions
diff --git a/UMain.pas b/UMain.pas
new file mode 100644
index 0000000..3fb485a
--- /dev/null
+++ b/UMain.pas
@@ -0,0 +1,6128 @@
+(*
+ Tux Commander - UMain - Main form and window-related functions
+ Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ Check for updates on tuxcmd.sourceforge.net
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*)
+unit UMain;
+
+interface
+
+uses
+ gtk2, gdk2, gdk2pixbuf, glib2, pango, StrUtils, SysUtils, Types, Classes, DateUtils,
+ GTKForms, GTKControls, GTKMenus, GTKStdCtrls, GTKExtCtrls, GTKView, GTKConsts, GTKUtils,
+ GTKClasses, GTKPixbuf, UEngines, UConfig, UGnome, UVFSCore, UCoreClasses;
+
+type
+ TFMain = class(TGTKForm)
+ MainVBox : TGTKVBox;
+ MainMenuHandleBox : TGTKHandleBox;
+ MainMenu : TGTKMenuBar;
+ LeftPanelBox, RightPanelBox : TGTKVBox;
+ PanelSeparator : TGTKHPaned;
+ LeftStatusBox, RightStatusBox, LeftPathLabelHBox, RightPathLabelHBox : TGTKHBox;
+ LeftPathLabel, RightPathLabel : TGTKLabel;
+ LeftPathLabelEventBox, RightPathLabelEventBox : TGTKEventBox;
+ LeftScrolledWindow, RightScrolledWindow : TGTKScrolledWindow;
+ LeftListView, RightListView: TGTKListView;
+ LeftStatusLine, RightStatusLine : TGTKLabel;
+ LeftUpButton, LeftRootButton, LeftHomeButton, RightUpButton, RightRootButton, RightHomeButton,
+ LeftBookmarkButton, RightBookmarkButton : TGTKButton;
+ LeftEqualButton, RightEqualButton : TGTKButton;
+ LeftDiskInfoLabel, RightDiskInfoLabel : TGTKLabel;
+ ButtonsBox : TGTKTable;
+ F2Button, F3Button, F4Button, F5Button, F6Button, F7Button, F8Button : TGTKButton;
+ mnuFile, mnuMark, mnuCommands, mnuShow, mnuSettings, mnuHelp : TGTKMenuItem;
+ miExit : TGTKMenuItem;
+ miSelectGroup, miUnselectGroup, miSelectAll, miUnselectAll, miInvertSelection : TGTKMenuItem;
+ miRefresh : TGTKMenuItem;
+ miShowDotFiles : TGTKMenuItem;
+ miFileTypes: TGTKMenuItem;
+ miAbout : TGTKMenuItem;
+ miVerifyChecksums, miCreateChecksums : TGTKMenuItem;
+ miSplitFile, miMergeFiles : TGTKMenuItem;
+ miChangePermissions, miChangeOwner: TGTKMenuItem;
+ miCreateSymlink, miEditSymlink: TGTKMenuItem;
+ LeftQuickFindVBox, RightQuickFindVBox: TGTKVBox;
+ LeftQuickFindHBox, RightQuickFindHBox: TGTKHBox;
+ LeftQuickFindLabel, RightQuickFindLabel: TGTKLabel;
+ LeftQuickFindEntry, RightQuickFindEntry: TGTKEntry;
+ LeftQuickFindSeparator, RightQuickFindSeparator, ButtonBoxSeparator: TGTKHSeparator;
+ CommandLineHBox: TGTKHBox;
+ CommandLineCombo: TGTKCombo;
+ CommandLineLabel: TGTKLabel;
+ SplitterPopupMenu: TGTKMenuItem;
+ FilePopupMenu: TGTKMenuItem;
+ miPreferences: TGTKMenuItem;
+ mnuBookmarks, miAddBookmark, miEditBookmarks, BookmarkPopup, BookmarkPopupDelete, miBookmarksSeparator: TGTKMenuItem;
+ miShowDirectorySizes, miTargetSource: TGTKMenuItem;
+ ButtonBoxSpace: TGTKEventBox;
+ MounterBarHandleBox : TGTKHandleBox;
+ MounterBarTable: TGTKTable;
+ MounterButtonPopupMenu, miMount, miUmount, miEject: TGTKMenuItem;
+ miMounterSettings, miNoMounterBar, miShowOneMounterBar, miShowTwoMounterBar: TGTKMenuItem;
+ LeftMounterTable, RightMounterTable: TGTKTable;
+ miColumns: TGTKMenuItem;
+ mnuPlugins, miTestPlugin: TGTKMenuItem;
+ miSavePosition: TGTKMenuItem;
+ LeftPanelNotebook, RightPanelNotebook: TEphyNotebook;
+ LeftListBox, RightListBox: TGTKVBox;
+ TabPopupMenu, miDuplicateTab, miCloseTab, miCloseAllTabs: TGTKMenuItem;
+ mnuNetwork, miConnections, miOpenConnection, miQuickConnect, miDisconnect: TGTKMenuItem;
+ miSearch: TGTKMenuItem;
+ LeftDisconnectButton, RightDisconnectButton, LeftLeaveArchiveButton, RightLeaveArchiveButton: TGTKButton;
+ OpenTerminalButton: TGTKButton;
+ miNewTab: TGTKMenuItem;
+ LeftPasswordButton, RightPasswordButton: TGTKImageButton;
+ procedure FormCreate(Sender: TObject); override;
+ procedure FormDestroy(Sender: TObject);
+ procedure FormResize(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure PanelSeparatorResize(Sender: TObject);
+ procedure miExitClick(Sender: TObject);
+ procedure miAboutClick(Sender: TObject);
+ procedure miRefreshClick(Sender: TObject);
+ procedure mnuMarkClick(Sender: TObject);
+ procedure ListViewKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+ procedure ListViewEnter(Sender: TObject; var Accept: boolean);
+ procedure PathLabelMouseDown(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+ procedure PathButtonClick(Sender: TObject);
+ function CompareFunc(Sender: TObject; var model: PGtkTreeModel; var a, b: PGtkTreeIter): integer;
+ procedure F5ButtonClick(Sender: TObject);
+ procedure F6ButtonClick(Sender: TObject);
+ procedure F7ButtonClick(Sender: TObject);
+ procedure F8ButtonClick(Sender: TObject);
+ procedure ListViewDblClick(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+ procedure ListViewMouseDown(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+ procedure ListViewMouseUp(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+ procedure InplaceEditTimerTimer(Sender: TObject);
+ procedure ListViewEdited(Sender: TObject; Column: TGTKTreeViewColumn; Item: TGTKListItem; var NewText: string; var AllowChange: boolean; var DataColumn: integer);
+ procedure ListViewSelectionChanged(Sender: TObject);
+ procedure QuickFindEntryEnter(Sender: TObject; var Accept: boolean);
+ procedure miVerifyChecksumsClick(Sender: TObject);
+ procedure miCreateChecksumsClick(Sender: TObject);
+ procedure miMergeFilesClick(Sender: TObject);
+ procedure miSplitFileClick(Sender: TObject);
+ procedure miShowDotFilesClick(Sender: TObject);
+ procedure F3F4ButtonClick(Sender: TObject);
+ procedure miFileTypesClick(Sender: TObject);
+ procedure CommandLineComboKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+ procedure FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+ procedure InactiveItemsTimerTimer(Sender: TObject);
+ function OldGTKConvertToSorted(Sender: TObject; const Index: integer): integer;
+ function OldGTKConvertFromSorted(Sender: TObject; const Index: integer): integer;
+ procedure SplitterPopupMenuClick(Sender: TObject);
+ procedure miChangePermissionsClick(Sender: TObject);
+ procedure miChangeOwnerClick(Sender: TObject);
+ procedure miCreateSymlinkClick(Sender: TObject);
+ procedure miEditSymlinkClick(Sender: TObject);
+ procedure FilePopupMenuPopup(Sender: TObject);
+ procedure FilePopupMenuItemClick(Sender: TObject);
+ procedure miPreferencesClick(Sender: TObject);
+ procedure miAddBookmarkClick(Sender: TObject);
+ procedure miBookmarkClick(Sender: TObject);
+ procedure BookmarkPopupDeleteClick(Sender: TObject);
+ procedure BookmarkItemMouseUp(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+ procedure BookmarkButtonClick(Sender: TObject);
+ procedure mnuBookmarksPopup(Sender: TObject);
+ procedure miShowDirectorySizesClick(Sender: TObject);
+ procedure miTargetSourceClick(Sender: TObject);
+ procedure MounterButtonClick(Sender: TObject);
+ procedure MounterButtonPopupMenuPopup(Sender: TObject);
+ procedure MounterButtonMouseDown(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+ procedure miMountClick(Sender: TObject);
+ procedure miUmountClick(Sender: TObject);
+ procedure miEjectClick(Sender: TObject);
+ procedure miMounterSettingsClick(Sender: TObject);
+ procedure miShowMounterBarClick(Sender: TObject);
+ procedure miColumnsClick(Sender: TObject);
+ procedure ListViewColumnsChanged(Sender: TObject);
+ procedure RebuildListViewsTimerTimer(Sender: TObject);
+ procedure miTestPluginClick(Sender: TObject);
+ procedure miPluginAboutClick(Sender: TObject);
+ procedure miSavePositionClick(Sender: TObject);
+ procedure TabNotebookSwitchPage(Sender: TObject; const NewTabNum: integer; const ShouldFocus: boolean);
+ procedure miDuplicateTabClick(Sender: TObject);
+ procedure miCloseTabClick(Sender: TObject);
+ procedure miCloseAllTabsClick(Sender: TObject);
+ procedure TabPopupMenuPopup(Sender: TObject);
+ procedure miOpenConnectionClick(Sender: TObject);
+ procedure miSearchClick(Sender: TObject);
+ procedure miDisconnectClick(Sender: TObject);
+ procedure DisconnectButtonClick(Sender: TObject);
+ procedure LeaveArchiveButtonClick(Sender: TObject);
+ procedure OpenTerminalButtonClick(Sender: TObject);
+ procedure ListViewColumnClicked(Sender: TObject);
+ procedure NotebookReordered(Sender: TObject; const Source, Dest: integer);
+ procedure NotebookTabClosed(Sender: TObject; const TabNum: integer; var CanClose: boolean);
+ procedure NotebookTabDoubleClick(Sender: TObject; const TabNum: integer);
+ function NotebookFindNotebookAtPointerEvent(Sender: TObject; const AbsX, AbsY: integer): TEphyNotebook;
+ function NotebookMoveTabToAnotherNotebook(Sender: TObject; Destination: TEphyNotebook; const SourceTabNo, DestTabNo: integer): boolean;
+ procedure NotebookTabFocusOnlyEvent(Sender: TObject; const TabNum: integer);
+ procedure miFilePropertiesClick(Sender: TObject);
+ procedure PasswordButtonClick(Sender: TObject);
+ private
+ LeftLastFocused, Editing, QuickFind, RedrawLeftInactive, RedrawRightInactive, StartUp, LeftTabPopup: boolean;
+ LastWidth, RunningEscSensitive: integer;
+ InplaceEditTimer, InactiveItemsTimer, RebuildListViewsTimer: TGTKTimer;
+ InplaceEditItem: TGTKListItem;
+ SavedCmdLine: string;
+ LastMounterButton: TGTKButton;
+ MounterTableList, MounterTableListLeft, MounterTableListRight: TList;
+ LeftNotebookBoxList, RightNotebookBoxList: TList;
+ LeftPathsHighlight, RightPathsHighlight: TStringList;
+ LeftTabEngines, RightTabEngines: TList;
+ LastUsedFilter: string;
+ procedure ConstructPanels;
+ procedure ConstructMenu;
+ procedure ConstructColumns(ListView: TGTKListView);
+ procedure AfterStart;
+ procedure ActivateItem(const ItemIndex: longint; const MouseActivate: boolean);
+ procedure UpdatePanelInfo;
+ procedure UpdatePanelInfoDown(LeftPanel: boolean);
+ procedure UpdateCaption;
+ procedure ChangingDir(LeftPanel: boolean; NewPath: string; HiliString1: string = ''; HiliString2: string = ''; const PreserveSelection: boolean = False; const AutoFallback: boolean = False; Plugin: TVFSPlugin = nil);
+ procedure DoSelect(SelectType: integer);
+ procedure ListViewCellDataFunc(Sender: TObject; tree_view: PGtkTreeView; tree_column : PGtkTreeViewColumn; cell : PGtkCellRenderer; tree_model : PGtkTreeModel; iter : PGtkTreeIter);
+ procedure DoGetDirSize(AllItems: boolean);
+ procedure DoDelete(LeftPanel: boolean; ListView: TGTKListView; Engine: TPanelEngine; DataList: TList);
+ procedure DoCopyMove(LeftPanel, CopyMode, ShiftPressed: boolean; ListView: TGTKListView; Engine: TPanelEngine; DataList: TList);
+ procedure DoRefresh(LeftPanel, StaySame, AutoFallback: boolean);
+ procedure DoQuickRename(LeftPanel: boolean; ListView: TGTKListView; const CalledFromKey: boolean);
+ procedure ActivateQuickFind(LeftPanel: boolean);
+ procedure DeactivateQuickFind(LeftPanel: boolean);
+ function QuickFindSendKey(LeftPanel: boolean; Key: word): boolean;
+ procedure ProcessMarkKey(KeyType, Key: integer);
+ procedure SwitchOtherPanel(LeftPanel, RequestNewAltO: boolean);
+ procedure EditViewFile(LeftPanel: boolean; AListView: TGTKListView; View, NewFile: boolean);
+ procedure RunFile(Path: string; Engine: TPanelEngine; CustomAction: integer);
+ function ActivateCommandLine(Key: word; const ActualPosition: boolean = False): boolean;
+ procedure ApplySettings(RebuildListViews, RebuildIcons, Startup: boolean);
+ procedure RefreshBookmarksMenu;
+ procedure PopupFileMenuPos;
+ procedure HandleFormFocusIn;
+ procedure SwitchPanelCtrlLeftRight(LeftPanel, LeftArrowPressed: boolean);
+ procedure FillMounterBar;
+ procedure RebuildListViews(DoRefresh: boolean);
+ procedure FillPluginMenu;
+ procedure NewTab(LeftPanel: boolean);
+ procedure SwitchTab(TabNo: integer; LeftPanel, SetFocus: boolean);
+ procedure CloseTab(TabNo: integer; LeftPanel: boolean);
+ procedure AddTabs(LeftPanel: boolean; TabList: TStringList; TabSortIDs, TabSortTypes: TList; SetTabActive: integer);
+ function HandleVFSArchive(const Ext, FullPath, HighlightItem, TargetPath: string): boolean;
+ procedure CloseVFS(LeftPanel, SurpressRefresh: boolean);
+ procedure ShowBookmarkQuick(LeftPanel: boolean);
+ procedure SetTabLabel(Notebook: TEphyNotebook; PageIndex: integer; ALabel, Tooltip: string);
+ procedure NewTabInternal(LeftPanel: boolean; _Engine: TPanelEngine; _Path: string; NewTabPosition: integer);
+ procedure CopyFilenamesToClipboard(FullPaths, LeftPanel: boolean);
+ function HandleRunFromArchive(var APath: string; Engine: TPanelEngine; Command, FileTypeDesc: string; BypassDialog: boolean): boolean;
+ function HandleSetPassword(Engine: TPanelEngine): boolean;
+ public
+ LeftPanelEngine, RightPanelEngine : TPanelEngine;
+ ColumnSortIDs: array[1..ConstNumPanelColumns] of integer;
+ LastClick: TDateTime;
+ procedure EditViewFileInternal(ParentWindow: TGTKControl; Filename: string; Engine: TPanelEngine; View, NewFile: boolean);
+ end;
+
+var
+ FMain: TFMain;
+
+implementation
+
+uses Libc,
+ UCore, USelect, UNewDir, UDirDelete, UProgress, UCopyMove,
+ UCoreUtils, ULocale, UChecksum, UChecksumDruid, USplitFile,
+ UFileTypeSettings, UFileAssoc, UChmod, UChown, USymlink,
+ UPreferences, UViewer, UToolTips, UMounterPrefs, UColumns,
+ UTestPlugin, UConnectionManager, USearch, UProperties,
+ URemoteWait, URunFromVFS, USetPassword, uVFSprototypes;
+
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+function form_event_handler(widget: PGtkWidget; event: PGdkEvent; user_data: gpointer): gboolean; cdecl; forward;
+
+procedure TFMain.FormCreate(Sender: TObject);
+begin
+ ReportGTKVersion;
+ StartUp := True;
+ RunningEscSensitive := 0;
+ Editing := False;
+ QuickFind := False;
+ LeftTabPopup := True;
+ LastClick := 0;
+ LastUsedFilter := '*.*';
+ RedrawLeftInactive := False;
+ RedrawRightInactive := False;
+ MounterTableList := TList.Create;
+ MounterTableListLeft := TList.Create;
+ MounterTableListRight := TList.Create;
+ LeftNotebookBoxList := TList.Create;
+ RightNotebookBoxList := TList.Create;
+ LeftPathsHighlight := TStringList.Create;
+ RightPathsHighlight := TStringList.Create;
+ LeftTabEngines := TList.Create;
+ RightTabEngines := TList.Create;
+ Caption := ConstAppTitle;
+ WindowPosition := wpCenter;
+ MainVBox := TGTKVBox.Create(Self);
+ AddControl(MainVBox);
+ MainMenuHandleBox := TGTKHandleBox.Create(Self);
+ MainVBox.AddControlEx(MainMenuHandleBox, False, True, 0);
+ MainMenu := TGTKMenuBar.Create(Self);
+ MainMenuHandleBox.AddControl(MainMenu);
+ ConstructMenu;
+ InplaceEditTimer := TGTKTimer.Create(Self);
+ InplaceEditTimer.Enabled := False;
+ InplaceEditTimer.OnTimer := InplaceEditTimerTimer;
+ InactiveItemsTimer := TGTKTimer.Create(Self);
+ InactiveItemsTimer.Enabled := False;
+ InactiveItemsTimer.Interval := ConfInactiveTimerDelay;
+ if not Application.GTKVersion_2_6_0_Up then InactiveItemsTimer.OnTimer := InactiveItemsTimerTimer;
+ RebuildListViewsTimer := TGTKTimer.Create(Self);
+ RebuildListViewsTimer.Enabled := False;
+ RebuildListViewsTimer.OnTimer := RebuildListViewsTimerTimer;
+ MounterBarHandleBox := TGTKHandleBox.Create(Self);
+ MounterBarHandleBox.SetSizeRequest(10, -1);
+ MainVBox.AddControlEx(MounterBarHandleBox, False, True, 0);
+ MounterBarTable := TGTKTable.Create(Self);
+ MounterBarHandleBox.AddControl(MounterBarTable);
+ LeftPanelBox := TGTKVBox.Create(Self);
+ RightPanelBox := TGTKVBox.Create(Self);
+ PanelSeparator := TGTKHPaned.Create(Self);
+ MainVBox.AddControlEx(PanelSeparator, True, True, 0);
+ PanelSeparator.Child1 := LeftPanelBox;
+ PanelSeparator.Child2 := RightPanelBox;
+ ConstructPanels;
+ CommandLineHBox := TGTKHBox.Create(Self);
+ CommandLineHBox.Homogeneous := False;
+ CommandLineCombo := TGTKCombo.Create(Self);
+ CommandLineCombo.DisableActivate;
+ CommandLineCombo.MatchValue := False;
+ CommandLineCombo.CaseSensitive := True;
+// CommandLineCombo.Entry.OnKeyDown := CommandLineComboKeyDown;
+ CommandLineLabel := TGTKLabel.Create(Self);
+ CommandLineLabel.Alignment := taRightJustify;
+ CommandLineLabel.SetAlignment(1, 0.5);
+ CommandLineLabel.SetSizeRequest(300, -1);
+ OpenTerminalButton := TGTKButton.Create(Self);
+ OpenTerminalButton.Caption := LANGOpenTerminalButton_Caption;
+ OpenTerminalButton.BorderStyle := bsNone;
+ OpenTerminalButton.CanFocus := False;
+ OpenTerminalButton.Tooltip := LANGOpenTerminalButton_Tooltip;
+ OpenTerminalButton.OnClick := OpenTerminalButtonClick;
+ CommandLineHBox.AddControlEx(CommandLineLabel, False, False, 0);
+ CommandLineHBox.AddControlEx(CommandLineCombo, True, True, 5);
+ CommandLineHBox.AddControlEx(TGTKVSeparator.Create(Self), False, False, 2);
+ CommandLineHBox.AddControlEx(OpenTerminalButton, False, False, 2);
+ MainVBox.AddControlEx(TGTKHSeparator.Create(Self), False, False, 2);
+ MainVBox.AddControlEx(CommandLineHBox, False, False, 0);
+ ButtonsBox := TGTKTable.Create(Self);
+ F2Button := TGTKButton.Create(Self);
+ F3Button := TGTKButton.Create(Self);
+ F4Button := TGTKButton.Create(Self);
+ F5Button := TGTKButton.Create(Self);
+ F6Button := TGTKButton.Create(Self);
+ F7Button := TGTKButton.Create(Self);
+ F8Button := TGTKButton.Create(Self);
+ ButtonsBox.AddControlEx(0, 0, 1, 1, F2Button, [taoExpand, taoFill], [taoShrink, taoExpand, taoFill], 0, 0);
+ ButtonsBox.AddControlEx(1, 0, 1, 1, TGTKVSeparator.Create(Self), [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 2, 4);
+ ButtonsBox.AddControlEx(2, 0, 1, 1, F3Button, [taoExpand, taoFill], [taoShrink, taoExpand, taoFill], 0, 0);
+ ButtonsBox.AddControlEx(3, 0, 1, 1, TGTKVSeparator.Create(Self), [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 2, 4);
+ ButtonsBox.AddControlEx(4, 0, 1, 1, F4Button, [taoExpand, taoFill], [taoShrink, taoExpand, taoFill], 0, 0);
+ ButtonsBox.AddControlEx(5, 0, 1, 1, TGTKVSeparator.Create(Self), [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 2, 4);
+ ButtonsBox.AddControlEx(6, 0, 1, 1, F5Button, [taoExpand, taoFill], [taoShrink, taoExpand, taoFill], 0, 0);
+ ButtonsBox.AddControlEx(7, 0, 1, 1, TGTKVSeparator.Create(Self), [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 2, 4);
+ ButtonsBox.AddControlEx(8, 0, 1, 1, F6Button, [taoExpand, taoFill], [taoShrink, taoExpand, taoFill], 0, 0);
+ ButtonsBox.AddControlEx(9, 0, 1, 1, TGTKVSeparator.Create(Self), [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 2, 4);
+ ButtonsBox.AddControlEx(10, 0, 1, 1, F7Button, [taoExpand, taoFill], [taoShrink, taoExpand, taoFill], 0, 0);
+ ButtonsBox.AddControlEx(11, 0, 1, 1, TGTKVSeparator.Create(Self), [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 2, 4);
+ ButtonsBox.AddControlEx(12, 0, 1, 1, F8Button, [taoExpand, taoFill], [taoShrink, taoExpand, taoFill], 0, 0);
+ ButtonBoxSeparator := TGTKHSeparator.Create(Self);
+ ButtonBoxSpace := TGTKEventBox.Create(Self);
+ MainVBox.AddControlEx(ButtonBoxSpace, False, False, 2);
+ MainVBox.AddControlEx(ButtonBoxSeparator, False, False, 2);
+ MainVBox.AddControlEx(ButtonsBox, False, False, 0);
+ F2Button.BorderStyle := bsNone;
+ F3Button.BorderStyle := bsNone;
+ F4Button.BorderStyle := bsNone;
+ F5Button.BorderStyle := bsNone;
+ F6Button.BorderStyle := bsNone;
+ F7Button.BorderStyle := bsNone;
+ F8Button.BorderStyle := bsNone;
+ F2Button.Caption := LANGF2Button_Caption;
+ F3Button.Caption := LANGF3Button_Caption;
+ F4Button.Caption := LANGF4Button_Caption;
+ F5Button.Caption := LANGF5Button_Caption;
+ F6Button.Caption := LANGF6Button_Caption;
+ F7Button.Caption := LANGF7Button_Caption;
+ F8Button.Caption := LANGF8Button_Caption;
+ F2Button.OnClick := F6ButtonClick;
+ F3Button.OnClick := F3F4ButtonClick;
+ F4Button.OnClick := F3F4ButtonClick;
+ F5Button.OnClick := F5ButtonClick;
+ F6Button.OnClick := F6ButtonClick;
+ F7Button.OnClick := F7ButtonClick;
+ F8Button.OnClick := F8ButtonClick;
+ F2Button.CanFocus := False;
+ F3Button.CanFocus := False;
+ F4Button.CanFocus := False;
+ F5Button.CanFocus := False;
+ F6Button.CanFocus := False;
+ F7Button.CanFocus := False;
+ F8Button.CanFocus := False;
+ PanelSeparator.PopupMenu := SplitterPopupMenu;
+ LeftListView.PopupMenu := FilePopupMenu;
+ RightListView.PopupMenu := FilePopupMenu;
+
+ // Events
+ OnResize := FormResize;
+ OnDestroy := FormDestroy;
+ OnKeyDown := FormKeyDown;
+ OnClose := FormClose;
+ g_signal_connect_after(FWidget, 'event-after', G_CALLBACK(@form_event_handler), nil);
+ PanelSeparator.OnResize := PanelSeparatorResize;
+ LeftListView.OnKeyDown := ListViewKeyDown;
+ RightListView.OnKeyDown := ListViewKeyDown;
+ LeftListView.OnEnter := ListViewEnter;
+ RightListView.OnEnter := ListViewEnter;
+ LeftPathLabelEventBox.OnMouseDown := PathLabelMouseDown;
+ RightPathLabelEventBox.OnMouseDown := PathLabelMouseDown;
+ LeftUpButton.OnClick := PathButtonClick;
+ LeftRootButton.OnClick := PathButtonClick;
+ LeftHomeButton.OnClick := PathButtonClick;
+ RightUpButton.OnClick := PathButtonClick;
+ RightRootButton.OnClick := PathButtonClick;
+ RightHomeButton.OnClick := PathButtonClick;
+ LeftEqualButton.OnClick := miTargetSourceClick;
+ RightEqualButton.OnClick := miTargetSourceClick;
+ LeftDisconnectButton.OnClick := DisconnectButtonClick;
+ RightDisconnectButton.OnClick := DisconnectButtonClick;
+ LeftLeaveArchiveButton.OnClick := LeaveArchiveButtonClick;
+ RightLeaveArchiveButton.OnClick := LeaveArchiveButtonClick;
+ LeftListView.CompareFunc := CompareFunc;
+ RightListView.CompareFunc := CompareFunc;
+ LeftListView.CellDataFunc := ListViewCellDataFunc;
+ RightListView.CellDataFunc := ListViewCellDataFunc;
+ LeftListView.OnMouseDown := ListViewMouseDown;
+ RightListView.OnMouseDown := ListViewMouseDown;
+ LeftListView.OnMouseUp := ListViewMouseUp;
+ RightListView.OnMouseUp := ListViewMouseUp;
+{ LeftListView.OnDblClick := ListViewDblClick;
+ RightListView.OnDblClick := ListViewDblClick;}
+ LeftListView.OnSelectionChanged := ListViewSelectionChanged;
+ RightListView.OnSelectionChanged := ListViewSelectionChanged;
+ LeftQuickFindEntry.OnEnter := QuickFindEntryEnter;
+ RightQuickFindEntry.OnEnter := QuickFindEntryEnter;
+ LeftPanelNotebook.OnTabSwitched := TabNotebookSwitchPage;
+ RightPanelNotebook.OnTabSwitched := TabNotebookSwitchPage;
+ LeftPanelNotebook.PopupMenu := TabPopupMenu;
+ RightPanelNotebook.PopupMenu := TabPopupMenu;
+ AfterStart;
+end;
+
+procedure TFMain.ConstructPanels;
+begin
+ LeftMounterTable := TGTKTable.Create(Self);
+ LeftMounterTable.SetSizeRequest(10, -1);
+ RightMounterTable := TGTKTable.Create(Self);
+ RightMounterTable.SetSizeRequest(10, -1);
+ LeftMounterTable.BorderWidth := 2;
+ RightMounterTable.BorderWidth := 2;
+ LeftPanelBox.AddControlEx(LeftMounterTable, False, False, 0);
+ RightPanelBox.AddControlEx(RightMounterTable, False, False, 0);
+ LeftStatusBox := TGTKHBox.Create(Self);
+ RightStatusBox := TGTKHBox.Create(Self);
+ LeftStatusBox.Homogeneous := False;
+ RightStatusBox.Homogeneous := False;
+ LeftPathLabel := TGTKLabel.Create(Self);
+ RightPathLabel := TGTKLabel.Create(Self);
+ LeftPathLabel.SetSizeRequest(10, -1);
+ RightPathLabel.SetSizeRequest(10, -1);
+ LeftPathLabelEventBox := TGTKEventBox.Create(Self);
+ RightPathLabelEventBox := TGTKEventBox.Create(Self);
+ LeftPathLabelHBox := TGTKHBox.Create(Self);
+ RightPathLabelHBox := TGTKHBox.Create(Self);
+ LeftPathLabelHBox.Homogeneous := False;
+ RightPathLabelHBox.Homogeneous := False;
+ LeftBookmarkButton := TGTKButton.Create(Self); LeftBookmarkButton.Caption := '❇';
+ RightBookmarkButton := TGTKButton.Create(Self); RightBookmarkButton.Caption := '❇';
+ LeftPasswordButton := TGTKImageButton.Create(Self); LeftPasswordButton.Icon := StockLock16;
+ RightPasswordButton := TGTKImageButton.Create(Self); RightPasswordButton.Icon := StockLock16;
+ LeftPasswordButton.BorderStyle := bsNone;
+ RightPasswordButton.BorderStyle := bsNone;
+ LeftBookmarkButton.SetSizeRequest(22, 22); LeftBookmarkButton.Tooltip := LANGBookmarkButton_Tooltip;
+ RightBookmarkButton.SetSizeRequest(22, 22); RightBookmarkButton.Tooltip := LANGBookmarkButton_Tooltip;
+ LeftPasswordButton.SetSizeRequest(28, 22); LeftPasswordButton.Tooltip := LANGPasswordButton_Tooltip;
+ RightPasswordButton.SetSizeRequest(28, 22); RightPasswordButton.Tooltip := LANGPasswordButton_Tooltip;
+ LeftPasswordButton.Visible := False;
+ RightPasswordButton.Visible := False;
+ LeftBookmarkButton.CanFocus := False;
+ RightBookmarkButton.CanFocus := False;
+ LeftPasswordButton.CanFocus := False;
+ RightPasswordButton.CanFocus := False;
+ LeftBookmarkButton.OnClick := BookmarkButtonClick;
+ RightBookmarkButton.OnClick := BookmarkButtonClick;
+ LeftPasswordButton.OnClick := PasswordButtonClick;
+ RightPasswordButton.OnClick := PasswordButtonClick;
+ LeftScrolledWindow := TGTKScrolledWindow.Create(Self);
+ RightScrolledWindow := TGTKScrolledWindow.Create(Self);
+ LeftListView := TGTKListView.CreateTyped(Self, True, [lcPointer]);
+ RightListView := TGTKListView.CreateTyped(Self, True, [lcPointer]);
+ if not Application.GTKVersion_2_0_5_Up then begin
+ LeftListView.FromSortedCoversionFunc := OldGTKConvertFromSorted;
+ LeftListView.ToSortedCoversionFunc := OldGTKConvertToSorted;
+ RightListView.FromSortedCoversionFunc := OldGTKConvertFromSorted;
+ RightListView.ToSortedCoversionFunc := OldGTKConvertToSorted;
+ end;
+ LeftStatusLine := TGTKLabel.Create(Self);
+ RightStatusLine := TGTKLabel.Create(Self);
+ LeftQuickFindVBox := TGTKVBox.Create(Self);
+ LeftQuickFindHBox := TGTKHBox.Create(Self);
+ LeftQuickFindLabel := TGTKLabel.Create(Self);
+ LeftQuickFindEntry := TGTKEntry.Create(Self);
+ LeftQuickFindEntry.CanFocus := False;
+ LeftQuickFindSeparator := TGTKHSeparator.Create(Self);
+ LeftQuickFindHBox.AddControlEx(LeftQuickFindLabel, False, False, 0);
+ LeftQuickFindHBox.AddControlEx(LeftQuickFindEntry, True, True, 5);
+ LeftQuickFindHBox.Homogeneous := False;
+ LeftQuickFindVBox.AddControlEx(LeftQuickFindHBox, False, False, 5);
+ LeftQuickFindVBox.AddControlEx(LeftQuickFindSeparator, False, False, 0);
+ LeftQuickFindLabel.Caption := LANGQuickFind;
+ LeftQuickFindVBox.Hide;
+ RightQuickFindVBox := TGTKVBox.Create(Self);
+ RightQuickFindHBox := TGTKHBox.Create(Self);
+ RightQuickFindLabel := TGTKLabel.Create(Self);
+ RightQuickFindEntry := TGTKEntry.Create(Self);
+ RightQuickFindEntry.CanFocus := False;
+ RightQuickFindSeparator := TGTKHSeparator.Create(Self);
+ RightQuickFindHBox.AddControlEx(RightQuickFindLabel, False, False, 0);
+ RightQuickFindHBox.AddControlEx(RightQuickFindEntry, True, True, 5);
+ RightQuickFindHBox.Homogeneous := False;
+ RightQuickFindVBox.AddControlEx(RightQuickFindHBox, False, False, 5);
+ RightQuickFindVBox.AddControlEx(RightQuickFindSeparator, False, False, 0);
+ RightQuickFindLabel.Caption := LANGQuickFind;
+ RightQuickFindVBox.Hide;
+ LeftDisconnectButton := TGTKButton.Create(Self);
+ LeftDisconnectButton.Caption := '✖';
+ LeftDisconnectButton.CanFocus := False;
+ LeftDisconnectButton.SetSizeRequest(22, 22);
+ LeftDisconnectButton.Tooltip := LANGDisconnectButton_Tooltip;
+ LeftDisconnectButton.Visible := False;
+ RightDisconnectButton := TGTKButton.Create(Self);
+ RightDisconnectButton.Caption := '✖';
+ RightDisconnectButton.CanFocus := False;
+ RightDisconnectButton.SetSizeRequest(22, 22);
+ RightDisconnectButton.Tooltip := LANGDisconnectButton_Tooltip;
+ RightDisconnectButton.Visible := False;
+ LeftLeaveArchiveButton := TGTKButton.Create(Self);
+ LeftLeaveArchiveButton.Caption := '⇚';
+ LeftLeaveArchiveButton.CanFocus := False;
+ LeftLeaveArchiveButton.SetSizeRequest(22, 22);
+ LeftLeaveArchiveButton.Tooltip := LANGLeaveArchiveButton_Tooltip;
+ LeftLeaveArchiveButton.Visible := False;
+ RightLeaveArchiveButton := TGTKButton.Create(Self);
+ RightLeaveArchiveButton.Caption := '⇚';
+ RightLeaveArchiveButton.CanFocus := False;
+ RightLeaveArchiveButton.SetSizeRequest(22, 22);
+ RightLeaveArchiveButton.Tooltip := LANGLeaveArchiveButton_Tooltip;
+ RightLeaveArchiveButton.Visible := False;
+ LeftPathLabelHBox.AddControlEx(LeftPathLabelEventBox, True, True, 0);
+ LeftPathLabelHBox.AddControlEx(LeftPasswordButton, False, False, 0);
+ LeftPathLabelHBox.AddControlEx(LeftDisconnectButton, False, True, 0);
+ LeftPathLabelHBox.AddControlEx(LeftLeaveArchiveButton, False, True, 0);
+ LeftPathLabelHBox.AddControlEx(LeftBookmarkButton, False, False, 0);
+ RightPathLabelHBox.AddControlEx(RightPathLabelEventBox, True, True, 0);
+ RightPathLabelHBox.AddControlEx(RightPasswordButton, False, False, 0);
+ RightPathLabelHBox.AddControlEx(RightDisconnectButton, False, True, 0);
+ RightPathLabelHBox.AddControlEx(RightLeaveArchiveButton, False, True, 0);
+ RightPathLabelHBox.AddControlEx(RightBookmarkButton, False, False, 0);
+ LeftPathLabelEventBox.AddControl(LeftPathLabel);
+ RightPathLabelEventBox.AddControl(RightPathLabel);
+ LeftPanelNotebook := TEphyNotebook.Create(Self);
+ LeftPanelNotebook.Visible := False;
+ LeftPanelNotebook.SetSizeRequest(10, -1);
+ LeftPanelNotebook.Scrollable := True;
+ LeftPanelNotebook.ShowBorder := False;
+ LeftPanelNotebook.CanFocus := False; // Notebook should be focusable to allow scrolling when many tabs -- temporarily disabled
+ LeftPanelNotebook.ShowCloseButtons := True;
+ LeftPanelNotebook.AllowDragDrop := True;
+ LeftPanelNotebook.AllowDragOutside := True;
+ LeftPanelNotebook.ShowTooltips := True;
+ LeftPanelNotebook.OnNotebookReordered := NotebookReordered;
+ LeftPanelNotebook.OnTabClose := NotebookTabClosed;
+ LeftPanelNotebook.OnTabDoubleClick := NotebookTabDoubleClick;
+ LeftPanelNotebook.OnFindNotebookAtPointer := NotebookFindNotebookAtPointerEvent;
+ LeftPanelNotebook.OnMoveTabToAnotherNotebook := NotebookMoveTabToAnotherNotebook;
+ LeftPanelNotebook.OnTabFocusOnlyEvent := NotebookTabFocusOnlyEvent;
+ RightPanelNotebook := TEphyNotebook.Create(Self);
+ RightPanelNotebook.Visible := False;
+ RightPanelNotebook.SetSizeRequest(10, -1);
+ RightPanelNotebook.Scrollable := True;
+ RightPanelNotebook.ShowBorder := False;
+ RightPanelNotebook.CanFocus := False;
+ RightPanelNotebook.ShowCloseButtons := True;
+ RightPanelNotebook.AllowDragDrop := True;
+ RightPanelNotebook.AllowDragOutside := True;
+ RightPanelNotebook.ShowTooltips := True;
+ RightPanelNotebook.OnNotebookReordered := NotebookReordered;
+ RightPanelNotebook.OnTabClose := NotebookTabClosed;
+ RightPanelNotebook.OnTabDoubleClick := NotebookTabDoubleClick;
+ RightPanelNotebook.OnFindNotebookAtPointer := NotebookFindNotebookAtPointerEvent;
+ RightPanelNotebook.OnMoveTabToAnotherNotebook := NotebookMoveTabToAnotherNotebook;
+ RightPanelNotebook.OnTabFocusOnlyEvent := NotebookTabFocusOnlyEvent;
+ LeftListBox := TGTKVBox.Create(Self);
+ LeftListBox.AddControlEx(LeftScrolledWindow, True, True, 0);
+ RightListBox := TGTKVBox.Create(Self);
+ RightListBox.AddControlEx(RightScrolledWindow, True, True, 0);
+ LeftPanelBox.AddControlEx(LeftStatusBox, False, True, 0);
+ RightPanelBox.AddControlEx(RightStatusBox, False, True, 0);
+ LeftPanelBox.AddControlEx(LeftPathLabelHBox, False, False, 1);
+ RightPanelBox.AddControlEx(RightPathLabelHBox, False, False, 1);
+ LeftPanelBox.AddControlEx(LeftPanelNotebook, True, True, 0);
+ RightPanelBox.AddControlEx(RightPanelNotebook, True, True, 0);
+ LeftPanelBox.AddControlEx(LeftListBox, True, True, 0);
+ RightPanelBox.AddControlEx(RightListBox, True, True, 0);
+ LeftPanelBox.AddControlEx(LeftQuickFindVBox, False, True, 0);
+ RightPanelBox.AddControlEx(RightQuickFindVBox, False, True, 0);
+ LeftPanelBox.AddControlEx(LeftStatusLine, False, True, 0);
+ RightPanelBox.AddControlEx(RightStatusLine, False, True, 0);
+ LeftScrolledWindow.AddControl(LeftListView);
+ RightScrolledWindow.AddControl(RightListView);
+ LeftScrolledWindow.HorizScrollBarPolicy := sbAutomatic;
+ RightScrolledWindow.HorizScrollBarPolicy := sbAutomatic;
+ LeftScrolledWindow.VertScrollBarPolicy := sbAutomatic;
+ RightScrolledWindow.VertScrollBarPolicy := sbAutomatic;
+ LeftScrolledWindow.ShadowType := stShadowIn;
+ RightScrolledWindow.ShadowType := stShadowIn;
+ LeftUpButton := TGTKButton.Create(Self); LeftUpButton.Caption := '..';
+ LeftRootButton := TGTKButton.Create(Self); LeftRootButton.Caption := '/';
+ LeftHomeButton := TGTKButton.Create(Self); LeftHomeButton.Caption := '~';
+ LeftEqualButton := TGTKButton.Create(Self); LeftEqualButton.Caption := '=';
+ LeftUpButton.SetSizeRequest(22, 22); LeftUpButton.Tooltip := LANGUpButton_Tooltip;
+ LeftRootButton.SetSizeRequest(22, 22); LeftRootButton.Tooltip := LANGRootButton_Tooltip;
+ LeftHomeButton.SetSizeRequest(22, 22); LeftHomeButton.Tooltip := LANGHomeButton_Tooltip;
+ LeftEqualButton.SetSizeRequest(22, 22); LeftEqualButton.Tooltip := LANGLeftEqualButton_Tooltip;
+ LeftDiskInfoLabel := TGTKLabel.Create(Self);
+ LeftStatusBox.AddControlEx(LeftDiskInfoLabel, True, True, 0);
+ LeftStatusBox.AddControlEndEx(LeftUpButton, False, False, 0);
+ LeftStatusBox.AddControlEndEx(LeftRootButton, False, False, 0);
+ LeftStatusBox.AddControlEndEx(LeftHomeButton, False, False, 0);
+ LeftStatusBox.AddControlEndEx(LeftEqualButton, False, False, 0);
+ RightUpButton := TGTKButton.Create(Self); RightUpButton.Caption := '..';
+ RightRootButton := TGTKButton.Create(Self); RightRootButton.Caption := '/';
+ RightHomeButton := TGTKButton.Create(Self); RightHomeButton.Caption := '~';
+ RightEqualButton := TGTKButton.Create(Self); RightEqualButton.Caption := '=';
+ RightUpButton.SetSizeRequest(22, 22); RightUpButton.Tooltip := LANGUpButton_Tooltip;
+ RightRootButton.SetSizeRequest(22, 22); RightRootButton.Tooltip := LANGRootButton_Tooltip;
+ RightHomeButton.SetSizeRequest(22, 22); RightHomeButton.Tooltip := LANGHomeButton_Tooltip;
+ RightEqualButton.SetSizeRequest(22, 22); RightEqualButton.Tooltip := LANGRightEqualButton_Tooltip;
+ LeftUpButton.CanFocus := False;
+ LeftRootButton.CanFocus := False;
+ LeftHomeButton.CanFocus := False;
+ LeftEqualButton.CanFocus := False;
+ RightUpButton.CanFocus := False;
+ RightRootButton.CanFocus := False;
+ RightHomeButton.CanFocus := False;
+ RightEqualButton.CanFocus := False;
+ RightDiskInfoLabel := TGTKLabel.Create(Self);
+ RightStatusBox.AddControlEx(RightDiskInfoLabel, True, True, 0);
+ RightStatusBox.AddControlEndEx(RightUpButton, False, False, 0);
+ RightStatusBox.AddControlEndEx(RightRootButton, False, False, 0);
+ RightStatusBox.AddControlEndEx(RightHomeButton, False, False, 0);
+ RightStatusBox.AddControlEndEx(RightEqualButton, False, False, 0);
+ ConstructColumns(LeftListView);
+ ConstructColumns(RightListView);
+ LeftPathLabel.XAlign := 0;
+ LeftPathLabel.XPadding := 5;
+ LeftPathLabel.YPadding := 1;
+ RightPathLabel.XAlign := 0;
+ RightPathLabel.XPadding := 5;
+ RightPathLabel.YPadding := 1;
+ LeftDiskInfoLabel.XAlign := 0;
+ LeftDiskInfoLabel.XPadding := 5;
+ LeftDiskInfoLabel.YAlign := 0.5;
+ RightDiskInfoLabel.XAlign := 0;
+ RightDiskInfoLabel.XPadding := 5;
+ RightDiskInfoLabel.YAlign := 0.5;
+ LeftStatusLine.XAlign := 0;
+ LeftStatusLine.XPadding := 5;
+ LeftStatusLine.YAlign := 0.5;
+ RightStatusLine.XAlign := 0;
+ RightStatusLine.XPadding := 5;
+ RightStatusLine.YAlign := 0.5;
+{ LeftStatusBox.SetSizeRequest(1, 18);
+ RightStatusBox.SetSizeRequest(1, 18); }
+ LeftStatusLine.SetSizeRequest(1, 18);
+ RightStatusLine.SetSizeRequest(1, 18);
+ LeftDiskInfoLabel.SetSizeRequest(1, -1);
+ RightDiskInfoLabel.SetSizeRequest(1, -1);
+ LeftQuickFindVBox.SetSizeRequest(1, -1);
+ RightQuickFindVBox.SetSizeRequest(1, -1);
+end;
+
+procedure TFMain.ConstructMenu;
+const ShowDotFilesShortcut: TGDKShortCut = ( Key: 46; Locked: False; ModAlt: False; ModShift: False; ModCtrl: True);
+var i: integer;
+ Item: TGTKMenuItem;
+ Group: TGTKMenuItemGroup;
+begin
+ mnuFile := TGTKMenuItem.Create(Self);
+ mnuFile.Caption := LANGmnuFile_Caption;
+ MainMenu.Items.Add(mnuFile);
+// mnuFile.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miChangePermissions := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miChangePermissions.Caption := LANGmiChangePermissions_Caption;
+ miChangePermissions.StockIcon := 'gtk-convert';
+ miChangePermissions.OnClick := miChangePermissionsClick;
+ mnuFile.Add(miChangePermissions);
+ miChangeOwner := TGTKMenuItem.Create(Self);
+ miChangeOwner.Caption := LANGmiChangeOwner_Caption;
+ miChangeOwner.OnClick := miChangeOwnerClick;
+ mnuFile.Add(miChangeOwner);
+ mnuFile.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miCreateSymlink := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miCreateSymlink.Caption := LANGmiCreateSymlink_Caption;
+ miCreateSymlink.StockIcon := 'gtk-jump-to';
+ miCreateSymlink.OnClick := miCreateSymlinkClick;
+ mnuFile.Add(miCreateSymlink);
+ miEditSymlink := TGTKMenuItem.Create(Self);
+ miEditSymlink.Caption := LANGmiEditSymlink_Caption;
+ miEditSymlink.OnClick := miEditSymlinkClick;
+ mnuFile.Add(miEditSymlink);
+ mnuFile.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miSplitFile := TGTKMenuItem.Create(Self);
+ miSplitFile.Caption := LANGmiSplitFileCaption;
+ miSplitFile.OnClick := miSplitFileClick;
+ mnuFile.Add(miSplitFile);
+ miMergeFiles := TGTKMenuItem.Create(Self);
+ miMergeFiles.Caption := LANGmiMergeFilesCaption;
+ miMergeFiles.OnClick := miMergeFilesClick;
+ mnuFile.Add(miMergeFiles);
+ mnuFile.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miVerifyChecksums := TGTKMenuItem.Create(Self);
+ miVerifyChecksums.Caption := LANGmiVerifyChecksums;
+ miVerifyChecksums.OnClick := miVerifyChecksumsClick;
+ mnuFile.Add(miVerifyChecksums);
+ miCreateChecksums := TGTKMenuItem.Create(Self);
+ miCreateChecksums.Caption := LANGmiCreateChecksumsCaption;
+ miCreateChecksums.OnClick := miCreateChecksumsClick;
+ mnuFile.Add(miCreateChecksums);
+ mnuFile.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miExit := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miExit.Caption := LANGmiExit_Caption;
+ miExit.StockIcon := 'gtk-quit';
+ miExit.OnClick := miExitClick;
+ mnuFile.Add(miExit);
+
+ mnuMark := TGTKMenuItem.Create(Self);
+ mnuMark.Caption := LANGmnuMark_Caption;
+ MainMenu.Items.Add(mnuMark);
+// mnuMark.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miSelectGroup := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miSelectGroup.Caption := LANGmiSelectGroup_Caption;
+ miSelectGroup.ShortCuts.Add(MakeGDKShortCut(GDK_KP_PLUS, False, False, False, False));
+ miSelectGroup.StockIcon := 'gtk-add';
+ miSelectGroup.OnClick := mnuMarkClick;
+ mnuMark.Add(miSelectGroup);
+ miUnselectGroup := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miUnselectGroup.Caption := LANGmiUnselectGroup_Caption;
+ miUnselectGroup.ShortCuts.Add(MakeGDKShortCut(GDK_KP_MINUS, False, False, False, False));
+ miUnselectGroup.StockIcon := 'gtk-remove';
+ miUnselectGroup.OnClick := mnuMarkClick;
+ mnuMark.Add(miUnselectGroup);
+ miSelectAll := TGTKMenuItem.Create(Self);
+ miSelectAll.Caption := LANGmiSelectAll_Caption;
+ miSelectAll.ShortCuts.Add(MakeGDKShortCut(GDK_KP_PLUS, False, False, False, True));
+ miSelectAll.OnClick := mnuMarkClick;
+ mnuMark.Add(miSelectAll);
+ miUnselectAll := TGTKMenuItem.Create(Self);
+ miUnselectAll.Caption := LANGmiUnselectAll_Caption;
+ miUnselectAll.ShortCuts.Add(MakeGDKShortCut(GDK_KP_MINUS, False, False, False, True));
+ miUnselectAll.OnClick := mnuMarkClick;
+ mnuMark.Add(miUnselectAll);
+ miInvertSelection := TGTKMenuItem.Create(Self);
+ miInvertSelection.Caption := LANGmiInvertSelection_Caption;
+ miInvertSelection.ShortCuts.Add(MakeGDKShortCut(GDK_KP_ASTERISK, False, False, False, False));
+ miInvertSelection.OnClick := mnuMarkClick;
+ mnuMark.Add(miInvertSelection);
+
+ mnuCommands := TGTKMenuItem.Create(Self);
+ mnuCommands.Caption := LANGmnuCommands_Caption;
+ MainMenu.Items.Add(mnuCommands);
+// mnuCommands.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miSearch := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miSearch.StockIcon := 'gtk-find';
+ miSearch.Caption := LANGmiSearchCaption2;
+ miSearch.ShortCuts.AddName('<Alt>F7');
+ miSearch.OnClick := miSearchClick;
+ mnuCommands.Add(miSearch);
+ mnuCommands.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miRefresh := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miRefresh.Caption := LANGmiRefresh_Caption;
+ miRefresh.StockIcon := 'gtk-refresh';
+ miRefresh.ShortCuts.AddName('<Control>R');
+ miRefresh.OnClick := miRefreshClick;
+ mnuCommands.Add(miRefresh);
+ miShowDirectorySizes := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miShowDirectorySizes.Caption := LANGmiShowDirectorySizes_Caption;
+ miShowDirectorySizes.OnClick := miShowDirectorySizesClick;
+ mnuCommands.Add(miShowDirectorySizes);
+ mnuCommands.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miNewTab := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miNewTab.Caption := LANGmiNewTab_Caption;
+ miNewTab.ShortCuts.AddName('<Control>T');
+ miNewTab.OnClick := miDuplicateTabClick;
+ miNewTab.StockIcon := 'gtk-index';
+ mnuCommands.Add(miNewTab);
+ mnuCommands.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miTargetSource := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miTargetSource.Caption := LANGmiTargetSource_Caption;
+// miTargetSource.ShortCuts.AddName('<Alt>O');
+ miTargetSource.OnClick := miTargetSourceClick;
+ mnuCommands.Add(miTargetSource);
+
+ mnuShow := TGTKMenuItem.Create(Self);
+ mnuShow.Caption := LANGmnuShow_Caption;
+ MainMenu.Items.Add(mnuShow);
+// mnuShow.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miShowDotFiles := TGTKMenuItem.CreateTyped(Self, itCheck);
+ miShowDotFiles.Caption := LANGmiShowDotFiles_Caption;
+ miShowDotFiles.Checked := ConfShowDotFiles;
+ miShowDotFiles.OnClick := miShowDotFilesClick;
+ miShowDotFiles.ShortCuts.Add(ShowDotFilesShortcut);
+ mnuShow.Add(miShowDotFiles);
+ mnuShow.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miNoMounterBar := TGTKMenuItem.CreateTyped(Self, itRadio, nil);
+ miNoMounterBar.Caption := LANGmiNoMounterBarCaption;
+ miNoMounterBar.Checked := ConfShowMounterBar = 0;
+ Group := miNoMounterBar.Group;
+ mnuShow.Add(miNoMounterBar);
+ miShowOneMounterBar := TGTKMenuItem.CreateTyped(Self, itRadio, Group);
+ miShowOneMounterBar.Caption := LANGmiShowOneMounterBarCaption;
+ miShowOneMounterBar.Checked := ConfShowMounterBar = 1;
+ Group := miShowOneMounterBar.Group;
+ mnuShow.Add(miShowOneMounterBar);
+ miShowTwoMounterBar := TGTKMenuItem.CreateTyped(Self, itRadio, Group);
+ miShowTwoMounterBar.Caption := LANGmiShowTwoMounterBarCaption;
+ miShowTwoMounterBar.Checked := ConfShowMounterBar = 2;
+ mnuShow.Add(miShowTwoMounterBar);
+ // Assign of the events has to be done after all radio items are created
+ miNoMounterBar.OnClick := miShowMounterBarClick;
+ miShowOneMounterBar.OnClick := miShowMounterBarClick;
+ miShowTwoMounterBar.OnClick := miShowMounterBarClick;
+
+ mnuBookmarks := TGTKMenuItem.Create(Self);
+ mnuBookmarks.Caption := LANGmnuBookmarks_Caption;
+ mnuBookmarks.OnPopup := mnuBookmarksPopup;
+ mnuBookmarks.OnClick := mnuBookmarksPopup;
+ MainMenu.Items.Add(mnuBookmarks);
+// mnuBookmarks.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miAddBookmark := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miAddBookmark.Caption := LANGmiAddBookmark_Caption;
+ miAddBookmark.StockIcon := 'gtk-add';
+ miAddBookmark.OnClick := miAddBookmarkClick;
+ mnuBookmarks.Add(miAddBookmark);
+ miEditBookmarks := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miEditBookmarks.Caption := LANGmiEditBookmarks_Caption;
+ miEditBookmarks.Enabled := False;
+ miEditBookmarks.Visible := False;
+ miEditBookmarks.Tooltip := 'Currently not implemented - use the popup menu';
+ mnuBookmarks.Add(miEditBookmarks);
+ miBookmarksSeparator := TGTKMenuItem.CreateTyped(Self, itSeparator);
+ mnuBookmarks.Add(miBookmarksSeparator);
+
+ BookmarkPopup := TGTKMenuItem.Create(Self);
+ BookmarkPopupDelete := TGTKMenuItem.Create(Self);
+ BookmarkPopupDelete.Caption := LANGBookmarkPopupDelete_Caption;
+ BookmarkPopupDelete.OnClick := BookmarkPopupDeleteClick;
+ BookmarkPopup.Add(BookmarkPopupDelete);
+
+ mnuNetwork := TGTKMenuItem.Create(Self);
+ mnuNetwork.Caption := LANGmnuNetworkCaption;
+ MainMenu.Items.Add(mnuNetwork);
+// mnuNetwork.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miConnections := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miConnections.Caption := LANGmiConnectionsCaption;
+ miConnections.StockIcon := 'gtk-network';
+ miConnections.Enabled := False;
+ mnuNetwork.Add(miConnections);
+ mnuNetwork.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miOpenConnection := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miOpenConnection.Caption := LANGmiOpenConnectionCaption;
+ miOpenConnection.OnClick := miOpenConnectionClick;
+ miOpenConnection.StockIcon := 'gtk-connect';
+ miOpenConnection.ShortCuts.AddName('<Control>F');
+ mnuNetwork.Add(miOpenConnection);
+ miQuickConnect := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miQuickConnect.Caption := LANGmiQuickConnectCaption;
+ miQuickConnect.Enabled := False;
+ miQuickConnect.ShortCuts.AddName('<Control>N');
+ mnuNetwork.Add(miQuickConnect);
+ mnuNetwork.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miDisconnect := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miDisconnect.Caption := LANGmiDisconnect_Caption;
+ miDisconnect.Enabled := False;
+ miDisconnect.ShortCuts.AddName('<Control>D');
+ miDisconnect.StockIcon := 'gtk-disconnect';
+ miDisconnect.OnClick := miDisconnectClick;
+ mnuNetwork.Add(miDisconnect);
+
+ mnuPlugins := TGTKMenuItem.Create(Self);
+ mnuPlugins.Caption := LANGmnuPluginsCaption;
+ MainMenu.Items.Add(mnuPlugins);
+// mnuPlugins.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miTestPlugin := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miTestPlugin.Caption := LANGmiTestPluginCaption;
+ miTestPlugin.OnClick := miTestPluginClick;
+ mnuPlugins.Add(miTestPlugin);
+ mnuPlugins.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+
+ mnuSettings := TGTKMenuItem.Create(Self);
+ mnuSettings.Caption := LANGmnuSettings_Caption;
+ MainMenu.Items.Add(mnuSettings);
+// mnuSettings.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miPreferences := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miPreferences.Caption := LANGmiPreferences_Caption;
+ miPreferences.StockIcon := 'gtk-preferences';
+ miPreferences.OnClick := miPreferencesClick;
+ mnuSettings.Add(miPreferences);
+ miFileTypes := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miFileTypes.Caption := LANGmiFileTypes_Caption;
+ miFileTypes.OnClick := miFileTypesClick;
+ mnuSettings.Add(miFileTypes);
+ miMounterSettings := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miMounterSettings.Caption := LANGmiMounterSettingsCaption;
+ miMounterSettings.OnClick := miMounterSettingsClick;
+ mnuSettings.Add(miMounterSettings);
+ miColumns := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miColumns.Caption := LANGmiColumnsCaption;
+ miColumns.OnClick := miColumnsClick;
+ mnuSettings.Add(miColumns);
+ mnuSettings.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miSavePosition := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miSavePosition.Caption := LANGmiSavePositionCaption;
+ miSavePosition.OnClick := miSavePositionClick;
+ mnuSettings.Add(miSavePosition);
+
+ mnuHelp := TGTKMenuItem.Create(Self);
+ mnuHelp.Caption := LANGmnuHelp_Caption;
+ MainMenu.Items.Add(mnuHelp);
+// mnuHelp.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ miAbout := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miAbout.Caption := LANGmiAbout_Caption;
+ miAbout.StockIcon := 'gtk-about';
+ miAbout.OnClick := miAboutClick;
+ mnuHelp.Add(miAbout);
+
+ // Splitter popup menu
+ SplitterPopupMenu := TGTKMenuItem.Create(Self);
+// SplitterPopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itTearOff));
+ for i := 2 to 8 do begin
+ Item := TGTKMenuItem.Create(Self);
+ Item.Caption := Format('%d - %d', [i * 10, (10 - i) * 10]);
+ Item.Data := Pointer(i * 10);
+ Item.OnClick := SplitterPopupMenuClick;
+ SplitterPopupMenu.Add(Item);
+ end;
+
+ // Files popup menu
+ FilePopupMenu := TGTKMenuItem.Create(Self);
+ FilePopupMenu.OnPopup := FilePopupMenuPopup;
+
+ // Mounter popup menu
+ MounterButtonPopupMenu := TGTKMenuItem.Create(Self);
+ MounterButtonPopupMenu.OnPopup := MounterButtonPopupMenuPopup;
+ miMount := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miMount.Caption := LANGmiMountCaption;
+ miMount.StockIcon := 'gtk-connect';
+ miMount.OnClick := miMountClick;
+ MounterButtonPopupMenu.Add(miMount);
+ miUmount := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miUmount.Caption := LANGmiUmountCaption;
+ miUmount.StockIcon := 'gtk-disconnect';
+ miUmount.OnClick := miUmountClick;
+ MounterButtonPopupMenu.Add(miUmount);
+ miEject := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miEject.Caption := LANGmiEjectCaption;
+// miEject.StockIcon := 'gtk-cdrom';
+ miEject.OnClick := miEjectClick;
+ MounterButtonPopupMenu.Add(miEject);
+
+ // Tab popup menu
+ TabPopupMenu := TGTKMenuItem.Create(Self);
+ TabPopupMenu.OnPopup := TabPopupMenuPopup;
+ miDuplicateTab := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miDuplicateTab.Caption := LANGmiDuplicateTabCaption;
+ miDuplicateTab.ShortCuts.AddName('<Control>T');
+ miDuplicateTab.OnClick := miDuplicateTabClick;
+ miDuplicateTab.StockIcon := 'gtk-index';
+ TabPopupMenu.Add(miDuplicateTab);
+ TabPopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ miCloseTab := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miCloseTab.Caption := LANGmiCloseTabCaption;
+ miCloseTab.ShortCuts.AddName('<Control>W');
+ miCloseTab.OnClick := miCloseTabClick;
+ miCloseTab.StockIcon := 'gtk-close';
+ TabPopupMenu.Add(miCloseTab);
+ miCloseAllTabs := TGTKMenuItem.CreateTyped(Self, itImageText);
+ miCloseAllTabs.Caption := LANGmiCloseAllTabsCaption;
+ miCloseAllTabs.OnClick := miCloseAllTabsClick;
+ TabPopupMenu.Add(miCloseAllTabs);
+end;
+
+procedure TFMain.ConstructColumns(ListView: TGTKListView);
+var i, FirstColumn, LastColumn: integer;
+ Column: TGTKTreeViewColumn;
+ FontDesc: PPangoFontDescription;
+begin
+ ListView.SelectionMode := smBrowse;
+ GetFirstLastPanelColumn(FirstColumn, LastColumn);
+
+ for i := 1 to ConstNumPanelColumns do
+ if ConfColumnVisible[i] then begin
+
+ // First column should have filetype icon
+ if (i = FirstColumn) and ConfUseFileTypeIcons then begin
+ Column := ListView.Columns.AddTyped(ctImageText);
+ Column.SetImageProperty('ypad', 0);
+ Column.SetImageProperty('yalign', 0.5);
+ Column.SetImageProperty('xpad', 0);
+ Column.SetImageProperty('xalign', 0.5);
+ if (ConfRowHeight > 0) and ConfUseFileTypeIcons then begin
+ Column.SetImageProperty('width', ConfRowHeight);
+ Column.SetImageProperty('height', ConfRowHeight);
+ end;
+ end else Column := ListView.Columns.Add;
+
+
+ Column.Caption := ConfColumnTitlesShort[ConfColumnIDs[i]];
+
+ if (i < LastColumn){ or Application.GTKVersion_2_4_0_Up} then begin
+{ Column.MinWidth := 10;
+ Column.MaxWidth := 500; }
+{ Column.SizingMode := smFixed;
+ Column.FixedWidth := ConfColumnSizes[i]; }
+ g_object_set(G_OBJECT(Column.FColumn), 'sizing', 2, 'fixed-width', ConfColumnSizes[i], nil);
+ end else g_object_set(G_OBJECT(Column.FColumn), 'sizing', 0, nil);
+ // Column.SizingMode := smFixed; // smAutoSize;
+
+ gtk_tree_view_column_set_spacing(Column.FColumn, 1); // Bug with column spacing?
+
+ Column.Resizable := True;
+ Column.Reorderable := True;
+// if not ConfUseSystemFont then ListView.Columns[i - 1].SetProperty('font', ConfPanelFont);
+ Column.SetProperty('ypad', 0);
+ Column.SetProperty('yalign', 0.5);
+ Column.Tag := i;
+ g_object_set_data(G_OBJECT(Column.FColumn), 'Column_ID', Pointer(i));
+ if ConfRowHeight > 0 then Column.SetProperty('height', ConfRowHeight);
+ Column.SortID := ListView.Columns.Count - 1;
+ ColumnSortIDs[Column.SortID + 1] := ConfColumnIDs[i];
+ if ConfRowHeight < 0 then gtk_cell_renderer_text_set_fixed_height_from_font(PGtkCellRendererText(Column.FRenderer), 1);
+{ gtk_cell_renderer_text_set_fixed_height_from_font(PGtkCellRendererText(Column.FRenderer), 1);
+ gtk_cell_renderer_set_fixed_size(PGtkCellRenderer(Column.FRenderer), ConfColumnSizes[i], ConfRowHeight); }
+ if ConfColumnIDs[i] < 3 then begin // Filename column
+ Column.OnEdited := ListViewEdited;
+ if Application.GTKVersion_2_6_0_Up then Column.SetProperty('ellipsize', 3);
+ end;
+ if ConfColumnIDs[i] in [4, 8, 9] then begin
+ Column.SetProperty('xalign', 1);
+ Column.Alignment := 1;
+ end;
+ if Application.GTKVersion_2_4_0_Up then Column.SetProperty('single-paragraph-mode', 1);
+ Column.OnClicked := ListViewColumnClicked;
+
+ end;
+
+ // Set the list font
+ if not ConfUseSystemFont then begin
+ FontDesc := pango_font_description_from_string(PChar(ConfPanelFont));
+ gtk_widget_modify_font(ListView.FWidget, FontDesc);
+ end else gtk_widget_modify_font(ListView.FWidget, nil);
+
+ // Set the fixed row height - temporarily disabled due to bug in custom drawing
+// if Application.GTKVersion_2_4_0_Up then g_object_set(ListView.FWidget, 'fixed_height_mode', integer(True), nil);
+end;
+
+procedure TFMain.FormDestroy(Sender: TObject);
+begin
+ LeftNotebookBoxList.Free;
+ RightNotebookBoxList.Free;
+end;
+
+procedure TFMain.FormClose(Sender: TObject; var Action: TCloseAction);
+
+ function InternalCloseEngine(Engine, FallbackEngine: TPanelEngine): TPanelEngine;
+ begin
+ Result := FallbackEngine;
+ if not Assigned(Engine.ParentEngine) or (not (Engine is TVFSEngine)) then Exit;
+ Result := Engine.ParentEngine;
+// if not TVFSEngine(Engine).VFSClose then DebugMsg(['Error closing the engine...']);
+// Engine.Free;
+ end;
+
+var i: integer;
+ b, DontShowAgain: boolean;
+ res: TMessageButton;
+begin
+ // Find all opened connections and warn user
+ b := False;
+ if LeftPanelNotebook.Visible and Assigned(LeftTabEngines) and (LeftTabEngines.Count > 0) then
+ for i := 0 to LeftTabEngines.Count - 1 do
+ if TPanelEngine(LeftTabEngines[i]) is TVFSEngine then begin
+ b := True;
+ Break;
+ end;
+ if (not b) or (RightPanelNotebook.Visible and Assigned(RightTabEngines) and (RightTabEngines.Count > 0)) then
+ for i := 0 to RightTabEngines.Count - 1 do
+ if TPanelEngine(RightTabEngines[i]) is TVFSEngine then begin
+ b := True;
+ Break;
+ end;
+ b := b or (LeftPanelEngine is TVFSEngine) or (RightPanelEngine is TVFSEngine);
+ if b and ConfOpenConnectionsWarning then begin
+ res := MessageBoxShowOnce(LANGOpenConnectionsWarning, LANGDontShowAgain, DontShowAgain, [mbYes, mbNo], mbWarning, mbYes, mbNo);
+ if DontShowAgain then begin
+ ConfOpenConnectionsWarning := False;
+ WriteMainGUISettings;
+ end;
+ if res = mbNo then begin
+ Action := caNone;
+ Exit;
+ end;
+ end;
+
+ // Close all active connections
+ if b then begin
+ if (not LeftPanelNotebook.Visible) and (LeftPanelEngine is TVFSEngine) then CloseVFS(True, True)
+ else
+ for i := 0 to LeftTabEngines.Count - 1 do try
+ if LeftPanelNotebook.PageIndex = i then CloseVFS(True, True) else
+ if Assigned(LeftTabEngines[i]) and (TPanelEngine(LeftTabEngines[i]) is TVFSEngine) then begin
+ LeftPanelTabs[i] := TPanelEngine(LeftTabEngines[i]).SavePath;
+ LeftTabEngines[i] := InternalCloseEngine(LeftTabEngines[i], LeftLocalEngine);
+ end;
+ except end;
+ if (not RightPanelNotebook.Visible) and (RightPanelEngine is TVFSEngine) then CloseVFS(False, True)
+ else
+ for i := 0 to RightTabEngines.Count - 1 do try
+ if RightPanelNotebook.PageIndex = i then CloseVFS(False, True) else
+ if TPanelEngine(RightTabEngines[i]) is TVFSEngine then begin
+ RightPanelTabs[i] := TPanelEngine(RightTabEngines[i]).SavePath;
+ RightTabEngines[i] := InternalCloseEngine(RightTabEngines[i], RightLocalEngine);
+ end;
+ except end;
+ end;
+
+ // Unset the columns changed signal because it is called on window close
+ LeftListView.OnColumnsChanged := nil;
+ RightListView.OnColumnsChanged := nil;
+
+ ConfMainWindowState := Integer(WindowState);
+ if ConfMainWindowState <> 0 then begin
+ ConfMainWindowPosLeft := TGTKControl(Self).Left;
+ ConfMainWindowPosTop := TGTKControl(Self).Top;
+ ConfMainWindowWidth := TGTKControl(Self).Width;
+ ConfMainWindowHeight := TGTKControl(Self).Height;
+ end else begin
+ ConfMainWindowPosLeft := Left;
+ ConfMainWindowPosTop := Top;
+ ConfMainWindowWidth := Width;
+ ConfMainWindowHeight := Height;
+ end;
+ for i := 0 to LeftListView.Columns.Count - 1 do
+ ConfColumnSizes[LeftListView.Columns[i].Tag] := LeftListView.Columns[i].Width;
+ ConfMainWindowLeftSortColumn := LeftListView.SortColumnID;
+ ConfMainWindowLeftSortType := Integer(LeftListView.SortOrder);
+ ConfMainWindowRightSortColumn := RightListView.SortColumnID;
+ ConfMainWindowRightSortType := Integer(RightListView.SortOrder);
+
+ ConfLeftTabBarTabIndex := LeftPanelNotebook.PageIndex;
+ ConfRightTabBarTabIndex := RightPanelNotebook.PageIndex;
+end;
+
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.AfterStart;
+var i: integer;
+ TmpList: TStringList;
+ TmpList2, TmpList3: TList;
+begin
+ LeftPanelEngine := LeftLocalEngine;
+ RightPanelEngine := RightLocalEngine;
+
+ // Apply the settings
+ ApplySettings(False, False, True);
+
+ MounterBarHandleBox.Visible := ConfShowMounterBar = 1;
+ LeftMounterTable.Visible := ConfShowMounterBar = 2;
+ RightMounterTable.Visible := ConfShowMounterBar = 2;
+ FillMounterBar;
+
+ LeftListView.SetFocus;
+ if CommandLineHistory.Count > 0 then
+ for i := 0 to CommandLineHistory.Count - 1 do
+ CommandLineCombo.Items.Append(CommandLineHistory[i]);
+ CommandLineCombo.Entry.Text := '';
+
+ RefreshBookmarksMenu;
+
+ ButtonsBox.Visible := ConfShowFuncButtons;
+ ButtonBoxSeparator.Visible := ConfShowFuncButtons;
+ ButtonBoxSpace.Visible := not ConfShowFuncButtons;
+
+ FillPluginMenu;
+
+ FileListTipsInstall(PGtkTreeView(LeftListView.FWidget));
+ FileListTipsInstall(PGtkTreeView(RightListView.FWidget));
+ FileListTipsEnable;
+
+ // Load and restore panel tabs
+ if ConfSavePanelTabs then try
+ TmpList := TStringList.Create;
+ TmpList2 := TList.Create;
+ TmpList3 := TList.Create;
+ ReadTabs(True, TmpList, TmpList2, TmpList3);
+ if (TmpList.Count > 0) and (TmpList2.Count > 0) and (TmpList3.Count > 0) then
+ AddTabs(True, TmpList, TmpList2, TmpList3, ConfLeftTabBarTabIndex);
+ TmpList.Clear;
+ TmpList2.Clear;
+ TmpList3.Clear;
+ ReadTabs(False, TmpList, TmpList2, TmpList3);
+ if (TmpList.Count > 0) and (TmpList2.Count > 0) and (TmpList3.Count > 0) then
+ AddTabs(False, TmpList, TmpList2, TmpList3, ConfRightTabBarTabIndex);
+ TmpList.Free;
+ TmpList2.Free;
+ TmpList3.Free;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TFMain.AfterStart, loading tabs: (', E.ClassName, '): ', E.Message]);
+ end;
+
+ // Refresh the lists
+ ChangingDir(True, ConfLeftPath, '', '', False, True); // AutoFallback
+ ChangingDir(False, ConfRightPath, '', '', False, True);
+ LeftListView.SetSortInfo(ConfMainWindowLeftSortColumn, TGTKTreeViewSortOrder(ConfMainWindowLeftSortType));
+ RightListView.SetSortInfo(ConfMainWindowRightSortColumn, TGTKTreeViewSortOrder(ConfMainWindowRightSortType));
+
+ // Set window position and size
+ SetDefaultSize(ConfMainWindowWidth, ConfMainWindowHeight);
+ if (ConfMainWindowPosLeft > -1) and (ConfMainWindowPosTop > -1)
+ then WindowMove(ConfMainWindowPosLeft, ConfMainWindowPosTop);
+ if ConfWMCompatMode then Show;
+ case integer(ConfMainWindowState) of
+ Ord(wsMaximized) : Maximize;
+ Ord(wsMinimized) : Minimize;
+ end;
+ if not ConfWMCompatMode then Show;
+
+ // Other things
+ StartUp := False; // Set the flag to process Splitter repositioning
+ PanelSeparator.Position := Round(Width * (ConfPanelSep / 100));
+
+ Application.ProcessMessages; // Need to process all messages before unlocking
+ InternalLockInit(False);
+
+ LeftListView.OnColumnsChanged := ListViewColumnsChanged;
+ RightListView.OnColumnsChanged := ListViewColumnsChanged;
+ LeftListView.SetFocus;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.PanelSeparatorResize(Sender: TObject);
+begin
+ if not StartUp then ConfPanelSep := Round((PanelSeparator.Position / Width) * 100);
+end;
+
+procedure TFMain.miExitClick(Sender: TObject);
+begin
+ Close;
+end;
+
+procedure TFMain.miAboutClick(Sender: TObject);
+begin
+ InternalLock;
+ ShowAbout;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+end;
+
+procedure TFMain.ListViewKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+var AListView: TGTKListView;
+ ANotebook: TEphyNotebook;
+ LeftPanel: boolean;
+ vadj, hadj: PGtkAdjustment;
+ x: integer;
+begin
+ if not Assigned(Sender) or not (Sender is TGTKListView) then DebugMsg(['**** ListViewKeyDown: Sender is not TGTKListView or not valid']);
+ AListView := Sender as TGTKListView;
+ if LeftListView.Focused then LeftPanel := True
+ else if RightListView.Focused then LeftPanel := False
+ else LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ ANotebook := LeftPanelNotebook;
+ vadj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(LeftScrolledWindow.FWidget));
+ hadj := gtk_scrolled_window_get_hadjustment(PGtkScrolledWindow(LeftScrolledWindow.FWidget));
+ end else begin
+ ANotebook := RightPanelNotebook;
+ vadj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(RightScrolledWindow.FWidget));
+ hadj := gtk_scrolled_window_get_hadjustment(PGtkScrolledWindow(RightScrolledWindow.FWidget));
+ end;
+ FileListTipsHide;
+ case Key of
+ GDK_TAB, 65056 : if (ssCtrl in Shift) and ANotebook.Visible then begin
+ Accept := False;
+ x := (ANotebook.PageIndex + 1 - 2*Ord(ssShift in Shift)) mod ANotebook.ChildrenCount;
+ if x < 0 then x := ANotebook.ChildrenCount - 1;
+ ANotebook.PageIndex := x;
+ end else begin
+ Accept := False;
+ DeactivateQuickFind(LeftPanel);
+ Application.ProcessMessages;
+ if InternalLockUnlocked then // prevent changing focus when busy
+ if LeftPanel then RightListView.SetFocus
+ else LeftListView.SetFocus;
+ end;
+ GDK_RETURN, GDK_KP_ENTER : if (Key = GDK_RETURN) and (Shift = [ssAlt, ssShift]) then DoGetDirSize(True) else
+ if ([ssAlt] = Shift) or ([ssCtrl] = Shift) then begin
+ CommandLineComboKeyDown(Sender, Key, Shift, Accept);
+ Accept := False;
+ CommandLineCombo.Entry.SetFocus;
+ CommandLineCombo.Entry.SelectRegion(Length(CommandLineCombo.Entry.Text), Length(CommandLineCombo.Entry.Text));
+ end else
+ if Length(Trim(CommandLineCombo.Entry.Text)) > 0 then CommandLineComboKeyDown(Sender, Key, Shift, Accept)
+ else if Assigned(AListView.Selected) then ActivateItem(AListView.Selected.Index, False);
+ GDK_BACKSPACE : if QuickFind then begin Accept := False; QuickFindSendKey(LeftPanel, Key); end
+ else if LeftPanel then PathButtonClick(LeftUpButton)
+ else PathButtonClick(RightUpButton);
+ GDK_Right : begin
+ if [ssCtrl] = Shift then SwitchPanelCtrlLeftRight(LeftPanel, False) else
+ if ConfLynxLikeMotion then begin
+ if Assigned(AListView.Selected) then ActivateItem(AListView.Selected.Index, False);
+ end;
+ Accept := False;
+ end;
+ GDK_Left : begin
+ if [ssCtrl] = Shift then SwitchPanelCtrlLeftRight(LeftPanel, True) else
+ if ConfLynxLikeMotion then
+ if LeftPanel then PathButtonClick(LeftUpButton)
+ else PathButtonClick(RightUpButton);
+ Accept := False;
+ end;
+ GDK_INSERT : DoSelect(5);
+ GDK_SPACE : begin
+ Accept := False;
+ if QuickFind then QuickFindSendKey(LeftPanel, Key)
+ else if Length(CommandLineCombo.Entry.Text) > 0 then ActivateCommandLine(Key)
+ else begin
+ if not PDataItem(AListView.Selected.Data)^.Selected then DoGetDirSize(False);
+ DoSelect(8);
+ end;
+ end;
+ GDK_F1 : if Shift = [ssAlt] then begin
+ ShowBookmarkQuick(True);
+ Accept := False;
+ end;
+ GDK_F2 : if Shift = [ssAlt] then begin
+ ShowBookmarkQuick(False);
+ Accept := False;
+ end else
+ if (Shift = [ssShift]) or (Shift = [ssCtrl]) then begin
+ CopyFilenamesToClipboard(Shift = [ssCtrl], LeftPanel);
+ end else begin
+ DeactivateQuickFind(LeftPanel);
+ Accept:= False;
+ F6ButtonClick(nil);
+ end;
+ GDK_F3 : begin
+ DeactivateQuickFind(LeftPanel);
+ Accept:= False;
+ F3F4ButtonClick(F3Button);
+ end;
+ GDK_F4 : begin
+ DeactivateQuickFind(LeftPanel);
+ Accept:= False;
+ if ssShift in Shift then EditViewFile(LeftPanel, AListView, False, True)
+ else F3F4ButtonClick(F4Button);
+ end;
+ GDK_F5 : begin
+ DeactivateQuickFind(LeftPanel);
+ Accept:= False;
+ if ssShift in Shift then F5ButtonClick(nil)
+ else F5ButtonClick(Sender);
+ end;
+ GDK_F6 : begin
+ DeactivateQuickFind(LeftPanel);
+ Accept:= False;
+ if ssShift in Shift then begin
+ if not Assigned(AListView.Columns[0].FColumn^.editable_widget) then Editing := False;
+ DoQuickRename(Sender = LeftListView, AListView, True)
+ end else F6ButtonClick(Sender);
+ end;
+ GDK_F7 : begin
+ DeactivateQuickFind(LeftPanel);
+ Accept:= False;
+ if ssAlt in Shift then miSearchClick(Sender)
+ else F7ButtonClick(Sender);
+ end;
+ GDK_F8, GDK_Delete_Key : begin
+ DeactivateQuickFind(LeftPanel);
+ Accept:= False;
+ F8ButtonClick(Sender);
+ end;
+ GDK_ESCAPE : begin
+ if not QuickFind then CommandLineCombo.Entry.Text := '';
+ DeactivateQuickFind(LeftPanel);
+ if RunningEscSensitive > 0 then FMainEscPressed := True;
+ end;
+ GDK_S, GDK_Capital_S : if (ssAlt in Shift) or (ssCtrl in Shift)
+ then ActivateQuickFind(Sender = LeftListView)
+ else begin
+ Accept := False;
+ if QuickFind then QuickFindSendKey(LeftPanel, Key)
+ else ActivateCommandLine(Key);
+ end;
+ GDK_O, GDK_Capital_O : if ssAlt in Shift then SwitchOtherPanel(LeftPanel, False)
+ else begin
+ Accept := False;
+ if QuickFind then QuickFindSendKey(LeftPanel, Key)
+ else ActivateCommandLine(Key);
+ end;
+
+ GDK_P, GDK_Capital_P, GDK_N, GDK_Capital_N:
+ if ((Shift = [ssAlt]) or (Shift = [ssCtrl]) or ((Shift = []) and (not QuickFind))) { and (CommandLineHistory.Count > 0) }
+ then CommandLineComboKeyDown(Sender, Key, Shift, Accept)
+ else if QuickFind then QuickFindSendKey(LeftPanel, Key);
+ GDK_A, GDK_Capital_A: if (Shift = [ssAlt]) or (Shift = [ssCtrl]) or ((Shift = []) and (not QuickFind))
+ then CommandLineComboKeyDown(Sender, Key, Shift, Accept)
+ else if QuickFind then QuickFindSendKey(LeftPanel, Key);
+ GDK_WIN_POPUP : begin
+ Accept := False;
+ PopupFileMenuPos;
+ end;
+ GDK_HOME: if Shift = [ssCtrl] then begin
+ if LeftPanel then PathButtonClick(LeftHomeButton)
+ else PathButtonClick(RightHomeButton);
+ Accept := False;
+ end else if Assigned(AListView.Selected) and (AListView.ConvertToSorted(AListView.Selected.Index) = 0) then Accept := False;
+ GDK_END: if Assigned(AListView.Selected) and (AListView.ConvertToSorted(AListView.Selected.Index) = AListView.Items.Count - 1) then Accept := False;
+ GDK_SLASH, GDK_KP_SLASH: if Shift = [ssCtrl] then begin
+ if LeftPanel then PathButtonClick(LeftRootButton)
+ else PathButtonClick(RightRootButton);
+ Accept := False;
+ end;
+{ GDK_0..GDK_9: if ConfBookmarkQuickJump and (Shift = [ssAlt]) then QuickJumpToBookmark(LeftPanel, Key - GDK_1)
+ else begin
+ Accept := False;
+ if QuickFind then QuickFindSendKey(LeftPanel, Key)
+ else ActivateCommandLine(Key);
+ end; }
+ GDK_Down : if [ssCtrl] = Shift then begin
+ Accept := False;
+ CommandLineCombo.Entry.SetFocus;
+ CommandLineCombo.Entry.SelectAll;
+ end else begin
+ if QuickFind then QuickFindSendKey(LeftPanel, Key)
+ else if Assigned(AListView.Selected) and (AListView.ConvertToSorted(AListView.Selected.Index) = AListView.Items.Count - 1) then Accept := False;
+ end;
+ GDK_Up : if Assigned(AListView.Selected) and (AListView.ConvertToSorted(AListView.Selected.Index) = 0) then Accept := False;
+
+ GDK_Page_Up, GDK_Page_Down: if (Shift = [ssCtrl]) and ANotebook.Visible then
+ begin
+ Accept := False;
+ x := (ANotebook.PageIndex + 1 - 2*Ord(Key = GDK_Page_Up)) mod ANotebook.ChildrenCount;
+ if x < 0 then x := ANotebook.ChildrenCount - 1;
+ ANotebook.PageIndex := x;
+ end else begin
+ if Assigned(AListView.Selected) and
+ (((Key = GDK_Page_Up) and (AListView.ConvertToSorted(AListView.Selected.Index) = 0)) or
+ ((Key = GDK_Page_Down) and (AListView.ConvertToSorted(AListView.Selected.Index) = AListView.Items.Count - 1)))
+ then Accept := False;
+ end;
+
+ else if QuickFind then Accept := not QuickFindSendKey(LeftPanel, Key)
+ else Accept := not ActivateCommandLine(Key);
+ end;
+end;
+
+procedure TFMain.ListViewEnter(Sender: TObject; var Accept: boolean);
+var s: string;
+begin
+ LeftLastFocused := Sender = LeftListView;
+ if LeftLastFocused then begin
+ LeftPathLabelEventBox.ControlState := csSelected;
+ RightPathLabelEventBox.ControlState := csActive;
+ s := LeftPathLabel.Caption;
+ end else begin
+ LeftPathLabelEventBox.ControlState := csActive;
+ RightPathLabelEventBox.ControlState := csSelected;
+ s := RightPathLabel.Caption;
+ end;
+ CommandLineLabel.Caption := Format('%s@%s:%s>', [GetUserName, GetHostName, s]);
+ UpdateCaption;
+ miDisconnect.Enabled := (LeftLastFocused and (LeftPanelEngine is TVFSEngine) and (not TVFSEngine(LeftPanelEngine).ArchiveMode)) or
+ ((not LeftLastFocused) and (RightPanelEngine is TVFSEngine) and (not TVFSEngine(RightPanelEngine).ArchiveMode));
+end;
+
+procedure TFMain.FormResize(Sender: TObject);
+begin
+ if Width <> LastWidth then begin
+// DebugMsg(['FormResize: ', Width, 'x', Height]);
+ PanelSeparator.Position := Round(Width * (ConfPanelSep / 100));
+ CommandLineLabel.SetSizeRequest(Round(Width / 2.5), -1);
+ LastWidth := Width;
+ end;
+end;
+
+procedure TFMain.PathLabelMouseDown(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+begin
+ if Button = mbLeft then
+ if Sender = LeftPathLabelEventBox then LeftListView.SetFocus
+ else if Sender = RightPathLabelEventBox then RightListView.SetFocus;
+end;
+
+procedure TFMain.ActivateItem(const ItemIndex: longint; const MouseActivate: boolean);
+var Data: PDataItem;
+ LeftPanel: boolean;
+ DataList: TList;
+ Engine: TPanelEngine;
+ AListView: TGTKListView;
+ Ext: string;
+begin
+ if LeftListView.Focused then LeftPanel := True
+ else if RightListView.Focused then LeftPanel := False
+ else LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ DataList := LeftPanelData;
+ Engine := LeftPanelEngine;
+ AListView := LeftListView;
+ end else begin
+ DataList := RightPanelData;
+ Engine := RightPanelEngine;
+ AListView := RightListView;
+ end;
+ DeactivateQuickFind(LeftPanel);
+ if Application.GTKVersion_2_0_5_Up then Data := DataList[ItemIndex]
+ else Data := AListView.Items[ItemIndex].AsPointer(0);
+ DebugMsg(['Selected:', Data^.AName]);
+ if not Assigned(Data) then Exit;
+ if Data^.UpDir then ChangingDir(LeftPanel, '..') else
+ if Data^.IsDir then begin
+ if MouseActivate then begin
+ if AListView.Items.Count > 0 then AListView.Items[0].Selected := True;
+ Application.ProcessMessages;
+ end;
+ ChangingDir(LeftPanel, String(Data^.AName));
+ end else begin
+ Ext := ANSIUpperCase(Trim(Copy(String(Data^.AName), LastDelimiter('.', String(Data^.AName)) + 1, Length(String(Data^.AName)) - LastDelimiter('.', String(Data^.AName)))));
+ // Test for known internal functions
+ if (Ext = 'SFV') or (Ext = 'MD5') then miVerifyChecksumsClick(Self) else
+ if (Ext = 'CRC') or (Ext = '001') then miMergeFilesClick(Self) else
+ if not ((Engine is TLocalTreeEngine) and HandleVFSArchive(Ext, IncludeTrailingPathDelimiter(Engine.Path) + String(Data^.AName), String(Data^.AName), '/')) then
+ if (not ConfUseURI) or ((Engine is TVFSEngine) and TVFSEngine(Engine).ArchiveMode)
+ then RunFile(IncludeTrailingPathDelimiter(Engine.Path) + String(Data^.AName), Engine, -1)
+ else RunFile(ExcludeTrailingPathDelimiter(Engine.GetPrefix) + IncludeTrailingPathDelimiter(Engine.Path) + String(Data^.AName), Engine, -1);
+ end;
+end;
+
+procedure TFMain.ChangingDir(LeftPanel: boolean; NewPath: string; HiliString1: string = ''; HiliString2: string = ''; const PreserveSelection: boolean = False; const AutoFallback: boolean = False; Plugin: TVFSPlugin = nil);
+var ListView: TGTKListView;
+ Engine: TPanelEngine;
+ s, ss: string;
+ i, Sel, Err: integer;
+ b, bb: boolean;
+ tt: TDateTime;
+ DataList, DirList: TList;
+ SelectedFiles: TStringList;
+ ANotebook: TEphyNotebook;
+ ATabList: TStringList;
+ TabEngines: TList;
+ OpenDirThread: TOpenDirThread;
+
+ function LookupItem(const AName: string; const CaseSensitive: boolean): boolean;
+ var i: integer;
+ begin
+ Result := False;
+ for i := 0 to DataList.Count - 1 do
+ if (CaseSensitive and (ANSICompareStr(string(PDataItem(DataList[i])^.AName), AName) = 0)) or
+ ((not CaseSensitive) and (ANSICompareText(string(PDataItem(DataList[i])^.AName), AName) = 0)) then
+ begin
+ Sel := i;
+ Result := True;
+ Break;
+ end;
+ end;
+
+ procedure DoThread;
+ begin
+ try
+ OpenDirThread.AEngine := Engine;
+ OpenDirThread.APath := NewPath;
+ OpenDirThread.ASelItem := '';
+ OpenDirThread.AAutoFallBack := AutoFallback;
+ OpenDirThread.ADirList := DirList;
+ if Plugin <> nil then begin
+ DebugMsg(['Plugin <> nil']);
+ OpenDirThread.APlugin := Plugin;
+ OpenDirThread.AFullPath := HiliString1;
+ OpenDirThread.AHighlightItem := HiliString2;
+ end;
+ DebugMsg(['(II) TFMain.ChangingDir: begin thread']);
+ OpenDirThread.Resume;
+ tt := Now;
+ b := False;
+ FRemoteWait := nil;
+ repeat
+ Sleep(ConstInternalProgressTimer);
+// DebugMsg([' (II) TFMain.ChangingDir: sleep.']);
+ Application.ProcessMessages;
+ if not b and (MilliSecondsBetween(tt, Now) >= ConstRemoteWaitDialogDelay) then begin
+ FRemoteWait := TFRemoteWait.Create(Application);
+ FRemoteWait.ParentForm := FMain;
+ FRemoteWait.ShowModal;
+ b := True;
+ end;
+ if Assigned(FRemoteWait) then
+ if FRemoteWait.Cancelled then OpenDirThread.CancelIt := True;
+ until OpenDirThread.Finished;
+ if FRemoteWait <> nil then FRemoteWait.Free;
+ DebugMsg(['(II) TFMain.ChangingDir: end thread, running time = ', OpenDirThread.RunningTime, 'ms']);
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TFMain.ChangingDir:DoThread (', E.ClassName, '): ', E.Message]);
+ end;
+ end;
+
+begin
+ DebugMsg(['*** Begin changing dir to ', NewPath]);
+ if LeftPanel then begin
+ ListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ ANotebook := LeftPanelNotebook;
+ ATabList := LeftPanelTabs;
+ TabEngines := LeftTabEngines;
+ end else begin
+ ListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ ANotebook := RightPanelNotebook;
+ ATabList := RightPanelTabs;
+ TabEngines := RightTabEngines;
+ end;
+ try
+ if (NewPath = '..') and (Engine.ParentEngine <> nil) and (Engine.Path = '/') then begin
+ CloseVFS(LeftPanel, False);
+ Exit;
+ end;
+
+ InternalLock;
+ FileListTipsDisable;
+ SelectedFiles := nil;
+ if PreserveSelection then begin
+ SelectedFiles := TStringList.Create;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ if PDataItem(DataList[i])^.Selected and (not PDataItem(DataList[i])^.UpDir)
+ then SelectedFiles.Add(PDataItem(DataList[i])^.AName);
+ end;
+ Editing := False;
+ DeactivateQuickFind(LeftPanel);
+ DeactivateQuickFind(not LeftPanel);
+ DirList := TList.Create;
+
+ // Threading...
+ OpenDirThread := TOpenDirThread.Create;
+ DebugMsg(['TFMain.ChangingDir: Creating thread...']);
+ DoThread;
+
+ bb := OpenDirThread.VFSOpenResult = 0;
+ if OpenDirThread.VFSOpenResult <> 0 then begin
+ DebugMsg(['(II) TFMain.ChangingDir: OpenDirThread.VFSOpenResult <> 0']);
+ if OpenDirThread.VFSOpenResult = cVFS_BadPassword then begin
+ // Handle password
+ if not HandleSetPassword(OpenDirThread.xEngine) then Exit;
+ ss := OpenDirThread.xEngine.Password;
+ if Assigned(OpenDirThread.xEngine) then OpenDirThread.xEngine.Free;
+ DebugMsg(['TFMain.ChangingDir: Freeing thread...']);
+ OpenDirThread.Free;
+ OpenDirThread := TOpenDirThread.Create;
+ DebugMsg(['TFMain.ChangingDir: Creating thread...']);
+ OpenDirThread.Password := ss;
+ DoThread;
+ bb := OpenDirThread.VFSOpenResult = 0;
+ end;
+ end;
+ if Plugin <> nil then begin
+ HiliString1 := '';
+ HiliString2 := '';
+ end;
+ if not bb then begin
+ Application.MessageBox(LANGCouldntOpenURIArchive, [mbOK], mbError, mbOK, mbOK);
+ DebugMsg(['TFMain.ChangingDir: Freeing thread...']);
+ OpenDirThread.Free;
+ end else
+ if OpenDirThread.ChDirResult <> 0 then begin
+ if OpenDirThread.ChDirResult = 1 then Application.MessageBox(Format(LANGErrorGettingListingForSPanelNoPath, [LANGPanelStrings[LeftPanel], 'Exception']), [mbOK], mbError, mbNone, mbOK)
+ else Application.MessageBox(Format(LANGErrorGettingListingForSPanel, [LANGPanelStrings[LeftPanel], ANSIToUTF8(GetErrorString(OpenDirThread.ChDirResult)), ANSIToUTF8(NewPath)]), [mbOK], mbError, mbNone, mbOK);
+ DebugMsg(['TFMain.ChangingDir: Freeing thread...']);
+ OpenDirThread.Free;
+ end else begin
+ if OpenDirThread.ListingResult <> 0 then begin
+ Application.MessageBox(Format(LANGErrorGettingListingForSPanel, [LANGPanelStrings[LeftPanel], ANSIToUTF8(GetErrorString(OpenDirThread.ListingResult)), Engine.Path]), [mbOK], mbError, mbNone, mbOK);
+ Exit;
+ end;
+ s := OpenDirThread.ASelItem;
+ Engine := OpenDirThread.AEngine; // set current Engine from the thread (might have been modified due to VFS)
+ if LeftPanel then LeftPanelEngine := Engine
+ else RightPanelEngine := Engine;
+ DebugMsg(['TFMain.ChangingDir: Freeing thread...']);
+ OpenDirThread.Free;
+
+ FillPanel(DirList, ListView, Engine, LeftPanel); // This is time consuming
+ DirList.Free;
+ if DataList.Count > 0 then begin
+ if PreserveSelection and (SelectedFiles.Count > 0) and (DataList.Count > 0) then
+ for i := 0 to DataList.Count - 1 do
+ if (not PDataItem(DataList[i])^.UpDir) and (SelectedFiles.IndexOf(PDataItem(DataList[i])^.AName) >= 0)
+ then PDataItem(DataList[i])^.Selected := True;
+ Sel := 0;
+ b := (NewPath = '..') and (Length(Trim(s)) > 0) and LookupItem(s, True);
+ if not b then b := (HiliString1 <> '') and LookupItem(HiliString1, True);
+ if (not b) and (HiliString1 <> '') then LookupItem(HiliString1, False);
+ if (not b) and (HiliString2 <> '') then LookupItem(HiliString2, True);
+ if (not b) and (HiliString2 <> '') then LookupItem(HiliString2, False);
+ if (Engine.Path = '/') and (NewPath = '/') then Sel := ListView.ConvertFromSorted(0);
+ ListView.Items[Sel].Selected := True;
+// Application.ProcessMessages;
+ ListView.Items[Sel].SetCursor(0, False, not Application.GTKVersion_2_2_0_Up, 0.5, 0);
+// Application.ProcessMessages;
+ end;
+ UpdatePanelInfo;
+ UpdatePanelInfoDown(LeftPanel);
+ UpdatePanelInfoDown(not LeftPanel);
+ if ANotebook.Visible then begin
+ ATabList[ANotebook.PageIndex] := Engine.Path;
+ TabEngines[ANotebook.PageIndex] := Engine;
+ s := ExtractFileName(ExcludeTrailingPathDelimiter(Engine.Path));
+ if s = '' then s := '/';
+ SetTabLabel(ANotebook, ANotebook.PageIndex, ANSIToUTF8(s), ANSIToUTF8(Engine.Path));
+ end;
+ end; // of Chdir, Listing, ...
+ Engine.ExplicitChDir('/');
+ Application.ProcessMessages;
+ InternalUnLock;
+ FileListTipsEnable;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TFMain.ChangingDir (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+procedure TFMain.DoRefresh(LeftPanel, StaySame, AutoFallback: boolean);
+var ListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+ s1, s2: string;
+begin
+ if LeftPanel then begin
+ ListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ ListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+ s1 := ''; s2 := '';
+ FindNextSelected(ListView, DataList, s1, s2);
+ ChangingDir(LeftPanel, Engine.Path, s1, s2, StaySame, AutoFallback);
+end;
+
+procedure TFMain.UpdateCaption;
+var LeftPanel: boolean;
+ s: string;
+begin
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ if LeftPanelEngine.GetPrefix <> '' then s := ANSIToUTF8(Format(ConstFullPathFormatStr, [LeftPanelEngine.GetPrefix, LeftPanelEngine.Path]))
+ else s := ANSIToUTF8(LeftPanelEngine.Path);
+ end else
+ if RightPanelEngine.GetPrefix <> '' then s := ANSIToUTF8(Format(ConstFullPathFormatStr, [RightPanelEngine.GetPrefix, RightPanelEngine.Path]))
+ else s := ANSIToUTF8(RightPanelEngine.Path);
+ Caption := Format('Tux Commander [%s]', [s]);
+end;
+
+procedure TFMain.UpdatePanelInfo;
+var FSFree, FSSize: Int64;
+ FSName, s: string;
+ Time1, Time2: TDateTime;
+begin
+ UpdateCaption;
+ Time1 := Now;
+ if LeftPanelEngine.GetPrefix <> ''
+ then LeftPathLabel.Caption := ANSIToUTF8(Format(ConstFullPathFormatStr, [LeftPanelEngine.GetPrefix, LeftPanelEngine.Path]))
+ else LeftPathLabel.Caption := ANSIToUTF8(LeftPanelEngine.Path);
+ if RightPanelEngine.GetPrefix <> ''
+ then RightPathLabel.Caption := ANSIToUTF8(Format(ConstFullPathFormatStr, [RightPanelEngine.GetPrefix, RightPanelEngine.Path]))
+ else RightPathLabel.Caption := ANSIToUTF8(RightPanelEngine.Path);
+ LeftPathLabel.UseMarkup := True;
+ RightPathLabel.UseMarkup := True;
+ if LeftLastFocused then s := LeftPathLabel.Caption
+ else s := RightPathLabel.Caption;
+ CommandLineLabel.Caption := Format('%s@%s:%s>', [GetUserName, GetHostName, s]);
+ LeftPanelEngine.GetFileSystemInfo(LeftPanelEngine.Path, FSSize, FSFree, FSName);
+ if FSName <> ''
+ then LeftDiskInfoLabel.Caption := Format(LANGDiskStatVolNameFmt, [FSName,
+ ANSIToUTF8(FormatSize(FSFree, 1024)),
+ ANSIToUTF8(FormatSize(FSSize, 1024))])
+ else LeftDiskInfoLabel.Caption := Format(LANGDiskStatFmt,
+ [ANSIToUTF8(FormatSize(FSFree, 1024)),
+ ANSIToUTF8(FormatSize(FSSize, 1024))]);
+ RightPanelEngine.GetFileSystemInfo(RightPanelEngine.Path, FSSize, FSFree, FSName);
+ if FSName <> ''
+ then RightDiskInfoLabel.Caption := Format(LANGDiskStatVolNameFmt, [FSName,
+ ANSIToUTF8(FormatSize(FSFree, 1024)),
+ ANSIToUTF8(FormatSize(FSSize, 1024))])
+ else RightDiskInfoLabel.Caption := Format(LANGDiskStatFmt,
+ [ANSIToUTF8(FormatSize(FSFree, 1024)),
+ ANSIToUTF8(FormatSize(FSSize, 1024))]);
+ LeftDiskInfoLabel.UseMarkup := True;
+ RightDiskInfoLabel.UseMarkup := True;
+
+ // Update the visibility of VFS buttons
+ LeftDisconnectButton.Visible := (LeftPanelEngine is TVFSEngine) and (not TVFSEngine(LeftPanelEngine).ArchiveMode);
+ LeftLeaveArchiveButton.Visible := (LeftPanelEngine is TVFSEngine) and TVFSEngine(LeftPanelEngine).ArchiveMode;
+ RightDisconnectButton.Visible := (RightPanelEngine is TVFSEngine) and (not TVFSEngine(RightPanelEngine).ArchiveMode);
+ RightLeaveArchiveButton.Visible := (RightPanelEngine is TVFSEngine) and TVFSEngine(RightPanelEngine).ArchiveMode;
+ LeftPasswordButton.Visible := (LeftPanelEngine is TVFSEngine) and TVFSEngine(LeftPanelEngine).GetPasswordRequired;
+ RightPasswordButton.Visible := (RightPanelEngine is TVFSEngine) and TVFSEngine(RightPanelEngine).GetPasswordRequired;
+ miDisconnect.Enabled := (LeftLastFocused and (LeftPanelEngine is TVFSEngine) and (not TVFSEngine(LeftPanelEngine).ArchiveMode)) or
+ ((not LeftLastFocused) and (RightPanelEngine is TVFSEngine) and (not TVFSEngine(RightPanelEngine).ArchiveMode));
+ Time2 := Now;
+ DebugMsg(['UpdatePanelInfo: ', SecondOf(Time2 - Time1), ':', MillisecondOf(Time2 - Time1)]);
+end;
+
+procedure TFMain.UpdatePanelInfoDown(LeftPanel: boolean);
+var Size, TotalSize: Int64;
+ NumSel, TotalFiles: longint;
+ i: integer;
+ Data: PDataItem;
+ s: string;
+ DataList: TList;
+begin
+ if LeftPanel then DataList := LeftPanelData
+ else DataList := RightPanelData;
+ Size := 0;
+ TotalSize := 0;
+ NumSel := 0;
+ TotalFiles := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do begin
+ Data := DataList[i];
+ if (not Data^.UpDir) and ((not Data^.IsDir) or (Data^.IsDir and (Data^.Size > -1))) then begin
+ Inc(TotalSize, Data^.Size);
+ Inc(TotalFiles);
+ if Data^.Selected then begin
+ Inc(NumSel);
+ Inc(Size, Data^.Size);
+ end;
+ end;
+ end;
+ s := Format(LANGStatusLineFmt, [ANSIToUTF8(FormatSize(Size, 1024)),
+ ANSIToUTF8(FormatSize(TotalSize, 1024)), NumSel, TotalFiles]);
+ if LeftPanel then LeftStatusLine.Caption := s
+ else RightStatusLine.Caption := s;
+end;
+
+procedure TFMain.PathButtonClick(Sender: TObject);
+var NewPath: string;
+ LeftPanel: boolean;
+begin
+ LeftPanel := (Sender = LeftUpButton) or (Sender = LeftHomeButton) or (Sender = LeftRootButton);
+ if (Sender = LeftUpButton) or (Sender = RightUpButton) then NewPath := '..'
+ else if (Sender = LeftRootButton) or (Sender = RightRootButton) then NewPath := '/'
+ else if (Sender = LeftHomeButton) or (Sender = RightHomeButton) then NewPath := GetHomePath
+ else Exit;
+
+ // Close VFS connections
+ if ((Sender = LeftRootButton) or (Sender = LeftHomeButton)) and (not (LeftPanelEngine is TLocalTreeEngine)) then
+ while (LeftPanelEngine is TVFSEngine) do CloseVFS(LeftPanel, True);
+ if ((Sender = RightRootButton) or (Sender = RightHomeButton)) and (not (RightPanelEngine is TLocalTreeEngine)) then
+ while (RightPanelEngine is TVFSEngine) do CloseVFS(LeftPanel, True);
+
+ ChangingDir(LeftPanel, NewPath);
+ if LeftPanel then LeftListView.SetFocus
+ else RightListView.SetFocus;
+end;
+
+procedure TFMain.miRefreshClick(Sender: TObject);
+begin
+ DoRefresh(LeftListView.Focused, True, True);
+end;
+
+function TFMain.CompareFunc(Sender: TObject; var model: PGtkTreeModel; var a, b: PGtkTreeIter): integer;
+var Data1, Data2: PDataItem;
+ Path: PGtkTreePath;
+ DataList: TList;
+begin
+ Result := 0;
+ if not Application.GTKVersion_2_0_5_Up then begin
+ gtk_tree_model_get(model, a, 0, @Data1, -1);
+ gtk_tree_model_get(model, b, 0, @Data2, -1);
+ end else begin
+ if Sender = LeftListView then DataList := LeftPanelData
+ else DataList := RightPanelData;
+ Path := gtk_tree_model_get_path(model, a);
+ if not Assigned(Path) then Exit;
+ Data1 := DataList[gtk_tree_path_get_indices(Path)^];
+ gtk_tree_path_free(Path);
+ Path := gtk_tree_model_get_path(model, b);
+ if not Assigned(Path) then Exit;
+ Data2 := DataList[gtk_tree_path_get_indices(Path)^];
+ gtk_tree_path_free(Path);
+ end;
+ Result := LVCompareItems(Data1, Data2, (Sender as TGTKView).SortOrder = soAscending, FMain.ColumnSortIDs[(Sender as TGTKView).SortColumnID + 1]);
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.DoSelect(SelectType: integer);
+var Filter, s: string;
+ LeftPanel, ExpandSel, b, Found: boolean;
+ ListView: TGTKListView;
+ Engine: TPanelEngine;
+ i, j: integer;
+ Item: TGTKListItem;
+ Data: PDataItem;
+ DataList: TList;
+ Wilds: array of string;
+begin
+ try
+ InternalLock;
+ try
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else Exit;
+ if LeftPanel then begin
+ ListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ ListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+ DeactivateQuickFind(LeftPanel);
+ ExpandSel := False;
+ if SelectType in [1, 2] then try
+ FSelect := TFSelect.Create(Self);
+ case SelectType of
+ 1 : FSelect.Caption := LANGExpandSelection;
+ 2 : FSelect.Caption := LANGShrinkSelection;
+ end;
+{ FSelect.TitleLabel.Caption := Format('<span size="large" weight="ultrabold">%s</span>', [FSelect.Caption]);
+ FSelect.TitleLabel.UseMarkup := True; }
+ ExpandSel := SelectType = 1;
+ FSelect.ComboBox.Entry.Text := LastUsedFilter;
+ FSelect.ComboBox.Entry.SelectAll;
+ if FSelect.Run = mbOK
+ then begin
+ Filter := FSelect.ComboBox.Entry.Text;
+ LastUsedFilter := Filter;
+ if FSelect.ComboBox.Entry.Text <> '*.*' then
+ SaveItemToHistory(FSelect.ComboBox.Entry.Text, SelectHistory);
+ end else Exit;
+ finally
+ FSelect.Free;
+ end;
+
+ case SelectType of
+ 1, 2 : if ListView.Items.Count > 1 then begin
+ SetLength(Wilds, 0);
+ while LastDelimiter(ConfSelItemsDelim, Filter) > 0 do begin
+ i := LastDelimiter(ConfSelItemsDelim, Filter);
+ if i < Length(Filter) then begin
+ s := Copy(Filter, i + 1, Length(Filter) - i);
+ Delete(Filter, i, Length(Filter) - i + 1);
+ SetLength(Wilds, Length(Wilds) + 1);
+ Wilds[Length(Wilds) - 1] := s;
+ end;
+ end;
+ if Length(Filter) > 0 then begin
+ SetLength(Wilds, Length(Wilds) + 1);
+ Wilds[Length(Wilds) - 1] := Filter;
+ end;
+ Found := False;
+ for i := 0 to DataList.Count - 1 do begin
+ Data := DataList[i];
+ if Assigned(Data) and (not Data^.UpDir) and (ConfSelectAllDirs or (not Data^.IsDir)) {and (Data^.Selected <> ExpandSel)} then begin
+ b := False;
+ for j := 0 to Length(Wilds) - 1 do
+ b := b or IsWild(String(Data^.AName), Wilds[j], True);
+ if b then begin
+ Data^.Selected := ExpandSel;
+ Found := True;
+ end;
+ end;
+ end;
+ SetLength(Wilds, 0);
+ if not Found then Application.MessageBox(LANGNoMatchesFound, [mbOK], mbWarning, mbNone, mbOK);
+ end;
+ 3, 4 : if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ if (not PDataItem(DataList[i])^.UpDir) and (ConfSelectAllDirs or (not PDataItem(DataList[i])^.IsDir)) then
+ PDataItem(DataList[i])^.Selected := not PDataItem(DataList[i])^.Selected;
+ 5, 8 : begin
+ Item := ListView.Selected;
+ if Assigned(Item) and Assigned(Item.Data) then begin
+ Data := PDataItem(Item.Data);
+ if (Engine.Path = '/') or (Item.Index > 0) then Data^.Selected := not Data^.Selected;
+ if (ListView.ConvertToSorted(Item.Index) < ListView.Items.Count - 1) and
+ (((SelectType = 5) and ConfInsMoveDown) or ((SelectType = 8) and ConfSpaceMovesDown)) then begin
+ ListView.Selected := ListView.Items[ListView.ConvertFromSorted(ListView.ConvertToSorted(Item.Index) + 1)];
+ ListView.Selected.SetCursor(0, False, False, 0, 0);
+ end else Item.RedrawRow; // Move to the next item will invalidate it automatically
+ end;
+ end;
+ 6, 7: if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ if (not PDataItem(DataList[i])^.UpDir) and (ConfSelectAllDirs or (not PDataItem(DataList[i])^.IsDir)) then
+ PDataItem(DataList[i])^.Selected := SelectType = 6;
+ end;
+ if SelectType in [1..4, 6..7] then ListView.Invalidate; // Make changes appear
+ UpdatePanelInfoDown(LeftPanel);
+ Application.ProcessMessages;
+ except end;
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+procedure TFMain.ProcessMarkKey(KeyType, Key: integer);
+var LeftPanel: boolean;
+ ListView: TGTKListView;
+ Pos: integer;
+begin
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then ListView := LeftListView
+ else ListView := RightListView;
+ if Editing and Assigned(ListView.Columns[0].FColumn^.editable_widget) then begin
+ Pos := gtk_editable_get_position(PGtkEditable(ListView.Columns[0].FColumn^.editable_widget));
+ gtk_editable_insert_text(PGtkEditable(ListView.Columns[0].FColumn^.editable_widget), PChar(UTF8Encode(WideChar(KeyValToUnicode(Key)))), 1, @Pos);
+ gtk_editable_set_position(PGtkEditable(ListView.Columns[0].FColumn^.editable_widget), Pos);
+ end;
+ if CommandLineCombo.Entry.Focused then ActivateCommandLine(Key, True) else
+ if QuickFind then QuickFindSendKey(LeftPanel, Key)
+ else DoSelect(KeyType);
+end;
+
+procedure TFMain.mnuMarkClick(Sender: TObject);
+begin
+ if Sender = miSelectGroup then ProcessMarkKey(1, GDK_KP_PLUS) else
+ if Sender = miUnselectGroup then ProcessMarkKey(2, GDK_KP_MINUS) else
+ if Sender = miSelectAll then DoSelect(6) else
+ if Sender = miUnselectAll then DoSelect(7) else
+ if Sender = miInvertSelection then ProcessMarkKey(4, GDK_KP_ASTERISK);
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.ListViewCellDataFunc(Sender: TObject; tree_view: PGtkTreeView; tree_column : PGtkTreeViewColumn; cell : PGtkCellRenderer; tree_model : PGtkTreeModel; iter : PGtkTreeIter);
+var s: PChar;
+ Sel, ImageCol: boolean;
+ Data: PDataItem;
+ i, ColumnID, ColumnIdx: integer;
+ DataList: TList;
+ TreePath: PGtkTreePath;
+ AFGColor, ABGColor: PGdkColor;
+{ Rect, VisibleRect: TGdkRectangle; }
+begin
+ AFGColor := nil;
+ ABGColor := nil;
+ if Application.GTKVersion_2_0_5_Up then ColumnIdx := gtk_tree_view_column_get_sort_column_id(tree_column) else
+ begin
+ ColumnIdx := 0;
+ for i := 0 to (Sender as TGTKListView).Columns.Count - 1 do
+ if (cell = (Sender as TGTKListView).Columns[i].FRenderer) or (cell = (Sender as TGTKListView).Columns[i].FPixbufRenderer) then begin
+ ColumnIdx := i;
+ Break;
+ end;
+ end;
+ ColumnID := ColumnSortIDs[ColumnIdx + 1] - 1;
+ ImageCol := False;
+ if ColumnIdx = 0 then ImageCol := GTK_IS_CELL_RENDERER_PIXBUF(cell);
+ Data := nil;
+ if not Application.GTKVersion_2_0_5_Up then gtk_tree_model_get(tree_model, iter, 0, @Data, -1)
+ else begin
+ if Sender = LeftListView then DataList := LeftPanelData
+ else DataList := RightPanelData;
+ TreePath := gtk_tree_model_get_path(tree_model, iter);
+ if not Assigned(TreePath) then Exit;
+ (Sender as TGTKListView).ConvertPathToChild(TreePath);
+ Data := DataList[gtk_tree_path_get_indices(TreePath)^];
+ gtk_tree_path_free(TreePath);
+ end;
+(* gtk_tree_view_get_cell_area(tree_view, TreePath, nil, @Rect);
+ gtk_tree_view_get_visible_rect(tree_view, @VisibleRect);
+ if (Rect.height = 0) or (Rect.height <> ConfRowHeight) or (Rect.y = 0) or (Rect.y > VisibleRect.y + VisibleRect.height) then Exit; *)
+
+// DebugMsg(['Rendering text ', Data^.ColumnData[ColumnID]]);
+
+ if not Assigned(Data) then Exit;
+ Sel := gtk_tree_selection_iter_is_selected((Sender as TGTKView).FSelection, iter);
+ with Data^ do begin
+ // ################ Prepare colors
+ if Selected then AFGColor := SelectedItemGDKColor else begin
+ if Sel then begin
+ if (Sender as TGTKView).Focused
+ then AFGColor := ActiveItemGDKColor
+ else AFGColor := InactiveItemGDKColor;
+ end else AFGColor := ItemColor;
+ end;
+ if not Sel then ABGColor := NormalItemGDKBackground else
+ if (Sender as TGTKView).Focused then ABGColor := ActiveItemGDKBackground
+ else ABGColor := InactiveItemGDKBackground;
+
+
+
+ // ################ Setting the properties
+ if not ImageCol then begin
+ if Editing and (InplaceEditItem.Data = Data) and (ColumnID < 3) and ((ColumnID = 0) or (ColumnID = 1) or Assigned(tree_column^.editable_widget))
+ then begin
+ if (ColumnID = 0) or (ColumnID = 1) then s := PChar(ANSIToUTF8(string(AName))) else s := nil;
+ g_object_set(cell, 'text', s, 'foreground-gdk', AFGColor, nil);
+ if Application.GTKVersion_2_2_0_Up or (not ConfUseFileTypeIcons) then
+ g_object_set(cell, 'background-gdk', ABGColor, nil);
+ end
+ else begin // not editing
+ if ConfDirsInBold then begin
+ if IsDir or UpDir then g_object_set(cell, 'markup', PChar(Format('<span weight="bold">%s</span>', [QuoteMarkupStr(ColumnData[ColumnID])])), 'foreground-gdk', AFGColor, nil)
+ else g_object_set(cell, 'markup', PChar(QuoteMarkupStr(ColumnData[ColumnID])), 'foreground-gdk', AFGColor, nil);
+ end else g_object_set(cell, 'text', ColumnData[ColumnID], 'foreground-gdk', AFGColor, nil);
+ if Application.GTKVersion_2_2_0_Up or (not ConfUseFileTypeIcons) then
+ g_object_set(cell, 'background-gdk', ABGColor, nil); // Older versions have bug in color filling
+ end;
+ end else // this is the image column
+ if ConfUseFileTypeIcons then begin // Assign icons
+ if Application.GTKVersion_2_2_0_Up then
+ g_object_set(cell, 'cell-background-gdk', ABGColor, nil); // Older versions don't have this property
+ if Sel and (not (Sender as TGTKView).Focused) and Application.GTKVersion_2_2_0_Up then begin
+ if InactiveItemsTimer.Enabled then InactiveItemsTimer.Enabled := False;
+ if Sender = LeftListView then RedrawLeftInactive := True
+ else RedrawRightInactive := True;
+ InactiveItemsTimer.Enabled := not Application.GTKVersion_2_6_0_Up;
+ end;
+ if Icon <> nil then g_object_set(cell, 'pixbuf', Icon, nil);
+ end;
+ end;
+end;
+
+procedure TFMain.F7ButtonClick(Sender: TObject);
+var LeftPanel: boolean;
+ ListView: TGTKListView;
+ Engine: TPanelEngine;
+ NewDir: string;
+begin
+ try
+ InternalLock;
+ try
+ if Sender = F7Button then LeftPanel := LeftLastFocused else
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else Exit;
+ if LeftPanel then ListView := LeftListView
+ else ListView := RightListView;
+ if LeftPanel then Engine := LeftPanelEngine
+ else Engine := RightPanelEngine;
+
+ try
+ FNewDir := TFNewDir.Create(Self);
+ if FNewDir.Run = mbOK
+ then NewDir := Utf8ToAnsi(FNewDir.Entry.Text)
+ else Exit;
+ finally
+ FNewDir.Free;
+ end;
+
+ if NewDir = '' then Exit;
+ if not MakeDirectory(ListView, Engine, LeftPanel, NewDir) then Exit;
+ ChangingDir(LeftPanel, Engine.Path, NewDir);
+ DoRefresh(not LeftPanel, True, True);
+ except end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.DoGetDirSize(AllItems: boolean);
+var LeftPanel: boolean;
+ ListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+begin
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else Exit;
+ if LeftPanel then begin
+ ListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ ListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+
+ RunningEscSensitive := 1;
+ GetDirSize(ListView, Engine, DataList, AllItems);
+ FMainEscPressed := False;
+ RunningEscSensitive := 0;
+end;
+
+procedure TFMain.DoDelete(LeftPanel: boolean; ListView: TGTKListView; Engine: TPanelEngine; DataList: TList);
+var i, j : integer;
+ SelCount: longint;
+ s, s2, smsg, NextItem1, NextItem2: string;
+ Data: PDataItem;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+begin
+ try
+ InternalLock;
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then Inc(SelCount);
+
+ if (SelCount = 0) and ((not Assigned(ListView.Selected)) or PDataItem(ListView.Selected.Data)^.UpDir) then begin
+// WriteLn(integer(mbApply), ', ', integer(Application.MessageBox(LANGNoFilesSelected, [mbOK], mbInfo, mbNone, mbApply)));
+ Application.MessageBox(LANGNoFilesSelected, [mbOK], mbInfo, mbNone, mbOK);
+ Exit;
+ end;
+
+ Data := nil;
+ if Assigned(ListView.Selected) then Data := ListView.Selected.Data;
+ if SelCount > 0 then begin
+ j := 0;
+ s2 := '';
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then begin
+ s2 := s2 + #10 + AName;
+ Inc(j);
+ if j = 5 then Break;
+ end;
+ if SelCount > j then s2 := s2 + #10 + '...';
+ s := Format(LANGSelectedFilesDirectories, [SelCount]);
+ smsg := Format(LANGDoYouReallyWantToDeleteTheSS, [s, s2]);
+ end else begin
+ if Assigned(Data) then
+ if Data^.IsDir then s := Format(LANGDirectoryS, [ANSIToUTF8(string(Data^.AName))])
+ else s := Format(LANGFileS, [ANSIToUTF8(string(Data^.AName))]);
+ smsg := Format(LANGDoYouReallyWantToDeleteTheS, [s]);
+ end;
+ if Application.MessageBox(QuotePercentStr(smsg), [mbYes, mbNo], mbQuestion, mbNone, mbNo) <> mbYes then Exit;
+
+ FindNextSelected(ListView, DataList, NextItem1, NextItem2);
+ AWorkingThread := TWorkerThread.Create;
+ DebugMsg(['TFMain.DoDelete: Creating thread...']);
+ AFProgress := TFProgress.Create(Self);
+ try
+ AFProgress.SetNumBars(False);
+// AFProgress.ProgressBar.Max := 100;
+ AFProgress.ProgressBar.Value := 0;
+ AWorkingThread.ProgressForm := AFProgress;
+ if Assigned(ListView.Selected) then AWorkingThread.SelectedItem := ListView.Selected.Data;
+ AWorkingThread.Engine := Engine;
+ AWorkingThread.LeftPanel := LeftPanel;
+ AWorkingThread.DataList := DataList;
+ AWorkingThread.WorkerProcedure := DeleteFilesWorker;
+ AWorkingThread.Resume;
+
+// AFProgress.Run;
+
+ AFProgress.ParentForm := FMain;
+ AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+
+
+{ FProgress.ShowModal;
+ Application.ProcessMessages;
+ repeat
+ Sleep(100);
+ Application.ProcessMessages;
+// FProgress.Run;
+ until False; }
+
+{ FProgress.ShowModal;
+ DeleteFiles(FProgress, ListView, Engine, LeftPanel, DataList); }
+
+ finally
+ AFProgress.Free;
+ AWorkingThread.Free;
+ DebugMsg(['TFMain.DoDelete: Freeing thread...']);
+ end;
+ ChangingDir(LeftPanel, Engine.Path, NextItem1, NextItem2);
+ DoRefresh(not LeftPanel, True, True);
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+procedure TFMain.F8ButtonClick(Sender: TObject);
+var LeftPanel: boolean;
+ ListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+begin
+ try
+ if (Sender = F8Button) or (Sender is TGTKMenuItem)
+ then LeftPanel := LeftLastFocused else
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else Exit;
+ if LeftPanel then begin
+ ListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ ListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+ DoDelete(LeftPanel, ListView, Engine, DataList);
+ except end;
+end;
+
+procedure TFMain.F5ButtonClick(Sender: TObject);
+var LeftPanel: boolean;
+ ListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+begin
+ try
+ if Sender = F5Button then LeftPanel := LeftLastFocused else
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else Exit;
+ if LeftPanel then begin
+ ListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ ListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+ DoCopyMove(LeftPanel, True, Sender = nil, ListView, Engine, DataList);
+ except end;
+end;
+
+procedure TFMain.F6ButtonClick(Sender: TObject);
+var LeftPanel: boolean;
+ ListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+begin
+ try
+ if (Sender = F6Button) or (Sender = F2Button) or (Sender is TGTKMenuItem)
+ then LeftPanel := LeftLastFocused else
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else Exit;
+ if LeftPanel then begin
+ ListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ ListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+ DoCopyMove(LeftPanel, False, (Sender = nil) or (Sender = F2Button) or (Sender is TGTKMenuItem), ListView, Engine, DataList);
+ except end;
+end;
+
+procedure TFMain.DoCopyMove(LeftPanel, CopyMode, ShiftPressed: boolean; ListView: TGTKListView; Engine: TPanelEngine; DataList: TList);
+var i: integer;
+ SelCount: longint;
+ NewPath, SelSingle, NextItem1, NextItem2: string;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+ CurrentEngine, OppositeEngine: TPanelEngine;
+ s: string;
+begin
+ try
+ InternalLock;
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then Inc(SelCount);
+
+ if (SelCount = 0) and ((not Assigned(ListView.Selected)) or PDataItem(ListView.Selected.Data)^.UpDir) then begin
+ Application.MessageBox(LANGNoFilesSelected, [mbOK], mbInfo, mbNone, mbOK);
+ Exit;
+ end;
+
+ SelSingle := '';
+ if SelCount = 0 then begin
+ SelCount := 1;
+ SelSingle := PDataItem(ListView.Selected.Data)^.AName;
+ end;
+
+ if LeftPanel then begin
+ CurrentEngine := LeftPanelEngine;
+ OppositeEngine := RightPanelEngine;
+ end else begin
+ CurrentEngine := RightPanelEngine;
+ OppositeEngine := LeftPanelEngine;
+ end;
+
+ try
+ FCopyMove := TFCopyMove.Create(Self);
+ if CopyMode then begin
+ FCopyMove.Caption := LANGCopyFiles;
+ FCopyMove.Label1.Caption := Format(LANGCopyDFileDirectoriesTo, [SelCount]);
+ end else begin
+ FCopyMove.Caption := LANGMoveRenameFiles;
+ FCopyMove.Label1.Caption := Format(LANGMoveRenameDFileDirectoriesTo, [SelCount]);
+ end;
+ if ShiftPressed then begin
+ if SelSingle <> '' then FCopyMove.Entry.Text := ANSIToUTF8(SelSingle)
+ else FCopyMove.Entry.Text := '*.*';
+ end else
+ if OppositeEngine is TLocalTreeEngine then FCopyMove.Entry.Text := ANSIToUTF8(OppositeEngine.Path)
+ else FCopyMove.Entry.Text := ANSIToUTF8(Format(ConstFullPathFormatStr, [OppositeEngine.GetPrefix, OppositeEngine.Path]));
+ FCopyMove.Entry.SelectAll;
+ if FCopyMove.Run <> mbOK then Exit;
+ NewPath := UTF8ToANSI(FCopyMove.Entry.Text);
+ finally
+ FCopyMove.Free;
+ end;
+
+ // Handle password in archives
+ if (CurrentEngine is TVFSEngine) and (CurrentEngine as TVFSEngine).GetPasswordRequired and (Length((CurrentEngine as TVFSEngine).Password) < 1) then
+ if not HandleSetPassword(CurrentEngine) then Exit;
+ if (OppositeEngine is TVFSEngine) and (OppositeEngine as TVFSEngine).GetPasswordRequired and (Length((OppositeEngine as TVFSEngine).Password) < 1) then
+ if not HandleSetPassword(OppositeEngine) then Exit;
+
+ FindNextSelected(ListView, DataList, NextItem1, NextItem2);
+ AWorkingThread := TWorkerThread.Create;
+ DebugMsg(['TFMain.DoCopyMove: Creating thread...']);
+ AFProgress := TFProgress.Create(Self);
+ try
+ if CopyMode then AFProgress.Label1.Caption := LANGCopySC
+ else AFProgress.Label1.Caption := LANGMoveRenameSC;
+ AFProgress.SetNumBars(True);
+ AFProgress.ProgressBar.Value := 0;
+ AWorkingThread.ProgressForm := AFProgress;
+ if Assigned(ListView.Selected) then AWorkingThread.SelectedItem := ListView.Selected.Data;
+ AWorkingThread.DestEngine := nil;
+ AWorkingThread.SrcEngine := Engine;
+
+ // Determine on which engine the entered path is
+ if Pos(ConstPathDelim, NewPath) = 0 then begin
+ if OppositeEngine is TLocalTreeEngine then AWorkingThread.DestEngine := OppositeEngine else
+ if CurrentEngine is TLocalTreeEngine then AWorkingThread.DestEngine := CurrentEngine
+ else begin
+ Application.MessageBox(LANGCannotDetermineDestinationEngine, [mbOK], mbError, mbOK, mbOK);
+ Exit;
+ end;
+ end else begin
+ s := Copy(NewPath, 1, Pos(ConstPathDelim, NewPath) - 1);
+ if s = OppositeEngine.GetPrefix then AWorkingThread.DestEngine := OppositeEngine else
+ if s = CurrentEngine.GetPrefix then AWorkingThread.DestEngine := CurrentEngine
+ else begin
+ Application.MessageBox(LANGCannotDetermineDestinationEngine, [mbOK], mbError, mbOK, mbOK);
+ Exit;
+ end;
+ end;
+ if AWorkingThread = nil then begin // Something went terribly wrong
+ Application.MessageBox(LANGCannotDetermineDestinationEngine, [mbOK], mbError, mbOK, mbOK);
+ Exit;
+ end;
+
+ // Strip the engine prefix
+ if Pos(ConstPathDelim, NewPath) > 0 then Delete(NewPath, 1, Pos(ConstPathDelim, NewPath));
+
+ AWorkingThread.LeftPanel := LeftPanel;
+ AWorkingThread.DataList := DataList;
+ AWorkingThread.WorkerProcedure := CopyFilesWorker;
+// AWorkingThread.WorkerProcedure := DummyThreadWorker;
+ AWorkingThread.ParamBool3 := CopyMode;
+ AWorkingThread.ParamBool4 := False;
+ AWorkingThread.ParamString1 := NewPath;
+ AWorkingThread.ParamDataItem1 := nil;
+
+ AFProgress.ParentForm := FMain;
+ AFProgress.ShowModal;
+ Application.ProcessMessages;
+
+ DebugMsg(['*** Copy: AWorkingThread.Resume']);
+// DebugMsg(['*** Copy: xg_thread_supported = ', xg_thread_supported()]);
+ AWorkingThread.Resume;
+// AWorkingThread.WorkerProcedure(AWorkingThread);
+ DebugMsg(['*** Copy: AWorkingThread.Resumed.']);
+ ProcessProgressThread(AWorkingThread, AFProgress);
+// DebugMsg(['***************************x1']);
+ AFProgress.Close;
+// Beep;
+ finally
+// DebugMsg(['** ddddddddddddddd ???']);
+ AFProgress.Free;
+ DebugMsg(['TFMain.DoCopyMove: Freeing thread...']);
+ AWorkingThread.Free;
+ end;
+ ChangingDir(LeftPanel, Engine.Path, NextItem1, NextItem2);
+ DoRefresh(not LeftPanel, True, False);
+ finally
+ DebugMsg(['** TFMain.DoCopyMove finished']);
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+procedure TFMain.ListViewDblClick(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+begin
+ DebugMsg(['DblClick']);
+ Accept := True; // This causes selecting the item if clicked is different than selected
+ if (Sender as TGTKListView).GetItemAtPos(X, Y) <> (Sender as TGTKListView).Selected then Exit;
+ Accept := False;
+ DebugMsg(['DblClick OK']);
+ if not (Sender as TGTKListView).Focused then (Sender as TGTKListView).SetFocus;
+ if Assigned((Sender as TGTKListView).Selected) and Assigned((Sender as TGTKListView).Selected.Data)
+ then ActivateItem((Sender as TGTKListView).Selected.Index, True);
+end;
+
+procedure TFMain.ListViewMouseDown(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+var Item: TGTKListItem;
+ Click: TDateTime;
+begin
+ try
+ InternalLock;
+// DebugMsg(['ListViewMouseDown, X = ', X, ', Y = ', Y]);
+ if Button = mbLeft then begin
+ Click := Now;
+ if LastClick + ConfDblClickDelay/MSecsPerDay > Click then begin
+ Accept := False;
+ InplaceEditTimer.Enabled := False;
+ LastClick := 0;
+ ListViewDblClick(Sender, Button, Shift, X, Y, Accept);
+ Exit;
+ end;
+ LastClick := Click;
+ DebugMsg(['Click, Focus = ', (Sender as TGTKControl).Focused]);
+ if not (Sender as TGTKListView).Focused then Exit; // (Sender as TGTKListView).SetFocus;
+ Item := (Sender as TGTKListView).GetItemAtPos(X, Y);
+ if (Item = (Sender as TGTKListView).Selected) and Assigned(Item) and Assigned((Sender as TGTKListView).Selected) and
+ Assigned(Item.Data) and (not PDataItem(Item.Data)^.UpDir) and (Sender as TGTKListView).Focused and (not ConfDisableMouseRename) then
+ begin
+ DebugMsg(['Quick-Rename']);
+ InplaceEditTimer.Interval := ConfQuickRenameDelay;
+ InplaceEditTimer.Enabled := True;
+ InplaceEditItem := Item;
+ end;
+ Accept := True;
+ end else
+ if Button = mbRight then begin
+ if not (Sender as TGTKListView).Focused then (Sender as TGTKListView).SetFocus;
+ Item := (Sender as TGTKListView).GetItemAtPos(X, Y);
+ if Assigned(Item) then begin
+ Item.Selected := True;
+ Item.SetCursor(0, False, not Application.GTKVersion_2_2_0_Up, 0.5, 0);
+ end;
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+procedure TFMain.InplaceEditTimerTimer(Sender: TObject);
+var LeftPanel: boolean;
+ ListView: TGTKListView;
+begin
+ InplaceEditTimer.Enabled := False;
+ try
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ ListView := LeftListView;
+ end else begin
+ ListView := RightListView;
+ end;
+ if ListView.Selected <> InplaceEditItem then Exit;
+ DoQuickRename(LeftPanel, ListView, False);
+ except end;
+end;
+
+procedure TFMain.DoQuickRename(LeftPanel: boolean; ListView: TGTKListView; const CalledFromKey: boolean);
+var i: integer;
+begin
+ if (not Assigned(ListView.Selected)) or (not Assigned(ListView.Selected.Data)) or
+ PDataItem(ListView.Selected.Data)^.UpDir or Editing then Exit;
+ Editing := True;
+ if CalledFromKey then InplaceEditItem := ListView.Selected;
+ for i := 1 to ConstNumPanelColumns do
+ if ColumnSortIDs[i] in [1, 2] then begin
+ ListView.Columns[i - 1].SetProperty('editable', 1);
+ ListView.StartEditing(i - 1);
+ Break;
+ end;
+end;
+
+procedure TFMain.ListViewEdited(Sender: TObject; Column: TGTKTreeViewColumn; Item: TGTKListItem; var NewText: string; var AllowChange: boolean; var DataColumn: integer);
+var AListView: TGTKListView;
+ DataList: TList;
+ Engine: TPanelEngine;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+ i: integer;
+ s1, s2: string;
+begin
+ try
+ InternalLock;
+ AListView := (((Sender as TGTKTreeViewColumn).Parent as TGTKTreeViewColumns).Parent as TGTKListView);
+ for i := 1 to ConstNumPanelColumns do
+ if ColumnSortIDs[i] in [1, 2] then begin
+ AListView.Columns[i - 1].SetProperty('editable', 0);
+ Break;
+ end;
+ if AListView = LeftListView then begin
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+ Editing := False;
+ if (AListView.Selected = InplaceEditItem) and (AListView.Selected.Data = InplaceEditItem.Data) and
+ (String(PDataItem(InplaceEditItem.Data)^.AName) <> NewText) then
+ begin
+ AWorkingThread := TWorkerThread.Create;
+ DebugMsg(['TFMain.ListViewEdited: Creating thread...']);
+ AFProgress := TFProgress.Create(Self);
+ try
+ AFProgress.SetNumBars(True);
+ AFProgress.ProgressBar.Value := 0;
+ AFProgress.Label1.Caption := LANGMoveRenameSC;
+ AWorkingThread.ProgressForm := AFProgress;
+ if Assigned(AListView.Selected) then AWorkingThread.SelectedItem := AListView.Selected.Data;
+ AWorkingThread.SrcEngine := Engine;
+ AWorkingThread.DestEngine := Engine;
+ AWorkingThread.LeftPanel := AListView = LeftListView;
+ AWorkingThread.DataList := DataList;
+ AWorkingThread.WorkerProcedure := CopyFilesWorker;
+ AWorkingThread.ParamBool3 := False;
+ AWorkingThread.ParamBool4 := True;
+ AWorkingThread.ParamString1 := UTF8ToANSI(NewText);
+ AWorkingThread.ParamDataItem1 := InplaceEditItem.Data;
+ AWorkingThread.Resume;
+// AWorkingThread.WorkerProcedure(AWorkingThread);
+ AFProgress.ParentForm := FMain;
+ AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+ finally
+ AFProgress.Free;
+ DebugMsg(['TFMain.ListViewEdited: Freeing thread...']);
+ AWorkingThread.Free;
+ end;
+ s1 := ''; s2 := '';
+ FindNextSelected(AListView, DataList, s1, s2);
+ ChangingDir(AListView = LeftListView, Engine.Path, {String(PDataItem(InplaceEditItem.Data)^.AName),} NewText, s2);
+ DoRefresh(AListView <> LeftListView, True, True);
+ end;
+ AListView.SetFocus;
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+procedure TFMain.ListViewSelectionChanged(Sender: TObject);
+var i: integer;
+// AListView: TGTKListView;
+begin
+ if Editing and ((Sender as TGTKListView).Selected <> InplaceEditItem) then begin
+ Editing := False;
+ for i := 1 to ConstNumPanelColumns do
+ if ColumnSortIDs[i] in [1, 2] then begin
+ (Sender as TGTKListView).Columns[i - 1].SetProperty('editable', 0);
+ Break;
+ end;
+ end;
+ if QuickFind then DeactivateQuickFind(Sender = LeftListView);
+ if Sender = LeftListView then begin
+ if LeftPanelNotebook.Visible and (LeftPathsHighlight.Count > LeftPanelNotebook.PageIndex) and (LeftPanelNotebook.PageIndex >= 0) and
+ Assigned(LeftListView.Selected) and Assigned(LeftListView.Selected.Data)
+ then LeftPathsHighlight[LeftPanelNotebook.PageIndex] := PDataItem(LeftListView.Selected.Data)^.AName;
+ end else
+ if RightPanelNotebook.Visible and (RightPathsHighlight.Count > RightPanelNotebook.PageIndex) and (RightPanelNotebook.PageIndex >= 0) and
+ Assigned(RightListView.Selected) and Assigned(RightListView.Selected.Data)
+ then RightPathsHighlight[RightPanelNotebook.PageIndex] := PDataItem(RightListView.Selected.Data)^.AName;
+{ if Application.GTKVersion_2_6_0_Up then begin
+ AListView := Sender as TGTKListView;
+ if Assigned(AListView) and Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and Assigned(PDataItem(AListView.Selected.Data)^.ItemColor)
+ then gtk_widget_modify_text(AListView.FWidget, GTK_STATE_SELECTED, PDataItem(AListView.Selected.Data)^.ItemColor);
+ end; }
+end;
+
+procedure TFMain.ActivateQuickFind(LeftPanel: boolean);
+var Entry: TGTKEntry;
+begin
+ QuickFind := True;
+ if LeftPanel then begin
+ Entry := LeftQuickFindEntry;
+ LeftQuickFindVBox.Show;
+ end else begin
+ Entry := RightQuickFindEntry;
+ RightQuickFindVBox.Show;
+ end;
+ Entry.Text := '';
+end;
+
+procedure TFMain.QuickFindEntryEnter(Sender: TObject; var Accept: boolean);
+begin
+ Accept := False;
+ (Sender as TGTKControl).SetFocus;
+end;
+
+procedure TFMain.DeactivateQuickFind(LeftPanel: boolean);
+begin
+ QuickFind := False;
+ if LeftPanel then LeftQuickFindVBox.Hide
+ else RightQuickFindVBox.Hide;
+end;
+
+function TFMain.QuickFindSendKey(LeftPanel: boolean; Key: word): boolean;
+var Entry: TGTKEntry;
+ s, NewText: string;
+ i: integer;
+ AListView: TGTKListView;
+ DataList: TList;
+ Data: PDataItem;
+ Found: boolean;
+ OldSelectionChangedEvent: TNotifyEvent;
+begin
+ Result := False;
+ if not QuickFind then Exit;
+ if LeftPanel then begin
+ Entry := LeftQuickFindEntry;
+ AListView := LeftListView;
+ DataList := LeftPanelData;
+ end else begin
+ Entry := RightQuickFindEntry;
+ AListView := RightListView;
+ DataList := RightPanelData;
+ end;
+ if Key = GDK_BACKSPACE then begin
+ if Length(Entry.Text) > 0 then Entry.Text := AnsiToUTF8(Copy(UTF8ToAnsi(Entry.Text), 1, Length(UTF8ToAnsi(Entry.Text)) - 1));
+ NewText := UTF8ToAnsi(Entry.Text);
+ end else begin
+ s := UTF8ToANSI(UTF8Encode(WideChar(KeyValToUnicode(Key))));
+ if (Length(s) = 0) or (s = #0) then Exit;
+ NewText := UTF8ToAnsi(Entry.Text) + s;
+ end;
+ if (DataList.Count > 0) and (Length(NewText) > 0) then begin
+ Found := False;
+ for i := 0 to DataList.Count - 1 do begin
+ Data := DataList[AListView.ConvertFromSorted(i)];
+ if Assigned(Data) and (not Data^.UpDir) and (Pos(AnsiUpperCase(NewText), AnsiUpperCase(Data^.AName)) = 1) then begin
+ Found := True;
+ OldSelectionChangedEvent := AListView.OnSelectionChanged;
+ AListView.OnSelectionChanged := nil;
+ AListView.Selected := AListView.Items[AListView.ConvertFromSorted(i)];
+ AListView.Items[AListView.ConvertFromSorted(i)].SetCursor(0, False, False, 0, 0);
+ AListView.OnSelectionChanged := OldSelectionChangedEvent;
+ Break;
+ end;
+ end;
+ if Found then Entry.Text := AnsiToUTF8(NewText)
+ else Beep;
+ Result := True;
+ end;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.miVerifyChecksumsClick(Sender: TObject);
+var i, SelCount: integer;
+ b, LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) and (not IsDir) then Inc(SelCount);
+ if (SelCount = 0) and ((not Assigned(AListView.Selected)) or PDataItem(AListView.Selected.Data)^.UpDir or PDataItem(AListView.Selected.Data)^.IsDir) then begin
+ Application.MessageBox(LANGYouMustSelectAValidFile, [mbOK], mbError, mbNone, mbOK);
+ Exit;
+ end;
+
+ try
+ FChecksum := TFChecksum.Create(Self);
+ FChecksum.Engine := Engine;
+ FChecksum.DataList := DataList;
+ FChecksum.AListView := AListView;
+ if SelCount = 0 then b := FChecksum.ProcessFile(IncludeTrailingPathDelimiter(Engine.Path) + string(PDataItem(AListView.Selected.Data)^.AName))
+ else begin
+ b := False;
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if (not UpDir) and (not IsDir) and Selected then {$B+}
+ b := b or FChecksum.ProcessFile(IncludeTrailingPathDelimiter(Engine.Path) + string(AName));
+ {$B-}
+ end;
+ if b and (FChecksum.List.Count > 0) then FChecksum.Run;
+ finally
+ FChecksum.Free;
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.miCreateChecksumsClick(Sender: TObject);
+var i, SelCount: integer;
+ LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) and (not IsDir) then Inc(SelCount);
+ if (SelCount = 0) and ((not Assigned(AListView.Selected)) or PDataItem(AListView.Selected.Data)^.UpDir or PDataItem(AListView.Selected.Data)^.IsDir) then begin
+ Application.MessageBox(LANGYouMustSelectAtLeastOneFileToCalculateChecksum, [mbOK], mbError, mbNone, mbOK);
+ Exit;
+ end;
+
+ try
+ FChecksumDruid := TFChecksumDruid.Create(Self);
+ Engine.ExplicitChDir(Engine.Path);
+ FChecksumDruid.Engine := Engine;
+ if Engine.Path = '/' then FChecksumDruid.DirName := 'root'
+ else FChecksumDruid.DirName := ExtractFileName(ExcludeTrailingPathDelimiter(Engine.Path));
+ if SelCount = 0 then FChecksumDruid.FileNames.Add(IncludeTrailingPathDelimiter(Engine.Path) + string(PDataItem(AListView.Selected.Data)^.AName))
+ else
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if (not UpDir) and (not IsDir) and Selected then
+ FChecksumDruid.FileNames.Add(IncludeTrailingPathDelimiter(Engine.Path) + string(AName));
+ FChecksumDruid.Run;
+ finally
+ if FChecksumDruid.SeparateFileCheckBox.Checked
+ then DoRefresh(AListView = LeftListView, True, True)
+ else ChangingDir(AListView = LeftListView, Engine.Path, FChecksumDruid.FileNameEntry.Text, PDataItem(AListView.Selected.Data)^.AName);
+ DoRefresh(AListView <> LeftListView, True, True);
+ FChecksumDruid.Free;
+ Engine.ExplicitChDir('/');
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.miMergeFilesClick(Sender: TObject);
+var LeftPanel, HasInitialCRC: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ FilePath, s, TargetName: string;
+ TargetCRC: LongWord;
+ TargetSize: Int64;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ end;
+
+ if (not Assigned(AListView.Selected)) or (not Assigned(AListView.Selected.Data)) or PDataItem(AListView.Selected.Data)^.IsDir or
+ PDataItem(AListView.Selected.Data)^.UpDir then
+ begin
+ Application.MessageBox(LANGYouMustSelectAValidFile, [mbOK], mbError, mbNone, mbOK);
+ Exit;
+ end;
+
+ FilePath := '';
+ try
+ FNewDir := TFNewDir.Create(Self);
+ FNewDir.Caption := LANGMergeCaption;
+ FNewDir.Label1.SetSizeRequest(500, -1);
+ FNewDir.Label1.Caption := Format(LANGMergeSAndAllFilesWithAscendingNamesToTheFollowingDirectory, [ANSIToUTF8(PDataItem(AListView.Selected.Data)^.AName)]);
+ if LeftPanel then FNewDir.Entry.Text := ANSIToUTF8(RightPanelEngine.Path)
+ else FNewDir.Entry.Text := ANSIToUTF8(LeftPanelEngine.Path);
+ FNewDir.Entry.SelectAll;
+ if FNewDir.Run = mbOK
+ then FilePath := UTF8ToAnsi(FNewDir.Entry.Text)
+ else Exit;
+ finally
+ FNewDir.Free;
+ end;
+ if FilePath = '' then Exit;
+
+ AWorkingThread := TWorkerThread.Create;
+ DebugMsg(['TFMain.miMergeFilesClick: Creating thread...']);
+ AFProgress := TFProgress.Create(Self);
+ try
+ AWorkingThread.ParamString1 := FilePath;
+ AWorkingThread.ParamString2 := IncludeTrailingPathDelimiter(Engine.Path) + PDataItem(AListView.Selected.Data)^.AName;
+ HasInitialCRC := CRCGetInfo(AWorkingThread.ParamString2, Engine, TargetName, TargetCRC, TargetSize);
+ AWorkingThread.ParamString3 := TargetName;
+ AWorkingThread.ParamBool1 := HasInitialCRC;
+ AWorkingThread.ParamLongWord1 := TargetCRC;
+ AWorkingThread.ParamInt64 := TargetSize;
+ AFProgress.SetNumBars(HasInitialCRC);
+ AFProgress.ProgressBar.Value := 0;
+ AFProgress.Label1.Caption := LANGMergeSC;
+ AWorkingThread.ProgressForm := AFProgress;
+ AWorkingThread.Engine := Engine;
+ AWorkingThread.LeftPanel := LeftPanel;
+ AWorkingThread.WorkerProcedure := MergeFilesWorker;
+ AWorkingThread.Resume;
+ AFProgress.ParentForm := FMain;
+ AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+ s := AWorkingThread.ParamString3;
+ finally
+ AFProgress.Free;
+ DebugMsg(['TFMain.miMergeFilesClick: Freeing thread...']);
+ AWorkingThread.Free;
+ end;
+
+ ChangingDir(LeftPanel, Engine.Path, s, PDataItem(AListView.Selected.Data)^.AName);
+ DoRefresh(not LeftPanel, True, True);
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.miSplitFileClick(Sender: TObject);
+var LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ FilePath: string;
+ DeleteTarget: boolean;
+ MaxSize: Int64;
+ i: integer;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ end;
+
+ if (not Assigned(AListView.Selected)) or (not Assigned(AListView.Selected.Data)) or PDataItem(AListView.Selected.Data)^.IsDir or
+ PDataItem(AListView.Selected.Data)^.UpDir then
+ begin
+ Application.MessageBox(LANGYouMustSelectAValidFile, [mbOK], mbError, mbNone, mbOK);
+ Exit;
+ end;
+
+ FilePath := '';
+ try
+ FSplitFile := TFSplitFile.Create(Self);
+ FSplitFile.Label1.Caption := Format(LANGSplitTheFileSToDirectory, [ANSIToUTF8(PDataItem(AListView.Selected.Data)^.AName)]);
+ FSplitFile.Label1.UseUnderline := True;
+ if LeftPanel then FSplitFile.Entry.Text := AnsiToUtf8(RightPanelEngine.Path)
+ else FSplitFile.Entry.Text := AnsiToUtf8(LeftPanelEngine.Path);
+ FSplitFile.Entry.SelectAll;
+ if FSplitFile.Run = mbOK
+ then FilePath := UTF8ToAnsi(FSplitFile.Entry.Text)
+ else Exit;
+ DeleteTarget := FSplitFile.DeleteTargetCheckBox.Checked;
+ MaxSize := 0;
+ for i := 1 to Length(SplitConsts) do
+ if Trim(AnsiUpperCase(SplitConsts[i].Title)) = Trim(AnsiUpperCase(FSplitFile.SizeCombo.Entry.Text)) then
+ begin
+ MaxSize := SplitConsts[i].PartSize;
+ Break;
+ end;
+ if MaxSize = 0 then MaxSize := GetStrSize(UTF8ToANSI(FSplitFile.SizeCombo.Entry.Text));
+ finally
+ FSplitFile.Free;
+ end;
+ if FilePath = '' then Exit;
+
+ AWorkingThread := TWorkerThread.Create;
+ DebugMsg(['TFMain.miSplitFileClick: Creating thread...']);
+ AFProgress := TFProgress.Create(Self);
+ try
+ AWorkingThread.ParamString1 := IncludeTrailingPathDelimiter(Engine.Path) + PDataItem(AListView.Selected.Data)^.AName;
+ AWorkingThread.ParamString2 := FilePath;
+ AWorkingThread.ParamBool1 := DeleteTarget;
+ AWorkingThread.ParamInt64 := MaxSize;
+ AFProgress.SetNumBars(MaxSize > 0);
+ AFProgress.ProgressBar.Value := 0;
+ AFProgress.Label1.Caption := LANGSplitSC;
+ AWorkingThread.ProgressForm := AFProgress;
+ AWorkingThread.Engine := Engine;
+ AWorkingThread.LeftPanel := LeftPanel;
+ AWorkingThread.WorkerProcedure := SplitFilesWorker;
+ AWorkingThread.Resume;
+ AFProgress.ParentForm := FMain;
+ AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+ finally
+ AFProgress.Free;
+ DebugMsg(['TFMain.miSplitFileClick: Freeing thread...']);
+ AWorkingThread.Free;
+ end;
+
+ DoRefresh(LeftPanel, True, True);
+ DoRefresh(not LeftPanel, True, True);
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.SwitchOtherPanel(LeftPanel, RequestNewAltO: boolean);
+var AListView: TGTKListView;
+ SrcEngine, OrigSrcEngine, TargetEngine: TPanelEngine;
+ s: string;
+ DontShowAgain: boolean;
+begin
+ if LeftPanel then begin
+ AListView := LeftListView;
+ SrcEngine := LeftPanelEngine;
+ TargetEngine := RightPanelEngine;
+ end else begin
+ AListView := RightListView;
+ SrcEngine := RightPanelEngine;
+ TargetEngine := LeftPanelEngine;
+ end;
+ OrigSrcEngine := SrcEngine;
+
+ if not (SrcEngine is TLocalTreeEngine) then begin
+ if ConfSwitchOtherPanelBehaviour < 0 then begin
+ MessageBoxShowOnce(LANGSwitchOtherPanelWarning, LANGDontShowAgain, DontShowAgain, [mbOK], mbWarning, mbOK, mbOK);
+ if DontShowAgain then begin
+ ConfSwitchOtherPanelBehaviour := 1;
+ WriteMainGUISettings;
+ end;
+ end;
+// Exit;
+ end;
+
+ // don't change dir in VFS engines
+ while not (SrcEngine is TLocalTreeEngine) do SrcEngine := SrcEngine.ParentEngine;
+ while not (TargetEngine is TLocalTreeEngine) do TargetEngine := TargetEngine.ParentEngine;
+
+ if (not ConfNewStyleAltO) and (not RequestNewAltO) then begin
+ s := ExcludeTrailingPathDelimiter(SrcEngine.Path);
+ if OrigSrcEngine = SrcEngine then begin
+ if (not Assigned(AListView.Selected)) or (not Assigned(AListView.Selected.Data)) or PDataItem(AListView.Selected.Data)^.UpDir or
+ (not PDataItem(AListView.Selected.Data)^.IsDir)
+ then begin if Length(s) > 1 then s := IncludeTrailingPathDelimiter(Copy(s, 1, LastDelimiter(PathDelim, s))); end
+ else s := IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(s) + PDataItem(AListView.Selected.Data)^.AName);
+ end;
+ if IncludeTrailingPathDelimiter(TargetEngine.Path) <> s then begin
+ if LeftPanel then RightPanelEngine := TargetEngine
+ else LeftPanelEngine := TargetEngine;
+ ChangingDir(not LeftPanel, s);
+ end;
+ // Move one item down
+ if (OrigSrcEngine = SrcEngine) and Assigned(AListView.Selected) and (AListView.ConvertToSorted(AListView.Selected.Index) < AListView.Items.Count - 1) then begin
+ AListView.Selected := AListView.Items[AListView.ConvertFromSorted(AListView.ConvertToSorted(AListView.Selected.Index) + 1)];
+ AListView.Selected.SetCursor(0, False, False, 0, 0);
+ end;
+ end else begin
+ if IncludeTrailingPathDelimiter(TargetEngine.Path) <> IncludeTrailingPathDelimiter(SrcEngine.Path) then begin
+ if LeftPanel then RightPanelEngine := TargetEngine
+ else LeftPanelEngine := TargetEngine;
+ ChangingDir(not LeftPanel, SrcEngine.Path);
+ end;
+ end;
+end;
+
+procedure TFMain.miShowDotFilesClick(Sender: TObject);
+begin
+ ConfShowDotFiles := miShowDotFiles.Checked;
+ DoRefresh(True, True, True);
+ DoRefresh(False, True, True);
+end;
+
+procedure TFMain.F3F4ButtonClick(Sender: TObject);
+var LeftPanel: boolean;
+ AListView: TGTKListView;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ end else begin
+ AListView := RightListView;
+ end;
+ if (not Assigned(AListView.Selected)) or (not Assigned(AListView.Selected.Data)) or PDataItem(AListView.Selected.Data)^.IsDir or
+ PDataItem(AListView.Selected.Data)^.UpDir then
+ begin
+ Application.MessageBox(LANGYouMustSelectAValidFile, [mbOK], mbError, mbNone, mbOK);
+ Exit;
+ end;
+ EditViewFile(LeftPanel, AListView, (Sender = F3Button) or ((Sender is TGTKMenuItem) and (Integer((Sender as TGTKMenuItem).Data) = 200)), False);
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.EditViewFile(LeftPanel: boolean; AListView: TGTKListView; View, NewFile: boolean);
+var ANewDir: TFNewDir;
+ Engine: TPanelEngine;
+ AFile, s: string;
+ Stat: PDataItemSL;
+ Error, x: integer;
+// AViewer: TViewerThread;
+ AViewer: TFViewer;
+begin
+ try
+ InternalLock;
+ if LeftPanel then Engine := LeftPanelEngine
+ else Engine := RightPanelEngine;
+ if NewFile then begin
+ ANewDir := TFNewDir.Create(Self);
+ try
+ ANewDir.Caption := LANGEdit;
+ ANewDir.Label1.Caption := LANGEnterFilenameToEdit;
+ ANewDir.Label1.UseUnderline := True;
+ ANewDir.Label1.FocusControl := ANewDir.Entry;
+ if Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and (not PDataItem(AListView.Selected.Data)^.IsDir) and
+ (not PDataItem(AListView.Selected.Data)^.UpDir)
+ then ANewDir.Entry.Text := AnsiToUTF8(PDataItem(AListView.Selected.Data)^.AName)
+ else ANewDir.Entry.Text := '';
+ if Length(ANewDir.Entry.Text) > 0 then ANewDir.Entry.SelectAll;
+ if ANewDir.Run <> mbOK then Exit;
+ AFile := IncludeTrailingPathDelimiter(Engine.Path) + UTF8ToAnsi(ANewDir.Entry.Text);
+ finally
+ ANewDir.Free;
+ end;
+ end else AFile := IncludeTrailingPathDelimiter(Engine.Path) + PDataItem(AListView.Selected.Data)^.AName;
+
+ EditViewFileInternal(Self, AFile, Engine, View, NewFile);
+
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+procedure TFMain.EditViewFileInternal(ParentWindow: TGTKControl; Filename: string; Engine: TPanelEngine; View, NewFile: boolean);
+var s: string;
+ Stat: PDataItemSL;
+ Error, x: integer;
+// AViewer: TViewerThread;
+ AViewer: TFViewer;
+begin
+ Stat := Engine.GetFileInfoSL(Filename);
+ if Assigned(Stat) and (Stat^.Size > ConfEditViewFileSizeLimit) and
+ (Application.MessageBox(LANGTheFileYouAreTryingToOpenIsQuiteBig, [mbYes, mbNo], mbWarning, mbNone, mbNo) = mbNo)
+ then Exit;
+
+ if View then s := ConfViewer
+ else s := ConfEditor;
+
+ if (Engine is TVFSEngine) and (not NewFile) then
+ if not HandleRunFromArchive(Filename, Engine, s, '', True) then Exit;
+
+ if ConfUseInternalViewer and View then begin
+(* AViewer := TViewerThread.Create(Self);
+ if not AViewer.LoadFile(AFile) then begin
+ Application.MessageBox(Format('Cannot load file ''%s''. Please check the permissions.', [ANSIToUTF8(AFile)]), [mbOK], mbError);
+ AViewer.Free;
+ end else AViewer.Resume; *)
+ AViewer := TFViewer.Create(ParentWindow);
+ if not AViewer.LoadFile(Filename) then begin
+ Application.MessageBox(Format(LANGCannotLoadFile, [ANSIToUTF8(Filename)]), [mbOK], mbError, mbNone, mbOK);
+ AViewer.Free;
+ end else begin
+// gtk_window_set_transient_for(PGtkWindow(AViewer.FWidget), PGtkWindow(ParentWindow.FWidget));
+ AViewer.Show;
+ end;
+ end else begin
+ if View then x := ConfViewerTerminalBehaviour
+ else x := ConfEditorTerminalBehaviour;
+ if not ExecuteProgram(Format('%s %s', [s, QuoteStr(Filename)]), ExtractFilePath(Filename), x = 0, x = 1, Error) then
+ Application.MessageBox(Format(LANGCannotExecuteSPleaseCheckTheConfiguration, [ANSIToUTF8(s)]), [mbOK], mbError, mbNone, mbOK);
+ end;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.miFileTypesClick(Sender: TObject);
+var x: pointer;
+begin
+ try
+ InternalLock;
+ FFileTypeSettings := TFFileTypeSettings.Create(Self);
+ ReadAssoc;
+ FFileTypeSettings.AssignAssocList(AssocList);
+ FFileTypeSettings.FillList;
+ if FFileTypeSettings.Run = mbOK then begin
+ RemoveIconRefs(FFileTypeSettings.IntAssocList, True);
+ RemoveIconRefs(AssocList, False);
+ FFileTypeSettings.CleanItems;
+ x := AssocList;
+ AssocList := FFileTypeSettings.IntAssocList;
+ FFileTypeSettings.IntAssocList := x;
+ RecreateIcons(AssocList);
+ DoRefresh(True, True, True);
+ DoRefresh(False, True, True);
+ WriteAssoc;
+ end;
+ finally
+ FFileTypeSettings.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.RunFile(Path: string; Engine: TPanelEngine; CustomAction: integer);
+var Command, Ext, FileTypeDesc: string;
+ i, j, Last, ac: integer;
+ b, AutodetectGUI, RunInTerminal: boolean;
+ Stat: PDataItemSL;
+ s: string;
+begin
+ try
+ InternalLock;
+ Command := '';
+ FileTypeDesc := '';
+ AutodetectGUI := True;
+ RunInTerminal := False;
+ if (Pos('.', ExtractFileName(Path)) > 0) and (LastDelimiter('.', ExtractFileName(Path)) < Length(ExtractFileName(Path))) then begin
+ Ext := ANSIUpperCase(Trim(Copy(ExtractFileName(Path), LastDelimiter('.', ExtractFileName(Path)) + 1, Length(ExtractFileName(Path)) - LastDelimiter('.', ExtractFileName(Path)))));
+ // Search in the association list
+ if AssocList.Count > 0 then
+ for i := 0 to AssocList.Count - 1 do
+ with TFileAssoc(AssocList[i]) do
+ if (ActionList.Count > 0) and (Length(Trim(Extensions)) > 0) then begin
+ b := False;
+ if Pos(';', Extensions) = 0 then b := ANSIUpperCase(Trim(Extensions)) = Ext else begin
+ Last := 0;
+ for j := 1 to Length(Extensions) do
+ if Extensions[j] = ';' then begin
+ if ANSIUpperCase(Trim(Copy(Extensions, Last + 1, j - Last - 1))) = Ext then begin
+ b := True;
+ Break;
+ end;
+ Last := j;
+ end;
+ if not b then b := ANSIUpperCase(Trim(Copy(Extensions, LastDelimiter(';', Extensions) + 1, Length(Extensions) - LastDelimiter(';', Extensions)))) = Ext;
+ end;
+ if b then begin
+ FileTypeDesc := FileTypeName;
+ if (CustomAction > ActionList.Count - 1) or (CustomAction = -1)
+ then ac := DefaultAction
+ else ac := CustomAction;
+ if ac > ActionList.Count - 1 then ac := 0;
+ if ActionList.Count >= ac then begin
+ Command := Trim(TAssocAction(ActionList[ac]).ActionCommand);
+ AutodetectGUI := TAssocAction(ActionList[ac]).AutodetectGUI;
+ RunInTerminal := TAssocAction(ActionList[ac]).RunInTerminal;
+ end;
+ if Command <> '' then Break;
+ end;
+ end;
+ end;
+
+ // Association not found, try to execute file itself
+ if Command = '' then begin
+ DebugMsg(['File association not found']);
+ if CustomAction > -1 then begin
+ DebugMsg(['Some strange error occured...']);
+ Exit;
+ end;
+ Stat := Engine.GetFileInfoSL(Path);
+ if Assigned(Stat) and Stat^.IsExecutable then begin
+ b := True;
+ if Engine is TVFSEngine then b := HandleRunFromArchive(Path, Engine, Command, FileTypeDesc, False); // not a local engine, extract to local first
+ if b then begin
+ Libc.__chdir(PChar(ExtractFilePath(Path)));
+ b := ExecuteProgram(QuoteStr(Path), ExtractFilePath(Path), AutodetectGUI, RunInTerminal, i);
+ Libc.__chdir(PChar('/'));
+ end else b := True; // Mask cancelled extraction from VFS
+ end else begin
+ if Engine is TVFSEngine then begin
+ HandleRunFromArchive(Path, Engine, Command, FileTypeDesc, False);
+ b := True;
+ end else
+ if Application.MessageBox(Format(LANGThereIsNoApplicationAssociatedWithS, [ANSIToUTF8(ExtractFileName(Path))]), [mbYes, mbNo], mbQuestion, mbNone, mbNo) = mbYes
+ then miFileTypesClick(Self);
+ Exit;
+ end;
+
+ end else begin
+ DebugMsg(['File association found: ', Command]);
+ s := Command;
+ b := True;
+ if Engine is TVFSEngine then b := HandleRunFromArchive(Path, Engine, Command, FileTypeDesc, False); // not a local engine, extract to local first
+ if Pos('%s', s) > 0 then s := Format(s, ['''' + QuoteStr(Path) + ''''])
+ else s := Format('%s %s', [s, QuoteStr(Path)]);
+// DebugMsg(['execute: ', s, ' , ', Command, ' , ', QuoteStr(Path)]);
+ if b then begin
+ Libc.__chdir(PChar(ExtractFilePath(Path)));
+ b := ExecuteProgram(s, ExtractFilePath(Path), AutodetectGUI, RunInTerminal, i);
+ Libc.__chdir(PChar('/'));
+ end else b := True; // Mask cancelled extraction from VFS
+ end;
+ if not b then Application.MessageBox(Format(LANGCannotExecuteSPleaseCheckTheConfiguration, [ANSIToUTF8(s)]), [mbOK], mbError, mbNone, mbOK);
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+procedure TFMain.CommandLineComboKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+var Error, OldPos, i: integer;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ s, s2, Orig: string;
+begin
+ try
+ InternalLock;
+ case Key of
+ GDK_RETURN, GDK_KP_ENTER: begin
+ Accept := False;
+ if LeftLastFocused then Engine := LeftPanelEngine
+ else Engine := RightPanelEngine;
+ // Insert filename
+ if (ssAlt in Shift) or (ssCtrl in Shift) then begin
+ if LeftLastFocused then AListView := LeftListView
+ else AListView := RightListView;
+ if Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and (not PDataItem(AListView.Selected.Data)^.UpDir) then begin
+ s2 := QuoteStr(String(PDataItem(AListView.Selected.Data)^.AName)) + ' ';
+ if Length(CommandLineCombo.Entry.Text) = 0 then begin
+ CommandLineCombo.Entry.Text := Format('./%s', [s2]);
+ CommandLineCombo.Entry.CursorPosition := Length(s2);
+ end else begin
+ OldPos := CommandLineCombo.Entry.CursorPosition;
+ s := CommandLineCombo.Entry.Text;
+ Insert(s2, s, OldPos + 1);
+ CommandLineCombo.Entry.Text := s;
+ CommandLineCombo.Entry.CursorPosition := OldPos + Length(s2);
+ end;
+ end;
+ Exit;
+ end;
+
+ Orig := Trim(CommandLineCombo.Entry.Text);
+ if Length(Orig) > 0 then begin
+ if ANSIUpperCase(Orig) = 'CD' then begin
+ if LeftLastFocused then PathButtonClick(LeftHomeButton)
+ else PathButtonClick(RightHomeButton);
+ end else
+ if (Length(Orig) > 3) and (ANSIUpperCase(Copy(Orig, 1, 3)) = 'CD ') then begin
+ ChangingDir(LeftLastFocused, ProcessPattern(Engine, Copy(Orig, 4, Length(Orig) - 3), Engine.Path, '', True));
+ end else begin
+ while not (Engine is TLocalTreeEngine) do Engine := Engine.ParentEngine;
+ ChDir(Engine.Path);
+ if not ExecuteProgram(Orig, Engine.Path, ConfCmdLineTerminalBehaviour = 0 , ConfCmdLineTerminalBehaviour = 1, Error) then
+ Application.MessageBox(LANGErrorExecutingCommand, [mbOK], mbError, mbNone, mbOK);
+ ChDir('/');
+ end;
+ end;
+ CommandLineCombo.Entry.Text := '';
+ if LeftLastFocused then LeftListView.SetFocus
+ else RightListView.SetFocus;
+
+ if Length(Orig) > 0 then begin
+ SaveItemToHistory(Orig, CommandLineHistory);
+ if CommandLineCombo.Items.Count > 0 then
+ for i := CommandLineCombo.Items.Count - 1 downto 0 do
+ CommandLineCombo.Items.Delete(i);
+ if CommandLineHistory.Count > 0 then
+ for i := 0 to CommandLineHistory.Count - 1 do
+ CommandLineCombo.Items.Append(CommandLineHistory[i]);
+ CommandLineCombo.Entry.Text := '';
+ end;
+ end;
+ GDK_Down, GDK_Up:
+ begin
+ Accept := False;
+ if LeftLastFocused then AListView := LeftListView
+ else AListView := RightListView;
+ if (not (([ssCtrl] = Shift) and (Key = GDK_Up))) and (
+ ((Key = GDK_Down) and (AListView.ConvertToSorted(AListView.Selected.Index) < AListView.Items.Count - 1)) or
+ ((Key = GDK_Up) and (AListView.ConvertToSorted(AListView.Selected.Index) > 0))) then
+ begin
+ AListView.Selected := AListView.Items[AListView.ConvertFromSorted(AListView.ConvertToSorted(AListView.Selected.Index) + (Ord(Key = GDK_Down) * 2) - 1)];
+ AListView.Selected.SetCursor(0, False, False, 0, 0);
+ end;
+ AListView.SetFocus;
+ end;
+ GDK_ESCAPE: begin
+ Accept := False;
+ CommandLineCombo.Entry.Text := '';
+ if LeftLastFocused then LeftListView.SetFocus
+ else RightListView.SetFocus;
+ end;
+ GDK_TAB: begin
+ Accept := False;
+ if LeftLastFocused then RightListView.SetFocus
+ else LeftListView.SetFocus;
+ end;
+ GDK_P, GDK_Capital_P: if ((Shift = [ssAlt]) or (Shift = [ssCtrl])) and (CommandLineHistory.Count > 0) then
+ begin
+ Accept := False;
+ Orig := Trim(CommandLineCombo.Entry.Text);
+ i := CommandLineHistory.IndexOf(Orig);
+ if i < 0 then begin
+ SavedCmdLine := Orig;
+ i := 0;
+ end else
+ if CommandLineHistory.Count > i + 1 then Inc(i);
+ CommandLineCombo.Entry.Text := CommandLineHistory[i];
+ CommandLineCombo.Entry.SetFocus;
+ CommandLineCombo.Entry.SelectRegion(Length(CommandLineCombo.Entry.Text), Length(CommandLineCombo.Entry.Text));
+ end else if not CommandLineCombo.Entry.Focused then ActivateCommandLine(Key);
+ GDK_N, GDK_Capital_N: if ((Shift = [ssAlt]) or (Shift = [ssCtrl])) and (CommandLineHistory.Count > 0) then
+ begin
+ Accept := False;
+ Orig := Trim(CommandLineCombo.Entry.Text);
+ i := CommandLineHistory.IndexOf(Orig);
+ if i < 0 then Exit else
+ if i = 0 then begin
+ s := SavedCmdLine;
+ SavedCmdLine := '';
+ end else
+ if CommandLineHistory.Count > i then s := CommandLineHistory[i - 1];
+ CommandLineCombo.Entry.Text := s;
+ CommandLineCombo.Entry.SetFocus;
+ CommandLineCombo.Entry.SelectRegion(Length(CommandLineCombo.Entry.Text), Length(CommandLineCombo.Entry.Text));
+ end else if not CommandLineCombo.Entry.Focused then ActivateCommandLine(Key);
+ GDK_A, GDK_Capital_A: if (Shift = [ssAlt]) or (Shift = [ssCtrl]) then
+ begin
+ Accept := False;
+ if LeftLastFocused then Engine := LeftPanelEngine
+ else Engine := RightPanelEngine;
+ s2 := QuoteStr(IncludeTrailingPathDelimiter(Engine.Path));
+ OldPos := CommandLineCombo.Entry.CursorPosition;
+ s := CommandLineCombo.Entry.Text;
+ Insert(s2, s, OldPos + 1);
+ CommandLineCombo.Entry.SetFocus;
+ CommandLineCombo.Entry.Text := s;
+ CommandLineCombo.Entry.CursorPosition := OldPos + Length(s2);
+ end else if not CommandLineCombo.Entry.Focused then ActivateCommandLine(Key);
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+function TFMain.ActivateCommandLine(Key: word; const ActualPosition: boolean = False): boolean;
+var s, s2: string;
+ OldPos: integer;
+begin
+ Result := False;
+ s := UTF8Encode(WideChar(KeyValToUnicode(Key)));
+ if (Length(s) = 0) or (s = #0) then Exit;
+ if ActualPosition and CommandLineCombo.Entry.Focused then begin
+ OldPos := CommandLineCombo.Entry.CursorPosition;
+ s2 := CommandLineCombo.Entry.Text;
+ Insert(s, s2, Length(ANSILeftStr(s2, OldPos)) + 1);
+ CommandLineCombo.Entry.Text := s2;
+ CommandLineCombo.Entry.CursorPosition := OldPos + 1;
+ end else begin
+ CommandLineCombo.Entry.Text := CommandLineCombo.Entry.Text + s;
+ CommandLineCombo.Entry.SetFocus;
+ CommandLineCombo.Entry.SelectRegion(Length(CommandLineCombo.Entry.Text), Length(CommandLineCombo.Entry.Text));
+ end;
+ Result := True;
+end;
+
+procedure TFMain.FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+var AListView: TGTKListView;
+begin
+ if CommandLineCombo.Entry.Focused then CommandLineComboKeyDown(Sender, Key, Shift, Accept);
+ if Editing and (Key = GDK_ESCAPE) then begin
+ Editing := False;
+ if LeftLastFocused then AListView := LeftListView
+ else AListView := RightListView;
+ AListView.Columns[0].SetProperty('editable', 0);
+ end;
+end;
+
+procedure TFMain.InactiveItemsTimerTimer(Sender: TObject);
+
+ procedure Redraw(AListView: TGTKListView; tree_view: PGtkTreeView);
+ var TreePath: PGtkTreePath;
+ Iter: TGtkTreeIter;
+ Rect: TGdkRectangle;
+ PixBuf, Icon: PGdkPixbuf;
+ cell_width, cell_height: integer;
+ begin
+ if (csDestroying in ComponentState) or (AListView = nil) or (AListView.FSelection = nil) then Exit;
+ if not gtk_tree_selection_get_selected(AListView.FSelection, nil, @Iter) then Exit;
+ TreePath := gtk_tree_model_get_path(gtk_tree_view_get_model(tree_view), @Iter);
+ if not Assigned(TreePath) then Exit;
+ gtk_tree_view_get_background_area(tree_view, TreePath, AListView.Columns[0].FColumn, @Rect);
+ gtk_tree_path_free(TreePath);
+ gtk_cell_renderer_get_size(AListView.Columns[0].FPixbufRenderer, PGtkWidget(tree_view), nil, nil, nil, @cell_width, @cell_height);
+ Icon := PDataItem(AListView.Selected.Data)^.Icon;
+ Rect.width := Rect.x + cell_width + AListView.Columns[0].FRenderer^.xpad * 2 + 1;
+ PixBuf := gdk_pixbuf_new(GDK_COLORSPACE_RGB, True, 8, Rect.width, Rect.height);
+ gdk_pixbuf_fill(PixBuf, InactiveItemBGColorNum);
+ gdk_pixbuf_render_to_drawable_alpha(PixBuf, PGdkDrawable(gtk_tree_view_get_bin_window(tree_view)), 0, 0, Rect.x, Rect.y,
+ Rect.width, Rect.height, GDK_PIXBUF_ALPHA_FULL, 0, GDK_RGB_DITHER_NORMAL, 0, 0);
+ gdk_pixbuf_unref(PixBuf);
+ gdk_pixbuf_render_to_drawable_alpha(Icon, PGdkDrawable(gtk_tree_view_get_bin_window(tree_view)), 0, 0,
+ Rect.x + AListView.Columns[0].FRenderer^.xpad, Rect.y + Rect.height div 2 - (16 div 2),
+ 16, 16, GDK_PIXBUF_ALPHA_FULL, 0, GDK_RGB_DITHER_NORMAL, 0, 0);
+ end;
+
+
+begin
+ if Assigned(Sender) and Assigned(InactiveItemsTimer) and Assigned(LeftListView) and Assigned(RightListView) and
+ (not (csDestroying in ComponentState)) then
+ try
+ InactiveItemsTimer.Enabled := False;
+ if RedrawLeftInactive and (not LeftListView.Focused) // and (not ConfInactiveItemDefaultColors)
+ then Redraw(LeftListView, PGtkTreeView(LeftListView.FWidget));
+ if RedrawRightInactive and (not RightListView.Focused) // and (not ConfInactiveItemDefaultColors)
+ then Redraw(RightListView, PGtkTreeView(RightListView.FWidget));
+ RedrawLeftInactive := False;
+ RedrawRightInactive := False;
+ except end;
+end;
+
+
+(********************************************************************************************************************************)
+function TFMain.OldGTKConvertToSorted(Sender: TObject; const Index: integer): integer;
+var DataList, List: TList;
+ i: integer;
+ AListView: TGTKListView;
+begin
+ Result := -1;
+ if Sender = LeftListView then begin
+ DataList := LeftPanelData;
+ AListView := LeftListView;
+ end else begin
+ DataList := RightPanelData;
+ AListView := RightListView;
+ end;
+ List := nil; // Silent compiler warnings
+ if Assigned(DataList) and (DataList.Count > 0) then
+ try
+ List := TList.Create;
+ for i := 0 to DataList.Count - 1 do List.Add(DataList[i]);
+ if (List.Count > 1) and (AListView.SortOrder <> soNone) then
+ SortDataList(List, AListView.SortOrder = soAscending, AListView.SortColumnID);
+ Result := List.IndexOf(DataList[Index]);
+ finally
+ List.Free;
+ end;
+end;
+
+function TFMain.OldGTKConvertFromSorted(Sender: TObject; const Index: integer): integer;
+var DataList, List: TList;
+ i: integer;
+ AListView: TGTKListView;
+begin
+ Result := -1;
+ if Sender = LeftListView then begin
+ DataList := LeftPanelData;
+ AListView := LeftListView;
+ end else begin
+ DataList := RightPanelData;
+ AListView := RightListView;
+ end;
+ List := nil; // Silent compiler warnings
+ if Assigned(DataList) and (DataList.Count > 0) then
+ try
+ List := TList.Create;
+ for i := 0 to DataList.Count - 1 do List.Add(DataList[i]);
+ if (List.Count > 1) and (AListView.SortOrder <> soNone) then
+ SortDataList(List, AListView.SortOrder = soAscending, AListView.SortColumnID);
+ Result := DataList.IndexOf(List[Index]);
+ finally
+ List.Free;
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.SplitterPopupMenuClick(Sender: TObject);
+begin
+ if not (Sender is TGTKMenuItem) then Exit;
+ ConfPanelSep := Integer((Sender as TGTKMenuItem).Data);
+ PanelSeparator.Position := Round(Width * (ConfPanelSep / 100));
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.miChangePermissionsClick(Sender: TObject);
+var LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+ i: longint;
+ SelCount: longint;
+ AFile, NextItem1, NextItem2: string;
+ Stat: PDataItemSL;
+ UsrManager: TUserManager;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then Inc(SelCount);
+ if (SelCount = 0) and ((not Assigned(AListView.Selected)) or PDataItem(AListView.Selected.Data)^.UpDir) then begin
+ Application.MessageBox(LANGNoFilesSelected, [mbOK], mbInfo, mbNone, mbOK);
+ Exit;
+ end;
+
+ AFile := '';
+ if SelCount = 0 then AFile := PDataItem(AListView.Selected.Data)^.AName else
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then begin
+ AFile := AName;
+ Break;
+ end;
+
+ // Handle password
+ if (Engine is TVFSEngine) and TVFSEngine(Engine).GetPasswordRequired and (Length(TVFSEngine(Engine).Password) < 1) then
+ if not HandleSetPassword(Engine) then Exit;
+
+ if AFile <> '' then
+ try
+ FChmod := TFChmod.Create(Self);
+ Stat := Engine.GetFileInfoSL(IncludeTrailingPathDelimiter(Engine.Path) + AFile);
+ if not Assigned(Stat) then Exit;
+ UsrManager := TUserManager.Create;
+ try
+ FChmod.AssignMode(Stat^.Mode, AFile, UsrManager.GetUserName(Stat^.UID), UsrManager.GetGroupName(Stat^.GID));
+ finally
+ UsrManager.Free;
+ end;
+ if FChmod.Run = mbOK then begin
+ FindNextSelected(AListView, DataList, NextItem1, NextItem2);
+
+ AWorkingThread := TWorkerThread.Create;
+ AFProgress := TFProgress.Create(Self);
+ try
+ AFProgress.SetNumBars(False);
+ AFProgress.ProgressBar.Value := 0;
+ AFProgress.Label1.Caption := LANGChmodProgress;
+ AWorkingThread.ProgressForm := AFProgress;
+ if Assigned(AListView.Selected) then AWorkingThread.SelectedItem := AListView.Selected.Data;
+ AWorkingThread.ParamBool1 := FChmod.RecursiveCheckButton.Checked;
+ AWorkingThread.ParamInt1 := FChmod.RecursiveOptionMenu.ItemIndex;
+ AWorkingThread.ParamCardinal1 := FChmod.LastMode;
+ AWorkingThread.Engine := Engine;
+ AWorkingThread.LeftPanel := LeftPanel;
+ AWorkingThread.DataList := DataList;
+ AWorkingThread.WorkerProcedure := ChmodFilesWorker;
+ AWorkingThread.Resume;
+ AFProgress.ParentForm := FMain;
+ if (SelCount > 1) or FChmod.RecursiveCheckButton.Checked then AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+ finally
+ AFProgress.Free;
+ AWorkingThread.Free;
+ end;
+ ChangingDir(LeftPanel, Engine.Path, NextItem1, NextItem2);
+ DoRefresh(not LeftPanel, True, True);
+ end;
+ finally
+ FChmod.Free;
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.miChangeOwnerClick(Sender: TObject);
+var LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+ i: integer;
+ SelCount: longint;
+ AFile, NextItem1, NextItem2: string;
+ Stat: PDataItemSL;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then Inc(SelCount);
+ if (SelCount = 0) and ((not Assigned(AListView.Selected)) or PDataItem(AListView.Selected.Data)^.UpDir) then begin
+ Application.MessageBox(LANGNoFilesSelected, [mbOK], mbInfo, mbNone, mbOK);
+ Exit;
+ end;
+
+ AFile := '';
+ if SelCount = 0 then AFile := PDataItem(AListView.Selected.Data)^.AName else
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then begin
+ AFile := AName;
+ Break;
+ end;
+
+ // Handle password
+ if (Engine is TVFSEngine) and TVFSEngine(Engine).GetPasswordRequired and (Length(TVFSEngine(Engine).Password) < 1) then
+ if not HandleSetPassword(Engine) then Exit;
+
+ if AFile <> '' then
+ try
+ FChown := TFChown.Create(Self);
+ Stat := Engine.GetFileInfoSL(IncludeTrailingPathDelimiter(Engine.Path) + AFile);
+ if not Assigned(Stat) then Exit;
+ FChown.AssignMode(Stat^.Mode, AFile, Stat^.UID, Stat^.GID);
+ if FChown.Run = mbOK then begin
+ FindNextSelected(AListView, DataList, NextItem1, NextItem2);
+
+ AWorkingThread := TWorkerThread.Create;
+ AFProgress := TFProgress.Create(Self);
+ try
+ AFProgress.SetNumBars(False);
+ AFProgress.ProgressBar.Value := 0;
+ AFProgress.Label1.Caption := LANGChownProgress;
+ AWorkingThread.ProgressForm := AFProgress;
+ if Assigned(AListView.Selected) then AWorkingThread.SelectedItem := AListView.Selected.Data;
+ AWorkingThread.ParamBool1 := FChown.RecursiveCheckButton.Checked;
+ AWorkingThread.ParamCardinal1 := FChown.LastUID;
+ AWorkingThread.ParamCardinal2 := FChown.LastGID;
+ AWorkingThread.Engine := Engine;
+ AWorkingThread.LeftPanel := LeftPanel;
+ AWorkingThread.DataList := DataList;
+ AWorkingThread.WorkerProcedure := ChownFilesWorker;
+ AWorkingThread.Resume;
+ AFProgress.ParentForm := FMain;
+ if (SelCount > 1) or FChown.RecursiveCheckButton.Checked then AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+ finally
+ AFProgress.Free;
+ AWorkingThread.Free;
+ end;
+
+ ChangingDir(LeftPanel, Engine.Path, NextItem1, NextItem2);
+ DoRefresh(not LeftPanel, True, True);
+ end;
+ finally
+ FChown.Free;
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.miCreateSymlinkClick(Sender: TObject);
+var LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine, EngineOpposite: TPanelEngine;
+ s1, s2: string;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ EngineOpposite := RightPanelEngine;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ EngineOpposite := LeftPanelEngine;
+ end;
+
+ if (not Assigned(AListView.Selected)) or (not Assigned(AListView.Selected.Data)) or PDataItem(AListView.Selected.Data)^.UpDir
+ then s1 := ExcludeTrailingPathDelimiter(Engine.Path)
+ else s1 := IncludeTrailingPathDelimiter(Engine.Path) + PDataItem(AListView.Selected.Data)^.AName;
+ if Engine.Path <> EngineOpposite.Path
+ then s2 := IncludeTrailingPathDelimiter(EngineOpposite.Path) + PDataItem(AListView.Selected.Data)^.AName
+ else s2 := '';
+
+ // Handle password
+ if (Engine is TVFSEngine) and TVFSEngine(Engine).GetPasswordRequired and (Length(TVFSEngine(Engine).Password) < 1) then
+ if not HandleSetPassword(Engine) then Exit;
+
+ if CreateSymlink(s1, s2, Engine) then begin
+ DoRefresh(LeftPanel, True, True);
+ DoRefresh(not LeftPanel, True, True);
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.miEditSymlinkClick(Sender: TObject);
+var LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ end;
+
+ if (not Assigned(AListView.Selected)) or (not Assigned(AListView.Selected.Data)) or (not PDataItem(AListView.Selected.Data)^.IsLnk) or
+ PDataItem(AListView.Selected.Data)^.UpDir then
+ begin
+ Application.MessageBox(LANGYouMustSelectAValidSymbolicLink, [mbOK], mbError, mbNone, mbOK);
+ Exit;
+ end;
+
+ // Handle password
+ if (Engine is TVFSEngine) and TVFSEngine(Engine).GetPasswordRequired and (Length(TVFSEngine(Engine).Password) < 1) then
+ if not HandleSetPassword(Engine) then Exit;
+
+ if EditSymlink(IncludeTrailingPathDelimiter(Engine.Path) + PDataItem(AListView.Selected.Data)^.AName, Engine) then begin
+ DoRefresh(LeftPanel, True, True);
+ DoRefresh(not LeftPanel, True, True);
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.FilePopupMenuPopup(Sender: TObject);
+
+ procedure ClearPopupMenu(Popup: TGTKMenuItem);
+ begin
+ while Popup.Count > 0 do begin
+ if Popup.Items[0].Count > 0 then ClearPopupMenu(Popup.Items[0]);
+ Popup.Items[0].Free;
+ Popup.Delete(0);
+ end;
+ end;
+
+var Item: TGTKMenuItem;
+ DataItem: PDataItemSL;
+ Engine: TPanelEngine;
+ AListView: TGTKListView;
+ FileName, ShortFName, Ext: string;
+ UpDir, b, Found: boolean;
+ i, j, Last: integer;
+begin
+ ClearPopupMenu(FilePopupMenu);
+ if LeftLastFocused then begin
+ Engine := LeftPanelEngine;
+ AListView := LeftListView;
+ end else begin
+ Engine := RightPanelEngine;
+ AListView := RightListView;
+ end;
+ FileName := IncludeTrailingPathDelimiter(Engine.Path);
+ if Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and (not PDataItem(AListView.Selected.Data)^.UpDir)
+ then FileName := FileName + PDataItem(AListView.Selected.Data)^.AName;
+ ShortFName := ExtractFileName(ExcludeTrailingPathDelimiter(FileName));
+ DataItem := Engine.GetFileInfoSL(FileName);
+ if not Assigned(DataItem) then begin
+ DebugMsg(['Error: File data not assigned. Bug ???! FileName = ', FileName]);
+ Exit;
+ end;
+ UpDir := PDataItem(AListView.Selected.Data)^.UpDir;
+
+ if not DataItem^.IsDir then begin
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := Format(LANGPopupRunS, [ANSIToUTF8(QuoteMarkupStr(ShortFName))]);
+ Item.StockIcon := 'gtk-execute';
+ Item.Data := Pointer(1);
+ Item.OnClick := FilePopupMenuItemClick;
+ Item.Enabled := Engine.FileCanRun(FileName);
+ FilePopupMenu.Add(Item);
+ end else begin
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ if UpDir then Item.Caption := LANGPopupGoUp
+ else Item.Caption := Format(LANGPopupOpenS, [ANSIToUTF8(QuoteMarkupStr(ShortFName))]);
+ Item.StockIcon := 'gtk-open';
+ Item.Data := Pointer(1);
+ Item.OnClick := FilePopupMenuItemClick;
+ FilePopupMenu.Add(Item);
+ end;
+
+ // Find actions for meta-item
+ if AssocList.Count > 0 then
+ for i := 0 to AssocList.Count - 1 do
+ if ((DataItem^.IsDir and (TFileAssoc(AssocList[i]).FileTypeName = ConstFTAMetaDirectory)) or
+ ((not DataItem^.IsDir) and (TFileAssoc(AssocList[i]).FileTypeName = ConstFTAMetaFile))) and
+ (TFileAssoc(AssocList[i]).ActionList.Count > 0) then
+ with TFileAssoc(AssocList[i]) do begin
+ FilePopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ for j := 0 to ActionList.Count - 1 do begin
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := Format(LANGPopupOpenWithS, [TAssocAction(ActionList[j]).ActionName]);
+ Item.Data := ActionList[j];
+ Item.OnClick := FilePopupMenuItemClick;
+ FilePopupMenu.Add(Item);
+ end;
+ Break;
+ end;
+ FilePopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+
+ // Find and add actions for this file type
+ Found := False;
+ if Pos('.', ShortFName) > 0 then begin
+ Ext := ANSIUpperCase(Trim(Copy(ShortFName, LastDelimiter('.', ShortFName) + 1, Length(ShortFName) - LastDelimiter('.', ShortFName))));
+ if AssocList.Count > 0 then
+ for i := 0 to AssocList.Count - 1 do
+ with TFileAssoc(AssocList[i]) do
+ if (ActionList.Count > 0) and (Length(Trim(Extensions)) > 0) then begin
+ b := False;
+ if Pos(';', Extensions) = 0 then b := ANSIUpperCase(Trim(Extensions)) = Ext else begin
+ Last := 0;
+ for j := 1 to Length(Extensions) do
+ if Extensions[j] = ';' then begin
+ if ANSIUpperCase(Trim(Copy(Extensions, Last + 1, j - Last - 1))) = Ext then begin
+ b := True;
+ Break;
+ end;
+ Last := j;
+ end;
+ if not b then b := ANSIUpperCase(Trim(Copy(Extensions, LastDelimiter(';', Extensions) + 1, Length(Extensions) - LastDelimiter(';', Extensions)))) = Ext;
+ end;
+ if b and (ActionList.Count > 0) then begin
+ Found := True;
+ for j := 0 to ActionList.Count - 1 do begin
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := Format(LANGPopupOpenWithS, [TAssocAction(ActionList[j]).ActionName]);
+ if ((j = 0) and (DefaultAction > ActionList.Count - 1)) or (j = DefaultAction) then
+ Item.Caption := Item.Caption + LANGPopupDefault;
+ Item.Data := ActionList[j];
+ Item.OnClick := FilePopupMenuItemClick;
+ FilePopupMenu.Add(Item);
+ end;
+ end;
+ end;
+ end;
+ if (not Found) and (not DataItem^.IsDir) then begin
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGPopupOpenWith;
+ Item.Data := Pointer(2);
+ Item.OnClick := FilePopupMenuItemClick;
+ FilePopupMenu.Add(Item);
+ end;
+
+ // Other items
+ if not DataItem^.IsDir then begin
+ FilePopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGPopupViewFile;
+ Item.StockIcon := 'gtk-find';
+ Item.Data := Pointer(200); // This number HAVE to be here due to F3F4ButtonClick method using
+ Item.OnClick := F3F4ButtonClick;
+ FilePopupMenu.Add(Item);
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGPopupEditFile;
+ Item.Data := Pointer(201); // Here too
+ Item.OnClick := F3F4ButtonClick;
+ FilePopupMenu.Add(Item);
+ end;
+ if not DataItem^.IsDir then FilePopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGPopupMakeSymlink;
+ Item.StockIcon := 'gtk-jump-to';
+ Item.OnClick := miCreateSymlinkClick;
+ FilePopupMenu.Add(Item);
+ if DataItem^.IsLnk then begin
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGmiEditSymlink_Caption;
+ Item.OnClick := miEditSymlinkClick;
+ FilePopupMenu.Add(Item);
+ end;
+ FilePopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGmiChangePermissions_Caption;
+ Item.StockIcon := 'gtk-convert';
+ Item.OnClick := miChangePermissionsClick;
+ Item.Enabled := not UpDir;
+ FilePopupMenu.Add(Item);
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGmiChangeOwner_Caption;
+ Item.OnClick := miChangeOwnerClick;
+ Item.Enabled := not UpDir;
+ FilePopupMenu.Add(Item);
+ FilePopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGPopupRename;
+ Item.OnClick := F6ButtonClick;
+ Item.Enabled := not UpDir;
+ FilePopupMenu.Add(Item);
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGPopupDelete;
+ Item.StockIcon := 'gtk-delete';
+ Item.OnClick := F8ButtonClick;
+ Item.Enabled := not UpDir;
+ FilePopupMenu.Add(Item);
+// FilePopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
+ Item := TGTKMenuItem.CreateTyped(Self, itImageText);
+ Item.Caption := LANGFilePopupMenu_Properties;
+ Item.StockIcon := 'gtk-properties';
+ Item.OnClick := miFilePropertiesClick;
+ Item.Enabled := False;
+ Item.Visible := False;
+// Item.Enabled := not UpDir;
+ FilePopupMenu.Add(Item);
+end;
+
+procedure TFMain.FilePopupMenuItemClick(Sender: TObject);
+var Engine: TPanelEngine;
+ DataItem: PDataItemSL;
+ AListView: TGTKListView;
+ FileName, ShortFName, s, APath: string;
+ Error: integer;
+ b: boolean;
+begin
+ try
+ InternalLock;
+ if (not Assigned(Sender)) or (not (Sender is TGTKMenuItem)) then begin
+ DebugMsg(['Error: Popup menuitem is invalid']);
+ end;
+ if LeftLastFocused then begin
+ Engine := LeftPanelEngine;
+ AListView := LeftListView;
+ end else begin
+ Engine := RightPanelEngine;
+ AListView := RightListView;
+ end;
+ FileName := IncludeTrailingPathDelimiter(Engine.Path);
+ if Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and (not PDataItem(AListView.Selected.Data)^.UpDir)
+ then FileName := FileName + PDataItem(AListView.Selected.Data)^.AName;
+ ShortFName := ExtractFileName(ExcludeTrailingPathDelimiter(FileName));
+ DataItem := Engine.GetFileInfoSL(FileName);
+ if not Assigned(DataItem) then begin
+ DebugMsg(['Error: File data not assigned. Bug ???! FileName = ', FileName]);
+ Exit;
+ end;
+ if ConfUseURI and ((Engine is TVFSEngine) and (not TVFSEngine(Engine).ArchiveMode))
+ then FileName := ExcludeTrailingPathDelimiter(Engine.GetPrefix) + FileName;
+
+ case Integer((Sender as TGTKMenuItem).Data) of
+ 1: if DataItem^.IsDir then ActivateItem(AListView.Selected.Index, False)
+ else begin
+ b := True;
+ if Engine is TVFSEngine then b := HandleRunFromArchive(FileName, Engine, '', '', False); // not a local engine, extract to local first
+ if b then begin
+ Libc.__chdir(PChar(ExtractFilePath(FileName)));
+ b := ExecuteProgram(QuoteStr(FileName), ExtractFilePath(FileName), True, False, Error);
+ Libc.__chdir(PChar('/'));
+ end else b := True; // Mask cancelled extraction from VFS
+ if not b then Application.MessageBox(LANGErrorExecutingCommand, [mbOK], mbError, mbNone, mbOK);
+ end;
+ 2: if Application.MessageBox(Format(LANGThereIsNoApplicationAssociatedWithS, [ANSIToUTF8(ShortFName)]), [mbYes, mbNo], mbQuestion, mbNone, mbNo) = mbYes
+ then miFileTypesClick(Self);
+ else begin
+ b := True;
+ s := TAssocAction((Sender as TGTKMenuItem).Data).ActionCommand;
+ if Engine is TVFSEngine then b := HandleRunFromArchive(FileName, Engine, s, '', False); // not a local engine, extract to local first
+ if Pos('%s', s) > 0 then s := Format(s, ['''' + QuoteStr(FileName) + ''''])
+ else s := Format('%s %s', [s, QuoteStr(FileName)]);
+ if b then begin
+ Libc.__chdir(PChar(ExtractFilePath(FileName)));
+ b := ExecuteProgram(s, ExtractFilePath(FileName), TAssocAction((Sender as TGTKMenuItem).Data).AutodetectGUI,
+ TAssocAction((Sender as TGTKMenuItem).Data).RunInTerminal, Error);
+ Libc.__chdir(PChar('/'));
+ end else b := True; // Mask cancelled extraction from VFS
+ if not b then Application.MessageBox(Format(LANGCannotExecuteSPleaseCheckTheConfiguration, [ANSIToUTF8(FileName)]), [mbOK], mbError, mbNone, mbOK);
+ end;
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalUnLock;
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.ListViewMouseUp(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+var AListView: TGTKListView;
+ i, FirstColumn, LastColumn: integer;
+ LeftLV, b: boolean;
+begin
+ if Button = mbLeft then begin
+ AListView := Sender as TGTKListView;
+ LeftLV := AListView = LeftListView;
+ GetFirstLastPanelColumn(FirstColumn, LastColumn);
+ b := True;
+ for i := 0 to AListView.Columns.Count - 1 do
+ if (AListView.Columns[i].Tag <> LastColumn) or (FirstColumn = LastColumn) then
+ b := b and (ConfColumnSizes[AListView.Columns[i].Tag] = AListView.Columns[i].Width);
+ if not b then begin
+ DebugMsg(['*** ListView Mouse Up -> resizing columns']);
+ for i := 0 to AListView.Columns.Count - 1 do
+ ConfColumnSizes[AListView.Columns[i].Tag] := AListView.Columns[i].Width;
+ if LeftLV then AListView := RightListView
+ else AListView := LeftListView;
+ // Change target widths
+ for i := 0 to AListView.Columns.Count - 1 do
+ if ConfColumnSizes[AListView.Columns[i].Tag] <> AListView.Columns[i].Width then
+ AListView.Columns[i].FixedWidth := ConfColumnSizes[AListView.Columns[i].Tag];
+ end;
+ end;
+end;
+
+procedure TFMain.ListViewColumnClicked(Sender: TObject);
+var ANotebook: TEphyNotebook;
+ AListView: TGTKListView;
+ LeftLV: boolean;
+begin
+ AListView := ((Sender as TGTKTreeViewColumn).Parent as TGTKTreeViewColumns).Parent as TGTKListView;
+ LeftLV := AListView = LeftListView;
+
+ // Check for sort change
+ if LeftLV then ANotebook := LeftPanelNotebook
+ else ANotebook := RightPanelNotebook;
+ try
+ if ANotebook.Visible then begin
+ DebugMsg(['*** ListView Mouse Up -> saving sort info to tab ', ANotebook.PageIndex, ', SortColumnID = ', AListView.SortColumnID]);
+ if LeftLV then begin
+ LeftTabSortIDs[ANotebook.PageIndex] := Pointer(AListView.SortColumnID);
+ LeftTabSortTypes[ANotebook.PageIndex] := Pointer(Integer(AListView.SortOrder));
+ end else begin
+ RightTabSortIDs[ANotebook.PageIndex] := Pointer(AListView.SortColumnID);
+ RightTabSortTypes[ANotebook.PageIndex] := Pointer(Integer(AListView.SortOrder));
+ end;
+ end;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TFMain.ListViewColumnClicked(', E.ClassName, '): ', E.Message]);
+ end;
+
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.miPreferencesClick(Sender: TObject);
+begin
+ try
+ InternalLock;
+ FPreferences := TFPreferences.Create(Self);
+ FPreferences.AssignDefaultValues;
+ if FPreferences.Run = mbOK then begin
+ FPreferences.SaveSettings;
+ WriteMainGUISettings;
+ ApplySettings(FPreferences.RebuildListViews, FPreferences.RebuildIcons, False);
+ end;
+ finally
+ FPreferences.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.ApplySettings(RebuildListViews, RebuildIcons, Startup: boolean);
+var i: integer;
+begin
+ InactiveItemsTimer.Enabled := False;
+
+ ButtonsBox.Visible := ConfShowFuncButtons;
+ ButtonBoxSeparator.Visible := ConfShowFuncButtons;
+ ButtonBoxSpace.Visible := not ConfShowFuncButtons;
+
+ // Rebuild Icons
+ if RebuildIcons then begin
+ if ConfRowHeight > 0 then ConfRowHeightReal := ConfRowHeight
+ else ConfRowHeightReal := ConfDefaultRowHeight;
+ FolderIcon.Free;
+ FileIcon.Free;
+ UpDirIcon.Free;
+ SymLinkEmblem.Free;
+ FolderIconLnk.Free;
+ FileIconLnk.Free;
+ LoadIcons;
+ RecreateIcons(AssocList, False);
+ end;
+
+ // Rebuild ListViews
+ if RebuildListViews then FMain.RebuildListViews(False);
+ InactiveItemsTimer.Enabled := False;
+
+ // Colors Section
+ SetupColors;
+ gtk_widget_modify_base(LeftListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKBackground);
+ gtk_widget_modify_base(RightListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKBackground);
+ gtk_widget_modify_base(LeftListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKBackground);
+ gtk_widget_modify_base(RightListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKBackground);
+// if Application.GTKVersion_2_6_0_Up then begin
+ gtk_widget_modify_base(LeftListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKBackground);
+ gtk_widget_modify_base(RightListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKBackground);
+
+ gtk_widget_modify_text(LeftListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKColor);
+ gtk_widget_modify_text(RightListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKColor);
+ gtk_widget_modify_text(LeftListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKColor);
+ gtk_widget_modify_text(RightListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKColor);
+ gtk_widget_modify_text(LeftListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKColor);
+ gtk_widget_modify_text(RightListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKColor);
+// end;
+
+ // Resize commandline history
+ if ConfNumHistoryItems < CommandLineHistory.Count then begin
+ try
+ for i := CommandLineHistory.Count downto ConfNumHistoryItems + 1 do
+ CommandLineHistory.Delete(i - 1);
+ if CommandLineCombo.Items.Count > 0 then
+ for i := CommandLineCombo.Items.Count - 1 downto 0 do
+ CommandLineCombo.Items.Delete(i);
+ if CommandLineHistory.Count > 0 then
+ for i := 0 to CommandLineHistory.Count - 1 do
+ CommandLineCombo.Items.Append(CommandLineHistory[i]);
+ except end;
+ CommandLineCombo.Entry.Text := '';
+ end;
+
+ // Refresh the lists
+ if not Startup then begin
+ DoRefresh(True, True, True);
+ DoRefresh(False, True, True);
+ if RebuildListViews then begin
+ LeftListView.SetSortInfo(ConfMainWindowLeftSortColumn, TGTKTreeViewSortOrder(ConfMainWindowLeftSortType));
+ RightListView.SetSortInfo(ConfMainWindowRightSortColumn, TGTKTreeViewSortOrder(ConfMainWindowRightSortType));
+ end;
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.RefreshBookmarksMenu;
+const ShortcutKeys = '1234567890';
+var i: integer;
+ Item: TGTKMenuItem;
+begin
+ if mnuBookmarks.Count > 4 then
+ for i := mnuBookmarks.Count - 1 downto 4 do begin
+ mnuBookmarks.Items[i].Free;
+ mnuBookmarks.Delete(i);
+ end;
+ miAddBookmark.Visible := True;
+ miEditBookmarks.Visible := False;
+ miBookmarksSeparator.Visible := False;
+
+ if Bookmarks.Count > 0 then begin
+ miBookmarksSeparator.Visible := True;
+ for i := 0 to Bookmarks.Count - 1 do begin
+ Item := TGTKMenuItem.CreateTyped(Self, itLabel);
+ Item.Caption := Format('_%s %s', [Chr(Ord('a') + i), ANSIToUTF8(QuoteMarkupStr(Bookmarks[i]))]);
+ Item.Data := Pointer(i);
+ Item.OnClick := miBookmarkClick;
+ Item.OnMouseUp := BookmarkItemMouseUp;
+ if i < Length(ShortcutKeys) - 1 then Item.ShortCuts.AddName(Format('<Alt>%s', [ShortcutKeys[i + 1]]));
+ mnuBookmarks.Add(Item);
+ end;
+ end;
+end;
+
+procedure TFMain.miAddBookmarkClick(Sender: TObject);
+var LeftPanel: boolean;
+ s: string;
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then s := LeftPanelEngine.Path
+ else s := RightPanelEngine.Path;
+ s := ExcludeTrailingPathDelimiter(s);
+ if Bookmarks.IndexOf(s) > -1 then begin
+ Application.MessageBox(LANGTheCurrentDirectoryAlreadyExistsInTheBookmarksList, [mbOK], mbError);
+ Exit;
+ end;
+ Bookmarks.Add(s);
+ WriteBookmarks;
+ RefreshBookmarksMenu;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.miBookmarkClick(Sender: TObject);
+var LeftPanel: boolean;
+begin
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+
+ // Close VFS connections
+ if LeftPanel then while (LeftPanelEngine is TVFSEngine) do CloseVFS(LeftPanel, True)
+ else while (RightPanelEngine is TVFSEngine) do CloseVFS(LeftPanel, True);
+
+ ChangingDir(LeftPanel, Bookmarks[Integer((Sender as TGTKMenuItem).Data)]);
+end;
+
+procedure TFMain.BookmarkPopupDeleteClick(Sender: TObject);
+begin
+ try
+ Bookmarks.Delete(Integer((Sender as TGTKMenuItem).Data));
+ WriteBookmarks;
+ RefreshBookmarksMenu;
+ except
+ on E: Exception do
+ DebugMsg(['*** Error deleting item: ', E.Message]);
+ end;
+end;
+
+procedure TFMain.BookmarkItemMouseUp(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+begin
+ if Button = mbRight then begin
+ Accept := False;
+ BookmarkPopup.PopUp;
+ BookmarkPopupDelete.Data := (Sender as TGTKMenuItem).Data;
+ end;
+end;
+
+(********************************************************************************************************************************)
+function form_event_handler(widget: PGtkWidget; event: PGdkEvent; user_data: gpointer): gboolean; cdecl;
+begin
+ Result := False;
+ if event^._type = GDK_FOCUS_CHANGE then
+ if event^.focus_change._in = 1 then FMain.HandleFormFocusIn
+ else FileListTipsHide;
+end;
+
+procedure TFMain.HandleFormFocusIn;
+var ChangedMainGUI, ChangedAssoc, ChangedBookmarks, ChangedMounter, ChangedConnMgr, APerformRefresh: boolean;
+begin
+ try
+ if (csDestroying in ComponentState) or (not Assigned(FMain)) then Exit;
+ if InternalLockUnlocked then begin
+ APerformRefresh := ConfFocusRefresh;
+
+ if CheckConfFilesMod(ChangedMainGUI, ChangedAssoc, ChangedBookmarks, ChangedMounter, ChangedConnMgr) then begin
+ if ChangedBookmarks then begin
+ DebugMsg(['Bookmark file changed ---> performing refresh']);
+ ReadBookmarks;
+ RefreshBookmarksMenu;
+ end;
+ if ChangedConnMgr then begin
+ DebugMsg(['Connection manager file changed ---> performing refresh']);
+ ReadConnections;
+ end;
+ try
+ InternalLock;
+ if (ChangedMainGUI or ChangedAssoc or ChangedMounter) and (Application.MessageBox(LANGSomeOtherInstanceChanged,
+ [mbYes, mbNo], mbWarning) = mbNo) then Exit;
+ if ChangedMounter then begin
+ DebugMsg(['Mounter file changed ---> performing refresh']);
+ ReadMounter;
+ FillMounterBar;
+ end;
+ if ChangedMainGUI then begin
+ DebugMsg(['GUI file changed ---> performing refresh']);
+ ReadMainGUISettings;
+ ApplySettings(True, True, False);
+ APerformRefresh := True;
+ end;
+ if ChangedAssoc then begin
+ DebugMsg(['Assoc file changed ---> performing refresh']);
+ ReadAssoc;
+ LoadIcons;
+ RemoveIconRefs(AssocList, False);
+ RecreateIcons(AssocList);
+ APerformRefresh := True;
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+ end;
+ if APerformRefresh then begin
+ DebugMsg(['ANN: Form Focus ---> refresh']);
+ DoRefresh(True, True, True);
+ DoRefresh(False, True, True);
+ if ConfFocusRefresh and ParamDebug then Beep;
+ end;
+ end;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TFMain.HandleFormFocusIn (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+(********************************************************************************************************************************)
+function Max(Int1, Int2: integer): integer;
+begin
+ if Int1 > Int2 then Result := Int1
+ else Result := Int2;
+end;
+
+procedure menu_position_cb(menu: PGtkMenu; x, y: Pgint; push_in: pgboolean; user_data: gpointer); cdecl;
+var menu_requisition: TGtkRequisition;
+ max_x, max_y: integer;
+begin
+ (* Calculate our preferred position. *)
+ gdk_window_get_origin(PGtkWidget(user_data).Window, x, y);
+ x^ := x^ + PGtkWidget(user_data).allocation.x + PGtkWidget(user_data).allocation.width;
+ y^ := y^ + PGtkWidget(user_data).allocation.y + PGtkWidget(user_data).allocation.height;
+
+ (* Now make sure we are on the screen. *)
+ gtk_widget_size_request(PGtkWidget(menu), @menu_requisition);
+ max_x := Max(0, gdk_screen_width () - menu_requisition.width);
+ max_y := Max(0, gdk_screen_height () - menu_requisition.height);
+ x^ := x^ - menu_requisition.width;
+
+ x^ := CLAMP(x^, 0, max_x);
+ y^ := CLAMP(y^, 0, max_y);
+end;
+
+procedure TFMain.BookmarkButtonClick(Sender: TObject);
+begin
+ miAddBookmark.Visible := True;
+ miEditBookmarks.Visible := False;
+ miBookmarksSeparator.Visible := mnuBookmarks.Count > 3;
+ gtk_menu_popup(PGtkMenu(mnuBookmarks.FMenu), nil, nil, menu_position_cb, (Sender as TGTKControl).FWidget, 1, GDK_CURRENT_TIME);
+ if (Sender = LeftBookmarkButton) {and (not LeftLastFocused)} then LeftListView.SetFocus else
+ if (Sender = RightBookmarkButton) {and LeftLastFocused} then RightListView.SetFocus;
+end;
+
+(********************************************************************************************************************************)
+procedure file_popup_position_cb(menu: PGtkMenu; x, y: Pgint; push_in: pgboolean; user_data: gpointer); cdecl;
+var menu_requisition: TGtkRequisition;
+ max_x, max_y: integer;
+ TreePath: PGtkTreePath;
+ Iter: TGtkTreeIter;
+ Rect: TGdkRectangle;
+ TreeView: PGtkTreeView;
+begin
+ TreeView := PGtkTreeView(TGTKListView(user_data).FWidget);
+ if not gtk_tree_selection_get_selected(gtk_tree_view_get_selection(TreeView), nil, @Iter) then Exit;
+ TreePath := gtk_tree_model_get_path(gtk_tree_view_get_model(TreeView), @iter);
+ if not Assigned(TreePath) then Exit;
+ gtk_tree_view_get_background_area(TreeView, TreePath, nil, @Rect);
+
+ gdk_window_get_origin(gtk_tree_view_get_bin_window(TreeView), x, y);
+ y^ := y^ + Rect.y + Rect.height;
+
+ gtk_widget_size_request(PGtkWidget(menu), @menu_requisition);
+ if y^ > gdk_screen_height - menu_requisition.height then begin
+ gdk_window_get_origin(gtk_tree_view_get_bin_window(TreeView), x, y);
+ y^ := y^ + Rect.y - menu_requisition.height;
+ end;
+
+ max_x := Max(0, gdk_screen_width () - menu_requisition.width);
+ max_y := Max(0, gdk_screen_height () - menu_requisition.height);
+
+ x^ := CLAMP(x^, 0, max_x);
+ y^ := CLAMP(y^, 0, max_y);
+end;
+
+procedure TFMain.PopupFileMenuPos;
+var AListView: TGTKListView;
+ LeftPanel: boolean;
+begin
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then AListView := LeftListView
+ else AListView := RightListView;
+ FilePopupMenuPopup(AListView);
+ if not Application.GTKVersion_2_0_5_Up then FilePopupMenu.PopUp else
+ gtk_menu_popup(PGtkMenu(FilePopupMenu.FMenu), nil, nil, file_popup_position_cb, AListView, 0, gtk_get_current_event_time());
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.miShowDirectorySizesClick(Sender: TObject);
+begin
+ DoGetDirSize(True);
+end;
+
+procedure TFMain.miTargetSourceClick(Sender: TObject);
+begin
+ if Sender = LeftEqualButton then SwitchOtherPanel(True, True) else
+ if Sender = RightEqualButton then SwitchOtherPanel(False, True) else
+ SwitchOtherPanel(LeftLastFocused, True);
+end;
+
+procedure TFMain.SwitchPanelCtrlLeftRight(LeftPanel, LeftArrowPressed: boolean);
+var AListView: TGTKListView;
+ SrcEngine, OrigSrcEngine, TargetEngine: TPanelEngine;
+ s: string;
+ DontShowAgain: boolean;
+begin
+ if LeftPanel then begin
+ AListView := LeftListView;
+ SrcEngine := LeftPanelEngine;
+ TargetEngine := RightPanelEngine;
+ end else begin
+ AListView := RightListView;
+ SrcEngine := RightPanelEngine;
+ TargetEngine := LeftPanelEngine;
+ end;
+ OrigSrcEngine := SrcEngine;
+
+ if ((not (SrcEngine is TLocalTreeEngine)) and (LeftPanel <> LeftArrowPressed)) or
+ ((not (TargetEngine is TLocalTreeEngine)) and (LeftPanel = LeftArrowPressed)) then
+ begin
+ if ConfSwitchOtherPanelBehaviour < 0 then begin
+ MessageBoxShowOnce(LANGSwitchOtherPanelWarning, LANGDontShowAgain, DontShowAgain, [mbOK], mbWarning, mbOK, mbOK);
+ if DontShowAgain then begin
+ ConfSwitchOtherPanelBehaviour := 1;
+ WriteMainGUISettings;
+ end;
+ end;
+ end;
+
+ // don't change dir in VFS engines
+ while not (SrcEngine is TLocalTreeEngine) do SrcEngine := SrcEngine.ParentEngine;
+ while not (TargetEngine is TLocalTreeEngine) do TargetEngine := TargetEngine.ParentEngine;
+
+ if LeftPanel <> LeftArrowPressed then begin
+ s := ExcludeTrailingPathDelimiter(SrcEngine.Path);
+ if (OrigSrcEngine = SrcEngine) and Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and
+ (not PDataItem(AListView.Selected.Data)^.UpDir) and PDataItem(AListView.Selected.Data)^.IsDir
+ then s := IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(s) + PDataItem(AListView.Selected.Data)^.AName);
+ if IncludeTrailingPathDelimiter(TargetEngine.Path) <> s then begin
+ if LeftPanel then RightPanelEngine := TargetEngine
+ else LeftPanelEngine := TargetEngine;
+ ChangingDir(not LeftPanel, s);
+ end;
+ end else begin
+ // Close opened VFS engines
+ if LeftPanel then begin
+ while (LeftPanelEngine is TVFSEngine) do CloseVFS(LeftPanel, True);
+ end else
+ while (RightPanelEngine is TVFSEngine) do CloseVFS(LeftPanel, True);
+ ChangingDir(LeftPanel, TargetEngine.Path);
+ end;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.FillMounterBar;
+
+ procedure ClearButtons(List: TList; Table: TGTKTable);
+ var i: integer;
+ begin
+ if List.Count > 0 then
+ for i := List.Count - 1 downto 0 do
+ Table.RemoveControl(TGTKControl(List[i]));
+ List.Clear;
+ end;
+
+ procedure FillTableButtons(List: TList; Table: TGTKTable);
+ var i: integer;
+ Button: TGTKButton;
+ Pixmap: TGDKPixbuf;
+ b: boolean;
+ Sep: TGTKVSeparator;
+ begin
+ if MounterList.Count > 0 then
+ for i := 0 to MounterList.Count - 1 do
+ with TMounterItem(MounterList[i]) do begin
+ if ConfMounterPushDown then begin
+ Button := TGTKImageToggleButton.Create(Self);
+ if Length(DisplayText) > 0 then (Button as TGTKImageToggleButton).Caption := DisplayText else
+ (Button as TGTKImageToggleButton).Caption := Copy(MountPath, LastDelimiter(PathDelim, ExcludeTrailingPathDelimiter(MountPath)) + 1,
+ Length(ExcludeTrailingPathDelimiter(MountPath)) - LastDelimiter(PathDelim, ExcludeTrailingPathDelimiter(MountPath)));
+ end else begin
+ Button := TGTKImageButton.Create(Self);
+ if Length(DisplayText) > 0 then (Button as TGTKImageButton).Caption := DisplayText else
+ (Button as TGTKImageButton).Caption := Copy(MountPath, LastDelimiter(PathDelim, ExcludeTrailingPathDelimiter(MountPath)) + 1,
+ Length(ExcludeTrailingPathDelimiter(MountPath)) - LastDelimiter(PathDelim, ExcludeTrailingPathDelimiter(MountPath)));
+ end;
+ Button.CanFocus := False;
+// DebugMsg(['Int64(MounterList[i]) = ', Int64(MounterList[i])]);
+// DebugMsg(['Integer(MounterList[i]) = ', Integer(MounterList[i])]);
+{$IFDEF CPU64}
+ Button.Tag := QWORD(MounterList[i]);
+{$ELSE}
+ Button.Tag := Longint(MounterList[i]);
+{$ENDIF}
+ Button.Tooltip := Format(LANGMountPointDevice, [ANSIToUTF8(MountPath), ANSIToUTF8(Device)]);
+ Button.BorderStyle := bsNone;
+ Button.PopupMenu := MounterButtonPopupMenu;
+ Button.OnMouseDown := MounterButtonMouseDown;
+
+ // Check the icon
+ b := FileExists(IconPath);
+ Pixmap := nil;
+ if b then begin
+ Pixmap := TGDKPixbuf.Create(Self);
+ Pixmap.LoadFromFile(IconPath);
+ b := Pixmap.FPixbuf <> nil;
+ if b then Pixmap.ScaleSimple(16, 16);
+ end;
+ if not b then
+ case DeviceType of
+ 0 : Pixmap := MounterHDD;
+ 1 : Pixmap := MounterRemovable;
+ 2 : Pixmap := MounterCD;
+ 3 : Pixmap := MounterFloppy;
+ 4 : Pixmap := MounterNetwork;
+ end;
+ if ConfMounterPushDown then begin
+ (Button as TGTKImageToggleButton).Icon := Pixmap;
+ (Button as TGTKImageToggleButton).Checked := Mounted;
+ end else (Button as TGTKImageButton).Icon := Pixmap;
+
+ Button.OnClick := MounterButtonClick; // It has to be here because setting the Checked property causes the signal emitting
+
+ Table.AddControlEx(2*i + 1, 0, 1, 1, Button, [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 0, 1);
+ List.Add(Button);
+ if i < MounterList.Count - 1 then begin
+ Sep := TGTKVSeparator.Create(Self);
+ Table.AddControlEx(2*(i + 1), 0, 1, 1, Sep, [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 2, 6);
+ List.Add(Sep);
+ end;
+ end;
+ end;
+
+
+var Lab: TGTKLabel;
+begin
+ if ConfMounterUseFSTab then FillDefaultFstabMounterItems;
+
+ // Clean all items
+ ClearButtons(MounterTableList, MounterBarTable);
+ ClearButtons(MounterTableListLeft, LeftMounterTable);
+ ClearButtons(MounterTableListRight, RightMounterTable);
+
+ // Fill the new items
+ Lab := TGTKLabel.Create(Self);
+ Lab.Caption := Format('<span weight="bold">%s</span>', [LANGMountSC]);
+ Lab.UseMarkup := True;
+ MounterTableList.Add(Lab);
+ MounterBarTable.AddControlEx(0, 0, 1, 1, Lab, [taoShrink, taoFill], [taoShrink, taoExpand, taoFill], 5, 1);
+ case ConfShowMounterBar of
+ 1: FillTableButtons(MounterTableList, MounterBarTable);
+ 2: begin
+ FillTableButtons(MounterTableListLeft, LeftMounterTable);
+ FillTableButtons(MounterTableListRight, RightMounterTable);
+ end;
+ end;
+end;
+
+procedure TFMain.MounterButtonClick(Sender: TObject);
+var Item: TMounterItem;
+ LeftPanel, b: boolean;
+ Engine: TPanelEngine;
+begin
+ if not (Sender is TGTKButton) then Exit;
+ try
+ Item := Pointer((Sender as TGTKButton).Tag);
+ if (not Assigned(Item)) or (Item.MountPath = '') then DebugMsg(['*** Error in mounter button: incorrect data']) else begin
+ if MounterTableListLeft.IndexOf(Sender) > -1 then LeftPanel := True else
+ if MounterTableListRight.IndexOf(Sender) > -1 then LeftPanel := False else LeftPanel := LeftLastFocused;
+ if LeftPanel then Engine := LeftPanelEngine
+ else Engine := RightPanelEngine;
+ try
+ b := Item.Mounted;
+ except
+ b := False;
+ end;
+
+ if ConfMounterPushDown then begin
+ if not b then b := Item.Mount else
+ if Pos(Item.MountPath, Engine.Path) = 1 then b := Item.Eject;
+ (Sender as TGTKToggleButton).OnClick := nil;
+ (Sender as TGTKToggleButton).Checked := Item.Mounted;
+ (Sender as TGTKToggleButton).OnClick := MounterButtonClick;
+ end else if not b then b := Item.Mount;
+
+ if b then begin
+ if Engine is TVFSEngine then CloseVFS(LeftPanel, True);
+ ChangingDir(LeftPanel, Item.MountPath);
+ DoRefresh(LeftPanel, True, True);
+ end;
+ if LeftPanel then LeftListView.SetFocus
+ else RightListView.SetFocus;
+ end;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in FMain.MounterButtonClick: (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+procedure TFMain.MounterButtonPopupMenuPopup(Sender: TObject);
+begin
+// DebugMsg(['aaaa']);
+ try
+// DebugMsg(['aaaa']);
+ if (not Assigned(LastMounterButton)) or (LastMounterButton.Tag = 0) then begin
+// DebugMsg(['aaaa']);
+ MounterButtonPopupMenu.PopDown;
+// DebugMsg(['aaaa']);
+ Exit;
+ end;
+// DebugMsg(['aaaaX']);
+// DebugMsg(['sizeof(LastMounterButton.Tag) = ', sizeof(LastMounterButton.Tag)]);
+// DebugMsg(['LastMounterButton.Tag = ', Int64(LastMounterButton.Tag)]);
+// DebugMsg(['TMounterItem(Pointer(QWord(LastMounterButton.Tag))).Device = ', TMounterItem(Pointer(QWord(LastMounterButton.Tag))).Device]);
+
+// DebugMsg(['TMounterItem(LastMounterButton.Tag).ClassName = ', TMounterItem(LastMounterButton.Tag).ClassName]);
+
+ miMount.Enabled := not TMounterItem(LastMounterButton.Tag).Mounted;
+// DebugMsg(['aaaaX']);
+ miUmount.Enabled := not miMount.Enabled;
+// DebugMsg(['aaaaX']);
+ miEject.Enabled := not miMount.Enabled;
+ except
+ on E: Exception do begin
+ DebugMsg(['*** Exception raised in FMain.MounterButtonClick: (', E.ClassName, '): ', E.Message]);
+ MounterButtonPopupMenu.PopDown;
+ end;
+ end;
+end;
+
+procedure TFMain.MounterButtonMouseDown(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
+begin
+ LastMounterButton := nil;
+ if (not (Sender is TGTKButton)) or ((Sender as TGTKButton).Tag = 0) then Exit;
+ LastMounterButton := Sender as TGTKButton;
+end;
+
+procedure TFMain.miMountClick(Sender: TObject);
+begin
+ if Assigned(LastMounterButton) then TMounterItem(LastMounterButton.Tag).Mount;
+ DoRefresh(LeftLastFocused, True, True);
+ DoRefresh(not LeftLastFocused, True, True);
+ if ConfMounterPushDown then begin
+ (LastMounterButton as TGTKToggleButton).OnClick := nil;
+ (LastMounterButton as TGTKToggleButton).Checked := TMounterItem(LastMounterButton.Tag).Mounted;
+ (LastMounterButton as TGTKToggleButton).OnClick := MounterButtonClick;
+ end;
+end;
+
+procedure TFMain.miUmountClick(Sender: TObject);
+begin
+ if Assigned(LastMounterButton) then TMounterItem(LastMounterButton.Tag).Umount;
+ DoRefresh(LeftLastFocused, True, True);
+ DoRefresh(not LeftLastFocused, True, True);
+ if ConfMounterPushDown then begin
+ (LastMounterButton as TGTKToggleButton).OnClick := nil;
+ (LastMounterButton as TGTKToggleButton).Checked := TMounterItem(LastMounterButton.Tag).Mounted;
+ (LastMounterButton as TGTKToggleButton).OnClick := MounterButtonClick;
+ end;
+end;
+
+procedure TFMain.miEjectClick(Sender: TObject);
+begin
+ if Assigned(LastMounterButton) then TMounterItem(LastMounterButton.Tag).Eject;
+ DoRefresh(LeftLastFocused, True, True);
+ DoRefresh(not LeftLastFocused, True, True);
+ if ConfMounterPushDown then begin
+ (LastMounterButton as TGTKToggleButton).OnClick := nil;
+ (LastMounterButton as TGTKToggleButton).Checked := TMounterItem(LastMounterButton.Tag).Mounted;
+ (LastMounterButton as TGTKToggleButton).OnClick := MounterButtonClick;
+ end;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.miMounterSettingsClick(Sender: TObject);
+var x: TList;
+begin
+ try
+ InternalLock;
+ FMounterPrefs := TFMounterPrefs.Create(Self);
+ ReadMounter;
+ FMounterPrefs.AssignAssocList(MounterList);
+ FMounterPrefs.FillList;
+ if FMounterPrefs.Run = mbOK then begin
+ FMounterPrefs.CleanItems;
+ x := MounterList;
+ MounterList := FMounterPrefs.InternalMounterList;
+ FMounterPrefs.InternalMounterList := x;
+ ConfMounterUseFSTab := FMounterPrefs.UseFSTabDefaultsCheckBox.Checked;
+ ConfMounterPushDown := FMounterPrefs.ToggleModeCheckBox.Checked;
+ WriteMounter;
+ FillMounterBar;
+ end;
+ finally
+ FMounterPrefs.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.miShowMounterBarClick(Sender: TObject);
+begin
+ if miShowOneMounterBar.Checked then ConfShowMounterBar := 1 else
+ if miShowTwoMounterBar.Checked then ConfShowMounterBar := 2 else ConfShowMounterBar := 0;
+ MounterBarHandleBox.Visible := ConfShowMounterBar = 1;
+ LeftMounterTable.Visible := ConfShowMounterBar = 2;
+ RightMounterTable.Visible := ConfShowMounterBar = 2;
+ FillMounterBar;
+end;
+
+procedure TFMain.miColumnsClick(Sender: TObject);
+begin
+ try
+ InternalLock;
+ FColumns := TFColumns.Create(Self);
+// FColumns.Show;
+ if FColumns.Run = mbOK then begin
+ FColumns.ApplyColumnList;
+ RebuildListViews(True);
+ end;
+ finally
+ FColumns.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.ListViewColumnsChanged(Sender: TObject);
+var SourceListView: TGTKListView;
+ i, j, k, ColIdx, ColumnID: integer;
+ Column: PGtkTreeViewColumn;
+ TempIDs, TempArrayI: array[1..ConstNumPanelColumns] of integer;
+ TempArrayB: array[1..ConstNumPanelColumns] of boolean;
+begin
+ DebugMsg(['*** Columns reordered ---> performing listview rebuild']);
+ LeftListView.OnMouseUp := nil;
+ RightListView.OnMouseUp := nil;
+ LeftListView.OnColumnsChanged := nil;
+ RightListView.OnColumnsChanged := nil;
+ SourceListView := Sender as TGTKListView;
+
+ // Copy the old items
+ for i := 1 to ConstNumPanelColumns do begin
+ TempIDs[i] := ConfColumnIDs[i];
+ TempArrayI[i] := ConfColumnSizes[i];
+ TempArrayB[i] := ConfColumnVisible[i];
+ end;
+
+ ColIdx := 1;
+ // Search for moved columns
+ for i := 0 to SourceListView.Columns.Count - 1 do begin
+ Column := gtk_tree_view_get_column(PGtkTreeView(SourceListView.FWidget), i);
+ ColumnID := ColumnSortIDs[gtk_tree_view_column_get_sort_column_id(column) + 1];
+ for j := ColIdx to ConstNumPanelColumns do
+ if TempArrayB[j] then begin
+ for k := 1 to ConstNumPanelColumns do
+ if ColumnID = TempIDs[k] then begin
+ DebugMsg(['moving from ', k, ' to ', j]);
+ ConfColumnIDs[j] := TempIDs[k];
+ ConfColumnSizes[j] := TempArrayI[k];
+ ConfColumnVisible[j] := TempArrayB[k];
+ Break;
+ end;
+ ColIdx := j + 1;
+ Break;
+ end;
+ end;
+
+ RebuildListViewsTimer.Interval := 100;
+ RebuildListViewsTimer.Enabled := True;
+end;
+
+procedure TFMain.RebuildListViews(DoRefresh: boolean);
+begin
+ LeftListView.OnColumnsChanged := nil;
+ RightListView.OnColumnsChanged := nil;
+ ConfMainWindowLeftSortColumn := LeftListView.SortColumnID;
+ ConfMainWindowLeftSortType := Integer(LeftListView.SortOrder);
+ ConfMainWindowRightSortColumn := RightListView.SortColumnID;
+ ConfMainWindowRightSortType := Integer(RightListView.SortOrder);
+ LeftListView.Items.Clear;
+ RightListView.Items.Clear;
+ LeftListView.Columns.Clear;
+ RightListView.Columns.Clear;
+ ConstructColumns(LeftListView);
+ ConstructColumns(RightListView);
+ InactiveItemsTimer.Enabled := False;
+ if DoRefresh then begin
+ FMain.DoRefresh(True, True, True);
+ FMain.DoRefresh(False, True, True);
+ LeftListView.SetSortInfo(ConfMainWindowLeftSortColumn, TGTKTreeViewSortOrder(ConfMainWindowLeftSortType));
+ RightListView.SetSortInfo(ConfMainWindowRightSortColumn, TGTKTreeViewSortOrder(ConfMainWindowRightSortType));
+ end;
+ LeftListView.OnColumnsChanged := ListViewColumnsChanged;
+ RightListView.OnColumnsChanged := ListViewColumnsChanged;
+end;
+
+procedure TFMain.RebuildListViewsTimerTimer(Sender: TObject);
+begin
+ RebuildListViewsTimer.Enabled := False;
+ RebuildListViews(True);
+ LeftListView.OnMouseUp := ListViewMouseUp;
+ RightListView.OnMouseUp := ListViewMouseUp;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.FillPluginMenu;
+var i: integer;
+ MenuItem1, MenuItem2: TGTKMenuItem;
+begin
+ if PluginList.Count = 0 then begin
+ MenuItem1 := TGTKMenuItem.CreateTyped(Self, itLabel);
+ MenuItem1.Caption := LANGNoPluginsFound;
+ MenuItem1.Enabled := False;
+ mnuPlugins.Add(MenuItem1);
+ end else
+ for i := 0 to PluginList.Count - 1 do begin
+ MenuItem1 := TGTKMenuItem.CreateTyped(Self, itImageText);
+ MenuItem1.Caption := ANSIToUTF8(TVFSPlugin(PluginList[i]).VFSName);
+ MenuItem2 := TGTKMenuItem.CreateTyped(Self, itImageText);
+ MenuItem2.Caption := LANGPluginAbout;
+ MenuItem2.Tag := i;
+ MenuItem2.OnClick := miPluginAboutClick;
+ mnuPlugins.Add(MenuItem1);
+ MenuItem1.Add(MenuItem2);
+ end;
+end;
+
+procedure TFMain.miTestPluginClick(Sender: TObject);
+var Engine: TVFSEngine;
+ b: boolean;
+begin
+ try
+ InternalLock;
+ FTestPlugin := TFTestPlugin.Create(Self);
+ if (FTestPlugin.Run = mbOK) and (PluginList.Count > 0) then begin
+ Engine := TVFSEngine.Create(PluginList[FTestPlugin.PluginOptionMenu.ItemIndex]);
+ if not Engine.VFSOpenURI(UTF8ToANSI(FTestPlugin.CommandEntry.Text)) then begin
+ Application.MessageBox(LANGCouldntOpenURI, [mbOK], mbError, mbOK, mbOK);
+ Exit;
+ end;
+ b := True;
+ if not FTestPlugin.AnonymousCheckButton.Checked then
+ b := HandleLogin(FTestPlugin, Engine, FTestPlugin.UserEntry.Text, FTestPlugin.PasswordEntry.Text);
+ if b then begin
+ if LeftLastFocused then LeftPanelEngine := Engine
+ else RightPanelEngine := Engine;
+ DoRefresh(LeftLastFocused, False, False);
+ end;
+ end;
+ finally
+ FTestPlugin.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.miPluginAboutClick(Sender: TObject);
+const Authors : array[0..1] of PChar = ('', nil);
+var AboutBox: PGtkWidget;
+ VFSItem: TVFSPlugin;
+begin
+ VFSItem := PluginList[(Sender as TGTKMenuItem).Tag];
+ InternalLock;
+ if (libGnomeUI2Handle = nil) or (@gnome_about_new = nil) then
+ Application.MessageBox(Format(LANGPluginAboutInside, [VFSItem.VFSName, VFSItem.VFSAbout, VFSItem.VFSCopyright]))
+ else begin
+ AboutBox := gnome_about_new(VFSItem.VFSName, nil, VFSItem.VFSCopyright, VFSItem.VFSAbout, @Authors, nil, nil, nil);
+ gtk_window_set_transient_for(GTK_WINDOW(AboutBox), GTK_WINDOW(FMain.FWidget));
+ gtk_dialog_run(GTK_DIALOG(AboutBox));
+ end;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+end;
+
+procedure TFMain.miSavePositionClick(Sender: TObject);
+begin
+ WriteMainSettings;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.NewTabInternal(LeftPanel: boolean; _Engine: TPanelEngine; _Path: string; NewTabPosition: integer);
+var AListView: TGTKListView;
+ AEngine: TPanelEngine;
+ ANotebook: TEphyNotebook;
+ ATabList: TStringList;
+ AVBoxList: TList;
+ APath, APathSave: string;
+ VBox: TGTKVBox;
+ DockedToNotebook: boolean;
+ PathsHighlight: TStringList;
+ TabEngines: TList;
+ TabSortIDs: TList;
+ TabSortTypes: TList;
+ i, InsertPos: integer;
+begin
+ if LeftPanel then begin
+ AListView := LeftListView;
+ AEngine := LeftPanelEngine;
+ ANotebook := LeftPanelNotebook;
+ ATabList := LeftPanelTabs;
+ AVBoxList := LeftNotebookBoxList;
+ PathsHighlight := LeftPathsHighlight;
+ TabEngines := LeftTabEngines;
+ TabSortIDs := LeftTabSortIDs;
+ TabSortTypes := LeftTabSortTypes;
+ end else begin
+ AListView := RightListView;
+ AEngine := RightPanelEngine;
+ ANotebook := RightPanelNotebook;
+ ATabList := RightPanelTabs;
+ AVBoxList := RightNotebookBoxList;
+ PathsHighlight := RightPathsHighlight;
+ TabEngines := RightTabEngines;
+ TabSortIDs := RightTabSortIDs;
+ TabSortTypes := RightTabSortTypes;
+ end;
+
+ DockedToNotebook := ANotebook.Visible;
+
+ VBox := nil;
+ for i := 0 to 0 + Ord(not DockedToNotebook) do begin
+ InsertPos := 0;
+ if (i = 1) or DockedToNotebook then begin
+ APath := _Path;
+ AEngine := _Engine;
+ InsertPos := NewTabPosition;
+ if (i = 1) and (InsertPos > 1) then InsertPos := 1;
+ end else APath := AEngine.Path;
+
+ ATabList.Insert(InsertPos, APath);
+ APath := ExtractFileName(ExcludeTrailingPathDelimiter(APath));
+ if APath = '' then APath := '/';
+ if i = 0 then APathSave := APath;
+ VBox := TGTKVBox.Create(Self);
+ AVBoxList.Insert(InsertPos, VBox);
+ PathsHighlight.Insert(InsertPos, PDataItem(AListView.Selected.Data)^.AName);
+ TabSortIDs.Insert(InsertPos, Pointer(AListView.SortColumnID));
+ TabSortTypes.Insert(InsertPos, Pointer(Integer(AListView.SortOrder)));
+ TabEngines.Insert(InsertPos, AEngine);
+ end;
+
+ if not DockedToNotebook then begin
+ ANotebook.InsertPage(0, AVBoxList[0], APathSave);
+ SetTabLabel(ANotebook, 0, APathSave, ATabList[0]);
+ end;
+
+ InsertPos := NewTabPosition;
+ if InsertPos > ATabList.Count then InsertPos := ATabList.Count;
+ if not ANotebook.Visible then ANotebook.Visible := True;
+ i := ANotebook.InsertPage(InsertPos, VBox, APath);
+ SetTabLabel(ANotebook, i, APath, ATabList[InsertPos]);
+ ANotebook.PageIndex := i;
+end;
+
+procedure TFMain.NewTab(LeftPanel: boolean);
+var AEngine: TPanelEngine;
+ ATabList: TStringList;
+ APath: string;
+ DontShowAgain: boolean;
+begin
+ if LeftPanel then begin
+ AEngine := LeftPanelEngine;
+ ATabList := LeftPanelTabs;
+ end else begin
+ AEngine := RightPanelEngine;
+ ATabList := RightPanelTabs;
+ end;
+
+ APath := AEngine.Path;
+ if AEngine is TVFSEngine then begin
+ while AEngine is TVFSEngine do begin
+ APath := AEngine.SavePath;
+ AEngine := AEngine.ParentEngine;
+ end;
+ // Show warning that we couldn't duplicate the VFS location
+ if ConfDuplicateTabWarning then begin
+ MessageBoxShowOnce(LANGDuplicateTabWarning, LANGDontShowAgain, DontShowAgain, [mbOK], mbInfo, mbOK, mbOK);
+ if DontShowAgain then begin
+ ConfDuplicateTabWarning := False;
+ WriteMainGUISettings;
+ end;
+ end;
+ end;
+
+ NewTabInternal(LeftPanel, AEngine, APath, ATabList.Count + Ord(ATabList.Count = 0));
+end;
+
+procedure TFMain.SwitchTab(TabNo: integer; LeftPanel, SetFocus: boolean);
+var ANotebook: TEphyNotebook;
+ AListView: TGTKListView;
+ AVBoxList: TList;
+ ListBox: TGTKVBox;
+ AScrolledWindow: TGTKScrolledWindow;
+ i: integer;
+begin
+ if LeftPanel then begin
+ ANotebook := LeftPanelNotebook;
+ AVBoxList := LeftNotebookBoxList;
+ ListBox := LeftListBox;
+ AScrolledWindow := LeftScrolledWindow;
+ AListView := LeftListView;
+ end else begin
+ ANotebook := RightPanelNotebook;
+ AVBoxList := RightNotebookBoxList;
+ ListBox := RightListBox;
+ AScrolledWindow := RightScrolledWindow;
+ AListView := RightListView;
+ end;
+
+ if (AVBoxList.Count < TabNo) or (TabNo < -1) then Exit;
+
+ // Remove any objects
+ g_object_ref(AScrolledWindow.FWidget);
+ if ListBox.ChildrenCount > 0 then ListBox.RemoveControl(AScrolledWindow);
+ if AVBoxList.Count > 0 then
+ for i := 0 to AVBoxList.Count - 1 do
+ if TGTKVBox(AVBoxList[i]).ChildrenCount > 0 then TGTKVBox(AVBoxList[i]).RemoveControl(AScrolledWindow);
+
+ if TabNo >= 0 then begin // Reparent to the tab
+ TGTKVBox(AVBoxList[TabNo]).AddControlEx(AScrolledWindow, True, True, 0);
+ ListBox.Visible := False;
+ ANotebook.Visible := True;
+ end else begin // Reparent back to the panel
+ ListBox.AddControlEx(AScrolledWindow, True, True, 0);
+ ListBox.Visible := True;
+ ANotebook.Visible := False;
+ end;
+ g_object_unref(AScrolledWindow.FWidget);
+ if SetFocus then AListView.SetFocus;
+end;
+
+procedure TFMain.TabNotebookSwitchPage(Sender: TObject; const NewTabNum: integer; const ShouldFocus: boolean);
+var LeftPanel: boolean;
+ ATabList: TStringList;
+ PathsHighlight: TStringList;
+ TabEngines: TList;
+ AListView: TGTKListView;
+ TabSortIDs: TList;
+ TabSortTypes: TList;
+begin
+ DebugMsg(['Switch page']);
+ LeftPanel := (Sender as TEphyNotebook) = LeftPanelNotebook;
+ if LeftPanel then begin
+ ATabList := LeftPanelTabs;
+ PathsHighlight := LeftPathsHighlight;
+ TabEngines := LeftTabEngines;
+ TabSortIDs := LeftTabSortIDs;
+ TabSortTypes := LeftTabSortTypes;
+ AListView := LeftListView;
+ end else begin
+ ATabList := RightPanelTabs;
+ PathsHighlight := RightPathsHighlight;
+ TabEngines := RightTabEngines;
+ TabSortIDs := RightTabSortIDs;
+ TabSortTypes := RightTabSortTypes;
+ AListView := RightListView;
+ end;
+ SwitchTab(NewTabNum, LeftPanel, ShouldFocus);
+ if LeftPanel then LeftPanelEngine := TabEngines[NewTabNum]
+ else RightPanelEngine := TabEngines[NewTabNum];
+ ChangingDir(LeftPanel, ATabList[NewTabNum], PathsHighlight[NewTabNum]);
+ AListView.SetSortInfo(Integer(TabSortIDs[NewTabNum]),
+ TGTKTreeViewSortOrder(Integer(TabSortTypes[NewTabNum])));
+end;
+
+procedure TFMain.miDuplicateTabClick(Sender: TObject);
+begin
+ if not CommandLineCombo.Entry.Focused then
+ if LeftListView.Focused then NewTab(True) else
+ if RightListView.Focused then NewTab(False) else
+ if (Sender is TGTKMenuItem) and LeftTabPopup then NewTab(True) else
+ if (Sender is TGTKMenuItem) and (not LeftTabPopup) then NewTab(False) else
+ DebugMsg(['Couldn''t duplicate tab: No listview focused.']);
+end;
+
+procedure TFMain.miCloseTabClick(Sender: TObject);
+begin
+ if not CommandLineCombo.Entry.Focused then
+ if LeftListView.Focused then CloseTab(LeftPanelNotebook.PageIndex, True) else
+ if RightListView.Focused then CloseTab(RightPanelNotebook.PageIndex, False) else
+ if (Sender is TGTKMenuItem) and LeftTabPopup then CloseTab(LeftPanelNotebook.PageIndex, True) else
+ if (Sender is TGTKMenuItem) and (not LeftTabPopup) then CloseTab(RightPanelNotebook.PageIndex, False) else
+ DebugMsg(['Couldn''t close tab: No listview focused.']);
+end;
+
+procedure TFMain.miCloseAllTabsClick(Sender: TObject);
+begin
+ if Application.MessageBox(LANGAreYouSureCloseAllTabs, [mbYes, mbNo], mbQuestion, mbYes, mbNo) = mbYes then
+ if (Sender is TGTKMenuItem) and LeftTabPopup then CloseTab(-1, True) else
+ if (Sender is TGTKMenuItem) and (not LeftTabPopup) then CloseTab(-1, False) else
+ DebugMsg(['Couldn''t close all tabs: No listview focused.']);
+end;
+
+procedure TFMain.CloseTab(TabNo: integer; LeftPanel: boolean);
+var ATabList: TStringList;
+ PathsHighlight: TStringList;
+ ANotebook: TEphyNotebook;
+ AVBoxList: TList;
+ i, NewPageIndex: integer;
+ TabEngines: TList;
+ Engine: TPanelEngine;
+ TabSortIDs: TList;
+ TabSortTypes: TList;
+ AListView: TGTKListView;
+begin
+ if LeftPanel then begin
+ ATabList := LeftPanelTabs;
+ PathsHighlight := LeftPathsHighlight;
+ ANotebook := LeftPanelNotebook;
+ AVBoxList := LeftNotebookBoxList;
+ TabEngines := LeftTabEngines;
+ TabSortIDs := LeftTabSortIDs;
+ TabSortTypes := LeftTabSortTypes;
+ AListView := LeftListView;
+ end else begin
+ ATabList := RightPanelTabs;
+ PathsHighlight := RightPathsHighlight;
+ ANotebook := RightPanelNotebook;
+ AVBoxList := RightNotebookBoxList;
+ TabEngines := RightTabEngines;
+ TabSortIDs := RightTabSortIDs;
+ TabSortTypes := RightTabSortTypes;
+ AListView := RightListView;
+ end;
+ DebugMsg(['Close tab, TabNo = ', TabNo, ', PageIndex = ', ANotebook.PageIndex]);
+
+ if (ANotebook.ChildrenCount < TabNo) or (TabNo < -1) or (not ANotebook.Visible) then begin
+ DebugMsg(['Couldn''t close tab: wrong TabNo']);
+ Exit;
+ end;
+ if (ANotebook.ChildrenCount > 2) and (TabNo >= 0) then begin
+ // Close one tab, leave tab bar visible
+ Engine := TabEngines[TabNo];
+// !!!!!!!!
+ NewPageIndex := ANotebook.PageIndex - Ord((TabNo = ANotebook.PageIndex) and (TabNo = ANotebook.ChildrenCount - 1))
+ + Ord((TabNo = ANotebook.PageIndex) and (ANotebook.ChildrenCount > TabNo + 1));
+// if (ANotebook.PageIndex = 0) and (NewPageIndex = 0) then NewPageIndex := 1;
+ ANotebook.PageIndex := NewPageIndex;
+ // Before remove, ensure some other page is active
+ ANotebook.RemovePage(TabNo);
+ ATabList.Delete(TabNo);
+ PathsHighlight.Delete(TabNo);
+ TabEngines.Delete(TabNo);
+// g_object_unref(TGTKVBox(AVBoxList[TabNo]).FWidget);
+ AVBoxList.Delete(TabNo);
+ TabSortIDs.Delete(TabNo);
+ TabSortTypes.Delete(TabNo);
+ // Try to close the VFS engine
+ if Engine is TVFSEngine then
+ try
+ if not TVFSEngine(Engine).VFSClose then DebugMsg(['Error closing the engine...']);
+ Engine.Free;
+ except end;
+
+ end else begin // Close last/all tabs, hide the tab bar
+ // Change dir to the opposite
+ if (TabNo >= 0) and (TabNo = ANotebook.PageIndex) then begin // we should not change directory while closing all tabs...
+ i := Ord(not Boolean(ANotebook.PageIndex));
+ if LeftPanel then LeftPanelEngine := TabEngines[i]
+ else RightPanelEngine := TabEngines[i];
+ ChangingDir(LeftPanel, ATabList[i], PathsHighlight[i]);
+ end;
+ // Remove the tabs
+ SwitchTab(-1, LeftPanel, False);
+ for i := ANotebook.ChildrenCount - 1 downto 0 do ANotebook.RemovePage(i);
+ ATabList.Clear;
+ PathsHighlight.Clear;
+ for i := 0 to TabEngines.Count - 1 do
+ if (TPanelEngine(TabEngines[i]) is TVFSEngine) and ((LeftPanel and (LeftPanelEngine <> TabEngines[i])) or
+ ((not LeftPanel) and (RightPanelEngine <> TabEngines[i]))) then
+ try
+ Engine := TabEngines[i];
+ if not TVFSEngine(Engine).VFSClose then DebugMsg(['Error closing the engine...']);
+ Engine.Free;
+ except end;
+
+ TabEngines.Clear;
+{ for i := 0 to AVBoxList.Count - 1 do
+ g_object_unref(TGTKVBox(AVBoxList[i]).FWidget); }
+ AVBoxList.Clear;
+ TabSortIDs.Clear;
+ TabSortTypes.Clear;
+ AListView.SetFocus;
+ end;
+end;
+
+procedure TFMain.TabPopupMenuPopup(Sender: TObject);
+begin
+ LeftTabPopup := Sender = LeftPanelNotebook;
+end;
+
+procedure TFMain.AddTabs(LeftPanel: boolean; TabList: TStringList; TabSortIDs, TabSortTypes: TList; SetTabActive: integer);
+var ANotebook: TEphyNotebook;
+ ATabList: TStringList;
+ AVBoxList: TList;
+ APath: string;
+ VBox: TGTKVBox;
+ PathsHighlight: TStringList;
+ TabEngines: TList;
+ i: integer;
+ ATabSortIDs: TList;
+ ATabSortTypes: TList;
+begin
+ if LeftPanel then begin
+ ANotebook := LeftPanelNotebook;
+ ATabList := LeftPanelTabs;
+ AVBoxList := LeftNotebookBoxList;
+ PathsHighlight := LeftPathsHighlight;
+ TabEngines := LeftTabEngines;
+ ATabSortIDs := LeftTabSortIDs;
+ ATabSortTypes := LeftTabSortTypes;
+ end else begin
+ ANotebook := RightPanelNotebook;
+ ATabList := RightPanelTabs;
+ AVBoxList := RightNotebookBoxList;
+ PathsHighlight := RightPathsHighlight;
+ TabEngines := RightTabEngines;
+ ATabSortIDs := RightTabSortIDs;
+ ATabSortTypes := RightTabSortTypes;
+ end;
+
+ if (not Assigned(TabList)) or (TabList.Count < 1) or (not Assigned(TabSortIDs)) or (TabSortIDs.Count < 1) or
+ (not Assigned(TabSortTypes)) or (TabSortTypes.Count < 1) then Exit;
+
+ for i := 0 to TabList.Count - 1 do begin
+ ATabList.Add(TabList[i]);
+ APath := ExtractFileName(ExcludeTrailingPathDelimiter(TabList[i]));
+ if APath = '' then APath := '/';
+ VBox := TGTKVBox.Create(Self);
+ AVBoxList.Add(VBox);
+ PathsHighlight.Add('');
+ ATabSortIDs.Add(TabSortIDs[i]);
+ ATabSortTypes.Add(TabSortTypes[i]);
+ if LeftPanel then TabEngines.Add(LeftPanelEngine)
+ else TabEngines.Add(RightPanelEngine);
+ ANotebook.AppendPage(VBox, APath);
+ SetTabLabel(ANotebook, ANotebook.ChildrenCount - 1, APath, TabList[i]);
+ end;
+
+ if not ANotebook.Visible then ANotebook.Visible := True;
+ ANotebook.PageIndex := SetTabActive;
+ TabNotebookSwitchPage(ANotebook, SetTabActive, True);
+end;
+
+procedure TFMain.SetTabLabel(Notebook: TEphyNotebook; PageIndex: integer; ALabel, Tooltip: string);
+begin
+ if (ConfTabMaxLength > 0) and (Length(ALabel) > ConfTabMaxLength) then
+ ALabel := Copy(ALabel, 1, ConfTabMaxLength) + '...';
+ Notebook.SetTabCaption(PageIndex, ALabel);
+ Notebook.SetTabTooltip(PageIndex, Tooltip);
+end;
+
+procedure TFMain.NotebookReordered(Sender: TObject; const Source, Dest: integer);
+var ANotebook: TEphyNotebook;
+ ATabList: TStringList;
+ AVBoxList: TList;
+ PathsHighlight: TStringList;
+ TabEngines: TList;
+ ATabSortIDs: TList;
+ ATabSortTypes: TList;
+begin
+ ANotebook := Sender as TEphyNotebook;
+ if ANotebook = LeftPanelNotebook then begin
+ ATabList := LeftPanelTabs;
+ AVBoxList := LeftNotebookBoxList;
+ PathsHighlight := LeftPathsHighlight;
+ TabEngines := LeftTabEngines;
+ ATabSortIDs := LeftTabSortIDs;
+ ATabSortTypes := LeftTabSortTypes;
+ end else begin
+ ATabList := RightPanelTabs;
+ AVBoxList := RightNotebookBoxList;
+ PathsHighlight := RightPathsHighlight;
+ TabEngines := RightTabEngines;
+ ATabSortIDs := RightTabSortIDs;
+ ATabSortTypes := RightTabSortTypes;
+ end;
+
+ ATabList.Move(Source, Dest);
+ AVBoxList.Move(Source, Dest);
+ PathsHighlight.Move(Source, Dest);
+ TabEngines.Move(Source, Dest);
+ ATabSortIDs.Move(Source, Dest);
+ ATabSortTypes.Move(Source, Dest);
+end;
+
+procedure TFMain.NotebookTabClosed(Sender: TObject; const TabNum: integer; var CanClose: boolean);
+begin
+ CloseTab(TabNum, Sender = LeftPanelNotebook);
+ CanClose := False;
+end;
+
+procedure TFMain.NotebookTabDoubleClick(Sender: TObject; const TabNum: integer);
+begin
+ CloseTab(TabNum, Sender = LeftPanelNotebook);
+end;
+
+function TFMain.NotebookFindNotebookAtPointerEvent(Sender: TObject; const AbsX, AbsY: integer): TEphyNotebook;
+var wx, wy: Integer;
+begin
+// DebugMsg([' *** NotebookFindNotebookAtPointerEvent(AbsX = ', AbsX, ', AbsY = ', AbsY, ')']);
+ Result := nil;
+
+ if LeftPanelNotebook.Visible then begin
+ gtk_widget_get_pointer(LeftPanelNotebook.FWidget, @wx, @wy);
+ if (wx > 0) and (wy > 0) and (wx < LeftPanelNotebook.FWidget^.allocation.width) and
+ (wy < LeftPanelNotebook.FWidget^.allocation.height) then Result := LeftPanelNotebook;
+ end else begin
+ gtk_widget_get_pointer(LeftScrolledWindow.FWidget, @wx, @wy);
+ if (wx > 0) and (wy > 0) and (wx < LeftScrolledWindow.FWidget^.allocation.width) and
+ (wy < LeftScrolledWindow.FWidget^.allocation.height) then Result := LeftPanelNotebook;
+ end;
+
+ if Result = nil then begin
+ if RightPanelNotebook.Visible then begin
+ gtk_widget_get_pointer(RightPanelNotebook.FWidget, @wx, @wy);
+ if (wx > 0) and (wy > 0) and (wx < RightPanelNotebook.FWidget^.allocation.width) and
+ (wy < RightPanelNotebook.FWidget^.allocation.height) then Result := RightPanelNotebook;
+ end else begin
+ gtk_widget_get_pointer(RightScrolledWindow.FWidget, @wx, @wy);
+ if (wx > 0) and (wy > 0) and (wx < RightScrolledWindow.FWidget^.allocation.width) and
+ (wy < RightScrolledWindow.FWidget^.allocation.height) then Result := RightPanelNotebook;
+ end;
+ end;
+
+{
+ if Result = LeftPanelNotebook then DebugMsg([' *** NotebookFindNotebookAtPointerEvent: inside LeftPanelNotebook']) else
+ if Result = RightPanelNotebook then DebugMsg([' *** NotebookFindNotebookAtPointerEvent: inside RightPanelNotebook']);
+ }
+end;
+
+function TFMain.NotebookMoveTabToAnotherNotebook(Sender: TObject; Destination: TEphyNotebook; const SourceTabNo, DestTabNo: integer): boolean;
+var LeftPanel: boolean;
+ ATargetEngine, ASrcEngine: TPanelEngine;
+ ATargetTabList, ASrcTabList: TStringList;
+ ATargetPathsHighlight, ASrcPathsHighlight: TStringList;
+ ATargetTabEngines, ASrcTabEngines: TList;
+ ATargetTabSortIDs, ASrcTabSortIDs: TList;
+ ATargetTabSortTypes, ASrcTabSortTypes: TList;
+ APath: string;
+ DontShowAgain: boolean;
+ dst_no: integer;
+begin
+ DontShowAgain := False;
+ DebugMsg([' *** NotebookMoveTabToAnotherNotebook(SourceTabNo = ', SourceTabNo, ', DestTabNo = ', DestTabNo, ')']);
+ LeftPanel := Sender = LeftPanelNotebook;
+ if LeftPanel then begin
+ ATargetEngine := RightPanelEngine;
+ ATargetTabList := RightPanelTabs;
+ ASrcEngine := LeftPanelEngine;
+ ASrcTabList := LeftPanelTabs;
+ ATargetPathsHighlight := RightPathsHighlight;
+ ATargetTabEngines := RightTabEngines;
+ ATargetTabSortIDs := RightTabSortIDs;
+ ATargetTabSortTypes := RightTabSortTypes;
+ ASrcPathsHighlight := LeftPathsHighlight;
+ ASrcTabEngines := LeftTabEngines;
+ ASrcTabSortIDs := LeftTabSortIDs;
+ ASrcTabSortTypes := LeftTabSortTypes;
+ end else begin
+ ATargetEngine := LeftPanelEngine;
+ ATargetTabList := LeftPanelTabs;
+ ASrcEngine := RightPanelEngine;
+ ASrcTabList := RightPanelTabs;
+ ATargetPathsHighlight := LeftPathsHighlight;
+ ATargetTabEngines := LeftTabEngines;
+ ATargetTabSortIDs := LeftTabSortIDs;
+ ATargetTabSortTypes := LeftTabSortTypes;
+ ASrcPathsHighlight := RightPathsHighlight;
+ ASrcTabEngines := RightTabEngines;
+ ASrcTabSortIDs := RightTabSortIDs;
+ ASrcTabSortTypes := RightTabSortTypes;
+ end;
+
+ if (SourceTabNo < 0) or (SourceTabNo > ASrcTabList.Count - 1) then begin
+ DebugMsg([' *** NotebookMoveTabToAnotherNotebook: invalid SourceTabNo']);
+ Exit;
+ end;
+
+ APath := TPanelEngine(ASrcTabEngines[SourceTabNo]).Path;
+ if TPanelEngine(ASrcTabEngines[SourceTabNo]) is TVFSEngine then begin
+ while TPanelEngine(ASrcTabEngines[SourceTabNo]) is TVFSEngine do begin
+ APath := TPanelEngine(ASrcTabEngines[SourceTabNo]).SavePath;
+ ASrcTabEngines[SourceTabNo] := TPanelEngine(ASrcTabEngines[SourceTabNo]).ParentEngine;
+ end;
+ // Show warning that we couldn't duplicate the VFS location
+ if ConfDuplicateTabWarning then begin
+ MessageBoxShowOnce(LANGDuplicateTabWarning, LANGDontShowAgain, DontShowAgain, [mbOK], mbInfo, mbOK, mbOK);
+ if DontShowAgain then begin
+ ConfDuplicateTabWarning := False;
+ WriteMainGUISettings;
+ end;
+ end;
+ end;
+
+ while ATargetEngine is TVFSEngine do
+ ATargetEngine := ATargetEngine.ParentEngine;
+
+ dst_no := DestTabNo;
+ if dst_no < 0 then dst_no := ATargetTabList.Count + Ord(ATargetTabList.Count = 0);
+ CloseTab(SourceTabNo, LeftPanel);
+ NewTabInternal(not LeftPanel, ATargetEngine, APath, dst_no);
+
+ Result := True;
+end;
+
+procedure TFMain.NotebookTabFocusOnlyEvent(Sender: TObject; const TabNum: integer);
+begin
+ if Sender = LeftPanelNotebook then LeftListView.SetFocus else
+ if Sender = RightPanelNotebook then RightListView.SetFocus
+ else Exit;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+function TFMain.HandleVFSArchive(const Ext, FullPath, HighlightItem, TargetPath: string): boolean;
+var i, j: integer;
+ Plugin: TVFSPlugin;
+begin
+ Result := False;
+ Plugin := nil;
+
+ // Try to find a plugin which can handle open the archive type
+ if PluginList.Count > 0 then
+ for i := 0 to PluginList.Count - 1 do begin
+ Plugin := TVFSPlugin(PluginList[i]);
+ if Length(Plugin.Extensions) > 0 then
+ for j := 0 to Length(Plugin.Extensions) - 1 do begin
+// DebugMsg(['Extension = "', Plugin.Extensions[j], '", Ext = "', Ext, '"']);
+ if AnsiCompareText(Plugin.Extensions[j], Ext) = 0 then begin
+ Result := True;
+ Break;
+ end;
+ end;
+ if Result then Break;
+ end;
+ if not Result then Exit; // we didn't find appropriate plugin
+ DebugMsg(['Found plugin ''', Plugin.VFSName, ''', trying to open the file ''', FullPath, '''']);
+
+ ChangingDir(LeftLastFocused, TargetPath, FullPath, HighlightItem, False, False, Plugin);
+end;
+
+procedure TFMain.CloseVFS(LeftPanel, SurpressRefresh: boolean);
+var Engine: TPanelEngine;
+begin
+ if LeftPanel then Engine := LeftPanelEngine
+ else Engine := RightPanelEngine;
+ if not Assigned(Engine.ParentEngine) or (not (Engine is TVFSEngine)) then Exit;
+ if LeftPanel then LeftPanelEngine := Engine.ParentEngine
+ else RightPanelEngine := Engine.ParentEngine;
+ if not SurpressRefresh then ChangingDir(LeftPanel, Engine.SavePath, Engine.ParentEngine.LastHighlightItem, '', False, True);
+
+ if not TVFSEngine(Engine).VFSClose then DebugMsg(['Error closing the engine...']);
+ Engine.Free;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.ShowBookmarkQuick(LeftPanel: boolean);
+var SenderControl: TGTKControl;
+begin
+ if LeftPanel then SenderControl := LeftBookmarkButton
+ else SenderControl := RightBookmarkButton;
+ miAddBookmark.Visible := False;
+ miEditBookmarks.Visible := False;
+ miBookmarksSeparator.Visible := False;
+
+ gtk_menu_popup(PGtkMenu(mnuBookmarks.FMenu), nil, nil, menu_position_cb, SenderControl.FWidget, 1, GDK_CURRENT_TIME);
+ if LeftPanel then LeftListView.SetFocus else RightListView.SetFocus;
+end;
+
+procedure TFMain.mnuBookmarksPopup(Sender: TObject);
+begin
+ miAddBookmark.Visible := True;
+ miEditBookmarks.Visible := False;
+ miBookmarksSeparator.Visible := mnuBookmarks.Count > 3;
+end;
+
+
+(********************************************************************************************************************************)
+procedure TFMain.miSearchClick(Sender: TObject);
+var Engine: TPanelEngine;
+ DataList: TList;
+ AListView: TGTKListView;
+ Ext: string;
+ i: integer;
+begin
+ if LeftLastFocused then Engine := LeftPanelEngine
+ else Engine := RightPanelEngine;
+
+ try
+ FSearch := TFSearch.Create(Self);
+ FSearch.ParentForm := FMain;
+ FSearch.Engine := Engine;
+ FSearch.SearchInEntry.Text := ANSIToUTF8(ExcludeTrailingPathDelimiter(Engine.Path));
+ if Length(FSearch.SearchInEntry.Text) < 1 then FSearch.SearchInEntry.Text := '/';
+ case FSearch.Run of
+ mbOK: ;
+ mbApply: begin
+ if Length(FSearch.GoToFileArchive) > 0 then begin
+ Ext := ANSIUpperCase(Trim(Copy(FSearch.GoToFileArchive, LastDelimiter('.', FSearch.GoToFileArchive) + 1, Length(FSearch.GoToFileArchive) - LastDelimiter('.', FSearch.GoToFileArchive))));
+ HandleVFSArchive(Ext, FSearch.GoToFileArchive, ExtractFileName(FSearch.GoToFileArchive), ExtractFilePath(FSearch.GoToFile));
+
+ if LeftLastFocused then begin
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ AListView := LeftListView;
+ end else begin
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ AListView := RightListView;
+ end;
+
+ if Engine is TVFSEngine then begin
+ Engine.SavePath := ExtractFilePath(FSearch.GoToFileArchive);
+// (Engine as TVFSEngine).ParentEngine.LastHighlightItem := ExtractFileName(FSearch.GoToFileArchive);
+ for i := 0 to DataList.Count - 1 do
+ if ANSICompareText(string(PDataItem(DataList[i])^.AName), ExtractFileName(FSearch.GoToFile)) = 0 then begin
+ AListView.Items[i].Selected := True;
+ AListView.Items[i].SetCursor(0, False, not Application.GTKVersion_2_2_0_Up, 0.5, 0);
+ Break;
+ end;
+ end;
+ end else ChangingDir(LeftLastFocused, ExtractFilePath(FSearch.GoToFile), ExtractFileName(FSearch.GoToFile));
+ end;
+ end;
+ finally
+ FSearch.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure TFMain.miOpenConnectionClick(Sender: TObject);
+var Engine: TVFSEngine;
+ SourceEngine: TPanelEngine;
+ i, j: integer;
+ VFSPlugin: TVFSPlugin;
+ ConnInfo: TConnMgrItem;
+ b: boolean;
+begin
+ try
+ InternalLock;
+ FConnectionManager := TFConnectionManager.Create(Self);
+ b := FConnectionManager.Run = mbOK;
+ WriteConnections; // Save the list to the file
+
+ if b then begin
+ if PluginList.Count = 0 then begin
+ Application.MessageBox(LANGThereIsNoModuleAvailable, [mbOK], mbError, mbOK, mbOK);
+ Exit;
+ end;
+ if FConnectionManager.ListView.Selected = nil then Exit;
+ ConnInfo := FConnectionManager.ListView.Selected.AsPointer(0);
+ if ConnInfo = nil then Exit;
+
+ // Find the VFS module to use for this connection
+ VFSPlugin := nil;
+ if Length(ConnInfo.PluginID) > 0 then
+ for i := 0 to PluginList.Count - 1 do
+ if TVFSPlugin(PluginList[i]).VFSName = ConnInfo.PluginID then begin
+ VFSPlugin := PluginList[i];
+ Break;
+ end;
+ if VFSPlugin = nil then begin
+ for i := 0 to PluginList.Count - 1 do begin
+ if Length(TVFSPlugin(PluginList[i]).Services) > 0 then
+ for j := 0 to Length(TVFSPlugin(PluginList[i]).Services) - 1 do
+ if AnsiCompareText(TVFSPlugin(PluginList[i]).Services[j], ConnInfo.ServiceType) = 0 then begin
+ VFSPlugin := PluginList[i];
+ Break;
+ end;
+ if VFSPlugin <> nil then Break;
+ end;
+ if VFSPlugin = nil then VFSPlugin := PluginList[0]; // Fallback in hope something else could handle it
+ end;
+
+ if (LeftLastFocused and (LeftPanelEngine is TVFSEngine)) or ((not LeftLastFocused) and (RightPanelEngine is TVFSEngine)) then
+ begin
+ if Application.MessageBox(LANGCloseOpenConnection, [mbYes, mbNo], mbWarning, mbYes, mbNo) <> mbYes then Exit;
+ CloseVFS(LeftLastFocused, True);
+ end;
+
+ // Construct the VFS Engine and try to open the connection
+ if LeftLastFocused then SourceEngine := LeftPanelEngine
+ else SourceEngine := RightPanelEngine;
+ Engine := TVFSEngine.Create(VFSPlugin);
+ Engine.ParentEngine := SourceEngine;
+ Engine.SavePath := SourceEngine.Path;
+ if not Engine.VFSOpenURI(ConnInfo.URI) then begin
+ Application.MessageBox(LANGCouldntOpenURI, [mbOK], mbError, mbOK, mbOK);
+ Exit;
+ end;
+ if LeftLastFocused then LeftPanelEngine := Engine
+ else RightPanelEngine := Engine;
+ DoRefresh(LeftLastFocused, False, False);
+ end;
+ finally
+ FConnectionManager.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+procedure TFMain.miDisconnectClick(Sender: TObject);
+begin
+ CloseVFS(LeftLastFocused, False);
+end;
+
+procedure TFMain.DisconnectButtonClick(Sender: TObject);
+begin
+ CloseVFS(Sender = LeftDisconnectButton, False);
+ if (Sender = LeftDisconnectButton) and (not LeftListView.Focused) then LeftListView.SetFocus else
+ if (Sender = RightDisconnectButton) and (not RightListView.Focused) then RightListView.SetFocus;
+end;
+
+procedure TFMain.LeaveArchiveButtonClick(Sender: TObject);
+begin
+ CloseVFS(Sender = LeftLeaveArchiveButton, False);
+ if (Sender = LeftLeaveArchiveButton) and (not LeftListView.Focused) then LeftListView.SetFocus else
+ if (Sender = RightLeaveArchiveButton) and (not RightListView.Focused) then RightListView.SetFocus;
+end;
+
+procedure TFMain.OpenTerminalButtonClick(Sender: TObject);
+var CurrentPath: string;
+ AEngine: TPanelEngine;
+ Error: integer;
+begin
+ Error := 0;
+ if LeftLastFocused then AEngine := LeftPanelEngine
+ else AEngine := RightPanelEngine;
+ while not (AEngine is TLocalTreeEngine) do AEngine := AEngine.ParentEngine;
+ CurrentPath := AEngine.Path;
+ ChDir(CurrentPath);
+ ExecuteProgram('bash', CurrentPath, False, True, Error);
+ ChDir('/');
+end;
+
+
+(********************************************************************************************************************************)
+procedure TFMain.miFilePropertiesClick(Sender: TObject);
+var LeftPanel: boolean;
+ AListView: TGTKListView;
+ Engine: TPanelEngine;
+ DataList: TList;
+ i: integer;
+ SelCount: longint;
+ AFile, NextItem1, NextItem2: string;
+ Stat: PDataItemSL;
+{ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress; }
+begin
+ try
+ InternalLock;
+ if LeftListView.Focused then LeftPanel := True else
+ if RightListView.Focused then LeftPanel := False else
+ LeftPanel := LeftLastFocused;
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then Inc(SelCount);
+ if (SelCount = 0) and ((not Assigned(AListView.Selected)) {or PDataItem(AListView.Selected.Data)^.UpDir}) then begin
+ Application.MessageBox(LANGNoFilesSelected, [mbOK], mbInfo, mbNone, mbOK);
+ Exit;
+ end;
+
+ AFile := '';
+ if SelCount = 0 then AFile := PDataItem(AListView.Selected.Data)^.AName else
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then begin
+ AFile := AName;
+ Break;
+ end;
+
+ if AFile <> '' then
+ try
+ FProperties := TFProperties.Create(Self);
+ Stat := Engine.GetFileInfoSL(IncludeTrailingPathDelimiter(Engine.Path) + AFile);
+ if not Assigned(Stat) then Exit;
+// FProperties.AssignMode(Stat^.Mode, AFile, Stat^.UID, Stat^.GID);
+ FProperties.DisplayFileName := AFile;
+ if FProperties.Run = mbOK then begin
+{ FindNextSelected(AListView, DataList, NextItem1, NextItem2);
+
+ AWorkingThread := TWorkerThread.Create;
+ AFProgress := TFProgress.Create(Self);
+ try
+ AFProgress.SetNumBars(False);
+ AFProgress.ProgressBar.Value := 0;
+ AFProgress.Label1.Caption := LANGChownProgress;
+ AWorkingThread.ProgressForm := AFProgress;
+ if Assigned(AListView.Selected) then AWorkingThread.SelectedItem := AListView.Selected.Data;
+ AWorkingThread.ParamBool1 := FChown.RecursiveCheckButton.Checked;
+ AWorkingThread.ParamCardinal1 := FChown.LastUID;
+ AWorkingThread.ParamCardinal2 := FChown.LastGID;
+ AWorkingThread.Engine := Engine;
+ AWorkingThread.LeftPanel := LeftPanel;
+ AWorkingThread.DataList := DataList;
+ AWorkingThread.WorkerProcedure := ChownFilesWorker;
+ AWorkingThread.Resume;
+ AFProgress.ParentForm := FMain;
+ if (SelCount > 1) or FChown.RecursiveCheckButton.Checked then AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+ finally
+ AFProgress.Free;
+ AWorkingThread.Free;
+ end; }
+
+ NextItem1 := '';
+ NextItem2 := '';
+ ChangingDir(LeftPanel, Engine.Path, NextItem1, NextItem2);
+ DoRefresh(not LeftPanel, True, True);
+ end;
+ finally
+ FProperties.Free;
+ end;
+ finally
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TFMain.CopyFilenamesToClipboard(FullPaths, LeftPanel: boolean);
+var DataList: TList;
+ Engine: TPanelEngine;
+ AListView: TGTKListView;
+ i, x: longint;
+ SelCount: longint;
+ clip: PGtkClipboard;
+ s: string;
+begin
+ if LeftPanel then begin
+ AListView := LeftListView;
+ Engine := LeftPanelEngine;
+ DataList := LeftPanelData;
+ end else begin
+ AListView := RightListView;
+ Engine := RightPanelEngine;
+ DataList := RightPanelData;
+ end;
+
+ SelCount := 0;
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do
+ with PDataItem(DataList[i])^ do
+ if Selected and (not UpDir) then Inc(SelCount);
+ if (SelCount = 0) and ((not Assigned(AListView.Selected)) or PDataItem(AListView.Selected.Data)^.UpDir)
+ then Exit; // Silently do nothing
+
+ if SelCount = 0 then begin
+ s := PDataItem(AListView.Selected.Data)^.AName;
+ if FullPaths then s := IncludeTrailingPathDelimiter(Engine.GetPath) + s;
+ end else begin
+ s := '';
+ if DataList.Count > 0 then
+ for i := 0 to DataList.Count - 1 do begin
+ x := AListView.ConvertFromSorted(i);
+ if (x >= 0) and (x < DataList.Count) and PDataItem(DataList[x])^.Selected then begin
+ if FullPaths then s := s + IncludeTrailingPathDelimiter(Engine.GetPath);
+ s := s + PDataItem(DataList[x])^.AName + #10;
+ end;
+ end;
+ end;
+
+ clip := gtk_clipboard_get(gdk_atom_intern('CLIPBOARD', False));
+ gtk_clipboard_set_text(clip, StringToPgchar(s), Length(s));
+end;
+
+
+(********************************************************************************************************************************)
+function TFMain.HandleRunFromArchive(var APath: string; Engine: TPanelEngine; Command, FileTypeDesc: string; BypassDialog: boolean): boolean;
+var Res: TMessageButton;
+ Stat: PDataItemSl;
+ s: string;
+ AWorkingThread: TWorkerThread;
+ AFProgress: TFProgress;
+ tmp: PChar;
+ LocalEngine: TLocalTreeEngine;
+ AListView: TGTKListView;
+ DataList: TList;
+ err: integer;
+begin
+ Result := False;
+ try
+ if not BypassDialog then begin
+ Stat := Engine.GetFileInfoSL(APath);
+ FRunFromVFS := TFRunFromVFS.Create(Self);
+ FRunFromVFS.FileNameLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', [APath]);
+ if FileTypeDesc = '' then FileTypeDesc := LANGHandleRunFromArchive_FileTypeDesc_Unknown;
+ FRunFromVFS.FileTypeLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', [FileTypeDesc]);
+ if Assigned(Stat) then begin
+ if (ConfSizeFormat < 5) or (Stat^.Size < 1024) then s := Format(' %s', [LANGHandleRunFromArchive_Bytes]);
+ FRunFromVFS.SizeLabel2.Caption := Format('%s%s<span weight="ultrabold"> </span>', [ANSIToUTF8(FormatSize(Stat^.Size, 0)), s]);
+ if (ConfSizeFormat < 5) or (Stat^.Size < 1024) then s := Format(' %s', [LANGHandleRunFromArchive_Bytes]);
+ FRunFromVFS.PackedSizeLabel2.Caption := Format('%s%s<span weight="ultrabold"> </span>', [ANSIToUTF8(FormatSize(Stat^.Size, 0)), s]);
+ FRunFromVFS.DateLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', [FormatDateTime('ddddd tt', Stat^.ModifyTime)]);
+ if (Command = '') and (not Stat^.IsExecutable) then begin
+ FRunFromVFS.OpensWithLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', [LANGHandleRunFromArchive_NotAssociated]);
+ FRunFromVFS.ExecuteButton.Enabled := False;
+ FRunFromVFS.ExecuteAllButton.Enabled := False;
+ end else begin
+ if Command = '' then Command := LANGHandleRunFromArchive_SelfExecutable;
+ FRunFromVFS.OpensWithLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', [Command]);
+ end;
+ end else begin
+ FRunFromVFS.SizeLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', ['??']);
+ FRunFromVFS.PackedSizeLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', ['??']);
+ FRunFromVFS.DateLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', ['??']);
+ FRunFromVFS.OpensWithLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', [Command]);
+ end;
+ FRunFromVFS.FileNameLabel2.UseMarkup := True;
+ FRunFromVFS.FileTypeLabel2.UseMarkup := True;
+ FRunFromVFS.SizeLabel2.UseMarkup := True;
+ FRunFromVFS.PackedSizeLabel2.UseMarkup := True;
+ FRunFromVFS.DateLabel2.UseMarkup := True;
+ FRunFromVFS.OpensWithLabel2.UseMarkup := True;
+
+ FreeDataItem(Stat);
+
+ Res := FRunFromVFS.Run;
+ FRunFromVFS.Close;
+ FRunFromVFS.Free;
+ Application.ProcessMessages;
+ end else Res := mbYes;
+ if Res in [mbYes, mbNo] then begin
+ Result := False;
+ // Handle password
+ if (Engine is TVFSEngine) and TVFSEngine(Engine).GetPasswordRequired and (Length(TVFSEngine(Engine).Password) < 1) then
+ if not HandleSetPassword(Engine) then Exit;
+
+ if Res = mbYes then DebugMsg(['(II) HandleRunFromArchive: Selected extract and execute single item'])
+ else DebugMsg(['(II) HandleRunFromArchive: Selected extract all and execute']);
+ s := ConfTempPath + '-XXXXXX';
+ tmp := strdup(PChar(s));
+ tmp := mkdtemp(tmp);
+ if tmp = nil then begin
+ err := errno;
+ DebugMsg(['(EE) HandleRunFromArchive: Couldn''t create temporary directory: ', strerror(err)]);
+ Application.MessageBox(PChar(Format(LANGHandleRunFromArchive_CouldntCreateTemporaryDirectory, [s, string(strerror(err))])), [mbOK], mbError, mbOK, mbOK);
+ Result := False;
+ Exit;
+ end;
+ DebugMsg(['(II) HandleRunFromArchive: Using temporary directory: ', tmp]);
+ UsedTempPaths.Add(string(tmp));
+
+ Engine.Path := ExtractFilePath(APath);
+ // Extract the files
+ try
+ AWorkingThread := TWorkerThread.Create;
+ DebugMsg(['TFMain.HandleRunFromArchive: Creating thread...']);
+ AFProgress := TFProgress.Create(Self);
+ AFProgress.Label1.Caption := LANGCopySC;
+ AFProgress.SetNumBars(True);
+ AFProgress.ProgressBar.Value := 0;
+ AWorkingThread.ProgressForm := AFProgress;
+ LocalEngine := TLocalTreeEngine.Create;
+ LocalEngine.SetPath(tmp);
+ AWorkingThread.ExtractFromVFSMode := True;
+ AWorkingThread.DestEngine := LocalEngine;
+ AWorkingThread.SrcEngine := Engine;
+ if LeftLastFocused then begin
+ AListView := LeftListView;
+ DataList := LeftPanelData;
+ end else begin
+ AListView := RightListView;
+ DataList := RightPanelData;
+ end;
+ if Assigned(AListView.Selected) then AWorkingThread.SelectedItem := AListView.Selected.Data;
+ AWorkingThread.ExtractFromVFSAll := Res = mbNo;
+ AWorkingThread.LeftPanel := LeftLastFocused;
+ AWorkingThread.DataList := DataList;
+ AWorkingThread.WorkerProcedure := CopyFilesWorker;
+ AWorkingThread.ParamBool3 := True;
+ AWorkingThread.ParamBool4 := False;
+ AWorkingThread.ParamBool5 := True;
+ AWorkingThread.ParamString1 := string(tmp);
+ AWorkingThread.ParamString2 := APath;
+ AWorkingThread.ParamDataItem1 := nil;
+ DebugMsg(['*** Copy: AWorkingThread.Resume']);
+ AWorkingThread.Resume;
+ DebugMsg(['*** Copy: AWorkingThread.Resumed.']);
+ AFProgress.ParentForm := FMain;
+ AFProgress.ShowModal;
+ ProcessProgressThread(AWorkingThread, AFProgress);
+ AFProgress.Close;
+ Result := {(not AWorkingThread.Cancelled) and} (not AWorkingThread.ErrorHappened);
+ finally
+ AFProgress.Free;
+ DebugMsg(['TFMain.HandleRunFromArchive: Freeing thread...']);
+ AWorkingThread.Free;
+ LocalEngine.Free;
+ end;
+
+ DebugMsg(['(II) HandleRunFromArchive: Old path = ', APath]);
+ if Result then begin
+ if Res = mbYes then APath := IncludeTrailingPathDelimiter(string(tmp)) + ExtractFileName(APath)
+ else APath := ExcludeTrailingPathDelimiter(string(tmp)) + APath;
+ end;
+ DebugMsg(['(II) HandleRunFromArchive: New path = ', APath]);
+
+
+ Libc.free(tmp);
+ DebugMsg(['(II) HandleRunFromArchive: Copy OK, Result = ', Result]);
+ end;
+
+ finally
+ Application.ProcessMessages;
+ end;
+end;
+
+procedure TFMain.PasswordButtonClick(Sender: TObject);
+begin
+ if Sender = LeftPasswordButton then HandleSetPassword(LeftPanelEngine) else
+ if Sender = RightPasswordButton then HandleSetPassword(RightPanelEngine);
+end;
+
+function TFMain.HandleSetPassword(Engine: TPanelEngine): boolean;
+begin
+ if not (Engine is TVFSEngine) then Exit;
+ try
+ FSetPassword := TFSetPassword.Create(Self);
+ FSetPassword.Entry.Text := TVFSEngine(Engine).Password;
+ if Length(FSetPassword.Entry.Text) > 0 then FSetPassword.Entry.SelectAll;
+ Result := FSetPassword.Run = mbOK;
+ if Result then TVFSEngine(Engine).Password := FSetPassword.Entry.Text;
+ FSetPassword.Free;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in FMain.HandleSetPassword: (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+
+
+
+
+end.
+