summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--UConfig.pas26
-rw-r--r--UConnectionManager.pas237
-rw-r--r--UCore.pas104
-rw-r--r--UMain.pas116
-rw-r--r--UQuickConnect.pas349
-rw-r--r--libgtk_kylix/GTKStdCtrls.pas3
-rw-r--r--tuxcmd.dpr1
-rw-r--r--vfs/UVFSCore.pas15
-rw-r--r--vfs/uVFSprototypes.pas3
9 files changed, 725 insertions, 129 deletions
diff --git a/UConfig.pas b/UConfig.pas
index ce0ca82..cfd79d3 100644
--- a/UConfig.pas
+++ b/UConfig.pas
@@ -25,8 +25,8 @@ uses Classes, ULocale;
resourcestring
ConstAppTitle = 'Tux Commander';
- ConstAboutVersion = '0.6.59-dev';
- ConstAboutBuildDate = '2008-11-16';
+ ConstAboutVersion = '0.6.60-dev';
+ ConstAboutBuildDate = '2008-11-17';
{$IFDEF FPC}
{$INCLUDE fpcver.inc}
@@ -114,6 +114,7 @@ var ConfPanelSep, ConfRowHeight, ConfRowHeightReal, ConfNumHistoryItems,
ApplicationShuttingDown: boolean;
ConfConnMgrActiveItem: integer;
ConfConnMgrDoNotSavePasswords, ConfConnMgrDoNotSynchronizeKeyring: boolean;
+ ConfQuickConnectPluginID: string;
@@ -258,6 +259,7 @@ begin
ConfRightClickSelect := False;
ConfConnMgrDoNotSavePasswords := False;
ConfConnMgrDoNotSynchronizeKeyring := False;
+ ConfQuickConnectPluginID := '';
// Setup default values for colors
@@ -915,7 +917,7 @@ procedure ReadConnections;
var s: string;
IniFile: TMyIniFile;
Sections: TStringList;
- i: integer;
+ i, j, k: integer;
Item: TConnMgrItem;
begin
try
@@ -942,6 +944,16 @@ begin
ConfConnMgrActiveItem := IniFile.ReadInteger('__General', 'ConnMgrActiveItem', ConfConnMgrActiveItem);
ConfConnMgrDoNotSavePasswords := IniFile.ReadBool('__General', 'ConnMgrDoNotSavePasswords', ConfConnMgrDoNotSavePasswords);
ConfConnMgrDoNotSynchronizeKeyring := IniFile.ReadBool('__General', 'ConnMgrDoNotSynchronizeKeyring', ConfConnMgrDoNotSynchronizeKeyring);
+ ConfQuickConnectPluginID := IniFile.ReadString('__General', 'QuickConnectPluginID', ConfQuickConnectPluginID);
+ end else
+ if Sections[i] = '__QuickConnectHistory' then begin
+ QuickConnectHistory.Clear;
+ if not InternalDeleteHistory then begin
+ j := IniFile.ReadInteger('__QuickConnectHistory', 'NumItems', 0);
+ if j > 0 then
+ for k := 0 to j - 1 do
+ QuickConnectHistory.Add(IniFile.ReadString('__QuickConnectHistory', Format('Item%d', [k]), ''));
+ end;
end else begin
Item := TConnMgrItem.Create;
with Item do begin
@@ -984,6 +996,11 @@ begin
IniFile.WriteInteger('__General', 'ConnMgrActiveItem', ConfConnMgrActiveItem);
IniFile.WriteBool('__General', 'ConnMgrDoNotSavePasswords', ConfConnMgrDoNotSavePasswords);
IniFile.WriteBool('__General', 'ConnMgrDoNotSynchronizeKeyring', ConfConnMgrDoNotSynchronizeKeyring);
+ IniFile.WriteString('__General', 'QuickConnectPluginID', ConfQuickConnectPluginID);
+ IniFile.WriteInteger('__QuickConnectHistory', 'NumItems', QuickConnectHistory.Count);
+ if QuickConnectHistory.Count > 0 then
+ for i := 0 to QuickConnectHistory.Count - 1 do
+ IniFile.WriteString('__QuickConnectHistory', Format('Item%d', [i]), QuickConnectHistory[i]);
if ConnectionMgrList.Count > 0 then
for i := 0 to ConnectionMgrList.Count - 1 do
with TConnMgrItem(ConnectionMgrList[i]) do begin
@@ -1159,6 +1176,8 @@ initialization
CommandLineHistory.CaseSensitive := True;
Bookmarks := TStringList.Create;
Bookmarks.CaseSensitive := True;
+ QuickConnectHistory := TStringList.Create;
+ QuickConnectHistory.CaseSensitive := True;
// Initialize the modules
DoInitPlugins;
// Initialize locales
@@ -1186,5 +1205,6 @@ finalization
LeftLocalEngine.Free;
RightLocalEngine.Free;
CommandLineHistory.Free;
+ QuickConnectHistory.Free;
Bookmarks.Free;
end.
diff --git a/UConnectionManager.pas b/UConnectionManager.pas
index 3703b02..2b39a51 100644
--- a/UConnectionManager.pas
+++ b/UConnectionManager.pas
@@ -24,7 +24,7 @@ interface
uses
glib2, gdk2, gtk2, pango, SysUtils, Types, Classes, GTKControls, GTKForms, GTKStdCtrls, GTKExtCtrls, GTKConsts, GTKView,
GTKUtils, GTKDialogs, GTKPixbuf, GTKClasses,
- UCore, UCoreClasses, UVFSCore, UEngines, URemoteWait;
+ UCore, UCoreClasses, UVFSCore, UEngines;
type
TFConnectionManager = class(TGTKDialog)
@@ -37,11 +37,14 @@ type
ListViewScrolledWindow: TGTKScrolledWindow;
ListViewTable: TGTKTable;
AddConnectionButton, EditButton, RemoveButton: TGTKImageButton;
+ QuickConnectButton: TGTKImageButton;
ButtonBox: TGTKVButtonBox;
ActionButtonBox: TGTKHButtonBox;
- ConnectButton, CloseButton: TGTKButton;
+ ConnectButton, StopButton, CloseButton: TGTKButton;
DoNotSavePasswordsCheckBox, DoNotSynchronizeKeyringCheckBox: TGTKCheckButton;
procedure FormCreate(Sender: TObject); override;
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure FormResponse(Sender: TObject; const ResponseID: integer);
procedure ListViewSelectionChanged(Sender: TObject);
procedure FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
procedure AddConnectionButtonClick(Sender: TObject);
@@ -51,16 +54,17 @@ type
procedure ListViewKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
procedure CloseButtonClick(Sender: TObject);
procedure ConnectButtonClick(Sender: TObject);
+ procedure StopButtonClick(Sender: TObject);
+ procedure QuickConnectButtonClick(Sender: TObject);
private
- FSilenceError: boolean;
- AFRemoteWait: TFRemoteWait;
- FActiveConnInfo: TConnMgrItem;
- FVFSAskPasswordTry: integer;
procedure FillList;
procedure DoConnect;
public
+ FSilenceError: boolean;
+ Thread: TOpenConnectionThread;
SourcePanelEngine: TPanelEngine;
ConnectedEngine: TVFSEngine;
+ function DoConnectInternal(const URI: string; Engine: TVFSEngine; VFSDialogsParentWindow: PGtkWidget): boolean;
end;
var
@@ -68,12 +72,13 @@ var
implementation
-uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, uVFSprototypes;
+uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, UQuickConnect;
procedure TFConnectionManager.FormCreate(Sender: TObject);
var Column: TGTKTreeViewColumn;
begin
+ Thread := nil;
ConnectedEngine := nil;
SetDefaultSize(650, 500);
Caption := LANGConnMgr_Caption;
@@ -84,6 +89,9 @@ begin
ConnectButton.Caption := LANGConnMgr_ConnectButton;
// ConnectButton.Default := True;
CloseButton := TGTKButton.CreateFromStock(Self, GTK_STOCK_CLOSE);
+ StopButton := TGTKButton.CreateFromStock(Self, GTK_STOCK_STOP);
+ StopButton.Visible := False;
+ StopButton.Enabled := False;
// Default := ConnectButton;
ActionButtonBox := TGTKHButtonBox.Create(Self);
ActionButtonBox.Layout := blEnd;
@@ -91,6 +99,7 @@ begin
ActionButtonBox.BorderWidth := 0;
ActionButtonBox.AddControlEnd(CloseButton);
ActionButtonBox.AddControlEnd(ConnectButton);
+ ActionButtonBox.AddControlEnd(StopButton);
ActionArea.AddControlEx(ActionButtonBox, False, False, 0);
@@ -159,26 +168,30 @@ begin
RemoveButton.Caption := LANGConnMgr_RemoveButtonCaption;
RemoveButton.UseUnderline := True;
RemoveButton.Tooltip := LANGConnMgr_RemoveButtonTooltip;
-
+
+ QuickConnectButton := TGTKImageButton.Create(Self);
+ QuickConnectButton.SetFromStock('gtk-connect', isSmallToolbar);
+ QuickConnectButton.Caption := LANGmiQuickConnectCaption;
+ QuickConnectButton.UseUnderline := True;
+
ButtonBox := TGTKVButtonBox.Create(Self);
ButtonBox.Spacing := 10;
+ ButtonBox.AddControl(QuickConnectButton);
+// ButtonBox.AddControl(TGTKHSeparator.Create(Self));
+ ButtonBox.AddControl(TGTKEventBox.Create(Self));
ButtonBox.AddControl(AddConnectionButton);
ButtonBox.AddControl(EditButton);
ButtonBox.AddControl(RemoveButton);
DoNotSavePasswordsCheckBox := TGTKCheckButton.CreateWithLabel(Self, '_Do not store passwords internally (but still use gnome-keyring)');
DoNotSavePasswordsCheckBox.Tooltip := 'By checking this option on, Tux Commander will never save passwords into its connection list. Due to the GVFS nature, gnome-keyring will still be used to retrieve stored passwords from your desktop session.';
- DoNotSynchronizeKeyringCheckBox := TGTKCheckButton.CreateWithLabel(Self, 'Do not synchronize passwords to _gnome-keyring');
+ DoNotSynchronizeKeyringCheckBox := TGTKCheckButton.CreateWithLabel(Self, 'Do not synchronize passwords to gnome-_keyring');
DoNotSynchronizeKeyringCheckBox.Tooltip := 'Don''t tell gnome-keyring to save any passwords.';
ListViewTable.AddControlEx(0, 1, 3, 5, ListViewScrolledWindow, [taoExpand, taoFill], [taoExpand, taoFill], 0, 5);
ListViewTable.AddControlEx(0, 6, 3, 1, DoNotSavePasswordsCheckBox, [taoExpand, taoFill], [taoShrink], 10, 0);
ListViewTable.AddControlEx(0, 7, 3, 1, DoNotSynchronizeKeyringCheckBox, [taoExpand, taoFill], [taoShrink], 10, 2);
ListViewTable.AddControlEx(3, 2, 1, 3, ButtonBox, [taoShrink, taoFill], [taoShrink], 5, 5);
-{ ListViewTable.AddControlEx(3, 2, 1, 1, AddConnectionButton, [taoShrink, taoFill], [taoShrink], 5, 5);
- ListViewTable.AddControlEx(3, 3, 1, 1, EditButton, [taoShrink, taoFill], [taoShrink], 5, 5);
- ListViewTable.AddControlEx(3, 4, 1, 1, RemoveButton, [taoShrink, taoFill], [taoShrink], 5, 5); }
-// ListViewTable.AddControlEx(3, 1, 1, 1, TGTKLabel.Create(Self), [taoShrink, taoFill], [taoExpand, taoFill], 0, 2);
ListViewTable.AddControlEx(3, 5, 1, 1, TGTKLabel.Create(Self), [taoShrink, taoFill], [taoExpand, taoFill], 0, 2);
@@ -193,7 +206,11 @@ begin
RemoveButton.OnClick := RemoveButtonClick;
CloseButton.OnClick := CloseButtonClick;
ConnectButton.OnClick := ConnectButtonClick;
+ StopButton.OnClick := StopButtonClick;
+ QuickConnectButton.OnClick := QuickConnectButtonClick;
OnKeyDown := FormKeyDown;
+ OnClose := FormClose;
+ OnResponse := FormResponse;
end;
procedure TFConnectionManager.ListViewSelectionChanged(Sender: TObject);
@@ -208,8 +225,13 @@ end;
procedure TFConnectionManager.FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
begin
case Key of
- GDK_RETURN, GDK_KP_ENTER: if Assigned(ListView.Selected) then DoConnect;
- GDK_ESCAPE: ModalResult := mbCancel;
+ GDK_RETURN, GDK_KP_ENTER: if StopButton.Visible then StopButtonClick(Sender) else
+ if Assigned(ListView.Selected) then DoConnect;
+ GDK_ESCAPE: begin
+ Accept := False;
+ if StopButton.Visible then StopButtonClick(Sender)
+ else ModalResult := mbCancel;
+ end;
end;
end;
@@ -225,6 +247,20 @@ begin
end;
end;
+procedure TFConnectionManager.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ if ListView.Selected <> nil then ConfConnMgrActiveItem := ListView.Selected.Index;
+ ConfConnMgrDoNotSavePasswords := DoNotSavePasswordsCheckBox.Checked;
+ ConfConnMgrDoNotSynchronizeKeyring := DoNotSynchronizeKeyringCheckBox.Checked;
+end;
+
+procedure TFConnectionManager.FormResponse(Sender: TObject; const ResponseID: integer);
+var Action: TCloseAction;
+begin
+ FormClose(Sender, Action);
+end;
+
+
(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure TFConnectionManager.AddConnectionButtonClick(Sender: TObject);
@@ -324,8 +360,6 @@ var i: integer;
Item: TGTKListItem;
ConnMgrItem: TConnMgrItem;
begin
- ReadConnections;
-
if ConnectionMgrList.Count > 0 then
for i := 0 to ConnectionMgrList.Count - 1 do begin
ConnMgrItem := ConnectionMgrList[i];
@@ -353,88 +387,36 @@ begin
DoConnect;
end;
-procedure vfs_ask_question_callback(const AMessage: PChar; const Choices: PPChar; choice: PInteger; cancel_choice: Integer; user_data: Pointer); cdecl;
-var ConnMgr: TFConnectionManager;
- DialogParent: PGtkWidget;
+procedure TFConnectionManager.StopButtonClick(Sender: TObject);
begin
- ConnMgr := user_data;
- DialogParent := nil;
-// DebugMsg(['******* vfs_ask_question_callback spawned, user_data = 0x', IntToHex(QWord(user_data), 16), ', ThreadID = 0x', IntToHex(pthread_self, 16)]);
- if ConnMgr is TFConnectionManager then begin
- if ConnMgr.AFRemoteWait <> nil then DialogParent := ConnMgr.AFRemoteWait.FWidget
- else DialogParent := ConnMgr.FWidget;
- end;
- HandleVFSAskQuestionCallback(DialogParent, AMessage, Choices, choice);
- if ConnMgr is TFConnectionManager then begin
- if choice <> nil then ConnMgr.FSilenceError := (choice^ < 0) or (choice^ = cancel_choice);
- end;
+ if Thread <> nil then Thread.FCancelRequested := True;
end;
-function vfs_ask_password_callback(const AMessage: PChar; const default_user: PChar; const default_domain: PChar; const default_password: PChar; flags: TVFSAskPasswordFlags;
- username, password: PPChar; anonymous: PInteger; domain: PPChar; password_save: PVFSPasswordSave;
- user_data: Pointer): LongBool; cdecl;
-var ConnMgr: TFConnectionManager;
- DialogParent: PGtkWidget;
+procedure TFConnectionManager.QuickConnectButtonClick(Sender: TObject);
+var AFQuickConnect: TFQuickConnect;
begin
- ConnMgr := user_data;
- DialogParent := nil;
-// DebugMsg(['******* vfs_ask_password_callback spawned, user_data = 0x', IntToHex(QWord(user_data), 16), ', ThreadID = 0x', IntToHex(pthread_self, 16)]);
- if ConnMgr is TFConnectionManager then begin
- Inc(ConnMgr.FVFSAskPasswordTry);
- if ConnMgr.AFRemoteWait <> nil then DialogParent := ConnMgr.AFRemoteWait.FWidget
- else DialogParent := ConnMgr.FWidget;
-
- if not ConnMgr.DoNotSavePasswordsCheckBox.Checked then
- flags := flags or VFS_ASK_PASSWORD_SAVE_INTERNAL;
-
- // Disable password saving if requested
- if ConnMgr.DoNotSynchronizeKeyringCheckBox.Checked then begin
- flags := flags and (not VFS_ASK_PASSWORD_SAVING_SUPPORTED);
- if password_save <> nil then password_save^ := VFS_PASSWORD_SAVE_NEVER;
- end;
- end;
-
- // First pass, supply stored password if we have one
- if (ConnMgr is TFConnectionManager) and (ConnMgr.FVFSAskPasswordTry = 1) and (password <> nil) and
- ((flags and VFS_ASK_PASSWORD_NEED_PASSWORD) = VFS_ASK_PASSWORD_NEED_PASSWORD) and ((flags and VFS_ASK_PASSWORD_NEED_USERNAME) = 0) and
- (ConnMgr.FActiveConnInfo <> nil) and (Length(ConnMgr.FActiveConnInfo.Password) > 0) then
- begin
- DebugMsg(['(II) vfs_ask_password_callback: Supplying stored password from Connection Manager']);
- Result := True;
- password^ := g_strdup(PChar(ConnMgr.FActiveConnInfo.Password));
- if password_save <> nil then
- if ConnMgr.DoNotSynchronizeKeyringCheckBox.Checked
- then password_save^ := VFS_PASSWORD_SAVE_NEVER
- else password_save^ := VFS_PASSWORD_SAVE_PERMANENTLY;
- end else begin
- // Show password dialog and continue in loop
- Result := HandleVFSAskPasswordCallback(DialogParent, AMessage, default_user, default_domain, default_password, flags, username, password, anonymous, domain, password_save);
- if ConnMgr is TFConnectionManager then begin
- ConnMgr.FSilenceError := Result = False;
- // Save password back to Connection Manager
- if Result and (password_save <> nil) and (password_save^ = VFS_PASSWORD_SAVE_PERMANENTLY) and
- (ConnMgr.FActiveConnInfo <> nil) and (password <> nil) and (strlen(password^) > 0) and
- (not ConnMgr.DoNotSavePasswordsCheckBox.Checked) then
- begin
- DebugMsg(['(II) vfs_ask_password_callback: Saving password to Connection Manager']);
- ConnMgr.FActiveConnInfo.Password := password^;
- end;
+ ConfConnMgrDoNotSavePasswords := DoNotSavePasswordsCheckBox.Checked;
+ ConfConnMgrDoNotSynchronizeKeyring := DoNotSynchronizeKeyringCheckBox.Checked;
+ try
+ AFQuickConnect := TFQuickConnect.Create(Self);
+ AFQuickConnect.SourcePanelEngine := SourcePanelEngine;
+ AFQuickConnect.ConnectionManager := Self;
+ if (AFQuickConnect.Run = mbOK) and (AFQuickConnect.ConnectedEngine <> nil) then begin
+ ConnectedEngine := AFQuickConnect.ConnectedEngine;
+ ModalResult := mbOK;
end;
+ finally
+ AFQuickConnect.Free;
end;
-
- // Strip password saving if requested
- if (ConnMgr is TFConnectionManager) and ConnMgr.DoNotSynchronizeKeyringCheckBox.Checked and (password_save <> nil) then
- password_save^ := VFS_PASSWORD_SAVE_NEVER;
end;
+(********************************************************************************************************************************)
procedure TFConnectionManager.DoConnect;
var Engine: TVFSEngine;
i, j: integer;
VFSPlugin: TVFSPlugin;
- b: boolean;
+ FActiveConnInfo: TConnMgrItem;
begin
- FSilenceError := False;
-
FActiveConnInfo := nil;
if ListView.Selected <> nil then FActiveConnInfo := ListView.Selected.AsPointer(0);
if FActiveConnInfo = nil then Exit;
@@ -467,30 +449,91 @@ begin
if (SourcePanelEngine is TVFSEngine) and (Application.MessageBox(PGtkWindow(FWidget), LANGCloseOpenConnection, [mbYes, mbNo], mbWarning, mbYes, mbNo) <> mbYes) then Exit;
+ ListViewTable.Enabled := False;
+ CloseButton.Enabled := False;
+ ConnectButton.Enabled := False;
+ ConnectButton.Visible := False;
+ StopButton.Enabled := True;
+ StopButton.Visible := True;
+ StopButton.Default := True;
+ StopButton.SetFocus;
+
+ ConfConnMgrDoNotSavePasswords := DoNotSavePasswordsCheckBox.Checked;
+ ConfConnMgrDoNotSynchronizeKeyring := DoNotSynchronizeKeyringCheckBox.Checked;
+
// Construct the VFS Engine and try to open the connection
Engine := TVFSEngine.Create(VFSPlugin);
Engine.ParentEngine := SourcePanelEngine;
Engine.SavePath := SourcePanelEngine.Path;
+ Engine.Password := FActiveConnInfo.Password;
+ Engine.PasswordUsed := False;
- AFRemoteWait := TFRemoteWait.Create(Application);
- AFRemoteWait.ParentForm := FConnectionManager;
- AFRemoteWait.ShowModal;
- Application.ProcessMessages;
-
- FVFSAskPasswordTry := 0;
- b := Engine.VFSOpenURI(UTF8ToStr(FActiveConnInfo.GetURI(False)), @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self);
-
- AFRemoteWait.Free;
- AFRemoteWait := nil;
- if not b then begin
+ if not DoConnectInternal(UTF8ToStr(FActiveConnInfo.GetURI(False)), Engine, FWidget) then begin
if not FSilenceError then Application.MessageBox(PGtkWindow(FWidget), LANGCouldntOpenURI, [mbOK], mbError, mbOK, mbOK);
+ ListViewTable.Enabled := True;
+ CloseButton.Enabled := True;
+ ConnectButton.Enabled := True;
+ ConnectButton.Visible := True;
+ StopButton.Visible := False;
+ StopButton.Enabled := False;
+ ListView.SetFocus;
+ Engine.Free;
Exit;
end;
+ if not DoNotSavePasswordsCheckBox.Checked then FActiveConnInfo.Password := Engine.Password;
+ Engine.Password := ''; // Security precaution
+ StopButton.Enabled := False;
ConnectedEngine := Engine;
ModalResult := mbOK;
end;
+function TFConnectionManager.DoConnectInternal(const URI: string; Engine: TVFSEngine; VFSDialogsParentWindow: PGtkWidget): boolean;
+begin
+ Result := False;
+ FSilenceError := False;
+ Thread := TOpenConnectionThread.Create;
+ try
+ Thread.VFSConnectionManagerMode := VFSDialogsParentWindow = FWidget;
+ Thread.VFSDialogsParentWindow := VFSDialogsParentWindow;
+ Thread.AEngine := Engine;
+ Thread.URI := URI;
+ Thread.Resume;
+ repeat
+ Sleep(ConstInternalProgressTimer);
+ Application.ProcessMessages;
+ if Thread.VFSAskQuestion_Display then begin
+ Thread.VFSAskQuestion_Display := False;
+ DebugMsg(['Main thread: displaying question dialog']);
+ HandleVFSAskQuestionCallback(FWidget, Thread.VFSAskQuestion_Message, Thread.VFSAskQuestion_Choices, Thread.VFSAskQuestion_Choice);
+ Thread.VFSCallbackEvent.SetEvent;
+ end;
+ if Thread.VFSAskPassword_Display then begin
+ Thread.VFSAskPassword_Display := False;
+ DebugMsg(['Main thread: displaying password prompt']);
+ Thread.VFSAskPassword_Result := HandleVFSAskPasswordCallback(FWidget,
+ Thread.VFSAskPassword_Message,
+ Thread.VFSAskPassword_default_user,
+ Thread.VFSAskPassword_default_domain,
+ Thread.VFSAskPassword_default_password,
+ Thread.VFSAskPassword_flags,
+ Thread.VFSAskPassword_username,
+ Thread.VFSAskPassword_password,
+ Thread.VFSAskPassword_anonymous,
+ Thread.VFSAskPassword_domain,
+ Thread.VFSAskPassword_password_save);
+ Thread.VFSCallbackEvent.SetEvent;
+ end;
+ until Thread.Finished;
+ Result := Thread.OpenResult;
+ FSilenceError := Thread.VFSCallbackCancelled;
+ Thread.Free;
+ Thread := nil;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TFConnectionManager.DoConnect (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
end.
diff --git a/UCore.pas b/UCore.pas
index b7f3067..afe8b10 100644
--- a/UCore.pas
+++ b/UCore.pas
@@ -20,7 +20,7 @@
unit UCore;
interface
-uses glib2, SyncObjs, Classes, GTKForms, GTKView, ULibc, UEngines, UCoreUtils, UProgress, UVFSCore, uVFSprototypes;
+uses glib2, gtk2, SyncObjs, Classes, GTKForms, GTKView, ULibc, UEngines, UCoreUtils, UProgress, UVFSCore, uVFSprototypes;
function FillPanel(List: TList; ListView: TGTKListView; Engine: TPanelEngine; LeftPanel: boolean): boolean;
@@ -59,6 +59,11 @@ type TVFSCallbackThread = class(TThread)
VFSCallbackCancelled: boolean;
+ VFSConnectionManagerMode: boolean;
+ VFSDialogsParentWindow: PGtkWidget;
+
+ FCancelRequested: boolean;
+
constructor Create(CreateSuspended: boolean);
destructor Destroy; override;
end;
@@ -100,7 +105,6 @@ type TVFSCallbackThread = class(TThread)
FCallbackLockEvent: TSimpleEvent;
-
// Parameters
ProgressForm: TFProgress;
Engine, SrcEngine, DestEngine: TPanelEngine;
@@ -169,11 +173,23 @@ type TVFSCallbackThread = class(TThread)
Finished, CancelIt: boolean;
RunningTime: Int64;
AFullPath, AHighlightItem: string;
+ constructor Create;
+ destructor Destroy; override;
+ end;
+ TOpenConnectionThread = class(TVFSCallbackThread)
+ private
+ protected
+ procedure Execute; override;
+ public
+ URI: string;
+ Finished: boolean;
+ OpenResult: boolean;
constructor Create;
destructor Destroy; override;
end;
+
// Thread aware functions (also half-thread-safe) without any piece of GTK code
procedure DeleteFilesWorker(SenderThread: TWorkerThread);
procedure CopyFilesWorker(SenderThread: TWorkerThread);
@@ -237,6 +253,7 @@ var LeftLocalEngine, RightLocalEngine: TPanelEngine;
FMainEscPressed: boolean;
UsedTempPaths: TStringList;
SelectHistory, SearchHistory: TStringList;
+ QuickConnectHistory: TStringList;
(********************************************************************************************************************************)
implementation
@@ -258,6 +275,9 @@ begin
VFSAskQuestion_Display := False;
VFSAskPassword_Display := False;
VFSCallbackCancelled := False;
+ VFSConnectionManagerMode := False;
+ VFSDialogsParentWindow := FMain.FWidget;
+ FCancelRequested := False;
end;
destructor TVFSCallbackThread.Destroy;
@@ -282,9 +302,16 @@ begin
Exit;
end;
+ if Thread.FCancelRequested then begin
+ DebugMsg(['!! (WARNING): vfs_ask_question_callback: FCancelRequested.']);
+ if (choice <> nil) then choice^ := -1;
+ Thread.VFSCallbackCancelled := True;
+ Exit;
+ end;
+
if pthread_self = Application.ThreadID then begin
- DebugMsg(['!! (WARNING): vfs_ask_question_callback called from the main thread, expected spawn from a OpenDirThread']);
- HandleVFSAskQuestionCallback(FMain.FWidget, AMessage, Choices, choice);
+ DebugMsg(['!! (WARNING): vfs_ask_question_callback called from the main thread, expected spawn from a TVFSCallbackThread']);
+ HandleVFSAskQuestionCallback(Thread.VFSDialogsParentWindow, AMessage, Choices, choice);
if (choice <> nil) then Thread.VFSCallbackCancelled := (choice^ < 0) or (choice^ = cancel_choice);
Exit;
end;
@@ -302,8 +329,8 @@ begin
Exit;
end;
- DebugMsg(['!! (ERROR): vfs_ask_question_callback spawned neither from the main thread nor from active OpenDirThread, dropping the callback to prevent data corruption.']);
- DebugMsg([' ThreadID = 0x', IntToHex(pthread_self, 16), ', OpenDirThread ID = 0x', IntToHex(Thread.FThreadID, 16), ', Application.ThreadID = 0x', IntToHex(Application.ThreadID, 16)]);
+ DebugMsg(['!! (ERROR): vfs_ask_question_callback spawned neither from the main thread nor from active TVFSCallbackThread, dropping the callback to prevent data corruption.']);
+ DebugMsg([' ThreadID = 0x', IntToHex(pthread_self, 16), ', TVFSCallbackThread ID = 0x', IntToHex(Thread.FThreadID, 16), ', Application.ThreadID = 0x', IntToHex(Application.ThreadID, 16)]);
end;
function vfs_ask_password_callback(const AMessage: PChar; const default_user: PChar; const default_domain: PChar; const default_password: PChar; flags: TVFSAskPasswordFlags;
@@ -319,6 +346,13 @@ begin
Exit;
end;
+ if Thread.FCancelRequested then begin
+ DebugMsg(['!! (WARNING): vfs_ask_password_callback: FCancelRequested.']);
+ Result := False;
+ Thread.VFSCallbackCancelled := True;
+ Exit;
+ end;
+
def_pass := default_password;
// Disable password saving if requested
@@ -326,27 +360,33 @@ begin
flags := flags and (not VFS_ASK_PASSWORD_SAVING_SUPPORTED);
if password_save <> nil then password_save^ := VFS_PASSWORD_SAVE_NEVER;
end;
- if ConfConnMgrDoNotSavePasswords then
- flags := flags and (not VFS_ASK_PASSWORD_SAVE_INTERNAL);
+ if ConfConnMgrDoNotSavePasswords then flags := flags and (not VFS_ASK_PASSWORD_SAVE_INTERNAL) else
+ if Thread.VFSConnectionManagerMode then flags := flags or VFS_ASK_PASSWORD_SAVE_INTERNAL;
+
// Use stored password, if previously set
- if ((flags and VFS_ASK_PASSWORD_ARCHIVE_MODE) = VFS_ASK_PASSWORD_ARCHIVE_MODE) and (password <> nil) and
- (Thread.AEngine is TVFSEngine) and (Length((Thread.AEngine as TVFSEngine).Password) > 0) then
+ if (((flags and VFS_ASK_PASSWORD_ARCHIVE_MODE) = VFS_ASK_PASSWORD_ARCHIVE_MODE) or Thread.VFSConnectionManagerMode) and
+ (password <> nil) and (Thread.AEngine is TVFSEngine) and (Length((Thread.AEngine as TVFSEngine).Password) > 0) then
begin
if not (Thread.AEngine as TVFSEngine).PasswordUsed then begin
DebugMsg([' (II) vfs_ask_password_callback: reusing manually set password']);
password^ := g_strdup(PChar((Thread.AEngine as TVFSEngine).Password));
(Thread.AEngine as TVFSEngine).PasswordUsed := True;
- Result := True;
+ if (password_save <> nil) and Thread.VFSConnectionManagerMode then
+ if ConfConnMgrDoNotSynchronizeKeyring then password_save^ := VFS_PASSWORD_SAVE_NEVER
+ else password_save^ := VFS_PASSWORD_SAVE_PERMANENTLY;
Thread.VFSCallbackCancelled := False;
+ Result := True;
Exit;
- end else def_pass := PChar((Thread.AEngine as TVFSEngine).Password);
+ end else
+ if (flags and VFS_ASK_PASSWORD_ARCHIVE_MODE) = VFS_ASK_PASSWORD_ARCHIVE_MODE then
+ def_pass := PChar((Thread.AEngine as TVFSEngine).Password);
end;
// Ask for password
if pthread_self = Application.ThreadID then begin
- DebugMsg(['!! (WARNING): vfs_ask_password_callback called from the main thread, expected spawn from a OpenDirThread']);
- Result := HandleVFSAskPasswordCallback(FMain.FWidget, AMessage, default_user, default_domain, def_pass, flags, username, password, anonymous, domain, password_save);
+ DebugMsg(['!! (WARNING): vfs_ask_password_callback called from the main thread, expected spawn from a TVFSCallbackThread']);
+ Result := HandleVFSAskPasswordCallback(Thread.VFSDialogsParentWindow, AMessage, default_user, default_domain, def_pass, flags, username, password, anonymous, domain, password_save);
Thread.VFSCallbackCancelled := Result = False;
end else
if pthread_self = Thread.FThreadID then begin
@@ -370,14 +410,14 @@ begin
Thread.VFSCallbackCancelled := Result = False;
end else
begin
- DebugMsg(['!! (ERROR): vfs_ask_password_callback spawned neither from the main thread nor from active OpenDirThread, dropping the callback to prevent data corruption.']);
- DebugMsg([' ThreadID = 0x', IntToHex(pthread_self, 16), ', OpenDirThread ID = 0x', IntToHex(Thread.FThreadID, 16), ', Application.ThreadID = 0x', IntToHex(Application.ThreadID, 16)]);
+ DebugMsg(['!! (ERROR): vfs_ask_password_callback spawned neither from the main thread nor from active TVFSCallbackThread, dropping the callback to prevent data corruption.']);
+ DebugMsg([' ThreadID = 0x', IntToHex(pthread_self, 16), ', TVFSCallbackThread ID = 0x', IntToHex(Thread.FThreadID, 16), ', Application.ThreadID = 0x', IntToHex(Application.ThreadID, 16)]);
end;
// Save password back to the engine
- if ((flags and VFS_ASK_PASSWORD_ARCHIVE_MODE) = VFS_ASK_PASSWORD_ARCHIVE_MODE) and
- Result and (password <> nil) and (strlen(password^) > 0) and
- (Thread.AEngine is TVFSEngine) then
+ if Result and (password <> nil) and (strlen(password^) > 0) and (Thread.AEngine is TVFSEngine) and
+ (((flags and VFS_ASK_PASSWORD_ARCHIVE_MODE) = VFS_ASK_PASSWORD_ARCHIVE_MODE) or
+ (Thread.VFSConnectionManagerMode and (password_save <> nil) and (password_save^ = VFS_PASSWORD_SAVE_PERMANENTLY))) then
begin
(Thread.AEngine as TVFSEngine).Password := string(password^);
(Thread.AEngine as TVFSEngine).PasswordUsed := True;
@@ -2903,6 +2943,32 @@ begin
end;
end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+constructor TOpenConnectionThread.Create;
+begin
+ inherited Create(True);
+ FreeOnTerminate := False;
+ Finished := False;
+ OpenResult := False;
+end;
+
+destructor TOpenConnectionThread.Destroy;
+begin
+ inherited Destroy;
+end;
+
+procedure TOpenConnectionThread.Execute;
+begin
+ PrepareExecute;
+ try
+ OpenResult := (AEngine as TVFSEngine).VFSOpenURI(URI, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self);
+ finally
+ Finished := True;
+ end;
+end;
+
(********************************************************************************************************************************)
(********************************************************************************************************************************)
function PurgeDirectory(APath: string): boolean;
diff --git a/UMain.pas b/UMain.pas
index c77ea4d..e799466 100644
--- a/UMain.pas
+++ b/UMain.pas
@@ -182,6 +182,7 @@ type
procedure miPathBoxCopyPathClick(Sender: TObject);
procedure miCopyNamesClick(Sender: TObject);
procedure RightMouseSelectPopupTimerTimer(Sender: TObject);
+ procedure miQuickConnectClick(Sender: TObject);
private
LeftLastFocused, Editing, QuickFind, RedrawLeftInactive, RedrawRightInactive, StartUp, LeftTabPopup: boolean;
LastWidth, RunningEscSensitive: integer;
@@ -242,6 +243,7 @@ type
function HandleKey(Key: Word; Shift: TShiftState; LeftPanel: boolean): boolean;
function IsEditing(AListView: TGTKListView): boolean;
function PanelFindEditableWidget(AListView: TGTKListView): PGtkWidget;
+ function CheckForUnsavedConnection(Engine: TVFSEngine; AllowCancel: boolean): boolean; // Returns False to Cancel
public
LeftPanelEngine, RightPanelEngine : TPanelEngine;
ColumnSortIDs: array[1..ConstNumPanelColumns] of integer;
@@ -260,7 +262,8 @@ uses ULibc,
UFileTypeSettings, UFileAssoc, UChmod, UChown, USymlink,
UPreferences, UViewer, UToolTips, UMounterPrefs, UColumns,
UTestPlugin, UConnectionManager, USearch, UProperties,
- URemoteWait, URunFromVFS, uVFSprototypes;
+ URemoteWait, URunFromVFS, uVFSprototypes, UQuickConnect,
+ UConnectionProperties;
@@ -901,7 +904,7 @@ begin
mnuNetwork.Add(miOpenConnection);
miQuickConnect := TGTKMenuItem.CreateTyped(Self, itImageText);
miQuickConnect.Caption := LANGmiQuickConnectCaption;
- miQuickConnect.Enabled := False;
+ miQuickConnect.OnClick := miQuickConnectClick;
miQuickConnect.ShortCuts.AddName('<Control>N');
mnuNetwork.Add(miQuickConnect);
mnuNetwork.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
@@ -1118,6 +1121,7 @@ procedure TFMain.FormClose(Sender: TObject; var Action: TCloseAction);
Result := FallbackEngine;
if not Assigned(Engine.ParentEngine) or (not (Engine is TVFSEngine)) then Exit;
Result := Engine.ParentEngine;
+ CheckForUnsavedConnection(Engine as TVFSEngine, False);
if not TVFSEngine(Engine).VFSClose then DebugMsg(['Error closing the engine...']);
Engine.Free;
end;
@@ -1170,8 +1174,10 @@ begin
LeftPanelTabs[i] := s;
end else
while Assigned(LeftTabEngines[i]) and (TPanelEngine(LeftTabEngines[i]) is TVFSEngine) do begin
- LeftPanelTabs[i] := TPanelEngine(LeftTabEngines[i]).SavePath;
+ s := TPanelEngine(LeftTabEngines[i]).SavePath;
LeftTabEngines[i] := InternalCloseEngine(LeftTabEngines[i], LeftLocalEngine);
+ if s <> '' then LeftPanelTabs[i] := s
+ else LeftPanelTabs[i] := TPanelEngine(LeftTabEngines[i]).Path;
end;
except end;
@@ -1187,8 +1193,10 @@ begin
RightPanelTabs[i] := s;
end else
while Assigned(RightTabEngines[i]) and (TPanelEngine(RightTabEngines[i]) is TVFSEngine) do begin
- RightPanelTabs[i] := TPanelEngine(RightTabEngines[i]).SavePath;
+ s := TPanelEngine(RightTabEngines[i]).SavePath;
RightTabEngines[i] := InternalCloseEngine(RightTabEngines[i], RightLocalEngine);
+ if s <> '' then RightPanelTabs[i] := s
+ else RightPanelTabs[i] := TPanelEngine(RightTabEngines[i]).Path;
end;
except end;
end;
@@ -5627,6 +5635,12 @@ begin
DebugMsg(['Couldn''t close tab: wrong TabNo']);
Exit;
end;
+
+ if TabNo > 0 then begin
+ Engine := TabEngines[TabNo];
+ if (Engine is TVFSEngine) and (not CheckForUnsavedConnection(Engine as TVFSEngine, True)) then Exit;
+ end;
+
if (ANotebook.ChildrenCount > 2) and (TabNo >= 0) then begin
// Close one tab, leave tab bar visible
Engine := TabEngines[TabNo];
@@ -5673,6 +5687,7 @@ begin
Engine := TabEngines[i];
while Engine is TVFSEngine do
try
+ if (i <> TabNo) and (not CheckForUnsavedConnection(Engine as TVFSEngine, False)) then Exit;
xEngine := Engine;
Engine := xEngine.ParentEngine;
if not TVFSEngine(xEngine).VFSClose then DebugMsg(['Error closing the engine...']);
@@ -5966,7 +5981,19 @@ 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 (not Assigned(Engine.ParentEngine)) or (not (Engine is TVFSEngine)) then begin
+ if LeftPanel then begin
+ LeftPanelEngine := LeftLocalEngine;
+ Result := LeftPanelEngine.Path;
+ end else begin
+ RightPanelEngine := RightLocalEngine;
+ Result := RightPanelEngine.Path;
+ end;
+ Exit;
+ end;
+
+ if not CheckForUnsavedConnection(Engine as TVFSEngine, (not SuppressRefresh) and (not ApplicationShuttingDown)) then Exit;
+
if LeftPanel then LeftPanelEngine := Engine.ParentEngine
else RightPanelEngine := Engine.ParentEngine;
@@ -5978,6 +6005,55 @@ begin
Engine.Free;
end;
+function TFMain.CheckForUnsavedConnection(Engine: TVFSEngine; AllowCancel: boolean): boolean; // Returns False to Cancel
+var Buttons: TMessageButtons;
+ CancelButton: TMessageButton;
+ AFConnectionProperties: TFConnectionProperties;
+ URI: string;
+ ConnMgrItem: TConnMgrItem;
+begin
+ Result := True;
+ URI := Engine.GetPathURI;
+ if Engine.OpenedFromQuickConnect and (Length(Trim(URI)) > 0) then begin
+ Buttons := [mbYes, mbNo];
+ CancelButton := mbNo;
+ if AllowCancel then begin
+ Include(Buttons, mbCancel);
+ CancelButton := mbCancel;
+ end;
+ case Application.MessageBox('The active connection has not been saved. Do you want to save it to Connection Manager?', Buttons, mbWarning, mbYes, CancelButton) of
+ mbYes: begin
+ AFConnectionProperties := TFConnectionProperties.Create(Self);
+ try
+ AFConnectionProperties.URIEntry.Text := URI;
+ if AFConnectionProperties.Run = mbOK then begin
+ ReadConnections;
+ ConnMgrItem := TConnMgrItem.Create;
+ ConnMgrItem.ConnectionName := AFConnectionProperties.NameEntry.Text;
+ ConnMgrItem.ServiceType := AFConnectionProperties.GetService;
+ ConnMgrItem.Server := AFConnectionProperties.ServerEntry.Text;
+ ConnMgrItem.Username := AFConnectionProperties.UserNameEntry.Text;
+ ConnMgrItem.Password := AFConnectionProperties.PasswordEntry.Text;
+ ConnMgrItem.TargetDir := AFConnectionProperties.TargetDirEntry.Text;
+ ConnMgrItem.PluginID := '';
+ if AFConnectionProperties.PluginOptionMenu.ItemIndex <> 0 then
+ ConnMgrItem.PluginID := TVFSPlugin(PluginList[AFConnectionProperties.PluginOptionMenu.ItemIndex - 1]).VFSName;
+ ConnectionMgrList.Add(ConnMgrItem);
+ WriteConnections;
+ end;
+ finally
+ AFConnectionProperties.Free;
+ end;
+ Result := True;
+ end;
+ mbNo: Result := True;
+ mbCancel: Result := False;
+ else {Cancel?} Result := not AllowCancel;
+ end;
+ end;
+end;
+
+
(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure TFMain.ShowBookmarkQuick(LeftPanel: boolean);
@@ -6061,14 +6137,11 @@ var b: boolean;
begin
try
InternalLock;
-
+ ReadConnections;
FConnectionManager := TFConnectionManager.Create(Self);
if LeftLastFocused then FConnectionManager.SourcePanelEngine := LeftPanelEngine
else FConnectionManager.SourcePanelEngine := RightPanelEngine;
b := FConnectionManager.Run = mbOK;
- if FConnectionManager.ListView.Selected <> nil then ConfConnMgrActiveItem := FConnectionManager.ListView.Selected.Index;
- ConfConnMgrDoNotSavePasswords := FConnectionManager.DoNotSavePasswordsCheckBox.Checked;
- ConfConnMgrDoNotSynchronizeKeyring := FConnectionManager.DoNotSynchronizeKeyringCheckBox.Checked;
WriteConnections; // Save connection manager data
if b and (FConnectionManager.ConnectedEngine <> nil) then begin
@@ -6084,6 +6157,31 @@ begin
end;
end;
+procedure TFMain.miQuickConnectClick(Sender: TObject);
+var b: boolean;
+begin
+ try
+ InternalLock;
+ ReadConnections;
+ FQuickConnect := TFQuickConnect.Create(Self);
+ if LeftLastFocused then FQuickConnect.SourcePanelEngine := LeftPanelEngine
+ else FQuickConnect.SourcePanelEngine := RightPanelEngine;
+ b := FQuickConnect.Run = mbOK;
+ WriteConnections; // Save connection manager data
+
+ if b and (FQuickConnect.ConnectedEngine <> nil) then begin
+ if FQuickConnect.SourcePanelEngine is TVFSEngine then CloseVFS(LeftLastFocused, True);
+ if LeftLastFocused then LeftPanelEngine := FQuickConnect.ConnectedEngine
+ else RightPanelEngine := FQuickConnect.ConnectedEngine;
+ DoRefresh(LeftLastFocused, False, False);
+ end;
+ finally
+ FQuickConnect.Free;
+ Application.ProcessMessages;
+ InternalLockInit(False);
+ end;
+end;
+
procedure TFMain.miDisconnectClick(Sender: TObject);
begin
CloseVFS(LeftLastFocused, False);
diff --git a/UQuickConnect.pas b/UQuickConnect.pas
new file mode 100644
index 0000000..d92e335
--- /dev/null
+++ b/UQuickConnect.pas
@@ -0,0 +1,349 @@
+(*
+ Tux Commander - UQuickConnect - Quick connection dialog
+ 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 UQuickConnect;
+
+interface
+
+uses
+ glib2, gdk2, gtk2, pango, SysUtils, Types, Classes, GTKControls, GTKForms, GTKStdCtrls, GTKExtCtrls, GTKConsts, GTKView,
+ GTKUtils, GTKDialogs, GTKPixbuf, GTKClasses, GTKMenus,
+ UCore, UCoreClasses, UVFSCore, UEngines, UConnectionManager;
+
+type
+ TFQuickConnect = class(TGTKDialog)
+ TitleFrame: TGTKFrame;
+ TitleLabel: TGTKLabel;
+ TitleEventBox: TGTKEventBox;
+ TitleIcon: TGTKImage;
+ TitleHBox: TGTKHBox;
+ Table: TGTKTable;
+ ActionButtonBox: TGTKHButtonBox;
+ ConnectButton, StopButton, CloseButton: TGTKButton;
+ Label1, Label2: TGTKLabel;
+ URIComboBox: TGTKCombo;
+ PluginOptionMenu: TGTKOptionMenu;
+ procedure FormCreate(Sender: TObject); override;
+ procedure FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure FormResponse(Sender: TObject; const ResponseID: integer);
+ procedure CloseButtonClick(Sender: TObject);
+ procedure ConnectButtonClick(Sender: TObject);
+ procedure StopButtonClick(Sender: TObject);
+ procedure ComboBoxKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+ procedure ComboBoxChanged(Sender: TObject);
+ private
+ AFConnectionManager: TFConnectionManager;
+ SavedData: string;
+ procedure DoConnect;
+ public
+ SourcePanelEngine: TPanelEngine;
+ ConnectedEngine: TVFSEngine;
+ ConnectionManager: TFConnectionManager;
+ end;
+
+var
+ FQuickConnect: TFQuickConnect;
+
+implementation
+
+uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, uVFSprototypes;
+
+
+procedure TFQuickConnect.FormCreate(Sender: TObject);
+var i: integer;
+ MenuItem: TGTKMenuItem;
+begin
+ SavedData := '';
+ ConnectedEngine := nil;
+ ConnectionManager := nil;
+ AFConnectionManager := nil;
+ SetDefaultSize(435, 200);
+ Caption := 'Quick connect';
+ Buttons := [];
+ ShowSeparator := False;
+
+ ConnectButton := TGTKButton.Create(Self);
+ ConnectButton.Caption := LANGConnMgr_ConnectButton;
+// ConnectButton.Default := True;
+ CloseButton := TGTKButton.CreateFromStock(Self, GTK_STOCK_CLOSE);
+ StopButton := TGTKButton.CreateFromStock(Self, GTK_STOCK_STOP);
+ StopButton.Visible := False;
+ StopButton.Enabled := False;
+// Default := ConnectButton;
+ ActionButtonBox := TGTKHButtonBox.Create(Self);
+ ActionButtonBox.Layout := blEnd;
+ ActionButtonBox.Spacing := 10;
+ ActionButtonBox.BorderWidth := 0;
+ ActionButtonBox.AddControlEnd(CloseButton);
+ ActionButtonBox.AddControlEnd(ConnectButton);
+ ActionButtonBox.AddControlEnd(StopButton);
+
+ ActionArea.AddControlEx(ActionButtonBox, False, False, 0);
+
+ TitleEventBox := TGTKEventBox.Create(Self);
+ TitleLabel := TGTKLabel.Create(Self);
+ TitleLabel.Caption := Format('<span size="x-large" weight="ultrabold">%s</span>', ['Quick connect']);
+ TitleLabel.UseMarkup := True;
+ TitleLabel.XAlign := 0;
+ TitleLabel.XPadding := 0;
+ TitleLabel.YPadding := 3;
+ TitleEventBox.ControlState := csPrelight;
+ TitleFrame := TGTKFrame.CreateWithoutLabel(Self);
+ TitleFrame.ShadowType := stShadowOut;
+ TitleIcon := TGTKImage.Create(Self);
+ TitleIcon.SetFromStock('gtk-connect', isLargeToolbar);
+ TitleHBox := TGTKHBox.Create(Self);
+ TitleHBox.Homogeneous := False;
+ TitleHBox.AddControlEx(TGTKEventBox.Create(Self), False, False, 5);
+ TitleHBox.AddControlEx(TitleIcon, False, False, 0);
+ TitleHBox.AddControlEx(TitleLabel, True, True, 10);
+ TitleEventBox.AddControl(TitleHBox);
+ TitleFrame.AddControl(TitleEventBox);
+ ClientArea.AddControlEx(TitleFrame, False, True, 0);
+
+ Table := TGTKTable.Create(Self);
+ Table.BorderWidth := 25;
+ ClientArea.AddControlEx(Table, True, True, 0);
+
+ URIComboBox := TGtkCombo.Create(Self);
+ URIComboBox.DisableActivate;
+ PluginOptionMenu := TGTKOptionMenu.Create(Self);
+
+ Label1 := TGTKLabel.Create(Self);
+ Label1.Caption := Format('<span weight="ultrabold">%s</span>', ['C_onnect to URI:']);
+ Label1.FocusControl := URIComboBox.Entry;
+ Label1.UseMarkup := True;
+ Label1.UseUnderline := True;
+ Label1.XAlign := 0;
+ Label2 := TGTKLabel.Create(Self);
+ Label2.Caption := LANGConnProp_VFSModule;
+ Label2.FocusControl := PluginOptionMenu;
+ Label2.UseUnderline := True;
+ Label2.XAlign := 0;
+
+ if QuickConnectHistory.Count > 0 then
+ for i := 0 to QuickConnectHistory.Count - 1 do
+ URIComboBox.Items.Append(QuickConnectHistory[i]);
+ URIComboBox.Entry.Text := '';
+
+ // Fill the plugins menu
+ MenuItem := TGTKMenuItem.CreateTyped(Self, itLabel);
+ MenuItem.Caption := LANGConnProp_MenuItemCaption;
+ PluginOptionMenu.Items.Add(MenuItem);
+ for i := 0 to PluginList.Count - 1 do begin
+ MenuItem := TGTKMenuItem.CreateTyped(Self, itImageText);
+ MenuItem.SetCaptionPlain(Format('%s [%s]', [TVFSPlugin(PluginList[i]).VFSName,
+ ExtractFileName(TVFSPlugin(PluginList[i]).FullPath)]));
+ PluginOptionMenu.Items.Add(MenuItem);
+ end;
+
+ // Find last used plugin
+ if Length(Trim(ConfQuickConnectPluginID)) > 0 then
+ for i := 0 to PluginList.Count - 1 do
+ if TVFSPlugin(PluginList[i]).VFSName = ConfQuickConnectPluginID then begin
+ PluginOptionMenu.ItemIndex := i + 1;
+ Break;
+ end;
+
+// Table.AddControlEx(1, 1, 2, 1, TGTKEventBox.Create(Self), [taoExpand, taoFill], [taoShrink], 0, 2);
+ Table.AddControlEx(0, 0, 2, 1, Label1, [taoShrink, taoFill], [taoShrink], 0, 2);
+ Table.AddControlEx(0, 1, 2, 1, URIComboBox, [taoExpand, taoFill], [taoShrink], 0, 5);
+ Table.AddControlEx(0, 2, 1, 1, Label2, [taoShrink, taoFill], [taoShrink], 10, 5);
+ Table.AddControlEx(1, 2, 1, 1, PluginOptionMenu, [taoExpand, taoFill], [taoShrink], 0, 5);
+
+ CloseButton.OnClick := CloseButtonClick;
+ ConnectButton.OnClick := ConnectButtonClick;
+ StopButton.OnClick := StopButtonClick;
+ OnKeyDown := FormKeyDown;
+ OnClose := FormClose;
+ OnResponse := FormResponse;
+ URIComboBox.Entry.OnKeyDown := ComboBoxKeyDown;
+ URIComboBox.Entry.OnChanged := ComboBoxChanged;
+ ComboBoxChanged(Sender);
+end;
+
+procedure TFQuickConnect.FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+begin
+ case Key of
+ GDK_RETURN, GDK_KP_ENTER: if StopButton.Visible then StopButtonClick(Sender)
+ else DoConnect;
+ GDK_ESCAPE: begin
+ Accept := False;
+ if StopButton.Visible then StopButtonClick(Sender)
+ else ModalResult := mbCancel;
+ end;
+ end;
+end;
+
+procedure TFQuickConnect.ComboBoxKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+var Orig, s: string;
+ i: integer;
+begin
+ case Key of
+ GDK_UP, GDK_DOWN: if Shift = [] then begin
+ Accept := False;
+ if QuickConnectHistory.Count > 0 then begin
+ Orig := Trim(URIComboBox.Entry.Text);
+ i := QuickConnectHistory.IndexOf(Orig);
+
+ if Key = GDK_DOWN then begin
+ if i < 0 then begin
+ SavedData := Orig;
+ i := 0;
+ end else
+ if QuickConnectHistory.Count > i + 1 then Inc(i);
+ s := QuickConnectHistory[i];
+ end else begin
+ if i < 0 then Exit else
+ if i = 0 then begin
+ s := SavedData;
+ SavedData := '';
+ end else
+ if QuickConnectHistory.Count > i then s := QuickConnectHistory[i - 1];
+ end;
+
+ URIComboBox.Entry.Text := s;
+ URIComboBox.Entry.SetFocus;
+ URIComboBox.Entry.SelectAll;
+ end;
+ end;
+ end;
+end;
+
+procedure TFQuickConnect.ComboBoxChanged(Sender: TObject);
+begin
+ ConnectButton.Enabled := Length(Trim(URIComboBox.Entry.Text)) > 0;
+end;
+
+procedure TFQuickConnect.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ if Length(Trim(URIComboBox.Entry.Text)) > 0 then
+ SaveItemToHistory(URIComboBox.Entry.Text, QuickConnectHistory);
+ if PluginOptionMenu.ItemIndex <> 0
+ then ConfQuickConnectPluginID := TVFSPlugin(PluginList[PluginOptionMenu.ItemIndex - 1]).VFSName
+ else ConfQuickConnectPluginID := '';
+end;
+
+procedure TFQuickConnect.FormResponse(Sender: TObject; const ResponseID: integer);
+var Action: TCloseAction;
+begin
+ FormClose(Sender, Action);
+end;
+
+(********************************************************************************************************************************)
+procedure TFQuickConnect.CloseButtonClick(Sender: TObject);
+begin
+ ModalResult := mbCancel;
+end;
+
+procedure TFQuickConnect.ConnectButtonClick(Sender: TObject);
+begin
+ DoConnect;
+end;
+
+procedure TFQuickConnect.StopButtonClick(Sender: TObject);
+begin
+ if (AFConnectionManager <> nil) and (AFConnectionManager.Thread <> nil) then
+ AFConnectionManager.Thread.FCancelRequested := True;
+end;
+
+procedure TFQuickConnect.DoConnect;
+var Engine: TVFSEngine;
+ i, j: integer;
+ VFSPlugin: TVFSPlugin;
+ Scheme: string;
+begin
+ if ConnectionManager <> nil then AFConnectionManager := ConnectionManager
+ else AFConnectionManager := TFConnectionManager.Create(Self);
+
+ if PluginList.Count = 0 then begin
+ Application.MessageBox(PGtkWindow(FWidget), LANGThereIsNoModuleAvailable, [mbOK], mbError, mbOK, mbOK);
+ Exit;
+ end;
+
+ // Find VFS module to use for this connection
+ VFSPlugin := nil;
+ if PluginOptionMenu.ItemIndex <> 0 then ConfQuickConnectPluginID := TVFSPlugin(PluginList[PluginOptionMenu.ItemIndex - 1]).VFSName
+ else ConfQuickConnectPluginID := '';
+ if Length(ConfQuickConnectPluginID) > 0 then
+ for i := 0 to PluginList.Count - 1 do
+ if TVFSPlugin(PluginList[i]).VFSName = ConfQuickConnectPluginID then begin
+ VFSPlugin := PluginList[i];
+ Break;
+ end;
+ if VFSPlugin = nil then begin
+ Scheme := '';
+ if Pos('://', URIComboBox.Entry.Text) > 0 then
+ Scheme := Copy(URIComboBox.Entry.Text, 1, Pos('://', URIComboBox.Entry.Text) - 1);
+ 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 WideCompareText(TVFSPlugin(PluginList[i]).Services[j], Scheme) = 0 then begin
+ VFSPlugin := PluginList[i];
+ Break;
+ end;
+ if VFSPlugin <> nil then Break;
+ end;
+ if VFSPlugin = nil then VFSPlugin := PluginList[0]; // Fallback in hope some other plugin can handle it
+ end;
+
+ if (SourcePanelEngine is TVFSEngine) and (Application.MessageBox(PGtkWindow(FWidget), LANGCloseOpenConnection, [mbYes, mbNo], mbWarning, mbYes, mbNo) <> mbYes) then Exit;
+
+ Table.Enabled := False;
+ CloseButton.Enabled := False;
+ ConnectButton.Enabled := False;
+ ConnectButton.Visible := False;
+ StopButton.Enabled := True;
+ StopButton.Visible := True;
+ StopButton.Default := True;
+ StopButton.SetFocus;
+
+ // Construct the VFS Engine and try to open the connection
+ Engine := TVFSEngine.Create(VFSPlugin);
+ Engine.ParentEngine := SourcePanelEngine;
+ Engine.SavePath := SourcePanelEngine.Path;
+ Engine.OpenedFromQuickConnect := True;
+
+ if not AFConnectionManager.DoConnectInternal(URIComboBox.Entry.Text, Engine, FWidget) then begin
+ if not AFConnectionManager.FSilenceError then Application.MessageBox(PGtkWindow(FWidget), LANGCouldntOpenURI, [mbOK], mbError, mbOK, mbOK);
+ Table.Enabled := True;
+ CloseButton.Enabled := True;
+ ConnectButton.Enabled := True;
+ ConnectButton.Visible := True;
+ StopButton.Visible := False;
+ StopButton.Enabled := False;
+ URIComboBox.Entry.SetFocus;
+ Engine.Free;
+ Exit;
+ end;
+
+ Engine.Password := ''; // Security precaution
+ StopButton.Enabled := False;
+ ConnectedEngine := Engine;
+
+ if ConnectionManager = nil then AFConnectionManager.Free;
+ ModalResult := mbOK;
+end;
+
+
+
+end.
+
+
diff --git a/libgtk_kylix/GTKStdCtrls.pas b/libgtk_kylix/GTKStdCtrls.pas
index 1cccdf8..f61560f 100644
--- a/libgtk_kylix/GTKStdCtrls.pas
+++ b/libgtk_kylix/GTKStdCtrls.pas
@@ -1,6 +1,6 @@
(*
GTK-Kylix Library: GTKStdCtrls - Standard visual controls (such as buttons, labels, entry)
- Version 0.6.23 (last updated 2007-12-08)
+ Version 0.6.24 (last updated 2008-11-17)
Copyright (C) 2007 Tomas Bzatek <tbzatek@users.sourceforge.net>
This library is free software; you can redistribute it and/or
@@ -797,6 +797,7 @@ begin
inherited Create(AOwner);
FLinked := True;
FWidget := Widget;
+ g_signal_connect(PGtkObject(FWidget), 'changed', G_CALLBACK(@TGTKEditable_Changed), Self);
end;
destructor TGTKEntry.Destroy;
diff --git a/tuxcmd.dpr b/tuxcmd.dpr
index b55bde1..1aa4b87 100644
--- a/tuxcmd.dpr
+++ b/tuxcmd.dpr
@@ -65,6 +65,7 @@ uses
UGlibThreads in 'UGlibThreads.pas',
URunFromVFS in 'URunFromVFS.pas',
ULibc in 'ULibc.pas',
+ UQuickConnect in 'UQuickConnect.pas',
UTranslation_EN in 'translations/UTranslation_EN.pas',
UTranslation_CZ in 'translations/UTranslation_CZ.pas',
UTranslation_RU in 'translations/UTranslation_RU.pas',
diff --git a/vfs/UVFSCore.pas b/vfs/UVFSCore.pas
index 7531e9c..6cd1114 100644
--- a/vfs/UVFSCore.pas
+++ b/vfs/UVFSCore.pas
@@ -38,6 +38,7 @@ type
FVFSListClose: TVFSListClose;
FVFSChangeDir: TVFSChangeDir;
FVFSGetPath: TVFSGetPath;
+ FVFSGetPathURI: TVFSGetPathURI;
FVFSGetPrefix: TVFSGetPrefix;
FVFSGetFileSystemSize: TVFSGetFileSystemSize;
FVFSGetFileSystemFree: TVFSGetFileSystemFree;
@@ -93,6 +94,7 @@ type
Password: string;
PasswordUsed: boolean;
RemoveFileOnClose: string;
+ OpenedFromQuickConnect: boolean;
constructor Create(SourcePlugin: TVFSPlugin);
function VFSOpenURI(URI: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean;
function VFSOpenEx(OpenFile: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): TVFSResult;
@@ -132,6 +134,7 @@ type
function GetPath: string; override;
procedure SetPath(Value: string); override;
function GetPrefix: string; override;
+ function GetPathURI: string;
function GetBlockSize: Cardinal; override;
procedure SetBlockSize(Value: Cardinal); override;
@@ -195,6 +198,7 @@ begin
@FVFSListNext := dlsym(ModuleHandle, 'VFSListNext');
@FVFSListClose := dlsym(ModuleHandle, 'VFSListClose');
@FVFSGetPath := dlsym(ModuleHandle, 'VFSGetPath');
+ @FVFSGetPathURI := dlsym(ModuleHandle, 'VFSGetPathURI');
@FVFSChangeDir := dlsym(ModuleHandle, 'VFSChangeDir');
@FVFSGetPrefix := dlsym(ModuleHandle, 'VFSGetPrefix');
@FVFSGetFileSystemSize := dlsym(ModuleHandle, 'VFSGetFileSystemSize');
@@ -296,6 +300,7 @@ begin
Password := '';
PasswordUsed := False;
RemoveFileOnClose := '';
+ OpenedFromQuickConnect := False;
if @FSourcePlugin.FVFSNew <> nil then FGlobs := FSourcePlugin.FVFSNew(@VFSLogFunc);
end;
@@ -506,6 +511,16 @@ begin
else Result := '/';
end;
+function TVFSEngine.GetPathURI: string;
+var x: PChar;
+begin
+ Result := '';
+ if (FGlobs <> nil) and (@FSourcePlugin.FVFSGetPathURI <> nil) then begin
+ x := FSourcePlugin.FVFSGetPathURI(FGlobs);
+ if x <> nil then Result := string(x);
+ end;
+end;
+
function TVFSEngine.ChangeDir(const NewPath: string): integer;
begin
DebugMsg(['^^VFS (II): ChangeDir begin']);
diff --git a/vfs/uVFSprototypes.pas b/vfs/uVFSprototypes.pas
index 35d6d8f..a67b303 100644
--- a/vfs/uVFSprototypes.pas
+++ b/vfs/uVFSprototypes.pas
@@ -232,6 +232,9 @@ type
// Try to change the directory when correct permissions
TVFSGetPath = function (g:TVFSGlobs): PChar; cdecl;
// Returns the current working path (not all plugins can support this; just return '/' in this case)
+ TVFSGetPathURI = function (g:TVFSGlobs): PChar; cdecl;
+ // Returns the current working path in the URI form
+ // !!!!!!!!!!! k temhle (a vsem ostatnim) funkcim pridat komentar, kdo ma vubec pamet dealokovat + udelat review pluginus
TVFSGetFileSystemSize = function (g:TVFSGlobs; const APath: PChar): Int64; cdecl;
// Gets the size of filesystem; the path is optional, specified to recognize various mounted filesystems in the tree
TVFSGetFileSystemFree = function (g:TVFSGlobs; const APath: PChar): Int64; cdecl;