lazarus/lcl/interfaces/gtk2/gtk2wsdialogs.pp

466 lines
14 KiB
ObjectPascal

{ $Id$}
{
*****************************************************************************
* Gtk2WSDialogs.pp *
* ---------------- *
* *
* *
*****************************************************************************
*****************************************************************************
* *
* This file is part of the Lazarus Component Library (LCL) *
* *
* See the file COPYING.modifiedLGPL, included in this distribution, *
* for details about the copyright. *
* *
* 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. *
* *
*****************************************************************************
}
unit Gtk2WSDialogs;
{$mode objfpc}{$H+}
interface
uses
////////////////////////////////////////////////////
// I M P O R T A N T
////////////////////////////////////////////////////
// To get as little as posible circles,
// uncomment only when needed for registration
////////////////////////////////////////////////////
Gtk2, Glib2, gdk2, pango,
SysUtils, Classes,
Controls, Dialogs, ExtDlgs,
GtkWSDialogs, GtkInt, GtkGlobals, GtkDef, GtkProc,
////////////////////////////////////////////////////
LCLType, WSDialogs, WSLCLClasses, FileUtil;
type
{ TGtk2WSCommonDialog }
TGtk2WSCommonDialog = class(TGtkWSCommonDialog)
private
protected
public
end;
{ TGtk2WSFileDialog }
TGtk2WSFileDialog = class(TGtkWSFileDialog)
private
protected
class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); override;
public
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
end;
{ TGtk2WSOpenDialog }
TGtk2WSOpenDialog = class(TGtkWSOpenDialog)
private
protected
class function CreateOpenDialogFilter(OpenDialog: TOpenDialog; SelWidget: PGtkWidget): string; override;
class procedure CreatePreviewDialogControl(PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget); override;
public
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
end;
{ TGtk2WSSaveDialog }
TGtk2WSSaveDialog = class(TGtkWSSaveDialog)
private
protected
public
end;
{ TGtk2WSSelectDirectoryDialog }
TGtk2WSSelectDirectoryDialog = class(TGtkWSSelectDirectoryDialog)
private
protected
public
end;
{ TGtk2WSColorDialog }
TGtk2WSColorDialog = class(TGtkWSColorDialog)
private
protected
public
end;
{ TGtk2WSColorButton }
TGtk2WSColorButton = class(TGtkWSColorButton)
private
protected
public
end;
{ TGtk2WSFontDialog }
TGtk2WSFontDialog = class(TGtkWSFontDialog)
private
protected
public
end;
implementation
// ---------------------- signals ----------------------------------------------
procedure gtkFileChooserSelectionChangedCB(Chooser: PGtkFileChooser;
Data: Pointer); cdecl;
var
cFilename: Pgchar;
theDialog: TFileDialog;
begin
//DebugLn(['gtkFileChooserSelectionChangedCB ']);
cFilename := gtk_file_chooser_get_filename(Chooser);
theDialog:=TFileDialog(Data);
try
if theDialog is TOpenDialog then
UpdateDetailView(TOpenDialog(theDialog));
finally
if Assigned(cFilename) then
g_free(cFilename);
end;
end;
procedure Gtk2FileChooserResponseCB(widget: PGtkFileChooser; arg1: gint;
data: gpointer); cdecl;
procedure AddFile(List: TStrings; const NewFile: string);
var
i: Integer;
begin
for i := 0 to List.Count-1 do
if List[i] = NewFile then
Exit;
List.Add(NewFile);
end;
var
TheDialog: TFileDialog;
cFilename: PChar;
cFilenames: PGSList;
cFilenames1: PGSList;
Files: TStringList;
begin
//DebugLn(['Gtk2FileChooserResponseCB ']);
theDialog := TFileDialog(data);
if arg1 = GTK_RESPONSE_CANCEL then
begin
TheDialog.UserChoice := mrCancel;
Exit;
end;
if theDialog is TOpenDialog then
begin
if ofAllowMultiSelect in TOpenDialog(theDialog).Options then
begin
TheDialog.FileName := '';
Files := TStringList(TheDialog.Files);
Files.Clear;
cFilenames := gtk_file_chooser_get_filenames(widget);
if Assigned(cFilenames) then
begin
cFilenames1 := cFilenames;
while Assigned(cFilenames1) do
begin
cFilename := PChar(cFilenames1^.data);
if Assigned(cFilename) then
begin
AddFile(Files, cFilename);
g_free(cFilename);
end;
cFilenames1 := cFilenames1^.next;
end;
g_slist_free(cFilenames);
end;
end;
end;
cFilename := gtk_file_chooser_get_filename(widget);
if Assigned(cFilename) then
begin
TheDialog.FileName := cFilename;
g_free(cFilename);
end;
//?? StoreCommonDialogSetup(theDialog);
theDialog.UserChoice := mrOK;
end;
procedure Gtk2FileChooserNotifyCB(dialog: PGObject; pspec: PGParamSpec;
user_data: gpointer); cdecl;
var
TheDialog: TFileDialog;
GtkFilter: PGtkFileFilter;
GtkFilterList: PGSList;
NewFilterIndex: Integer;
begin
//DebugLn(['Gtk2FileChooserNotifyCB ']);
if pspec^.name = 'filter' then
begin // filter changed
theDialog := TFileDialog(user_data);
GtkFilter := gtk_file_chooser_get_filter(dialog);
GtkFilterList := gtk_file_chooser_list_filters(dialog);
NewFilterIndex := g_slist_index(GtkFilterList, GtkFilter);
theDialog.IntfFileTypeChanged(NewFilterIndex + 1);
g_slist_free(GtkFilterList);
end;
end;
// ---------------------- END OF signals ---------------------------------------
{ TGtk2WSOpenDialog }
class function TGtk2WSOpenDialog.CreateOpenDialogFilter(
OpenDialog: TOpenDialog; SelWidget: PGtkWidget): string;
var
FilterList: TFPList;
i, j, k: integer;
GtkFilter: PGtkFileFilter;
MaskList: TStringList;
begin
ExtractFilterList(OpenDialog.Filter, FilterList, false);
if FilterList.Count > 0 then
begin
j := 1;
MaskList := TStringList.Create;
MaskList.Delimiter := ';';
for i := 0 to FilterList.Count-1 do
begin
GtkFilter := gtk_file_filter_new();
MaskList.DelimitedText := PFileSelFilterEntry(FilterList[i])^.Mask;
for k := 0 to MaskList.Count-1 do
gtk_file_filter_add_pattern(GtkFilter, PChar(MaskList.Strings[k]));
gtk_file_filter_set_name(GtkFilter, PFileSelFilterEntry(FilterList[i])^.Description);
gtk_file_chooser_add_filter(SelWidget, GtkFilter);
if j = OpenDialog.FilterIndex then
gtk_file_chooser_set_filter(SelWidget, GtkFilter);
Inc(j);
GtkFilter := nil;
end;
MaskList.Free;
end;
gtk_object_set_data(PGtkObject(SelWidget), 'LCLFilterList', FilterList);
Result := 'hm'; { Don't use '' as null return as this is used for *.* }
end;
class procedure TGtk2WSOpenDialog.CreatePreviewDialogControl(
PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget);
var
PreviewWidget: PGtkWidget;
AControl: TPreviewFileControl;
FileChooser: PGtkFileChooser;
begin
AControl := PreviewDialog.PreviewFileControl;
if AControl = nil then Exit;
FileChooser := PGtkFileChooser(SelWidget);
PreviewWidget := PGtkWidget(AControl.Handle);
gtk_object_set_data(PGtkObject(PreviewWidget),'LCLPreviewFixed',
PreviewWidget);
gtk_widget_set_size_request(PreviewWidget,AControl.Width,AControl.Height);
gtk_file_chooser_set_preview_widget(FileChooser, PreviewWidget);
gtk_widget_show(PreviewWidget);
end;
{
Adds some functionality to a gtk file selection dialog.
- multiselection
- range selection
- close on escape
- file information
- history pulldown
- filter pulldown
- preview control
requires: gtk+ 2.6
}
class function TGtk2WSOpenDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
var
FileSelWidget: PGtkFileChooser;
OpenDialog: TOpenDialog absolute ACommonDialog;
HelpButton: PGtkWidget;
InitialFilename: String;
//FrameWidget: PGtkWidget;
//HBox: PGtkWidget;
//FileDetailLabel: PGtkWidget;
begin
Result := TGtk2WSFileDialog.CreateHandle(ACommonDialog);
FileSelWidget := PGtkFileChooser(Result);
if OpenDialog.InheritsFrom(TSaveDialog) then
begin
if OpenDialog.InitialDir <> '' then
gtk_file_chooser_set_current_folder(FileSelWidget, Pgchar(OpenDialog.InitialDir));
end;
// Help button
if (ofShowHelp in OpenDialog.Options) then
begin
HelpButton := gtk_dialog_add_button(FileSelWidget, GTK_STOCK_HELP, GTK_RESPONSE_NONE);
g_signal_connect(PGtkObject(HelpButton),
'clicked', gtk_signal_func(@gtkDialogHelpclickedCB), OpenDialog);
end;
if ofAllowMultiSelect in OpenDialog.Options then
gtk_file_chooser_set_select_multiple(FileSelWidget, gboolean(gtrue));
// History List - a frame with an option menu
CreateOpenDialogHistory(OpenDialog, FileSelWidget);
// Filter
CreateOpenDialogFilter(OpenDialog, FileSelWidget);
// connect change event
g_signal_connect(PGtkObject(FileSelWidget),
'selection-changed', gtk_signal_func(@gtkFileChooserSelectionChangedCB),
OpenDialog);
(* TODO
// Details - a frame with a label
if (ofViewDetail in OpenDialog.Options) then begin
// create the frame around the information
FrameWidget:=gtk_frame_new(PChar(rsFileInformation));
//gtk_box_pack_start(GTK_BOX(FileSelWidget^.main_vbox),
// FrameWidget,false,false,0);
gtk_box_pack_start(GTK_BOX(gtk_file_chooser_get_extra_widget(
PGtkFileChooser(SelWidget))), FrameWidget,false,false,0);
gtk_widget_show(FrameWidget);
// create a HBox, so that the information is left justified
HBox:=gtk_hbox_new(false,0);
gtk_container_add(GTK_CONTAINER(FrameWidget), HBox);
// create the label for the file information
FileDetailLabel:=gtk_label_new(PChar(rsDefaultFileInfoValue));
gtk_box_pack_start(GTK_BOX(HBox),FileDetailLabel,false,false,5);
gtk_widget_show_all(HBox);
end else
FileDetailLabel:=nil;
gtk_object_set_data(PGtkObject(SelWidget), 'FileDetailLabel',
FileDetailLabel);
*)
// preview
if (OpenDialog is TPreviewFileDialog) then
CreatePreviewDialogControl(TPreviewFileDialog(OpenDialog), PGtkWidget(FileSelWidget));
// set initial filename (gtk expects an absolute filename)
InitialFilename := TrimFilename(OpenDialog.Filename);
if InitialFilename <> '' then
begin
if not FilenameIsAbsolute(InitialFilename) and (OpenDialog.InitialDir <> '') then
InitialFilename := TrimFilename(OpenDialog.InitialDir + PathDelim + InitialFilename);
if not FilenameIsAbsolute(InitialFilename) then
InitialFilename := CleanAndExpandFilename(InitialFilename);
gtk_file_chooser_set_filename(FileSelWidget, PChar(InitialFilename));
end;
//if InitialFilter <> 'none' then
// PopulateFileAndDirectoryLists(FileSelWidget, InitialFilter);
end;
{ TGtk2WSFileDialog }
class procedure TGtk2WSFileDialog.SetCallbacks(const AGtkWidget: PGtkWidget;
const AWidgetInfo: PWidgetInfo);
begin
TGtkWSCommonDialog.SetCallbacks(AGtkWidget, AWidgetInfo);
g_signal_connect(AGtkWidget, 'response', gtk_signal_func(@Gtk2FileChooserResponseCB), AWidgetInfo^.LCLObject);
g_signal_connect(AGtkWidget, 'notify', gtk_signal_func(@Gtk2FileChooserNotifyCB), AWidgetInfo^.LCLObject);
end;
{
Creates a new TFile/Open/SaveDialog
requires: gtk+ 2.6
}
class function TGtk2WSFileDialog.CreateHandle(const ACommonDialog: TCommonDialog
): THandle;
var
FileDialog: TFileDialog absolute ACommonDialog;
Action: TGtkFileChooserAction;
Button1: String;
Widget: PGtkWidget;
WidgetInfo: PWidgetInfo;
begin
Action := GTK_FILE_CHOOSER_ACTION_OPEN;
Button1 := GTK_STOCK_OPEN;
if (FileDialog is TSaveDialog) or (FileDialog is TSavePictureDialog) then
begin
Action := GTK_FILE_CHOOSER_ACTION_SAVE;
Button1 := GTK_STOCK_SAVE;
end
else
if FileDialog is TSelectDirectoryDialog then
begin
Action := GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
Button1 := GTK_STOCK_OPEN;
end;
Widget := gtk_file_chooser_dialog_new(PChar(FileDialog.Title), nil, Action,
PChar(GTK_STOCK_CANCEL), [GTK_RESPONSE_CANCEL, PChar(Button1), GTK_RESPONSE_OK, nil]);
(*gtk 2.8
if FileDialog is TSaveDialog then
begin
gtk_file_chooser_set_do_overwrite_confirmation(Widget,
ofOverwritePrompt in TOpenDialog(theDialog).Options);
end;
*)
if FileDialog.InitialDir <> '' then
gtk_file_chooser_set_current_folder(Widget, Pgchar(FileDialog.InitialDir));
if gtk_file_chooser_get_action(Widget) in
[GTK_FILE_CHOOSER_ACTION_SAVE, GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER]
then
gtk_file_chooser_set_current_name(Widget, Pgchar(FileDialog.FileName));
Result := THandle(PtrUInt(Widget));
WidgetInfo := CreateWidgetInfo(Widget);
WidgetInfo^.LCLObject := ACommonDialog;
TGtkWSCommonDialog.SetSizes(Widget, WidgetInfo);
SetCallbacks(Widget, WidgetInfo);
end;
initialization
////////////////////////////////////////////////////
// I M P O R T A N T
////////////////////////////////////////////////////
// To improve speed, register only classes
// which actually implement something
////////////////////////////////////////////////////
// RegisterWSComponent(TCommonDialog, TGtk2WSCommonDialog);
RegisterWSComponent(TFileDialog, TGtk2WSFileDialog);
RegisterWSComponent(TOpenDialog, TGtk2WSOpenDialog);
// RegisterWSComponent(TSaveDialog, TGtk2WSSaveDialog);
// RegisterWSComponent(TSelectDirectoryDialog, TGtk2WSSelectDirectoryDialog);
// RegisterWSComponent(TColorDialog, TGtk2WSColorDialog);
// RegisterWSComponent(TColorButton, TGtk2WSColorButton);
// RegisterWSComponent(TFontDialog, TGtk2WSFontDialog);
////////////////////////////////////////////////////
end.