Changeset View
Changeset View
Standalone View
Standalone View
core/textpage.cpp
Show First 20 Lines • Show All 708 Lines • ▼ Show 20 Line(s) | |||||
709 | 709 | | |||
710 | #endif | 710 | #endif | ||
711 | 711 | | |||
712 | return ret; | 712 | return ret; | ||
713 | } | 713 | } | ||
714 | 714 | | |||
715 | 715 | | |||
716 | RegularAreaRect* TextPage::findText( int searchID, const QString &query, SearchDirection direct, | 716 | RegularAreaRect* TextPage::findText( int searchID, const QString &query, SearchDirection direct, | ||
717 | Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *area ) | 717 | Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *area, | ||
718 | const bool wholeWords ) | ||||
718 | { | 719 | { | ||
719 | SearchDirection dir=direct; | 720 | SearchDirection dir=direct; | ||
720 | // invalid search request | 721 | // invalid search request | ||
721 | if ( d->m_words.isEmpty() || query.isEmpty() || ( area && area->isNull() ) ) | 722 | if ( d->m_words.isEmpty() || query.isEmpty() || ( area && area->isNull() ) ) | ||
722 | return nullptr; | 723 | return nullptr; | ||
723 | TextList::ConstIterator start; | 724 | TextList::ConstIterator start; | ||
724 | int start_offset = 0; | 725 | int start_offset = 0; | ||
725 | TextList::ConstIterator end; | 726 | TextList::ConstIterator end; | ||
Show All 33 Lines | 756 | case PreviousResult: | |||
759 | forward = false; | 760 | forward = false; | ||
760 | break; | 761 | break; | ||
761 | }; | 762 | }; | ||
762 | RegularAreaRect* ret = nullptr; | 763 | RegularAreaRect* ret = nullptr; | ||
763 | const TextComparisonFunction cmpFn = caseSensitivity == Qt::CaseSensitive | 764 | const TextComparisonFunction cmpFn = caseSensitivity == Qt::CaseSensitive | ||
764 | ? CaseSensitiveCmpFn : CaseInsensitiveCmpFn; | 765 | ? CaseSensitiveCmpFn : CaseInsensitiveCmpFn; | ||
765 | if ( forward ) | 766 | if ( forward ) | ||
766 | { | 767 | { | ||
767 | ret = d->findTextInternalForward( searchID, query, cmpFn, start, start_offset, end ); | 768 | ret = d->findTextInternalForward( searchID, query, cmpFn, start, start_offset, end, wholeWords ); | ||
768 | } | 769 | } | ||
769 | else | 770 | else | ||
770 | { | 771 | { | ||
771 | ret = d->findTextInternalBackward( searchID, query, cmpFn, start, start_offset, end ); | 772 | ret = d->findTextInternalBackward( searchID, query, cmpFn, start, start_offset, end, wholeWords ); | ||
772 | } | 773 | } | ||
773 | return ret; | 774 | return ret; | ||
774 | } | 775 | } | ||
776 | RegularAreaRect* TextPage::findText( int searchID, const QString &query, SearchDirection direct, | ||||
777 | Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *area ) | ||||
778 | { | ||||
779 | return findText( searchID, query, direct, caseSensitivity, area, false); | ||||
780 | } | ||||
775 | 781 | | |||
776 | // hyphenated '-' must be at the end of a word, so hyphenation means | 782 | // hyphenated '-' must be at the end of a word, so hyphenation means | ||
777 | // we have a '-' just followed by a '\n' character | 783 | // we have a '-' just followed by a '\n' character | ||
778 | // check if the string contains a '-' character | 784 | // check if the string contains a '-' character | ||
779 | // if the '-' is the last entry | 785 | // if the '-' is the last entry | ||
780 | static int stringLengthAdaptedWithHyphen(const QString &str, const TextList::ConstIterator &it, const TextList::ConstIterator &textListEnd) | 786 | static int stringLengthAdaptedWithHyphen(const QString &str, const TextList::ConstIterator &it, const TextList::ConstIterator &textListEnd) | ||
781 | { | 787 | { | ||
782 | int len = str.length(); | 788 | int len = str.length(); | ||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Line(s) | 839 | if (it == sp->it_end) { | |||
834 | break; | 840 | break; | ||
835 | } | 841 | } | ||
836 | } | 842 | } | ||
837 | 843 | | |||
838 | ret->simplify(); | 844 | ret->simplify(); | ||
839 | return ret; | 845 | return ret; | ||
840 | } | 846 | } | ||
841 | 847 | | |||
848 | // Checks if the word searched is whole | ||||
849 | | ||||
850 | bool TextPagePrivate::isWholeWord( const TextList::ConstIterator &start, | ||||
aacid: can this function be marked as const? seems like it could/should | |||||
851 | const TextList::ConstIterator &end, | ||||
852 | int start_offset, int end_offset) | ||||
853 | { | ||||
854 | // Divided in two parts, after the word and before | ||||
855 | bool part1 = false, part2 = false; | ||||
856 | | ||||
857 | // If I'm at the beginning/end of the text, I don't need to check after/before | ||||
yurchor: Typo: beggining -> beginning | |||||
858 | if( start == m_words.constBegin() && start_offset == 0) | ||||
aacid: add {} if you're going to have an else with {} | |||||
859 | part1 = true; | ||||
860 | | ||||
861 | else | ||||
862 | { | ||||
863 | // I have to check if it is the same textEntity | ||||
864 | TextList::ConstIterator before = start; | ||||
865 | if(start_offset != 0){ | ||||
866 | const TinyTextEntity* curEntity = *before; | ||||
867 | const QString& str = curEntity->text(); | ||||
868 | if( !str[start_offset-1].isLetterOrNumber() ) part1 = true; | ||||
869 | } | ||||
870 | // Else I check if the text before is a number or letter, if it isn't, a word begins here | ||||
871 | else{ | ||||
872 | before--; | ||||
873 | const TinyTextEntity* curEntity = *before; | ||||
874 | const QString& str = curEntity->text(); | ||||
875 | int len = stringLengthAdaptedWithHyphen( str, before, m_words.constEnd() ); | ||||
Make this const aacid: Make this const
Are we sure this is never going to be 0? I had a look at the… | |||||
Only if the tiny text entity is "-\n", I made it to see to make sure. joaonetto: Only if the tiny text entity is "-\n", I made it to see to make sure. | |||||
876 | if( !str[len-1].isLetterOrNumber() ) part1 = true; | ||||
877 | } | ||||
878 | } | ||||
879 | | ||||
880 | // For the end is a bit more complicated, some text entities can end at a \n, | ||||
881 | // and checking the next would get the first char in the next phrase. | ||||
882 | // So its checking this right here. | ||||
883 | TextList::ConstIterator after = end; | ||||
884 | const TinyTextEntity* endEntity = *after; | ||||
885 | const QString& endStr = endEntity->text(); | ||||
886 | | ||||
887 | int realEndStrSize = stringLengthAdaptedWithHyphen( endStr, after, m_words.constEnd() ); | ||||
aacid: const | |||||
888 | | ||||
889 | // I have to check if it's the same textEntity too, also check if ends with '\n' and if it does, it needs to be the last | ||||
890 | // char before \n | ||||
891 | if( (endStr.endsWith( QStringLiteral("\n")) && realEndStrSize == endStr.size() && end_offset == endStr.size() - 1) | ||||
892 | || (end_offset != endStr.size() && !endStr[end_offset].isLetterOrNumber()) ) | ||||
893 | part2 = true; | ||||
894 | | ||||
895 | // If it doesn't end in \n, I check the next char, as done in before. | ||||
896 | else if( end_offset == endStr.size() ) | ||||
897 | { | ||||
898 | after++; | ||||
899 | // Have to check if this is the end, because the end has no chars. | ||||
900 | if( after == m_words.constEnd() ) part2 = true; | ||||
901 | else | ||||
902 | { | ||||
903 | const TinyTextEntity* curEntity = *after; | ||||
904 | const QString& str = curEntity->text(); | ||||
905 | // Checking if the first char on the entity is a letter or number | ||||
906 | // Also check if it ends on -\n, if it does, should not match. | ||||
907 | if( !str[0].isLetterOrNumber() && !str.endsWith( (QStringLiteral("-\n")))) part2 = true; | ||||
908 | } | ||||
909 | } | ||||
910 | | ||||
911 | return part1 && part2; | ||||
912 | } | ||||
913 | | ||||
842 | RegularAreaRect* TextPagePrivate::findTextInternalForward( int searchID, const QString &_query, | 914 | RegularAreaRect* TextPagePrivate::findTextInternalForward( int searchID, const QString &_query, | ||
843 | TextComparisonFunction comparer, | 915 | TextComparisonFunction comparer, | ||
844 | const TextList::ConstIterator &start, | 916 | const TextList::ConstIterator &start, | ||
845 | int start_offset, | 917 | int start_offset, | ||
846 | const TextList::ConstIterator &end) | 918 | const TextList::ConstIterator &end, | ||
919 | bool wholeWords ) | ||||
847 | { | 920 | { | ||
848 | // normalize query search all unicode (including glyphs) | 921 | // normalize query search all unicode (including glyphs) | ||
849 | const QString query = _query.normalized(QString::NormalizationForm_KC); | 922 | const QString query = _query.normalized(QString::NormalizationForm_KC); | ||
850 | 923 | | |||
851 | // j is the current position in our query | 924 | // j is the current position in our query | ||
852 | // len is the length of the string in TextEntity | 925 | // len is the length of the string in TextEntity | ||
853 | // queryLeft is the length of the query we have left | 926 | // queryLeft is the length of the query we have left | ||
854 | int j=0, queryLeft=query.length(); | 927 | int j=0, queryLeft=query.length(); | ||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Line(s) | |||||
912 | #ifdef DEBUG_TEXTPAGE | 985 | #ifdef DEBUG_TEXTPAGE | ||
913 | qCDebug(OkularCoreDebug) << "\tmatched"; | 986 | qCDebug(OkularCoreDebug) << "\tmatched"; | ||
914 | #endif | 987 | #endif | ||
915 | j += min; | 988 | j += min; | ||
916 | queryLeft -= min; | 989 | queryLeft -= min; | ||
917 | 990 | | |||
918 | if (queryLeft==0) | 991 | if (queryLeft==0) | ||
919 | { | 992 | { | ||
993 | | ||||
994 | //If it's looking for whole words and this is not a whole word | ||||
995 | if(wholeWords && !isWholeWord(it_begin, it, offset_begin, offset + min)) | ||||
996 | { | ||||
997 | j = 0; | ||||
998 | queryLeft=query.length(); | ||||
aacid: spaces around = | |||||
999 | it = it_begin; | ||||
1000 | offset = offset_begin+1; | ||||
aacid: spaces around + | |||||
1001 | it_begin = TextList::ConstIterator(); | ||||
1002 | continue; | ||||
1003 | } | ||||
1004 | | ||||
1005 | else | ||||
1006 | { | ||||
920 | // save or update the search point for the current searchID | 1007 | // save or update the search point for the current searchID | ||
921 | QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | 1008 | QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | ||
922 | if ( sIt == m_searchPoints.end() ) | 1009 | if ( sIt == m_searchPoints.end() ) | ||
923 | { | 1010 | { | ||
924 | sIt = m_searchPoints.insert( searchID, new SearchPoint ); | 1011 | sIt = m_searchPoints.insert( searchID, new SearchPoint ); | ||
925 | } | 1012 | } | ||
926 | SearchPoint* sp = *sIt; | 1013 | SearchPoint* sp = *sIt; | ||
927 | sp->it_begin = it_begin; | 1014 | sp->it_begin = it_begin; | ||
928 | sp->it_end = it; | 1015 | sp->it_end = it; | ||
929 | sp->offset_begin = offset_begin; | 1016 | sp->offset_begin = offset_begin; | ||
930 | sp->offset_end = offset + min; | 1017 | sp->offset_end = offset + min; | ||
931 | return searchPointToArea(sp); | 1018 | return searchPointToArea(sp); | ||
932 | } | 1019 | } | ||
933 | 1020 | | |||
1021 | } | ||||
1022 | | ||||
934 | it++; | 1023 | it++; | ||
935 | offset = 0; | 1024 | offset = 0; | ||
936 | } | 1025 | } | ||
937 | } | 1026 | } | ||
938 | } | 1027 | } | ||
939 | // end of loop - it means that we've ended the textentities | 1028 | // end of loop - it means that we've ended the textentities | ||
940 | 1029 | | |||
941 | const QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | 1030 | const QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | ||
942 | if ( sIt != m_searchPoints.end() ) | 1031 | if ( sIt != m_searchPoints.end() ) | ||
943 | { | 1032 | { | ||
944 | SearchPoint* sp = *sIt; | 1033 | SearchPoint* sp = *sIt; | ||
945 | m_searchPoints.erase( sIt ); | 1034 | m_searchPoints.erase( sIt ); | ||
946 | delete sp; | 1035 | delete sp; | ||
947 | } | 1036 | } | ||
948 | return nullptr; | 1037 | return nullptr; | ||
949 | } | 1038 | } | ||
950 | 1039 | | |||
951 | RegularAreaRect* TextPagePrivate::findTextInternalBackward( int searchID, const QString &_query, | 1040 | RegularAreaRect* TextPagePrivate::findTextInternalForward( int searchID, const QString &_query, | ||
952 | TextComparisonFunction comparer, | 1041 | TextComparisonFunction comparer, | ||
953 | const TextList::ConstIterator &start, | 1042 | const TextList::ConstIterator &start, | ||
954 | int start_offset, | 1043 | int start_offset, | ||
955 | const TextList::ConstIterator &end) | 1044 | const TextList::ConstIterator &end ) | ||
956 | { | 1045 | { | ||
1046 | return findTextInternalForward(searchID, _query, comparer, start, start_offset, end, false); | ||||
1047 | } | ||||
1048 | | ||||
1049 | RegularAreaRect* TextPagePrivate::findTextInternalBackward( int searchID, const QString &_query, | ||||
1050 | TextComparisonFunction comparer, | ||||
1051 | const TextList::ConstIterator &start, | ||||
1052 | int start_offset, | ||||
1053 | const TextList::ConstIterator &end, | ||||
1054 | bool wholeWords ) | ||||
1055 | { | ||||
957 | // normalize query to search all unicode (including glyphs) | 1056 | // normalize query to search all unicode (including glyphs) | ||
958 | const QString query = _query.normalized(QString::NormalizationForm_KC); | 1057 | const QString query = _query.normalized(QString::NormalizationForm_KC); | ||
959 | 1058 | | |||
960 | // j is the current position in our query | 1059 | // j is the current position in our query | ||
961 | // len is the length of the string in TextEntity | 1060 | // len is the length of the string in TextEntity | ||
962 | // queryLeft is the length of the query we have left | 1061 | // queryLeft is the length of the query we have left | ||
963 | int j=query.length(), queryLeft=query.length(); | 1062 | int j=query.length(), queryLeft=query.length(); | ||
964 | 1063 | | |||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Line(s) | |||||
1030 | #ifdef DEBUG_TEXTPAGE | 1129 | #ifdef DEBUG_TEXTPAGE | ||
1031 | qCDebug(OkularCoreDebug) << "\tmatched"; | 1130 | qCDebug(OkularCoreDebug) << "\tmatched"; | ||
1032 | #endif | 1131 | #endif | ||
1033 | j -= min; | 1132 | j -= min; | ||
1034 | queryLeft -= min; | 1133 | queryLeft -= min; | ||
1035 | 1134 | | |||
1036 | if ( queryLeft == 0 ) | 1135 | if ( queryLeft == 0 ) | ||
1037 | { | 1136 | { | ||
1137 | | ||||
1138 | //If it's looking for whole words and this is not a whole word | ||||
1139 | if(wholeWords && !isWholeWord(it, it_begin, offset-min, offset_begin)) | ||||
1140 | { | ||||
1141 | j = query.length(); | ||||
1142 | queryLeft=query.length(); | ||||
1143 | it = it_begin; | ||||
1144 | offset = offset_begin-1; | ||||
1145 | it_begin = TextList::ConstIterator(); | ||||
1146 | continue; | ||||
1147 | } | ||||
1148 | else | ||||
1149 | { | ||||
1038 | // save or update the search point for the current searchID | 1150 | // save or update the search point for the current searchID | ||
1039 | QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | 1151 | QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | ||
1040 | if ( sIt == m_searchPoints.end() ) | 1152 | if ( sIt == m_searchPoints.end() ) | ||
1041 | { | 1153 | { | ||
1042 | sIt = m_searchPoints.insert( searchID, new SearchPoint ); | 1154 | sIt = m_searchPoints.insert( searchID, new SearchPoint ); | ||
1043 | } | 1155 | } | ||
1044 | SearchPoint* sp = *sIt; | 1156 | SearchPoint* sp = *sIt; | ||
1045 | sp->it_begin = it; | 1157 | sp->it_begin = it; | ||
1046 | sp->it_end = it_begin; | 1158 | sp->it_end = it_begin; | ||
1047 | sp->offset_begin = offset - min; | 1159 | sp->offset_begin = offset - min; | ||
1048 | sp->offset_end = offset_begin; | 1160 | sp->offset_end = offset_begin; | ||
1049 | return searchPointToArea(sp); | 1161 | return searchPointToArea(sp); | ||
1050 | } | 1162 | } | ||
1163 | } | ||||
1051 | 1164 | | |||
1052 | offset = 0; | 1165 | offset = 0; | ||
1053 | } | 1166 | } | ||
1054 | 1167 | | |||
1055 | } | 1168 | } | ||
1056 | 1169 | | |||
1057 | } | 1170 | } | ||
1058 | // end of loop - it means that we've ended the textentities | 1171 | // end of loop - it means that we've ended the textentities | ||
1059 | 1172 | | |||
1060 | const QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | 1173 | const QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); | ||
1061 | if ( sIt != m_searchPoints.end() ) | 1174 | if ( sIt != m_searchPoints.end() ) | ||
1062 | { | 1175 | { | ||
1063 | SearchPoint* sp = *sIt; | 1176 | SearchPoint* sp = *sIt; | ||
1064 | m_searchPoints.erase( sIt ); | 1177 | m_searchPoints.erase( sIt ); | ||
1065 | delete sp; | 1178 | delete sp; | ||
1066 | } | 1179 | } | ||
1067 | return nullptr; | 1180 | return nullptr; | ||
1068 | } | 1181 | } | ||
1069 | 1182 | | |||
1183 | RegularAreaRect * TextPagePrivate::findTextInternalBackward( int searchID, const QString &_query, | ||||
1184 | TextComparisonFunction comparer, | ||||
1185 | const TextList::ConstIterator &start, | ||||
1186 | int start_offset, | ||||
1187 | const TextList::ConstIterator &end ) | ||||
1188 | { | ||||
1189 | return findTextInternalBackward( searchID, _query, comparer, start, start_offset, end, false ); | ||||
1190 | } | ||||
1191 | | ||||
1070 | QString TextPage::text(const RegularAreaRect *area) const | 1192 | QString TextPage::text(const RegularAreaRect *area) const | ||
1071 | { | 1193 | { | ||
1072 | return text(area, AnyPixelTextAreaInclusionBehaviour); | 1194 | return text(area, AnyPixelTextAreaInclusionBehaviour); | ||
1073 | } | 1195 | } | ||
1074 | 1196 | | |||
1075 | QString TextPage::text(const RegularAreaRect *area, TextAreaInclusionBehaviour b) const | 1197 | QString TextPage::text(const RegularAreaRect *area, TextAreaInclusionBehaviour b) const | ||
1076 | { | 1198 | { | ||
1077 | if ( area && area->isNull() ) | 1199 | if ( area && area->isNull() ) | ||
▲ Show 20 Lines • Show All 961 Lines • Show Last 20 Lines |
can this function be marked as const? seems like it could/should