From f5ff9d9bd6c8926fd48a12ad252fe604c9e85eca Mon Sep 17 00:00:00 2001 From: mattias Date: Sat, 19 Nov 2005 11:55:08 +0000 Subject: [PATCH] gtk2 intf can now optionally use the file chooses, compile with HasGTK2_6 git-svn-id: trunk@8194 - --- lcl/interfaces/gtk/gtkint.pp | 10 +- lcl/interfaces/gtk/gtkobject.inc | 137 ---------------- lcl/interfaces/gtk2/gtk2int.pas | 9 + lcl/interfaces/gtk2/gtk2object.inc | 255 +++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+), 141 deletions(-) diff --git a/lcl/interfaces/gtk/gtkint.pp b/lcl/interfaces/gtk/gtkint.pp index e6b925f06a..6bc983f5d0 100644 --- a/lcl/interfaces/gtk/gtkint.pp +++ b/lcl/interfaces/gtk/gtkint.pp @@ -220,16 +220,16 @@ type AWinControl: TWinControl);virtual; procedure UntransientWindow(GtkWindow: PGtkWindow); procedure InitializeFileDialog(FileDialog: TFileDialog; - var SelWidget: PGtkWidget; Title: PChar); + var SelWidget: PGtkWidget; Title: PChar); virtual; procedure InitializeFontDialog(FontDialog: TFontDialog; var SelWidget: PGtkWidget; Title: PChar); procedure InitializeCommonDialog(ADialog: TObject; AWindow: PGtkWidget); function CreateOpenDialogFilter(OpenDialog: TOpenDialog; - SelWidget: PGtkWidget): string; + SelWidget: PGtkWidget): string; virtual; procedure CreatePreviewDialogControl(PreviewDialog: TPreviewFileDialog; - SelWidget: PGtkWidget); + SelWidget: PGtkWidget); virtual; procedure InitializeOpenDialog(OpenDialog: TOpenDialog; - SelWidget: PGtkWidget); + SelWidget: PGtkWidget); virtual; // misc Function GetCaption(Sender : TObject) : String; virtual; @@ -299,6 +299,7 @@ type end; {$I gtklistslh.inc} +{$I gtkfiledialogutilsh.inc} var GTKWidgetSet: TGTKWidgetSet; @@ -346,6 +347,7 @@ const GtkNil = nil; {$I gtklistsl.inc} +{$I gtkfiledialogutils.inc} {$I gtkobject.inc} {$I gtkwinapi.inc} {$I gtklclintf.inc} diff --git a/lcl/interfaces/gtk/gtkobject.inc b/lcl/interfaces/gtk/gtkobject.inc index 551cd3f001..8429795a28 100644 --- a/lcl/interfaces/gtk/gtkobject.inc +++ b/lcl/interfaces/gtk/gtkobject.inc @@ -4163,143 +4163,6 @@ begin gtk_object_set_data(PGtkObject(SelWidget), 'LCLHistoryList', HistoryList); end; -{------------------------------------------------------------------------------ - Function: ExtractFilterList - Params: const Filter: string; var FilterIndex: integer; - var FilterList: TStringList - Returns: - - - Converts a Delphi file filter of the form - 'description1|mask1|description2|mask2|...' - into a TFPList of PFileSelFilterEntry(s). - Multi masks: - - multi masks like '*.pas;*.pp' are converted into multiple entries. - - if the masks are found in the description they are adjusted - - if the mask is not included in the description it will be concatenated - For example: - 'Pascal files (*.pas;*.pp)|*.pas;*.lpr;*.pp; - is converted to three filter entries: - 'Pascal files (*.pas)' + '*.pas' - 'Pascal files (*.pp)' + '*.pp' - 'Pascal files (*.lpr)' + '*.lpr' - ------------------------------------------------------------------------------} -procedure ExtractFilterList(const Filter: string; out FilterList: TFPList; - SplitMultiMask: boolean); -var - Masks: TStringList; - CurFilterIndex: integer; - - procedure ExtractMasks(const MultiMask: string); - var CurMaskStart, CurMaskEnd: integer; - s: string; - begin - if Masks=nil then - Masks:=TStringList.Create - else - Masks.Clear; - CurMaskStart:=1; - while CurMaskStart<=length(MultiMask) do begin - CurMaskEnd:=CurMaskStart; - if SplitMultiMask then begin - while (CurMaskEnd<=length(MultiMask)) and (MultiMask[CurMaskEnd]<>';') - do - inc(CurMaskEnd); - end else begin - CurMaskEnd:=length(MultiMask)+1; - end; - s:=Trim(copy(MultiMask,CurMaskStart,CurMaskEnd-CurMaskStart)); - Masks.Add(s); - CurMaskStart:=CurMaskEnd+1; - end; - end; - - procedure AddEntry(const Desc, Mask: string); - var NewFilterEntry: PFileSelFilterEntry; - begin - New(NewFilterEntry); - NewFilterEntry^.Description:= StrAlloc(length(Desc)+1); - StrPCopy(NewFilterEntry^.Description, Desc); - NewFilterEntry^.Mask:= StrAlloc(length(Mask)+1); - StrPCopy(NewFilterEntry^.Mask, Mask); - NewFilterEntry^.FilterIndex:=CurFilterIndex; - FilterList.Add(NewFilterEntry); - end; - - // remove all but one masks from description string - function RemoveOtherMasks(const Desc: string; MaskIndex: integer): string; - var i, StartPos, EndPos: integer; - begin - Result:=Desc; - for i:=0 to Masks.Count-1 do begin - if i=MaskIndex then continue; - StartPos:=Pos(Masks[i],Result); - EndPos:=StartPos+length(Masks[i]); - if StartPos<1 then continue; - while (StartPos>1) and (Result[StartPos-1] in [' ',#9,';']) do - dec(StartPos); - while (EndPos<=length(Result)) and (Result[EndPos] in [' ',#9]) do - inc(EndPos); - if (StartPos>1) and (Result[StartPos-1]='(') - and (EndPos<=length(Result)) then begin - if (Result[EndPos]=')') then begin - dec(StartPos); - inc(EndPos); - end else if Result[EndPos]=';' then begin - inc(EndPos); - end; - end; - System.Delete(Result,StartPos,EndPos-StartPos); - end; - end; - - procedure AddEntries(const Desc: string; MultiMask: string); - var i: integer; - CurDesc: string; - begin - ExtractMasks(MultiMask); - for i:=0 to Masks.Count-1 do begin - CurDesc:=RemoveOtherMasks(Desc,i); - if (Masks.Count>1) and (Pos(Masks[i],CurDesc)<1) then begin - if (CurDesc='') or (CurDesc[length(CurDesc)]<>' ') then - CurDesc:=CurDesc+' '; - CurDesc:=CurDesc+'('+Masks[i]+')'; - end; - //debugln('AddEntries ',CurDesc,' ',Masks[i]); - AddEntry(CurDesc,Masks[i]); - end; - inc(CurFilterIndex); - end; - -var - CurDescStart, CurDescEnd, CurMultiMaskStart, CurMultiMaskEnd: integer; - CurDesc, CurMultiMask: string; -begin - FilterList:=TFPList.Create; - Masks:=nil; - CurFilterIndex:=0; - CurDescStart:=1; - while CurDescStart<=length(Filter) do begin - // extract next filter description - CurDescEnd:=CurDescStart; - while (CurDescEnd<=length(Filter)) and (Filter[CurDescEnd]<>'|') do - inc(CurDescEnd); - CurDesc:=copy(Filter,CurDescStart,CurDescEnd-CurDescStart); - // extract next filter multi mask - CurMultiMaskStart:=CurDescEnd+1; - CurMultiMaskEnd:=CurMultiMaskStart; - while (CurMultiMaskEnd<=length(Filter)) and (Filter[CurMultiMaskEnd]<>'|') do - inc(CurMultiMaskEnd); - CurMultiMask:=copy(Filter,CurMultiMaskStart,CurMultiMaskEnd-CurMultiMaskStart); - if CurDesc='' then CurDesc:=CurMultiMask; - // add filter(s) - if (CurMultiMask<>'') or (CurDesc<>'') then - AddEntries(CurDesc,CurMultiMask); - // next filter - CurDescStart:=CurMultiMaskEnd+1; - end; - Masks.Free; -end; - {------------------------------------------------------------------------------ Function: TGtkWidgetSet.CreateOpenDialogFilter Params: OpenDialog: TOpenDialog; SelWidget: PGtkWidget diff --git a/lcl/interfaces/gtk2/gtk2int.pas b/lcl/interfaces/gtk2/gtk2int.pas index 73302cd2be..6770d8c9c3 100644 --- a/lcl/interfaces/gtk2/gtk2int.pas +++ b/lcl/interfaces/gtk2/gtk2int.pas @@ -67,6 +67,15 @@ type MultiSelect, ExtendedSelect: boolean); override; //function SetTopIndex(Sender: TObject; NewTopIndex: integer): integer; override; procedure UpdateDCTextMetric(DC: TDeviceContext); override; + + procedure InitializeFileDialog(FileDialog: TFileDialog; + var SelWidget: PGtkWidget; Title: PChar); override; + function CreateOpenDialogFilter(OpenDialog: TOpenDialog; + SelWidget: PGtkWidget): string; override; + procedure InitializeOpenDialog(OpenDialog: TOpenDialog; + SelWidget: PGtkWidget); override; + procedure CreatePreviewDialogControl( + PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget); override; public {$I gtk2winapih.inc} {$I gtk2lclintfh.inc} diff --git a/lcl/interfaces/gtk2/gtk2object.inc b/lcl/interfaces/gtk2/gtk2object.inc index afc580449c..d299f567f2 100644 --- a/lcl/interfaces/gtk2/gtk2object.inc +++ b/lcl/interfaces/gtk2/gtk2object.inc @@ -126,6 +126,69 @@ begin Result := False; end; +{$IFDEF HasGTK2_6} +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 + 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; +{$ENDIF} + Procedure gtk_clb_toggle(cellrenderertoggle : PGtkCellRendererToggle; arg1 : PGChar; WinControl: TWinControl); cdecl; var @@ -1454,6 +1517,198 @@ begin end; end; +{------------------------------------------------------------------------------ + Function: TGtk2WidgetSet.InitializeOpenDialog + Params: OpenDialog: TOpenDialog; SelWidget: PGtkWidget + Returns: - + + 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 + ------------------------------------------------------------------------------} +procedure TGtk2WidgetSet.InitializeOpenDialog(OpenDialog: TOpenDialog; + SelWidget: PGtkWidget); +{$IFDEF HasGTK2_6} +var + FileSelWidget: PGtkFileChooser; + HelpButton: PGtkWidget; +{$ENDIF} +begin +{$IFDEF HasGTK2_6} + FileSelWidget := GTK_FILE_CHOOSER(SelWidget); + + // Help button + if (ofShowHelp in OpenDialog.Options) then begin + HelpButton := gtk_dialog_add_button(FileSelWidget, GTK_STOCK_HELP, GTK_RESPONSE_NONE); + + g_signal_connect( gtk_object(HelpButton), + 'clicked', gtk_signal_func(@gtkDialogHelpclickedCB), OpenDialog); + end; + + if ofAllowMultiSelect in OpenDialog.Options then + gtk_file_chooser_set_select_multiple(FileSelWidget, True); + + // History List - a frame with an option menu + CreateOpenDialogHistory(OpenDialog, SelWidget); + +// // Filter - a frame with an option menu + CreateOpenDialogFilter(OpenDialog,SelWidget); + + // 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_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), SelWidget); + + // set initial filename + if OpenDialog.Filename<>'' then + gtk_file_chooser_set_filename(FileSelWidget, PChar(OpenDialog.Filename)); + + //if InitialFilter <> 'none' then + // PopulateFileAndDirectoryLists(FileSelWidget, InitialFilter); +{$ELSE} + inherited InitializeOpenDialog(OpenDialog,SelWidget); +{$ENDIF NONO} +end; + +{------------------------------------------------------------------------------ + Function: TGtk2WidgetSet.InitializeFileDialog + Params: FileDialog: TFileDialog; var SelWidget: PGtkWidget + Returns: - + + Creates a new TFile/Open/SaveDialog + requires: gtk+ 2.6 + ------------------------------------------------------------------------------} +procedure TGtk2WidgetSet.InitializeFileDialog(FileDialog: TFileDialog; + var SelWidget: PGtkWidget; Title: PChar); +{$IFDEF HasGTK2_6} +var + Action: TGtkFileChooserAction; + Button1: String; +{$ENDIF} +begin +{$IFDEF HasGTK2_6} + Action := GTK_FILE_CHOOSER_ACTION_OPEN; + Button1 := GTK_STOCK_OPEN; + + if FileDialog is TSaveDialog then begin + Action := GTK_FILE_CHOOSER_ACTION_SAVE; + Button1 := GTK_STOCK_CANCEL; + end; + + SelWidget := gtk_file_chooser_dialog_new(Title, nil, Action, + PChar(GTK_STOCK_CANCEL), [GTK_RESPONSE_CANCEL, PChar(Button1), GTK_RESPONSE_OK, nil]); + + g_signal_connect(SelWidget, 'response', gtk_signal_func(@Gtk2FileChooserResponseCB), FileDialog); + +(*gtk 2.8 + if FileDialog is TSaveDialog then begin + gtk_file_chooser_set_do_overwrite_confirmation(SelWidget, + ofOverwritePrompt in TOpenDialog(theDialog).Options); + end; +*) + + if FileDialog is TOpenDialog then + InitializeOpenDialog(TOpenDialog(FileDialog), SelWidget); + + InitializeCommonDialog(TCommonDialog(FileDialog), SelWidget); +{$ELSE} + inherited InitializeFileDialog(FileDialog,SelWidget,Title); +{$ENDIF} +end; + +function TGtk2WidgetSet.CreateOpenDialogFilter(OpenDialog: TOpenDialog; + SelWidget: PGtkWidget): string; +{$IFDEF HasGTK2_6} +var + FilterList: TFPList; + i, j: integer; + s: String; + GtkFilter: PGtkFileFilter; +{$ENDIF} +begin +{$IFDEF HasGTK2_6} + ExtractFilterList(OpenDialog.Filter, FilterList, false); + if FilterList.Count > 0 then begin + j := 1; + for i := 0 to FilterList.Count-1 do begin + GtkFilter := gtk_file_filter_new(); + + gtk_file_filter_add_pattern(GtkFilter, PFileSelFilterEntry(FilterList[i])^.Mask); + 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; + end; + + gtk_object_set_data(PGtkObject(SelWidget), 'LCLFilterList', FilterList); + + Result := 'hm'; { Don't use '' as null return as this is used for *.* } +{$ELSE} + Result:=inherited CreateOpenDialogFilter(OpenDialog,SelWidget); +{$ENDIF} +end; + +procedure TGtk2WidgetSet.CreatePreviewDialogControl( + PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget); +{$IFDEF HasGTK2_6} +var + PreviewWidget: PGtkWidget; + AControl: TPreviewFileControl; + FileChooser: PGtkFileChooser; +{$ENDIF} +begin + {$IFDEF HasGTK2_6} + 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); + {$ELSE} + inherited CreatePreviewDialogControl(PreviewDialog,SelWidget); + {$ENDIF} +end; + {$IFDEF ASSERT_IS_ON} {$UNDEF ASSERT_IS_ON} {$C-}