Lines 49-54
Link Here
|
49 |
//-------------------------------------------------------------------------- |
49 |
//-------------------------------------------------------------------------- |
50 |
|
50 |
|
51 |
|
51 |
|
|
|
52 |
using ::com::sun::star::util::SearchOptions; |
53 |
|
52 |
BOOL lcl_GetTextWithBreaks( const ScEditCell& rCell, ScDocument* pDoc, String& rVal ) |
54 |
BOOL lcl_GetTextWithBreaks( const ScEditCell& rCell, ScDocument* pDoc, String& rVal ) |
53 |
{ |
55 |
{ |
54 |
// TRUE = more than 1 paragraph |
56 |
// TRUE = more than 1 paragraph |
Lines 657-662
BOOL ScTable::SearchAndReplace(const SvxSearchItem& rSearchItem,
Link Here
|
657 |
com::sun::star::util::SearchOptions aSearchOptions = rSearchItem.GetSearchOptions(); |
659 |
com::sun::star::util::SearchOptions aSearchOptions = rSearchItem.GetSearchOptions(); |
658 |
aSearchOptions.Locale = *ScGlobal::GetLocale(); |
660 |
aSearchOptions.Locale = *ScGlobal::GetLocale(); |
659 |
|
661 |
|
|
|
662 |
if (!aSearchOptions.searchString.getLength()) |
663 |
{ |
664 |
// Search for empty cells. |
665 |
return SearchAndReplaceEmptyCells(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc); |
666 |
} |
667 |
|
660 |
// #107259# reflect UseAsianOptions flag in SearchOptions |
668 |
// #107259# reflect UseAsianOptions flag in SearchOptions |
661 |
// (use only ignore case and width if asian options are disabled). |
669 |
// (use only ignore case and width if asian options are disabled). |
662 |
// This is also done in SvxSearchDialog CommandHdl, but not in API object. |
670 |
// This is also done in SvxSearchDialog CommandHdl, but not in API object. |
Lines 683-688
BOOL ScTable::SearchAndReplace(const SvxSearchItem& rSearchItem,
Link Here
|
683 |
return bFound; |
691 |
return bFound; |
684 |
} |
692 |
} |
685 |
|
693 |
|
|
|
694 |
bool ScTable::SearchAndReplaceEmptyCells( |
695 |
const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, ScMarkData& rMark, |
696 |
String& rUndoStr, ScDocument* pUndoDoc) |
697 |
{ |
698 |
SCCOL nColStart, nColEnd; |
699 |
SCROW nRowStart, nRowEnd; |
700 |
GetFirstDataPos(nColStart, nRowStart); |
701 |
GetLastDataPos(nColEnd, nRowEnd); |
702 |
|
703 |
ScRangeList aRanges; |
704 |
aRanges.Append(ScRange(nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab)); |
705 |
|
706 |
if (rSearchItem.GetSelection()) |
707 |
{ |
708 |
// current selection only. |
709 |
if (!rMark.IsMarked() && !rMark.IsMultiMarked()) |
710 |
// There is no selection. Bail out. |
711 |
return false; |
712 |
|
713 |
ScRangeList aMarkedRanges, aNewRanges; |
714 |
rMark.FillRangeListWithMarks(&aMarkedRanges, true); |
715 |
for (ScRangePtr p = aMarkedRanges.First(); p; p = aMarkedRanges.Next()) |
716 |
{ |
717 |
if (p->aStart.Col() > nColEnd || p->aStart.Row() > nRowEnd) |
718 |
// This range is outside the data area. Skip it. |
719 |
continue; |
720 |
|
721 |
// Shrink the range into data area only. |
722 |
if (p->aStart.Col() < nColStart) |
723 |
p->aStart.SetCol(rCol); |
724 |
if (p->aStart.Row() < nRowStart) |
725 |
p->aStart.SetRow(rRow); |
726 |
|
727 |
if (p->aEnd.Col() > nColEnd) |
728 |
p->aEnd.SetCol(nColEnd); |
729 |
if (p->aEnd.Row() > nRowEnd) |
730 |
p->aEnd.SetRow(nRowEnd); |
731 |
|
732 |
aNewRanges.Append(*p); |
733 |
} |
734 |
aRanges = aNewRanges; |
735 |
} |
736 |
|
737 |
sal_uInt16 nCommand = rSearchItem.GetCommand(); |
738 |
if (nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE) |
739 |
{ |
740 |
if (rSearchItem.GetBackward()) |
741 |
{ |
742 |
for (ScRangePtr p = aRanges.Last(); p; p = aRanges.Prev()) |
743 |
{ |
744 |
if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr, pUndoDoc)) |
745 |
return true; |
746 |
} |
747 |
} |
748 |
else |
749 |
{ |
750 |
for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next()) |
751 |
{ |
752 |
if (SearchRangeForEmptyCell(*p, rSearchItem, rCol, rRow, rUndoStr, pUndoDoc)) |
753 |
return true; |
754 |
} |
755 |
} |
756 |
} |
757 |
else if (nCommand == SVX_SEARCHCMD_FIND_ALL || nCommand == SVX_SEARCHCMD_REPLACE_ALL) |
758 |
{ |
759 |
bool bFound = false; |
760 |
ScMarkData aNewMark(rMark); |
761 |
aNewMark.ResetMark(); |
762 |
for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next()) |
763 |
bFound |= SearchRangeForAllEmptyCells(*p, rSearchItem, aNewMark, rUndoStr, pUndoDoc); |
764 |
rMark = aNewMark; |
765 |
return bFound; |
766 |
} |
767 |
return false; |
768 |
} |
769 |
|
770 |
bool ScTable::SearchRangeForEmptyCell( |
771 |
const ScRange& rRange, const SvxSearchItem& rSearchItem, |
772 |
SCCOL& rCol, SCROW& rRow, String& rUndoStr, ScDocument* /*pUndoDoc*/) |
773 |
{ |
774 |
sal_uInt16 nCmd = rSearchItem.GetCommand(); |
775 |
if (rSearchItem.GetBackward()) |
776 |
{ |
777 |
// backward search |
778 |
if (rSearchItem.GetRowDirection()) |
779 |
{ |
780 |
// row direction. |
781 |
SCROW nBeginRow = rRange.aEnd.Row() > rRow ? rRow : rRange.aEnd.Row(); |
782 |
for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow) |
783 |
{ |
784 |
SCCOL nBeginCol = rRange.aEnd.Col(); |
785 |
if (nRow == rRow && nBeginCol >= rCol) |
786 |
// always start from one cell before the cursor. |
787 |
nBeginCol = rCol - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0); |
788 |
|
789 |
for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol) |
790 |
{ |
791 |
ScBaseCell* pCell = aCol[nCol].GetCell(nRow); |
792 |
if (!pCell) |
793 |
{ |
794 |
// empty cell found. |
795 |
rCol = nCol; |
796 |
rRow = nRow; |
797 |
if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE && |
798 |
rSearchItem.GetReplaceString().Len()) |
799 |
{ |
800 |
aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString())); |
801 |
rUndoStr = String(); |
802 |
} |
803 |
return true; |
804 |
} |
805 |
} |
806 |
} |
807 |
} |
808 |
else |
809 |
{ |
810 |
// column direction. |
811 |
SCCOL nBeginCol = rRange.aEnd.Col() > rCol ? rCol : rRange.aEnd.Col(); |
812 |
for (SCCOL nCol = nBeginCol; nCol >= rRange.aStart.Col(); --nCol) |
813 |
{ |
814 |
SCROW nBeginRow = rRange.aEnd.Row(); |
815 |
if (nCol == rCol && nBeginRow >= rRow) |
816 |
// always start from one cell before the cursor. |
817 |
nBeginRow = rRow - (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0); |
818 |
for (SCROW nRow = nBeginRow; nRow >= rRange.aStart.Row(); --nRow) |
819 |
{ |
820 |
ScBaseCell* pCell = aCol[nCol].GetCell(nRow); |
821 |
if (!pCell) |
822 |
{ |
823 |
// empty cell found. |
824 |
rCol = nCol; |
825 |
rRow = nRow; |
826 |
if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE && |
827 |
rSearchItem.GetReplaceString().Len()) |
828 |
{ |
829 |
aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString())); |
830 |
rUndoStr = String(); |
831 |
} |
832 |
return true; |
833 |
} |
834 |
} |
835 |
} |
836 |
} |
837 |
} |
838 |
else |
839 |
{ |
840 |
// forward search |
841 |
if (rSearchItem.GetRowDirection()) |
842 |
{ |
843 |
// row direction. |
844 |
SCROW nBeginRow = rRange.aStart.Row() < rRow ? rRow : rRange.aStart.Row(); |
845 |
for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow) |
846 |
{ |
847 |
SCCOL nBeginCol = rRange.aStart.Col(); |
848 |
if (nRow == rRow && nBeginCol <= rCol) |
849 |
// always start from one cell past the cursor. |
850 |
nBeginCol = rCol + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0); |
851 |
for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol) |
852 |
{ |
853 |
ScBaseCell* pCell = aCol[nCol].GetCell(nRow); |
854 |
if (!pCell) |
855 |
{ |
856 |
// empty cell found. |
857 |
rCol = nCol; |
858 |
rRow = nRow; |
859 |
if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE && |
860 |
rSearchItem.GetReplaceString().Len()) |
861 |
{ |
862 |
aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString())); |
863 |
rUndoStr = String(); |
864 |
} |
865 |
return true; |
866 |
} |
867 |
} |
868 |
} |
869 |
} |
870 |
else |
871 |
{ |
872 |
// column direction. |
873 |
SCCOL nBeginCol = rRange.aStart.Col() < rCol ? rCol : rRange.aStart.Col(); |
874 |
for (SCCOL nCol = nBeginCol; nCol <= rRange.aEnd.Col(); ++nCol) |
875 |
{ |
876 |
SCROW nBeginRow = rRange.aStart.Row(); |
877 |
if (nCol == rCol && nBeginRow <= rRow) |
878 |
// always start from one cell past the cursor. |
879 |
nBeginRow = rRow + (nCmd == SVX_SEARCHCMD_FIND ? 1 : 0); |
880 |
for (SCROW nRow = nBeginRow; nRow <= rRange.aEnd.Row(); ++nRow) |
881 |
{ |
882 |
ScBaseCell* pCell = aCol[nCol].GetCell(nRow); |
883 |
if (!pCell) |
884 |
{ |
885 |
// empty cell found. |
886 |
rCol = nCol; |
887 |
rRow = nRow; |
888 |
if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE && |
889 |
rSearchItem.GetReplaceString().Len()) |
890 |
{ |
891 |
aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString())); |
892 |
rUndoStr = String(); |
893 |
} |
894 |
return true; |
895 |
} |
896 |
} |
897 |
} |
898 |
} |
899 |
} |
900 |
return false; |
901 |
} |
902 |
|
903 |
bool ScTable::SearchRangeForAllEmptyCells( |
904 |
const ScRange& rRange, const SvxSearchItem& rSearchItem, ScMarkData& rMark, |
905 |
String& rUndoStr, ScDocument* pUndoDoc) |
906 |
{ |
907 |
bool bFound = false; |
908 |
bool bReplace = (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) && |
909 |
(rSearchItem.GetReplaceString().Len() > 0); |
910 |
|
911 |
for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol) |
912 |
{ |
913 |
if (aCol[nCol].IsEmptyData()) |
914 |
{ |
915 |
// The entire column is empty. Add the whole column and move on. |
916 |
rMark.SetMultiMarkArea( |
917 |
ScRange(nCol, rRange.aStart.Row(), nTab, nCol, rRange.aEnd.Row(), nTab)); |
918 |
bFound = true; |
919 |
|
920 |
if (bReplace) |
921 |
{ |
922 |
const String& rNewStr = rSearchItem.GetReplaceString(); |
923 |
for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow) |
924 |
{ |
925 |
aCol[nCol].Insert(nRow, new ScStringCell(rNewStr)); |
926 |
if (pUndoDoc) |
927 |
// TODO: I'm using a string cell with empty content to |
928 |
// trigger deletion of cell instance on undo. Maybe I |
929 |
// should create a new cell type for this? |
930 |
pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String())); |
931 |
} |
932 |
rUndoStr = String(); |
933 |
} |
934 |
continue; |
935 |
} |
936 |
|
937 |
for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow) |
938 |
{ |
939 |
ScBaseCell* pCell = aCol[nCol].GetCell(nRow); |
940 |
if (!pCell) |
941 |
{ |
942 |
// empty cell found |
943 |
rMark.SetMultiMarkArea(ScRange(nCol, nRow, nTab)); |
944 |
bFound = true; |
945 |
|
946 |
if (bReplace) |
947 |
{ |
948 |
aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString())); |
949 |
if (pUndoDoc) |
950 |
// TODO: I'm using a string cell with empty content to |
951 |
// trigger deletion of cell instance on undo. Maybe I |
952 |
// should create a new cell type for this? |
953 |
pUndoDoc->PutCell(nCol, nRow, nTab, new ScStringCell(String())); |
954 |
} |
955 |
} |
956 |
} |
957 |
} |
958 |
return bFound; |
959 |
} |
960 |
|
961 |
|
686 |
|
962 |
|
687 |
|
963 |
|
688 |
|
964 |
|