View Issue Details

IDProjectCategoryView StatusLast Update
0028755LazarusLCLpublic2016-01-27 22:46
Reporterwp Assigned ToJesus Reyes  
PrioritynormalSeverityminorReproducibilityalways
Status assignedResolutionopen 
Product Version1.5 (SVN) 
Summary0028755: Complete clipboard support for TStringGrid in case of multiple selections
DescriptionSome time ago, the feature of using multiple selections was added to the TCustomGrid component family. Clipboard support, however, is not complete for multiple selections: Currently the copy operation transfers only the first selected range to the clipboard, and pasting is even blocked in case of multiple selections.

The provided patch completes clipboard support for the case of multiple selections:

The virtual method "DoCopyToClipboard" calculates the union of all selected ranges and passes this rectangle to the "CopyCellRectToClipboard" method which appends all cell strings to a csv-string for the clipboard. The union operation is needed because cells must be in the clipboard in an ordered fashion, line by line, left to right, top to bottom. This is because the simple csv clipboard format does not provide information on the cell coordinates. To prevent non-selected cells within the union block from being written to the clipboard the method "CopyCellRectToClipboard" has got a new (optional) parameter, "SelectedOnly", which restricts the generation of the clipboard string to the selected cells only.

When pasting non-contiguous multiple selections back to the grid it could happen that cells are erased by empty clipboard cells between the formerly selected blocks. The patch does not allow this and does not write empty cells back to the grid at all. For cases in which this is not desired a set of "TClipboardOptions" was introduced in which the (so far only) element "coPasteEmptyCell" can activate pasting of empty cells.

I am not 100% happy with the pasting function, but I do not see a way to overcome the issue with the missing cell coordinates without introducing a special clipboard format (which can cause a lot of other trouble as I see with fpspreadsheet).
TagsNo tags attached.
Fixed in Revision
LazTarget-
Widgetset
Attached Files

Relationships

related to 0029146 closedBart Broersma [Feature Request] HTML Support for TClipboard 

Activities

wp

2015-09-29 22:13

developer  

grids.pas.patch (6,061 bytes)   
Index: lcl/grids.pas
===================================================================
--- lcl/grids.pas	(revision 49896)
+++ lcl/grids.pas	(working copy)
@@ -165,6 +165,11 @@
   // TCellHintPriority determines how the overall hint is combined when more
   // multiple hint texts are to be displayed.
 
+  TClipboardOption = (
+    coPasteEmptyCells    // Empty cells in clipboard may overwrite cell content
+  );
+  TClipboardOptions = set of TClipboardOption;
+
 const
   soAll: TSaveOptions = [soDesign, soAttributes, soContent, soPosition];
   constRubberSpace: byte = 2;
@@ -1574,6 +1579,7 @@
     private
       FModified: boolean;
       FColsMap,FRowsMap: TMap;
+      FClipboardOptions: TClipboardOptions;
       function  GetCols(index: Integer): TStrings;
       function  GetObjects(ACol, ARow: Integer): TObject;
       function  GetRows(index: Integer): TStrings;
@@ -1584,7 +1590,7 @@
       procedure SetObjects(ACol, ARow: Integer; AValue: TObject);
       procedure SetRows(index: Integer; const AValue: TStrings);
       procedure WriteCells(Writer: TWriter);
-      procedure CopyCellRectToClipboard(const R:TRect);
+      procedure CopyCellRectToClipboard(const R:TRect; SelectedOnly: Boolean=false);
     protected
       procedure AssignTo(Dest: TPersistent); override;
       procedure AutoAdjustColumn(aCol: Integer); override;
@@ -1612,6 +1618,7 @@
       procedure SetCheckboxState(const aCol, aRow:Integer; const aState: TCheckboxState); override;
       procedure SetEditText(aCol, aRow: Longint; const aValue: string); override;
 
