1 /* Copyright (C) 2004 J.F.Dockes 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License as published by 4 * the Free Software Foundation; either version 2 of the License, or 5 * (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the 14 * Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 */ 17 #ifndef _DOCSEQ_H_INCLUDED_ 18 #define _DOCSEQ_H_INCLUDED_ 19 20 #include "autoconfig.h" 21 22 #include <string> 23 #include <list> 24 #include <vector> 25 #include <mutex> 26 #include <memory> 27 28 #include "rcldoc.h" 29 #include "hldata.h" 30 31 // Need this for the "Snippet" class def. 32 #include "rclquery.h" 33 34 // A result list entry. 35 struct ResListEntry { 36 Rcl::Doc doc; 37 std::string subHeader; 38 }; 39 40 /** Sort specification. */ 41 class DocSeqSortSpec { 42 public: DocSeqSortSpec()43 DocSeqSortSpec() : desc(false) {} isNotNull()44 bool isNotNull() const {return !field.empty();} reset()45 void reset() {field.erase();} 46 std::string field; 47 bool desc; 48 }; 49 50 /** Filtering spec. This is only used to filter by doc category for now, hence 51 the rather specialized interface */ 52 class DocSeqFiltSpec { 53 public: DocSeqFiltSpec()54 DocSeqFiltSpec() {} 55 enum Crit {DSFS_MIMETYPE, DSFS_QLANG, DSFS_PASSALL}; orCrit(Crit crit,const std::string & value)56 void orCrit(Crit crit, const std::string& value) { 57 crits.push_back(crit); 58 values.push_back(value); 59 } 60 std::vector<Crit> crits; 61 std::vector<std::string> values; reset()62 void reset() {crits.clear(); values.clear();} isNotNull()63 bool isNotNull() const {return crits.size() != 0;} 64 }; 65 66 /** Interface for a list of documents coming from some source. 67 68 The result list display data may come from different sources (ie: 69 history or Db query), and be post-processed (DocSeqSorted). 70 Additional functionality like filtering/sorting can either be 71 obtained by stacking DocSequence objects (ie: sorting history), or 72 by native capability (ex: docseqdb can sort and filter). The 73 implementation might be nicer by using more sophisticated c++ with 74 multiple inheritance of sort and filter virtual interfaces, but 75 the current one will have to do for now. 76 */ 77 class DocSequence { 78 public: DocSequence(const std::string & t)79 DocSequence(const std::string &t) : m_title(t) {} ~DocSequence()80 virtual ~DocSequence() {} 81 82 /** Get document at given rank. 83 * 84 * @param num document rank in sequence 85 * @param doc return data 86 * @param sh subheader to display before this result (ie: date change 87 * inside history) 88 * @return true if ok, false for error or end of data 89 */ 90 virtual bool getDoc(int num, Rcl::Doc &doc, std::string *sh = 0) = 0; 91 92 /** Get next page of documents. This accumulates entries into the result 93 * list parameter (doesn't reset it). */ 94 virtual int getSeqSlice(int offs, int cnt, 95 std::vector<ResListEntry>& result); 96 97 /** Get abstract for document. This is special because it may take time. 98 * The default is to return the input doc's abstract fields, but some 99 * sequences can compute a better value (ie: docseqdb) */ getAbstract(Rcl::Doc & doc,std::vector<std::string> & abs)100 virtual bool getAbstract(Rcl::Doc& doc, std::vector<std::string>& abs) { 101 abs.push_back(doc.meta[Rcl::Doc::keyabs]); 102 return true; 103 } getAbstract(Rcl::Doc & doc,std::vector<Rcl::Snippet> & abs,int,bool)104 virtual bool getAbstract(Rcl::Doc& doc, std::vector<Rcl::Snippet>& abs, 105 int, bool) { 106 abs.push_back(Rcl::Snippet(0, doc.meta[Rcl::Doc::keyabs])); 107 return true; 108 } getFirstMatchPage(Rcl::Doc &,std::string &)109 virtual int getFirstMatchPage(Rcl::Doc&, std::string&) { 110 return -1; 111 } 112 /** Get duplicates. */ docDups(const Rcl::Doc &,std::vector<Rcl::Doc> &)113 virtual bool docDups(const Rcl::Doc&, std::vector<Rcl::Doc>&) { 114 return false; 115 } 116 117 /** For an embedded document: get the immediately enclosing doc 118 * (e.g., for an attachment, the message it is attached to. Only 119 * makes sense is ipath is not empty. */ 120 virtual bool getEnclosing(Rcl::Doc&, Rcl::Doc&); 121 122 /** Get estimated total count in results */ 123 virtual int getResCnt() = 0; 124 125 /** Get title for result list */ title()126 virtual std::string title() { 127 return m_title; 128 } 129 130 /** Can do snippets ? */ snippetsCapable()131 virtual bool snippetsCapable() { 132 return false; 133 } 134 /** Get description for underlying query */ 135 virtual std::string getDescription() = 0; 136 137 /** Get search terms (for highlighting abstracts). Some sequences 138 * may have no associated search terms. Implement this for them. */ getTerms(HighlightData & hld)139 virtual void getTerms(HighlightData& hld) { 140 hld.clear(); 141 } expand(Rcl::Doc &)142 virtual std::list<std::string> expand(Rcl::Doc &) { 143 return std::list<std::string>(); 144 } getReason()145 virtual std::string getReason() { 146 return m_reason; 147 } 148 /** Optional functionality. */ canFilter()149 virtual bool canFilter() {return false;} canSort()150 virtual bool canSort() {return false;} setFiltSpec(const DocSeqFiltSpec &)151 virtual bool setFiltSpec(const DocSeqFiltSpec &) {return false;} setSortSpec(const DocSeqSortSpec &)152 virtual bool setSortSpec(const DocSeqSortSpec &) {return false;} getSourceSeq()153 virtual std::shared_ptr<DocSequence> getSourceSeq() { 154 return std::shared_ptr<DocSequence>();} 155 set_translations(const std::string & sort,const std::string & filt)156 static void set_translations(const std::string& sort, 157 const std::string& filt) { 158 o_sort_trans = sort; 159 o_filt_trans = filt; 160 } 161 162 163 protected: 164 friend class DocSeqModifier; 165 virtual std::shared_ptr<Rcl::Db> getDb() = 0; 166 static std::mutex o_dblock; 167 static std::string o_sort_trans; 168 static std::string o_filt_trans; 169 std::string m_reason; 170 171 private: 172 std::string m_title; 173 }; 174 175 /** A modifier has a child sequence which does the real work and does 176 * something with the results. Some operations are just delegated 177 */ 178 class DocSeqModifier : public DocSequence { 179 public: DocSeqModifier(std::shared_ptr<DocSequence> iseq)180 DocSeqModifier(std::shared_ptr<DocSequence> iseq) 181 : DocSequence(""), m_seq(iseq) 182 {} ~DocSeqModifier()183 virtual ~DocSeqModifier() {} 184 getAbstract(Rcl::Doc & doc,std::vector<std::string> & abs)185 virtual bool getAbstract(Rcl::Doc& doc, std::vector<std::string>& abs) 186 override{ 187 if (!m_seq) 188 return false; 189 return m_seq->getAbstract(doc, abs); 190 } getAbstract(Rcl::Doc & doc,std::vector<Rcl::Snippet> & abs,int maxlen,bool bypage)191 virtual bool getAbstract(Rcl::Doc& doc, std::vector<Rcl::Snippet>& abs, 192 int maxlen, bool bypage) override { 193 if (!m_seq) 194 return false; 195 return m_seq->getAbstract(doc, abs, maxlen, bypage); 196 } 197 /** Get duplicates. */ docDups(const Rcl::Doc & doc,std::vector<Rcl::Doc> & dups)198 virtual bool docDups(const Rcl::Doc& doc, std::vector<Rcl::Doc>& dups) 199 override { 200 if (!m_seq) 201 return false; 202 return m_seq->docDups(doc, dups); 203 } 204 snippetsCapable()205 virtual bool snippetsCapable() override { 206 if (!m_seq) 207 return false; 208 return m_seq->snippetsCapable(); 209 } getDescription()210 virtual std::string getDescription() override { 211 if (!m_seq) 212 return ""; 213 return m_seq->getDescription(); 214 } getTerms(HighlightData & hld)215 virtual void getTerms(HighlightData& hld) override { 216 if (!m_seq) 217 return; 218 m_seq->getTerms(hld); 219 } getEnclosing(Rcl::Doc & doc,Rcl::Doc & pdoc)220 virtual bool getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc) override { 221 if (!m_seq) 222 return false; 223 return m_seq->getEnclosing(doc, pdoc); 224 } getReason()225 virtual std::string getReason() override { 226 if (!m_seq) 227 return string(); 228 return m_seq->getReason(); 229 } title()230 virtual std::string title() override { 231 return m_seq->title(); 232 } getSourceSeq()233 virtual std::shared_ptr<DocSequence> getSourceSeq() override { 234 return m_seq; 235 } 236 237 protected: getDb()238 virtual std::shared_ptr<Rcl::Db> getDb() override { 239 if (!m_seq) 240 return 0; 241 return m_seq->getDb(); 242 } 243 244 std::shared_ptr<DocSequence> m_seq; 245 }; 246 247 class RclConfig; 248 249 // A DocSource can juggle docseqs of different kinds to implement 250 // sorting and filtering in ways depending on the base seqs capabilities 251 class DocSource : public DocSeqModifier { 252 public: DocSource(RclConfig * config,std::shared_ptr<DocSequence> iseq)253 DocSource(RclConfig *config, std::shared_ptr<DocSequence> iseq) 254 : DocSeqModifier(iseq), m_config(config) 255 {} canFilter()256 virtual bool canFilter() override {return true;} canSort()257 virtual bool canSort() override {return true;} 258 virtual bool setFiltSpec(const DocSeqFiltSpec &) override; 259 virtual bool setSortSpec(const DocSeqSortSpec &) override; 260 virtual bool getDoc(int num, Rcl::Doc &doc, std::string *sh = 0) override { 261 if (!m_seq) 262 return false; 263 return m_seq->getDoc(num, doc, sh); 264 } getResCnt()265 virtual int getResCnt() override { 266 if (!m_seq) 267 return 0; 268 return m_seq->getResCnt(); 269 } 270 virtual std::string title() override; 271 private: 272 bool buildStack(); 273 void stripStack(); 274 RclConfig *m_config; 275 DocSeqFiltSpec m_fspec; 276 DocSeqSortSpec m_sspec; 277 }; 278 279 #endif /* _DOCSEQ_H_ */ 280