(*
    Tux Commander - UConnectionManager - Connection manager dialog
    Copyright (C) 2004 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 UConnectionManager;

interface

uses
  glib2, gdk2, gtk2, pango, SysUtils, Types, Classes, GTKControls, GTKForms, GTKStdCtrls, GTKExtCtrls, GTKConsts, GTKView,
  GTKUtils, GTKDialogs, GTKPixbuf, GTKClasses, GTKMenus,
  UCore, UCoreClasses, UVFSCore, UEngines;

type
  TFConnectionManager = class(TGTKDialog)
    TitleFrame: TGTKFrame;
    TitleLabel: TGTKLabel;
    TitleEventBox: TGTKEventBox;
    TitleIcon: TGTKImage;
    TitleHBox: TGTKHBox;
    ListView: TGTKListView;
    ListViewScrolledWindow: TGTKScrolledWindow;
    ListViewTable: TGTKTable;
    AddConnectionButton, EditButton, RemoveButton, DuplicateButton: TGTKImageButton;
    QuickConnectButton: TGTKImageButton;
    ButtonBox: TGTKVButtonBox;
    ActionButtonBox: TGTKHButtonBox;
    ConnectButton, StopButton, CloseButton: TGTKButton;
    DoNotSavePasswordsCheckBox, DoNotSynchronizeKeyringCheckBox: TGTKCheckButton;
    ItemsPopupMenu, ConnectMenuItem, AddConnectionMenuItem, EditMenuItem, RemoveMenuItem, DuplicateMenuItem: TGTKMenuItem;
    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);
    procedure EditButtonClick(Sender: TObject);
    procedure DuplicateButtonClick(Sender: TObject);
    procedure RemoveButtonClick(Sender: TObject);
    procedure ListViewDblClick(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
    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
    procedure FillList;
    procedure DoConnect;
  public
    FSilenceError: boolean;
    Thread: TOpenConnectionThread;
    SourcePanelEngine: TPanelEngine;
    ConnectedEngine: TVFSEngine;
    function DoConnectInternal(const URI: string; Engine: TVFSEngine; VFSDialogsParentWindow: PGtkWidget; VFSQuickConnectMode: boolean): boolean;
  end;

var
  FConnectionManager: TFConnectionManager;

implementation

uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, UQuickConnect;


procedure TFConnectionManager.FormCreate(Sender: TObject);
const row_targets: TGtkTargetEntry = (target: 'GTK_TREE_MODEL_ROW'; flags: GTK_TARGET_SAME_WIDGET; info:  1;);
var Column: TGTKTreeViewColumn;
begin
  Thread := nil;
  ConnectedEngine := nil;
  SetDefaultSize(650, 500);
  Caption := LANGConnMgr_Caption;
  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>', [LANGConnMgr_OpenConnection]);
  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);

  ListViewTable := TGTKTable.Create(Self);
  ListViewTable.BorderWidth := 7;
  ClientArea.AddControlEx(ListViewTable, True, True, 0);

  ListView := TGTKListView.CreateTyped(Self, True, [lcPointer, lcText, lcText]);
  ListView.SelectionMode := smSingle;
  ListView.OnKeyDown := ListViewKeyDown;