+      property ClipboardOptions: TClipboardOptions read FClipboardOptions write FClipboardOptions;
       property Modified: boolean read FModified write FModified;
 
     public
@@ -1623,7 +1630,6 @@
       procedure Clean(CleanOptions: TGridZoneSet); overload;
       procedure Clean(aRect: TRect; CleanOptions: TGridZoneSet); overload;
       procedure Clean(StartCol,StartRow,EndCol,EndRow: integer; CleanOptions: TGridZoneSet); overload;
-      procedure CopyToClipboard(AUseSelection: boolean = false);
       procedure InsertRowWithValues(Index: Integer; Values: array of String);
       procedure LoadFromCSVStream(AStream: TStream; ADelimiter: Char=',';
         UseTitles: boolean=true; FromLine: Integer=0; SkipEmptyLines: Boolean=true);
@@ -1634,6 +1640,10 @@
       procedure SaveToCSVFile(AFileName: string; ADelimiter: Char=',';
         WriteTitles: boolean=true; VisibleColumnsOnly: boolean=false);
 
+      procedure CopyToClipboard(AUseSelection: boolean = false);
+      procedure CutToClipboard;
+      procedure PasteFromClipboard;
+
       property Cells[ACol, ARow: Integer]: string read GetCells write SetCells;
       property Cols[index: Integer]: TStrings read GetCols write SetCols;
       property DefaultTextStyle;
@@ -1664,6 +1674,7 @@
     property BorderSpacing;
     property BorderStyle;
     property CellHintPriority;
+    property ClipboardOptions;
     property Color;
     property ColCount;
     property ColumnClickSorts;
@@ -10373,7 +10384,8 @@
   end;
 end;
 
-procedure TCustomStringGrid.CopyCellRectToClipboard(const R: TRect);
+procedure TCustomStringGrid.CopyCellRectToClipboard(const R: TRect;
+  SelectedOnly: Boolean);
 var
   SelStr: String;
   i,j,k: LongInt;
@@ -10383,20 +10395,20 @@
 
     for j:=R.Left to R.Right do begin
 
-      if Columns.Enabled and (j>=FirstGridColumn) then begin
-
-        k := ColumnIndexFromGridColumn(j);
-        if not Columns[k].Visible then
-          continue;
-
-        if (i=0) then
-          SelStr := SelStr + Columns[k].Title.Caption
-        else
+      if not SelectedOnly or GetIsCellSelected(j, i) then
+      begin
+        if Columns.Enabled and (j>=FirstGridColumn) then begin
+          k := ColumnIndexFromGridColumn(j);
+          if not Columns[k].Visible then
+            continue;
+          if (i=0) then
+            SelStr := SelStr + Columns[k].Title.Caption
+          else
+            SelStr := SelStr + Cells[j,i];
+        end else
           SelStr := SelStr + Cells[j,i];
+      end;
 
-      end else
-        SelStr := SelStr + Cells[j,i];
-
       if j<>R.Right then
         SelStr := SelStr + #9;
     end;
@@ -10562,8 +10574,22 @@
 end;
 
 procedure TCustomStringGrid.DoCopyToClipboard;
+var
+  R: TRect;
+  i: Integer;
 begin
-  CopyCellRectToClipboard(Selection);
+  if HasMultiSelection then begin
+    // Calculate union of all selection rectangles
+    R := Selection;
+    for i:=0 to High(FSelections) do begin
+      if FSelections[i].Left < R.Left then R.Left := FSelections[i].Left;
+      if FSelections[i].Right > R.Right then R.Right := FSelections[i].Right;
+      if FSelections[i].Top < R.Top then R.Top := FSelections[i].Top;
+      if FSelections[i].Bottom > R.Bottom then R.Bottom := FSelections[i].Bottom;
+    end;
+    CopyCellRectToClipboard(R, true);
+  end else
+    CopyCellRectToClipboard(Selection, false);
 end;
 
 procedure TCustomStringGrid.DoCutToClipboard;
