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