diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2008-11-23 16:59:50 +0100 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2008-11-23 16:59:50 +0100 |
| commit | 2de0a7945bf5941cf0a163b86fa8facbb5b05f2d (patch) | |
| tree | db7cb80e32d9736d2d3aed54ee35315d164ae666 | |
| parent | 6c77cc430b1e78bd3d0acf1cc078e60775647956 (diff) | |
| download | tuxcmd-0.6.61.tar.xz | |
Connection Manager UI improvements (format change!)v0.6.61
- add Duplicate button
- add popup menu on the list view
- move selection when deleting
- add sorting to the list view
- save sorting state + column width
- simple cipher saved passwords
- use hash keys for each item when saving - allow duplicate entries
| -rw-r--r-- | UConfig.pas | 27 | ||||
| -rw-r--r-- | UConnectionManager.pas | 134 | ||||
| -rw-r--r-- | UCoreUtils.pas | 12 | ||||
| -rw-r--r-- | libgtk_kylix/GTKControls.pas | 2 |
4 files changed, 158 insertions, 17 deletions
diff --git a/UConfig.pas b/UConfig.pas index cfd79d3..3e2ab55 100644 --- a/UConfig.pas +++ b/UConfig.pas @@ -25,8 +25,8 @@ uses Classes, ULocale; resourcestring ConstAppTitle = 'Tux Commander'; - ConstAboutVersion = '0.6.60-dev'; - ConstAboutBuildDate = '2008-11-17'; + ConstAboutVersion = '0.6.61-dev'; + ConstAboutBuildDate = '2008-11-23'; {$IFDEF FPC} {$INCLUDE fpcver.inc} @@ -58,6 +58,7 @@ const ConfDefaultNormalItemFGColor = '#000000'; ConstNumPanelColumns = 10; ConstPathDelim = '#'; ConstFullPathFormatStr = '%s#%s'; + ConstConnMgrXORKey = 65; ConstTerminalCommand_xterm = 'xterm -T "TuxCommand" -e sh -c ''%s ; echo -n Press ENTER to exit... ; read'''; ConstTerminalCommand_rxvt = 'rxvt -T "TuxCommand" -e sh -c ''%s ; echo -n Press ENTER to exit... ; read'''; @@ -112,7 +113,7 @@ var ConfPanelSep, ConfRowHeight, ConfRowHeightReal, ConfNumHistoryItems, ConfUseSmoothScrolling: boolean; ApplicationShuttingDown: boolean; - ConfConnMgrActiveItem: integer; + ConfConnMgrActiveItem, ConfConnMgrSortColumn, ConfConnMgrSortType, ConfConnMgrColumn1Width: integer; ConfConnMgrDoNotSavePasswords, ConfConnMgrDoNotSynchronizeKeyring: boolean; ConfQuickConnectPluginID: string; @@ -140,7 +141,7 @@ function CheckConfFilesMod(var ChangedMainGUI, ChangedAssoc, ChangedBookmarks, C implementation -uses ULibc, SysUtils, UCoreUtils, UCore, UFileAssoc, UCoreClasses, UGnome, UVFSCore; +uses ULibc, glib2, SysUtils, UCoreUtils, UCore, UFileAssoc, UCoreClasses, UGnome, UVFSCore; var InternalQuickExit, InternalDeleteHistory: boolean; InternalMainGUIConfmtime, InternalBookmarksConfmtime, InternalFAssocConfmtime, InternalMounterConfmtime, @@ -260,6 +261,9 @@ begin ConfConnMgrDoNotSavePasswords := False; ConfConnMgrDoNotSynchronizeKeyring := False; ConfQuickConnectPluginID := ''; + ConfConnMgrSortColumn := -1; + ConfConnMgrSortType := 2; + ConfConnMgrColumn1Width := 230; // Setup default values for colors @@ -945,6 +949,9 @@ begin ConfConnMgrDoNotSavePasswords := IniFile.ReadBool('__General', 'ConnMgrDoNotSavePasswords', ConfConnMgrDoNotSavePasswords); ConfConnMgrDoNotSynchronizeKeyring := IniFile.ReadBool('__General', 'ConnMgrDoNotSynchronizeKeyring', ConfConnMgrDoNotSynchronizeKeyring); ConfQuickConnectPluginID := IniFile.ReadString('__General', 'QuickConnectPluginID', ConfQuickConnectPluginID); + ConfConnMgrSortColumn := IniFile.ReadInteger('__General', 'ConnMgrSortColumn', ConfConnMgrSortColumn); + ConfConnMgrSortType := IniFile.ReadInteger('__General', 'ConnMgrSortType', ConfConnMgrSortType); + ConfConnMgrColumn1Width := IniFile.ReadInteger('__General', 'ConnMgrColumn1Width', ConfConnMgrColumn1Width); end else if Sections[i] = '__QuickConnectHistory' then begin QuickConnectHistory.Clear; @@ -957,11 +964,11 @@ begin end else begin Item := TConnMgrItem.Create; with Item do begin - ConnectionName := Sections[i]; + ConnectionName := IniFile.ReadString(Sections[i], 'ConnectionName', ''); ServiceType := IniFile.ReadString(Sections[i], 'ServiceType', ''); Server := IniFile.ReadString(Sections[i], 'Server', ''); Username := IniFile.ReadString(Sections[i], 'Username', ''); - Password := IniFile.ReadString(Sections[i], 'Password', ''); + Password := XORStr(IniFile.ReadString(Sections[i], 'Password', ''), ConstConnMgrXORKey); TargetDir := IniFile.ReadString(Sections[i], 'TargetDir', ''); PluginID := IniFile.ReadString(Sections[i], 'PluginID', ''); end; @@ -997,6 +1004,9 @@ begin IniFile.WriteBool('__General', 'ConnMgrDoNotSavePasswords', ConfConnMgrDoNotSavePasswords); IniFile.WriteBool('__General', 'ConnMgrDoNotSynchronizeKeyring', ConfConnMgrDoNotSynchronizeKeyring); IniFile.WriteString('__General', 'QuickConnectPluginID', ConfQuickConnectPluginID); + IniFile.WriteInteger('__General', 'ConnMgrSortColumn', ConfConnMgrSortColumn); + IniFile.WriteInteger('__General', 'ConnMgrSortType', ConfConnMgrSortType); + IniFile.WriteInteger('__General', 'ConnMgrColumn1Width', ConfConnMgrColumn1Width); IniFile.WriteInteger('__QuickConnectHistory', 'NumItems', QuickConnectHistory.Count); if QuickConnectHistory.Count > 0 then for i := 0 to QuickConnectHistory.Count - 1 do @@ -1004,12 +1014,13 @@ begin if ConnectionMgrList.Count > 0 then for i := 0 to ConnectionMgrList.Count - 1 do with TConnMgrItem(ConnectionMgrList[i]) do begin - SectionTitle := ConnectionName; + SectionTitle := Format('%d_%d_%d', [g_str_hash(PChar(ConnectionName)), i, g_str_hash(PChar(GetURI(False)))]); IniFile.EraseSection(SectionTitle); + IniFile.WriteString(SectionTitle, 'ConnectionName', ConnectionName); IniFile.WriteString(SectionTitle, 'ServiceType', ServiceType); IniFile.WriteString(SectionTitle, 'Server', Server); IniFile.WriteString(SectionTitle, 'Username', Username); - if not ConfConnMgrDoNotSavePasswords then IniFile.WriteString(SectionTitle, 'Password', Password) + if not ConfConnMgrDoNotSavePasswords then IniFile.WriteString(SectionTitle, 'Password', XORStr(Password, ConstConnMgrXORKey)) else IniFile.WriteString(SectionTitle, 'Password', ''); IniFile.WriteString(SectionTitle, 'TargetDir', TargetDir); IniFile.WriteString(SectionTitle, 'PluginID', PluginID); diff --git a/UConnectionManager.pas b/UConnectionManager.pas index 2b39a51..9adcf4f 100644 --- a/UConnectionManager.pas +++ b/UConnectionManager.pas @@ -23,7 +23,7 @@ interface uses glib2, gdk2, gtk2, pango, SysUtils, Types, Classes, GTKControls, GTKForms, GTKStdCtrls, GTKExtCtrls, GTKConsts, GTKView, - GTKUtils, GTKDialogs, GTKPixbuf, GTKClasses, + GTKUtils, GTKDialogs, GTKPixbuf, GTKClasses, GTKMenus, UCore, UCoreClasses, UVFSCore, UEngines; type @@ -36,12 +36,13 @@ type ListView: TGTKListView; ListViewScrolledWindow: TGTKScrolledWindow; ListViewTable: TGTKTable; - AddConnectionButton, EditButton, RemoveButton: TGTKImageButton; + 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); @@ -49,6 +50,7 @@ type 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); @@ -76,6 +78,7 @@ 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; @@ -128,15 +131,21 @@ begin ListViewTable.BorderWidth := 7; ClientArea.AddControlEx(ListViewTable, True, True, 0); - ListView := TGTKListView.CreateTyped(Self, False, [lcPointer, lcText, lcText]); + 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 := 230; + Column.FixedWidth := ConfConnMgrColumn1Width; Column.SizingMode := smFixed; Column.Caption := LANGConnMgr_NameColumn; Column.Clickable := True; @@ -148,6 +157,8 @@ begin 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; @@ -168,6 +179,10 @@ begin RemoveButton.Caption := LANGConnMgr_RemoveButtonCaption; RemoveButton.UseUnderline := True; RemoveButton.Tooltip := LANGConnMgr_RemoveButtonTooltip; + DuplicateButton := TGTKImageButton.Create(Self); + DuplicateButton.Caption := 'D_uplicate...'; + DuplicateButton.UseUnderline := True; + DuplicateButton.Tooltip := 'Duplicate selected connection'; QuickConnectButton := TGTKImageButton.Create(Self); QuickConnectButton.SetFromStock('gtk-connect', isSmallToolbar); @@ -181,6 +196,7 @@ begin ButtonBox.AddControl(TGTKEventBox.Create(Self)); ButtonBox.AddControl(AddConnectionButton); ButtonBox.AddControl(EditButton); + ButtonBox.AddControl(DuplicateButton); ButtonBox.AddControl(RemoveButton); DoNotSavePasswordsCheckBox := TGTKCheckButton.CreateWithLabel(Self, '_Do not store passwords internally (but still use gnome-keyring)'); @@ -195,14 +211,45 @@ begin 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 := 'D_uplicate...'; + 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 then ListView.Items[ConfConnMgrActiveItem].SetCursor(0, False, False, 0, 0); + 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; @@ -217,8 +264,13 @@ 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; @@ -237,7 +289,8 @@ end; procedure TFConnectionManager.ListViewDblClick(Sender: TObject; Button: TGDKMouseButton; Shift: TShiftState; X, Y: Integer; var Accept: boolean); begin - if Assigned(ListView.Selected) then DoConnect; + 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); @@ -252,6 +305,9 @@ 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); @@ -286,9 +342,12 @@ begin 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; @@ -329,21 +388,70 @@ begin end; finally FConnectionProperties.Free; + ListView.SetFocus; end; end; -procedure TFConnectionManager.RemoveButtonClick(Sender: TObject); +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 PluginList.Count - 1 do + if TVFSPlugin(PluginList[i]).VFSName = ConnMgrItem.PluginID then begin + FConnectionProperties.PluginOptionMenu.ItemIndex := i + 1; + 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 then ConnMgrItem.PluginID := TVFSPlugin(PluginList[PluginOptionMenu.ItemIndex - 1]).VFSName; + 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(Format(LANGConnMgr_DoYouWantDelete, [Item.AsString(1)]), + 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 @@ -352,6 +460,16 @@ begin 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; diff --git a/UCoreUtils.pas b/UCoreUtils.pas index fb7056d..7a5a6b1 100644 --- a/UCoreUtils.pas +++ b/UCoreUtils.pas @@ -113,6 +113,8 @@ function EnsureUTF8String(s: PChar): PChar; overload; function Min(Val1, Val2: longint): longint; +function XORStr(const s: string; Key: byte): string; + procedure ReportGTKVersion; // Internal locking @@ -1578,6 +1580,16 @@ begin if Val1 < Val2 then Result := Val1 else Result := Val2; end; + +function XORStr(const s: string; Key: byte): string; +var i: integer; +begin + Result := s; + if Length(Result) > 0 then + for i := 1 to Length(Result) do + Result[i] := Char(Byte(Result[i]) xor Key); +end; + (********************************************************************************************************************************) procedure signal_proc(signal_number: integer); cdecl; diff --git a/libgtk_kylix/GTKControls.pas b/libgtk_kylix/GTKControls.pas index d839a65..46b03a2 100644 --- a/libgtk_kylix/GTKControls.pas +++ b/libgtk_kylix/GTKControls.pas @@ -444,7 +444,7 @@ begin // if Assigned(TGTKMenuItem(TGTKControl(widget).FPopupMenu).OnPopup) then TGTKMenuItem(TGTKControl(widget).FPopupMenu).OnPopup(TGTKMenuItem(TGTKControl(widget).FPopupMenu)); if Assigned(TGTKMenuItem(TGTKControl(widget).FPopupMenu).OnPopup) then TGTKMenuItem(TGTKControl(widget).FPopupMenu).OnPopup(TGTKControl(widget)); gtk_menu_popup(PGtkMenu(TGTKMenuItem(TGTKControl(widget).FPopupMenu).FMenu), nil, nil, nil, nil, event^.button, event^.time); - Result := True; + Result := False; // Allow list views to process their events - select an item beneath the cursor end; end; |