@@ -10576,11 +10602,6 @@
 
 procedure TCustomStringGrid.DoPasteFromClipboard;
 begin
-  // Unpredictable results when a multiple selection is pasted back in.
-  // Therefore we inhibit this here.
-  if HasMultiSelection then
-    exit;
-
   if EditingAllowed(Col) and Clipboard.HasFormat(CF_TEXT) then begin
     SelectionSetText(Clipboard.AsText);
   end;
@@ -10700,7 +10721,8 @@
           if not ValidateEntry(aCol,aRow,Cells[aCol,aRow],NewValue) then
             break;
           {$ENDIF}
-          Cells[aCol, aRow] := NewValue;
+          if (NewValue <> '') or (coPasteEmptyCells in FClipboardOptions) then
+            Cells[aCol, aRow] := NewValue;
         end;
     end;
   finally
@@ -10845,6 +10867,16 @@
     CopyCellRectToClipboard(Rect(0,0,ColCount-1,RowCount-1));
 end;
 
+procedure TCustomStringGrid.CutToClipboard;
+begin
+  doCutToClipboard;
+end;
+
+procedure TCustomStringGrid.PasteFromClipboard;
+begin
+  doPasteFromClipboard;
+end;
+
 procedure TCustomStringGrid.InsertRowWithValues(Index: Integer;
   Values: array of String);
 var
grids.pas.patch (6,061 bytes)   

wp

2015-09-30 11:56

developer   ~0086180

Please ignore the patch for the moment. I am playing with a dedicated clipboard format, it has lots of advantages which are worth the little additional effort.

wp

2015-09-30 15:27

developer   ~0086183

Here is a new patch which defines a simple clipboard format to keep the selection rectangles intact. This simplifies the logics of the pasting process considerably, the ClipboardOptions mentioned above are no longer required, and it is also possible to highlight the selections after pasting.

Tested under Windows (7) and Linux (Mint). Don't have access to OSX, though.

I am adding also a little demo to play with.

wp

2015-09-30 15:28

developer  

grids-v2.pas.patch (10,991 bytes)   
Index: lcl/grids.pas
===================================================================
--- lcl/grids.pas	(revision 49896)
+++ lcl/grids.pas	(working copy)
@@ -1584,11 +1584,12 @@
       procedure SetObjects(ACol, ARow: Integer; AValue: TObject);
       procedure SetRows(index: Integer; const AValue: TStrings);
       procedure WriteCells(Writer: TWriter);
-      procedure CopyCellRectToClipboard(const R:TRect);
+      procedure CopyCellRectToClipboard(const R:TRect; SelectedOnly: Boolean=false);
     protected
       procedure AssignTo(Dest: TPersistent); override;
       procedure AutoAdjustColumn(aCol: Integer); override;
       procedure CalcCellExtent(acol, aRow: Integer; var aRect: TRect); override;
+      function CombineCellsToString(const R: TRect; SelectedOnly: Boolean=false): String;
       procedure DefineProperties(Filer: TFiler); override;
       procedure DefineCellsProperty(Filer: TFiler); virtual;
       function  DoCompareCells(Acol,ARow,Bcol,BRow: Integer): Integer; override;
@@ -1607,7 +1608,8 @@
       procedure SaveContent(cfg: TXMLConfig); override;
       //procedure DrawInteriorCells; override;
       //procedure SelectEditor; override;
-      procedure SelectionSetText(TheText: String);
+      procedure SelectionSetText(TheText: String); overload;
+      procedure SelectionSetText(TheText: String; ARect: TRect); overload;
       procedure SetCells(ACol, ARow: Integer; const AValue: string); virtual;
       procedure SetCheckboxState(const aCol, aRow:Integer; const aState: TCheckboxState); override;
       procedure SetEditText(aCol, aRow: Longint; const aValue: string); override;