{
  gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(ListView.FWidget), GDK_BUTTON1_MASK, @row_targets, 1, GDK_ACTION_MOVE);
  gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(ListView.FWidget), @row_targets, 1, GDK_ACTION_MOVE);
}

  ListView.RulesHint := True;
  ListView.ShowHeaders := True;
  Column := ListView.Columns.Add;
  Column.AddAttribute('text', 1);
  Column.Resizable := True;
  Column.FixedWidth := ConfConnMgrColumn1Width;
  Column.SizingMode := smFixed;
  Column.Caption := LANGConnMgr_NameColumn;
  Column.Clickable := True;
  Column.SortID := 1;
  Column := ListView.Columns.Add;
  Column.AddAttribute('text', 2);
  Column.Resizable := True;
  Column.SizingMode := smFixed;
  Column.Caption := LANGConnMgr_URIColumn;
  Column.Clickable := True;
  Column.SortID := 2;
  ListView.SearchColumn := 1;
  ListView.SetSortInfo(ConfConnMgrSortColumn, TGTKTreeViewSortOrder(ConfConnMgrSortType));
  ListViewScrolledWindow := TGTKScrolledWindow.Create(Self);
  ListViewScrolledWindow.AddControl(ListView);
  ListViewScrolledWindow.HorizScrollBarPolicy := sbAutomatic;
  ListViewScrolledWindow.VertScrollBarPolicy := sbAutomatic;
  ListViewScrolledWindow.ShadowType := stShadowIn;

  AddConnectionButton := TGTKImageButton.Create(Self);
  AddConnectionButton.SetFromStock('gtk-add', isSmallToolbar);
  AddConnectionButton.Caption := LANGConnMgr_AddConnectionButtonCaption;
  AddConnectionButton.UseUnderline := True;
  AddConnectionButton.Tooltip := LANGConnMgr_AddConnectionButtonTooltip;
  EditButton := TGTKImageButton.Create(Self);
  EditButton.Caption := LANGConnMgr_EditButtonCaption;
  EditButton.UseUnderline := True;
  EditButton.Tooltip := LANGConnMgr_EditButtonTooltip;
  RemoveButton := TGTKImageButton.Create(Self);
  RemoveButton.SetFromStock('gtk-remove', isSmallToolbar);
  RemoveButton.Caption := LANGConnMgr_RemoveButtonCaption;
  RemoveButton.UseUnderline := True;
  RemoveButton.Tooltip := LANGConnMgr_RemoveButtonTooltip;
  DuplicateButton := TGTKImageButton.Create(Self);
  DuplicateButton.Caption := LANGFConnectionManager_DuplicateButton_Caption;
  DuplicateButton.UseUnderline := True;
  DuplicateButton.Tooltip := LANGFConnectionManager_DuplicateButton_Tooltip;

  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(DuplicateButton);
  ButtonBox.AddControl(RemoveButton);

  DoNotSavePasswordsCheckBox := TGTKCheckButton.CreateWithLabel(Self, LANGFConnectionManager_DoNotSavePasswordsCheckBox_Label);
  DoNotSavePasswordsCheckBox.Tooltip := LANGFConnectionManager_DoNotSavePasswordsCheckBox_Tooltip;
  DoNotSynchronizeKeyringCheckBox := TGTKCheckButton.CreateWithLabel(Self, LANGFConnectionManager_DoNotSynchronizeKeyringCheckBox_Label);
  DoNotSynchronizeKeyringCheckBox.Tooltip := LANGFConnectionManager_DoNotSynchronizeKeyringCheckBox_Tooltip;

  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, 5, 1, 1, TGTKLabel.Create(Self), [taoShrink, taoFill], [taoExpand, taoFill], 0, 2);


  ItemsPopupMenu := TGTKMenuItem.Create(Self);
  ConnectMenuItem := TGTKMenuItem.CreateTyped(Self, itImageText);
  ConnectMenuItem.Caption := LANGConnMgr_ConnectButton;
  ConnectMenuItem.StockIcon := 'gtk-connect';
  ConnectMenuItem.OnClick := ConnectButtonClick;
  AddConnectionMenuItem := TGTKMenuItem.CreateTyped(Self, itImageText);
  AddConnectionMenuItem.Caption := LANGConnMgr_AddConnectionButtonCaption;
  AddConnectionMenuItem.StockIcon := 'gtk-add';
  AddConnectionMenuItem.OnClick := AddConnectionButtonClick;
  EditMenuItem := TGTKMenuItem.CreateTyped(Self, itImageText);
  EditMenuItem.Caption := LANGConnMgr_EditButtonCaption;
  EditMenuItem.OnClick := EditButtonClick;
  RemoveMenuItem := TGTKMenuItem.CreateTyped(Self, itImageText);
  RemoveMenuItem.Caption := LANGConnMgr_RemoveButtonCaption;
  RemoveMenuItem.StockIcon := 'gtk-remove';
  RemoveMenuItem.OnClick := RemoveButtonClick;
  DuplicateMenuItem := TGTKMenuItem.CreateTyped(Self, itImageText);
  DuplicateMenuItem.Caption := LANGFConnectionManager_DuplicateMenuItem_Caption;
  DuplicateMenuItem.OnClick := DuplicateButtonClick;
  ItemsPopupMenu.Add(ConnectMenuItem);
  ItemsPopupMenu.Add(TGTKMenuItem.CreateTyped(Self, itSeparator));
  ItemsPopupMenu.Add(AddConnectionMenuItem);
  ItemsPopupMenu.Add(EditMenuItem);
  ItemsPopupMenu.Add(DuplicateMenuItem);
  ItemsPopupMenu.Add(RemoveMenuItem);

  FillList;
  ListView.OnSelectionChanged := ListViewSelectionChanged;
  ListView.OnDblClick := ListViewDblClick;
  ListView.PopupMenu := ItemsPopupMenu;
  ListView.SetFocus;
  if (ListView.Items.Count > 0) and (ConfConnMgrActiveItem >= 0) and (ConfConnMgrActiveItem < ListView.Items.Count) then begin
    ListView.Items[ConfConnMgrActiveItem].Selected := True;
    ListView.Items[ConfConnMgrActiveItem].SetCursor(0, False, False, 0, 0);
  end;
  ListViewSelectionChanged(Self);
  AddConnectionButton.OnClick := AddConnectionButtonClick;
  EditButton.OnClick := EditButtonClick;
  DuplicateButton.OnClick := DuplicateButtonClick;
  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);