@@ -1623,7 +1625,6 @@
       procedure Clean(CleanOptions: TGridZoneSet); overload;
       procedure Clean(aRect: TRect; CleanOptions: TGridZoneSet); overload;
       procedure Clean(StartCol,StartRow,EndCol,EndRow: integer; CleanOptions: TGridZoneSet); overload;
-      procedure CopyToClipboard(AUseSelection: boolean = false);
       procedure InsertRowWithValues(Index: Integer; Values: array of String);
       procedure LoadFromCSVStream(AStream: TStream; ADelimiter: Char=',';
         UseTitles: boolean=true; FromLine: Integer=0; SkipEmptyLines: Boolean=true);
@@ -1634,6 +1635,10 @@
       procedure SaveToCSVFile(AFileName: string; ADelimiter: Char=',';
         WriteTitles: boolean=true; VisibleColumnsOnly: boolean=false);
 
+      procedure CopyToClipboard(AUseSelection: boolean = false);
+      procedure CutToClipboard;
+      procedure PasteFromClipboard;
+
       property Cells[ACol, ARow: Integer]: string read GetCells write SetCells;
       property Cols[index: Integer]: TStrings read GetCols write SetCols;
       property DefaultTextStyle;
@@ -1786,6 +1791,15 @@
 const
   MULTISEL_MODIFIER = {$IFDEF Darwin}ssMeta{$ELSE}ssCtrl{$ENDIF};
 
+var
+  cfLazarusGrid: Integer = 0;
+
+procedure CheckClipboardFormat;
+begin
+  if cfLazarusGrid = 0 then
+    cfLazarusGrid := RegisterClipboardFormat('LazarusGrid');
+end;
+
 function BidiFlipX(X: Integer; const Width: Integer; const Flip: Boolean): Integer;
 begin
   if Flip then
@@ -4904,6 +4918,10 @@
   end
   else
     FRange:=Rect(FCol,FRow,FCol,FRow);
+
+  // Remove selections if they were used before with RangeSelect on.
+  if not (goRangeSelect in Options) then
+    SetLength(FSelections, 0);
 end;
 
 procedure TCustomGrid.WriteColumns(Writer: TWriter);
@@ -10373,39 +10391,44 @@
   end;
 end;
 
-procedure TCustomStringGrid.CopyCellRectToClipboard(const R: TRect);
+function TCustomStringGrid.CombineCellsToString(const R: TRect;
+  SelectedOnly: Boolean = false): String;
 var
-  SelStr: String;
   i,j,k: LongInt;
 begin
-  SelStr := '';
+  Result := '';
   for i:=R.Top to R.Bottom do begin
 
     for j:=R.Left to R.Right do begin
 
-      if Columns.Enabled and (j>=FirstGridColumn) then begin
+      if not SelectedOnly or GetIsCellSelected(j, i) then
+      begin
+        if Columns.Enabled and (j>=FirstGridColumn) then begin
+          k := ColumnIndexFromGridColumn(j);
+          if not Columns[k].Visible then
+            continue;
+          if (i=0) then
+            Result := Result + Columns[k].Title.Caption
+          else
+            Result := Result + Cells[j,i];
+        end else
+          Result := Result + Cells[j,i];
+      end;
 
-        k := ColumnIndexFromGridColumn(j);
-        if not Columns[k].Visible then
-          continue;
-
-        if (i=0) then
-          SelStr := SelStr + Columns[k].Title.Caption
-        else
-          SelStr := SelStr + Cells[j,i];
-
-      end else
-        SelStr := SelStr + Cells[j,i];
-
       if j<>R.Right then
-        SelStr := SelStr + #9;
+        Result := Result + #9;
     end;
 
-    SelStr := SelStr + #13#10;
+    Result := Result + #13#10;
   end;
-  Clipboard.AsText := SelStr;
 end;
 
+procedure TCustomStringGrid.CopyCellRectToClipboard(const R: TRect;
+  SelectedOnly: Boolean = false);
+begin
+  Clipboard.AsText := CombineCellsToString(R, SelectedOnly);
+end;
+
 procedure TCustomStringGrid.AssignTo(Dest: TPersistent);
 var
   i, j: Integer;
@@ -10562,8 +10585,49 @@
 end;
 
 procedure TCustomStringGrid.DoCopyToClipboard;
+var
+  R, Rs: TRect;
+  i: Integer;
+  s: String;
+  stream: TStream;
 begin
-  CopyCellRectToClipboard(Selection);
+  // Calculate union of all selection rectangles
+  R := Selection;
+  for i:=0 to High(FSelections) do begin
+    if FSelections[i].Left < R.Left then R.Left := FSelections[i].Left;
+    if FSelections[i].Right > R.Right then R.Right := FSelections[i].Right;
+    if FSelections[i].Top < R.Top then R.Top := FSelections[i].Top;
+    if FSelections[i].Bottom > R.Bottom then R.Bottom := FSelections[i].Bottom;
+  end;
+
+  // Write union to clipboard. It will have clipboard format CF_Text and is
+  // for pasting into other applications.
+  CopyCellRectToClipboard(R, true);
+
+  // Write selection coordinates to clipboard, as well as the csv-like concatenated
+  // cell strings of each selection. The selection coordinates are relative to
+  // the top/left corner of the union rectangle
+  stream := TMemorystream.Create;
+  try
+    // Write count of selections
+    stream.WriteWord(SelectedRangeCount);
+    for i:=0 to SelectedRangeCount-1 do begin
+      // Write current selected range
+      Rs := SelectedRange[i];
+      OffsetRect(Rs, -R.Left, -R.Top);
+      stream.Write(Rs, SizeOf(Rs));
+      // Write csv-like string of cell texts in current selection
+      s := CombineCellsToString(SelectedRange[i]);
+      stream.WriteDWord(Length(s));
+      stream.Write(s[1], Length(s));
+    end;
+    CheckClipboardFormat;
+    Clipboard.Open;
+    Clipboard.AddFormat(cfLazarusGrid, stream);
+    Clipboard.Close;
+  finally
+    stream.Free;
+  end;
 end;
 
 procedure TCustomStringGrid.DoCutToClipboard;
@@ -10575,14 +10639,54 @@
 end;
 
 procedure TCustomStringGrid.DoPasteFromClipboard;
+var
+  stream: TStream;
+  selArr: TGridRectArray;
+  i, n: DWord;
+  s: String;
 begin
-  // Unpredictable results when a multiple selection is pasted back in.
-  // Therefore we inhibit this here.
-  if HasMultiSelection then
-    exit;
-
-  if EditingAllowed(Col) and Clipboard.HasFormat(CF_TEXT) then begin
-    SelectionSetText(Clipboard.AsText);
+  if EditingAllowed(Col) then begin
+    // Check if clipboard contains information on selections
+    if Clipboard.HasFormat(cfLazarusGrid) then begin
+      stream := TMemorystream.Create;
+      try
+        // Read the clipboard
+        CheckClipboardFormat;
+        Clipboard.GetFormat(cfLazarusGrid, stream);
+        stream.Position := 0;
+        // Get selection count
+        n := stream.ReadWord;
+        SetLength(selArr, n);
+        i := 0;
+        while stream.Position < stream.Size do begin
+          // Read selection bounds (relative to top/left corner of union of all selections)
+          stream.Read(selArr[i], SizeOf(TGridRect));
+          // Read csv-style strings of this selection
+          n := stream.ReadDWord;
+          SetLength(s, n);
+          stream.Read(s[1], n);
+          // Apply to grid
+          SelectionSetText(s, selArr[i]);
+          inc(i);
+        end;
+        // Show selections as highlighted
+        if Length(selArr) > 0 then begin
+          for i := 0 to High(selArr) do
+            OffsetRect(selArr[i], Selection.Left, Selection.Top);
+          if Length(selArr) > 1 then begin
+            SetLength(FSelections, Length(selArr)-1);
+            for i := 0 to High(FSelections) do
+              FSelections[i] := selArr[i];
+          end;
+          Selection := selArr[High(selArr)];
+          InvalidateGrid;
+        end;
+      finally
+        stream.Free;
+      end;
+    end else
+    if Clipboard.HasFormat(CF_TEXT) then
+      SelectionSetText(Clipboard.AsText);
   end;
 end;
 