begin
  try
    EditButton.Enabled := Assigned(ListView.Selected);
    DuplicateButton.Enabled := Assigned(ListView.Selected);
    RemoveButton.Enabled := Assigned(ListView.Selected);
    ConnectButton.Enabled := Assigned(ListView.Selected);
    ConnectMenuItem.Enabled := Assigned(ListView.Selected);
    EditMenuItem.Enabled := Assigned(ListView.Selected);
    DuplicateMenuItem.Enabled := Assigned(ListView.Selected);
    RemoveMenuItem.Enabled := Assigned(ListView.Selected);
  except end;
end;

procedure TFConnectionManager.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
                                  if Assigned(ListView.Selected) then DoConnect;
    GDK_ESCAPE: begin
                  Accept := False;
                  if StopButton.Visible then StopButtonClick(Sender)
                                        else ModalResult := mbCancel;
                end;
  end;
end;

procedure TFConnectionManager.ListViewDblClick(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean);
begin
  if Assigned(ListView.Selected) and (Button = mbLeft) and (ListView.GetItemAtPos(X, Y) <> nil)
    then DoConnect;
end;

procedure TFConnectionManager.ListViewKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
begin
  case Key of
    GDK_Delete_Key: RemoveButtonClick(Sender);
  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;
  ConfConnMgrSortColumn := ListView.SortColumnID;
  ConfConnMgrSortType := Integer(ListView.SortOrder);
  ConfConnMgrColumn1Width := ListView.Columns[0].Width;
end;

procedure TFConnectionManager.FormResponse(Sender: TObject; const ResponseID: integer);
var Action: TCloseAction;
begin
  FormClose(Sender, Action);
end;