@@ -10650,6 +10754,15 @@
 
 procedure TCustomStringGrid.SelectionSetText(TheText: String);
 var
+  R: TRect;
+begin
+  R := Rect(0, 0, -1, -1);   // We cannot use "EmptyRect" here because 0 width means 1 column!
+  SelectionSetText(TheText, R);
+end;
+
+
+procedure TCustomStringGrid.SelectionSetText(TheText: String; ARect: TGridRect);
+var
   L,SubL: TStringList;
   i,j,StartCol,StartRow: Integer;
   procedure CollectCols(const S: String);
@@ -10679,23 +10792,29 @@
   aCol: Integer;
   aRow: Integer;
   NewValue: String;
+  n: Integer;
 begin
   L := TStringList.Create;
   SubL := TStringList.Create;
-  StartCol := Selection.left;
-  StartRow := Selection.Top;
+  StartCol := Selection.Left + ARect.Left;
+  StartRow := Selection.Top + ARect.Top;
   try
     L.Text := TheText;
     for j:=0 to L.Count-1 do begin
-      if j+StartRow >= RowCount then
+      aRow := j + StartRow;
+      if aRow >= RowCount then
         break;
       CollectCols(L[j]);
-      for i:=0 to SubL.Count-1 do
-        if (i+StartCol<ColCount) and (not GetColumnReadonly(i+StartCol)) then
+      if ARect.Right - ARect.Left < 0 then
+        n := SubL.Count else
+        n := ARect.Right - ARect.Left + 1;
+      for i:=0 to n-1 do begin
+        aCol := i + StartCol;
+        if (aCol < ColCount) and (not GetColumnReadonly(aCol)) then
         begin
-          aCol := i+StartCol;
-          aRow := j+StartRow;
-          NewValue := SubL[i];
+          if i < SubL.Count then
+            NewValue := SubL[i] else
+            NewValue := '';
           {$IFDEF EnableGridPasteValidateEntry}
           if not ValidateEntry(aCol,aRow,Cells[aCol,aRow],NewValue) then
             break;
@@ -10702,6 +10821,7 @@
           {$ENDIF}
           Cells[aCol, aRow] := NewValue;
         end;
+      end;
     end;
   finally
     SubL.Free;
@@ -10845,6 +10965,16 @@
     CopyCellRectToClipboard(Rect(0,0,ColCount-1,RowCount-1));
 end;
 
+procedure TCustomStringGrid.CutToClipboard;
+begin
+  doCutToClipboard;
+end;
+
+procedure TCustomStringGrid.PasteFromClipboard;
+begin
+  doPasteFromClipboard;
+end;
+
 procedure TCustomStringGrid.InsertRowWithValues(Index: Integer;
   Values: array of String);
 var
grids-v2.pas.patch (10,991 bytes)   

wp

2015-09-30 15:28

developer  

wp

2015-12-05 12:40

developer   ~0087797

Last edited: 2015-12-05 12:49

View 2 revisions

Reminder sent to: Jesus Reyes

Just a reminder - this patch has been unnoticed for almost 3 months now...

Bart Broersma

2015-12-05 15:38

developer   ~0087801

@wp: Jesus is currently kind of unavailable for a while.

Q: why copy as csv?
IMO the grid is a representation of a table, it contains tabular data,so why not put it as such on the clipboard?
And an overloaded version that can put it as CSV, or as HTML?

wp

2015-12-05 16:36

developer   ~0087802

Good idea, let me see what I can borrow from fpspreadsheet.

Bart Broersma

2015-12-06 12:32

developer   ~0087813

Last edited: 2015-12-06 14:31

View 2 revisions

In the SynExportHtml (not sur about the name) there is soe code examples w.r.t. copying to clipboard.
I also have some code snippets that deal with pasting html on Windows (which sucks with their stupid header) and Linux.

[edit]
My code snippets are in http://svn.code.sf.net/p/flyingsheep/code/trunk/MijnLib/lcl_misc.pp
[/edit]

wp

2015-12-06 16:59

developer   ~0087819

One thing to be discussed: the only advantage of the html format that I see would be the inclusion of cell formatting (background color, cell font, text justification) - without the format only the cell text would be transferred, and this is what csv does anyway. Since the TStringGrid does not store individual cell formats they must be retrieved from the DoPrepareCanvas method - not straightforward, but it can be done... Going one step further, pasting a html table back into the grid would require parsing the html stream to extract both cell text and cell formats, and the latter must be stored somehow to be put back into the DoPrepareCanvas method. That's very tough, in my eyes it requires a drastic change of the grid infrastructure. And of course, tables are not the only entities which can be contained in an html stream; the code must seek for a table, and if there are several tables it must decide which table to use.

So, in total, I am in doubt if it really makes sense to implement the html format for the clipboard at last for full copy & paste support.

Partial support, only CopyToClipboard, no PasteFromClipboard, would make more sense, but I think 99% of all grid applications use non-formatted data, and again, I doubt if the 1% is worth the effort and blown-up code base.

Bart Broersma

2015-12-06 17:38

developer   ~0087821

Last edited: 2015-12-06 17:40

View 3 revisions

Pasting HTML will be tough.
I have some code to parse a html table, but that simply gives you the text inside the cells, it strips all formatting from it.

Copying as HTML o.t.h. will enable to paste as a table inside any office application like MS Word or Libre Office Writer, which would be a nice asset.

Copying as CSV OTOH makes liitle sense to me (which may be my ignorance).
Which (common) applicatios allow to paste CSV (other then plain text)?

As to blowing up the code base: we could provide this functionality by means of a class helper, so it does not have to go inside grids unit?

As a side note: TClipBoard could do with Get/SetAsHtml methods.

wp

2015-12-06 18:06

developer   ~0087822

> Copying as HTML o.t.h. will enable to paste as a table inside any office
> application like MS Word or Libre Office Writer, which would be a nice asset.

> Copying as CSV OTOH makes liitle sense to me (which may be my ignorance).
> Which (common) applicatios allow to paste CSV (other then plain text)?

Excel and Calc work fine with csv copied via clipboard, the cells are split nicely at the tab cell delimiter, and they even extract numbers from the text (if FormatSettings are correct).

Word and Writer have some disadvantages, they get the csv from the stringgrid as a tab-separated pseudo-table which looks awful if cell content is word-wrapped. But it is easy to convert the selected, tab-separated text into a "real" table. Anyway, I'll give it a try again with "CopyToClipboard" only.

> As a side note: TClibBoard could do with Get/SetAsHtml methods.
Really? Where's that? At least not in the clipbrd unit. Or do you mean there should be a class helper for TClipboard providing these methods? Why not add it to TClipboard directly?

wp

2015-12-07 01:19

developer   ~0087830

Last edited: 2015-12-07 17:31

View 2 revisions