(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure TFConnectionManager.AddConnectionButtonClick(Sender: TObject);
var Item: TGTKListItem;
    ConnMgrItem: TConnMgrItem;
begin
  try
    FConnectionProperties := TFConnectionProperties.Create(Self);
    if FConnectionProperties.Run = mbOK then begin
      ConnMgrItem := TConnMgrItem.Create;
      with FConnectionProperties do begin
        ConnMgrItem.ConnectionName := NameEntry.Text;
        ConnMgrItem.ServiceType := GetService;
        ConnMgrItem.Server := ServerEntry.Text;
        ConnMgrItem.Username := UserNameEntry.Text;
        ConnMgrItem.Password := PasswordEntry.Text;
        ConnMgrItem.TargetDir := TargetDirEntry.Text;
        ConnMgrItem.PluginID := '';
        if (PluginOptionMenu.ItemIndex <> 0) and (PluginOptionMenu.Items[PluginOptionMenu.ItemIndex].Data <> nil) then
          ConnMgrItem.PluginID := TVFSPlugin(PluginOptionMenu.Items[PluginOptionMenu.ItemIndex].Data).ModuleID;
      end;
      ConnectionMgrList.Add(ConnMgrItem);
      Item := ListView.Items.Add;
      Item.SetValue(0, ConnMgrItem);
      Item.SetValue(1, ConnMgrItem.ConnectionName);
      Item.SetValue(2, FConnectionProperties.MakeURI(True));
      Item.Selected := True;
      Item.SetCursor(0, False, not Application.GTKVersion_2_2_0_Up, 0.5, 0);
    end;
  finally
    FConnectionProperties.Free;
    ListView.SetFocus;
  end;
end;

procedure TFConnectionManager.EditButtonClick(Sender: TObject);
var Item: TGTKListItem;
    ConnMgrItem: TConnMgrItem;
    i: integer;
begin
  try
    Item := ListView.Selected;
    if Item = nil then Exit;
    ConnMgrItem := Item.AsPointer(0);
    if ConnMgrItem = nil then Exit;
    FConnectionProperties := TFConnectionProperties.Create(Self);
    FConnectionProperties.NameEntry.Text := ConnMgrItem.ConnectionName;
    FConnectionProperties.URIEntry.Text := ConstructURI(True, False, ConnMgrItem.ServiceType, ConnMgrItem.Server, ConnMgrItem.Username, ConnMgrItem.Password, ConnMgrItem.TargetDir);
    FConnectionProperties.ServiceTypeOptionMenuChanged(Sender);
    //  Find the plugin by PluginID
    for i := 0 to FConnectionProperties.PluginOptionMenu.Items.Count - 1 do
      if (FConnectionProperties.PluginOptionMenu.Items[i].Data <> nil) and (TVFSPlugin(FConnectionProperties.PluginOptionMenu.Items[i].Data).ModuleID = ConnMgrItem.PluginID) then begin
        FConnectionProperties.PluginOptionMenu.ItemIndex := i;
        Break;
      end;

    if FConnectionProperties.Run = mbOK then begin
      with FConnectionProperties do begin
        ConnMgrItem.ConnectionName := NameEntry.Text;
        ConnMgrItem.ServiceType := GetService;
        ConnMgrItem.Server := ServerEntry.Text;
        ConnMgrItem.Username := UserNameEntry.Text;
        ConnMgrItem.Password := PasswordEntry.Text;
        ConnMgrItem.TargetDir := TargetDirEntry.Text;
        ConnMgrItem.PluginID := '';
        if (PluginOptionMenu.ItemIndex <> 0) and (PluginOptionMenu.Items[PluginOptionMenu.ItemIndex].Data <> nil) then
          ConnMgrItem.PluginID := TVFSPlugin(PluginOptionMenu.Items[PluginOptionMenu.ItemIndex].Data).ModuleID;
      end;
      Item.SetValue(1, ConnMgrItem.ConnectionName);
      Item.SetValue(2, FConnectionProperties.MakeURI(True));
    end;
  finally
    FConnectionProperties.Free;
    ListView.SetFocus;
  end;
end;

procedure TFConnectionManager.DuplicateButtonClick(Sender: TObject);
var Item: TGTKListItem;
    ConnMgrItem: TConnMgrItem;
    i: integer;
begin
  try
    Item := ListView.Selected;
    if Item = nil then Exit;
    ConnMgrItem := Item.AsPointer(0);
    if ConnMgrItem = nil then Exit;
    FConnectionProperties := TFConnectionProperties.Create(Self);
    FConnectionProperties.NameEntry.Text := '';
    FConnectionProperties.URIEntry.Text := ConstructURI(True, False, ConnMgrItem.ServiceType, ConnMgrItem.Server, ConnMgrItem.Username, ConnMgrItem.Password, ConnMgrItem.TargetDir);
    FConnectionProperties.ServiceTypeOptionMenuChanged(Sender);
    //  Find the plugin by PluginID
    for i := 0 to FConnectionProperties.PluginOptionMenu.Items.Count - 1 do
      if (FConnectionProperties.PluginOptionMenu.Items[i].Data <> nil) and (TVFSPlugin(FConnectionProperties.PluginOptionMenu.Items[i].Data).ModuleID = ConnMgrItem.PluginID) then begin
        FConnectionProperties.PluginOptionMenu.ItemIndex := i;
        Break;
      end;

    if FConnectionProperties.Run = mbOK then begin
      ConnMgrItem := TConnMgrItem.Create;
      with FConnectionProperties do begin
        ConnMgrItem.ConnectionName := NameEntry.Text;
        ConnMgrItem.ServiceType := GetService;
        ConnMgrItem.Server := ServerEntry.Text;
        ConnMgrItem.Username := UserNameEntry.Text;
        ConnMgrItem.Password := PasswordEntry.Text;
        ConnMgrItem.TargetDir := TargetDirEntry.Text;
        ConnMgrItem.PluginID := '';
        if (PluginOptionMenu.ItemIndex <> 0) and (PluginOptionMenu.Items[PluginOptionMenu.ItemIndex].Data <> nil) then
          ConnMgrItem.PluginID := TVFSPlugin(PluginOptionMenu.Items[PluginOptionMenu.ItemIndex].Data).ModuleID;
      end;
      ConnectionMgrList.Add(ConnMgrItem);
      Item := ListView.Items.Add;
      Item.SetValue(0, ConnMgrItem);
      Item.SetValue(1, ConnMgrItem.ConnectionName);
      Item.SetValue(2, FConnectionProperties.MakeURI(True));
      Item.Selected := True;
      Item.SetCursor(0, False, not Application.GTKVersion_2_2_0_Up, 0.5, 0);
    end;
  finally
    FConnectionProperties.Free;
    ListView.SetFocus;
  end;
end;

procedure TFConnectionManager.RemoveButtonClick(Sender: TObject);
var Item: TGTKListItem;
    ConnMgrItem: TConnMgrItem;
    i, OldIndex: integer;
begin
  Item := ListView.Selected;
  if Item = nil then Exit;
  ConnMgrItem := Item.AsPointer(0);
  if ConnMgrItem = nil then Exit;
  if Application.MessageBox(PGtkWindow(FWidget), Format(LANGConnMgr_DoYouWantDelete, [Item.AsString(1)]),
                            [mbYes, mbNo], mbQuestion, mbYes, mbNo) = mbYes then
  begin
    OldIndex := ListView.ConvertToSorted(Item.Index);
    if ConnectionMgrList.Count > 0 then
      for i := 0 to ConnectionMgrList.Count - 1 do
        if ConnectionMgrList[i] = ConnMgrItem then begin
          ConnectionMgrList.Delete(i);
          Break;
        end;
    ConnMgrItem.Free;
    ListView.Items.Delete(Item.Index);

    //  Preserve selection
    if ListView.Items.Count > 0 then begin
      if ListView.Items.Count <= OldIndex
        then OldIndex := ListView.ConvertFromSorted(ListView.Items.Count - 1)
        else OldIndex := ListView.ConvertFromSorted(OldIndex);
      ListView.Items[OldIndex].Selected := True;
      ListView.Items[OldIndex].SetCursor(0, False, not Application.GTKVersion_2_2_0_Up, 0.5, 0);
    end;
    ListView.SetFocus;
  end;
end;

procedure TFConnectionManager.FillList;
var i: integer;
    Item: TGTKListItem;
    ConnMgrItem: TConnMgrItem;
begin
  if ConnectionMgrList.Count > 0 then
    for i := 0 to ConnectionMgrList.Count - 1 do begin
      ConnMgrItem := ConnectionMgrList[i];
      Item := ListView.Items.Add;
      Item.SetValue(0, ConnMgrItem);
      Item.SetValue(1, ConnMgrItem.ConnectionName);
      Item.SetValue(2, ConstructURI(True, True, ConnMgrItem.ServiceType, ConnMgrItem.Server, ConnMgrItem.Username,
                                                ConnMgrItem.Password, ConnMgrItem.TargetDir));
    end;
  if (ConfConnMgrActiveItem < 0) or (ConfConnMgrActiveItem > ConnectionMgrList.Count) then
    ConfConnMgrActiveItem := 0;
  DoNotSavePasswordsCheckBox.Checked := ConfConnMgrDoNotSavePasswords;
  DoNotSynchronizeKeyringCheckBox.Checked := ConfConnMgrDoNotSynchronizeKeyring;
end;


(********************************************************************************************************************************)
procedure TFConnectionManager.CloseButtonClick(Sender: TObject);
begin
  ModalResult := mbCancel;
end;

procedure TFConnectionManager.ConnectButtonClick(Sender: TObject);
begin
  DoConnect;
end;

procedure TFConnectionManager.StopButtonClick(Sender: TObject);
begin
  if Thread <> nil then Thread.FCancelRequested := True;
end;

procedure TFConnectionManager.QuickConnectButtonClick(Sender: TObject);
var AFQuickConnect: TFQuickConnect;
begin
  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;
end;

(********************************************************************************************************************************)
procedure TFConnectionManager.DoConnect;
var Engine: TVFSEngine;
    i, j: integer;
    VFSPlugin: TVFSPlugin;
    FActiveConnInfo: TConnMgrItem;
    DontShowAgain: boolean;
    res: TMessageButton;
begin
  FActiveConnInfo := nil;
  if ListView.Selected <> nil then FActiveConnInfo := ListView.Selected.AsPointer(0);
  if FActiveConnInfo = nil then Exit;

  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 Length(FActiveConnInfo.PluginID) > 0 then
    for i := 0 to PluginList.Count - 1 do
      if TVFSPlugin(PluginList[i]).ModuleID = FActiveConnInfo.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 WideCompareText(TVFSPlugin(PluginList[i]).Services[j], FActiveConnInfo.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 some other plugin can handle it
  end;

  if (SourcePanelEngine is TVFSEngine) and ConfReplaceConnectionWarning then begin
    DontShowAgain := False;
    res := MessageBoxShowOnce(PGtkWindow(FWidget), LANGCloseOpenConnection, LANGDontShowAgain, DontShowAgain, [mbYes, mbNo], mbWarning, mbYes, mbNo);
    if DontShowAgain then begin
      ConfReplaceConnectionWarning := False;
      WriteMainGUISettings;
    end;
    if res <> mbYes then Exit;
  end;

  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;

  if not DoConnectInternal(UTF8ToStr(FActiveConnInfo.GetURI(False)), Engine, FWidget, False) 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; VFSQuickConnectMode: boolean): boolean;
begin
  Result := False;
  FSilenceError := False;
  Thread := TOpenConnectionThread.Create;
  try
    Thread.VFSConnectionManagerMode := VFSDialogsParentWindow = FWidget;
    Thread.VFSQuickConnectMode := VFSQuickConnectMode;
    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.