I am implementing now a new TClipboard property "AsHTML" and a new method "GetAsHTMLFragment", based on your nice code above with some modifications (I hope you don't mind). I'll post it as a separate report once testing is complete.

EDIT:
see 0029146
When this has been included in the LCL I'll activate the html clipboard in TStringGrid.

Jesus Reyes

2015-12-07 19:54

developer   ~0087836

I don't know if copy and paste of multiple selections should be really implemented into grids unit. Multiple selections is a specialism, and copy and paste of Multiple selections is a specialism of a specialism (I hope that makes sense). Don't even Libre Office supports copy and paste of multiple selections between itself, don't talk about between applications.

For example I implemented grids cell's multiselection in an external unit for the Xix Music Player http://sourceforge.net/projects/xixmusicplayer/ because the current implementation was something limited, if the feature can be used for that it would be great, althought in such case, the copy and paste would be preferable a "file" copy and paste and not a "text" copy and paste. That illustrates the difficulty on finding an adecuate target for the clipboard data.

I don't deny that the Need exist, but I think it should not be implemented in the grids unit. Any external implementation that can be re-used would do it.

Something perhaps better would be to implement the feature in such way that can be registered into the grids as a "plugin", of course, the grids would have to be modified for this, is something interesting to think about, but I guess it is a better alternative to adding more seldom used code to the grids.

Bart Broersma

2015-12-17 16:48

developer   ~0088041

ClibBoard in Trunk now has Html capabilities (but they may be altered a little bit in the near future).

Bart Broersma

2016-01-06 17:17

developer   ~0088701

> but I guess it is a better alternative to adding more seldom used code to the grids.

Why not simply have a unit that has functions like:
procedure SGCopyToClipBoard(AGrid: TStringGrid; SomeParamters...);

Bart Broersma

2016-01-27 13:37

developer   ~0089428

> Why not simply have a unit ...
Have a class helper in such a unit?

wp

2016-01-27 14:33

developer   ~0089434

The problem is that clipboard support and multiselect capabilities already are available in the grid. Just the correct combination of both is missing. In this particular case there is much less overhead involved if this is done in-place in the grids unit than if something else is constructed outside (except for an include file).

I've never used class helpers a lot. But I think this should not be the way to go. They are something to allow the application developer to add something to a class not implemented. Why should the component developer use them? He has all the possibilities to add what is needed. And - if I read this correctly ("only one helper type can be active for a type at the same time." (from the help file)) - then the extendability for the user is gone once the component developer already occupies this possibility.

Issue History

Date Modified Username Field Change
2015-09-29 22:13 wp New Issue
2015-09-29 22:13 wp Status new => assigned
2015-09-29 22:13 wp Assigned To => Jesus Reyes
2015-09-29 22:13 wp File Added: grids.pas.patch
2015-09-30 11:56 wp Note Added: 0086180
2015-09-30 15:27 wp Note Added: 0086183
2015-09-30 15:28 wp File Added: grids-v2.pas.patch
2015-09-30 15:28 wp File Added: Grid_MultiSelClipboard.zip
2015-12-05 12:40 wp Note Added: 0087797
2015-12-05 12:49 wp Note Edited: 0087797 View Revisions
2015-12-05 15:38 Bart Broersma Note Added: 0087801
2015-12-05 16:36 wp Note Added: 0087802
2015-12-06 12:32 Bart Broersma Note Added: 0087813
2015-12-06 14:31 Bart Broersma Note Edited: 0087813 View Revisions
2015-12-06 16:59 wp Note Added: 0087819
2015-12-06 17:38 Bart Broersma Note Added: 0087821
2015-12-06 17:39 Bart Broersma Note Edited: 0087821 View Revisions
2015-12-06 17:40 Bart Broersma Note Edited: 0087821 View Revisions
2015-12-06 18:06 wp Note Added: 0087822
2015-12-07 01:19 wp Note Added: 0087830
2015-12-07 17:31 wp Note Edited: 0087830 View Revisions
2015-12-07 19:54 Jesus Reyes Note Added: 0087836
2015-12-17 16:48 Bart Broersma Note Added: 0088041
2016-01-06 17:17 Bart Broersma Note Added: 0088701
2016-01-27 13:37 Bart Broersma Note Added: 0089428
2016-01-27 14:33 wp Note Added: 0089434
2016-01-27 22:46 Juha Manninen Relationship added related to 0029146